如何使用 LangChain + Ollama 实现本地 PDF 智能问答

背景介绍

市面上的 PDF 问答工具不少,但大多数需要将文档上传到云端处理。这带来了两个问题:首先,涉及敏感信息的文档不适合上传;其次,API 调用需要付费,长期使用成本不低。

Ollama 的出现改变了这一局面。它是一个开源的本地大模型运行框架,支持在个人电脑上运行各种开源 LLM,包括 Llama、Qwen、Mistral 等主流模型。结合 LangChain 的文档处理能力,我们可以在完全不依赖云服务的情况下,构建一个功能完整的 PDF 智能问答系统。

这篇文章将手把手教你如何搭建这个系统。所有代码都在本地运行,数据完全私密,而且除了 Ollama 之外不需要任何付费服务。

问题描述

在实际场景中,我们经常遇到以下挑战:

  • 一是文档数量多。一份上百页的技术文档,人工查找特定信息非常耗时。
  • 二是语义搜索困难。传统的全文搜索只能找到包含特定词汇的内容,无法理解”如何””为什么”这类问题的语义。
  • 三是隐私顾虑。公司内部文档、医疗记录、法律文件等敏感内容不适合上传到任何云服务。

基于 LangChain + Ollama 的本地 PDF 问答系统可以很好地解决这些问题。它允许用户用自然语言提问,系统会自动从 PDF 中定位相关内容并生成答案。整个过程完全离线,文档内容不会离开用户的电脑。

详细步骤

环境准备

首先需要安装 Ollama。访问 Ollama 官网下载对应系统的安装包。安装完成后,在终端中运行以下命令下载中文能力较强的 Qwen2.5 模型:

ollama pull qwen2.5:7b

这个模型有 7B 参数,在普通办公电脑上也能流畅运行。如果你的电脑配置较高,也可以选择 14B 或更大的版本,效果会更好。

接下来安装 Python 依赖。我们需要 LangChain、向量数据库、PDF 解析库等组件:

pip install langchain langchain-community langchain-huggingface faiss-cpu pypdf sentence-transformers ollama

这些包的作用分别是:langchain 提供问答链的核心框架;langchain-community 包含各种文档加载器和向量存储器;faiss-cpu 是 Facebook 开源的向量检索库;pypdf 用于解析 PDF 文件;ollama 则是连接本地大模型的桥梁。

核心代码实现

整个系统的架构分为三个部分:文档加载与分块、向量存储、问答检索。

第一步是加载 PDF 文档并进行处理。PDF 文档需要先被拆分成较小的文本块,每个块大约 500 到 1000 个字符。这样做的好处是向量表示更精确,检索结果更准确。

from langchain_community.document_loaders import PyPDFLoaderfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain_huggingface import HuggingFaceEmbeddingsfrom langchain_community.vectorstores import FAISSfrom langchain_community.chat_models import ChatOllamafrom langchain.chains import RetrievalQA# 1. 加载 PDF 文档pdf_path = "your_document.pdf"loader = PyPDFLoader(pdf_path)documents = loader.load()# 2. 拆分文本块text_splitter = RecursiveCharacterTextSplitter(    chunk_size=1000,    chunk_overlap=100)chunks = text_splitter.split_documents(documents)print(f"文档已拆分为 {len(chunks)} 个文本块")

文本分块是整个系统的基础。RecursiveCharacterTextSplitter 会递归地尝试按段落、句子、单词来拆分,尽量保持语义完整。chunk_overlap 参数设置相邻块之间的重叠字符数,这样可以避免在分块边界处切断连续的含义。

第二步是创建向量存储。文本块需要被转换为向量才能进行语义检索。我们使用开源的 sentence-transformers 模型来做嵌入:

# 3. 创建向量嵌入embeddings = HuggingFaceEmbeddings(    model_name="sentence-transformers/all-MiniLM-L6-v2")# 4. 构建向量数据库vectorstore = FAISS.from_documents(chunks, embeddings)# 保存向量数据库供后续使用vectorstore.save_local("faiss_index")print("向量数据库已保存")

这里使用的 all-MiniLM-L6-v2 是一个轻量级的嵌入模型,在效果和速度之间取得了很好的平衡。FAISS 是高效的向量检索库,可以在上百万个向量中快速找到最相似的几个。

第三步是构建问答系统。将向量检索和大模型连接起来,形成完整的问答链条:

# 5. 加载大模型llm = ChatOllama(    model="qwen2.5:7b",    temperature=0.7)# 6. 创建问答链qa_chain = RetrievalQA.from_chain_type(    llm=llm,    chain_type="stuff",    retriever=vectorstore.as_retriever(search_kwargs={"k": 3}),    return_source_documents=True)

RetrievalQA 是 LangChain 提供的问答链封装。它会先从向量数据库中检索出最相关的几个文本块,然后将问题和这些上下文一起发送给大模型。”stuff” 模式会把所有检索到的文档内容直接拼接送到模型的上下文窗口中。

现在可以开始问答了:

# 7. 提问query = "这份文档的核心观点是什么?"result = qa_chain({"query": query})print("问题:", query)print("
回答:", result["result"])print("
参考来源:")for i, doc in enumerate(result["source_documents"], 1):    print(f"{i}. {doc.metadata.get('source', '未知来源')} 第 {doc.metadata.get('page', '?')} 页")

运行结果

运行上述代码后,系统会输出类似以下结果:

文档已拆分为 156 个文本块向量数据库已保存问题: 这份文档的核心观点是什么?回答: 根据文档内容,核心观点是...(AI 生成的回答)参考来源:1. your_document.pdf 第 12 页2. your_document.pdf 第 15 页3. your_document.pdf 第 8 页

可以看到,系统不仅给出了答案,还标注了答案来自哪些页面。用户可以点击这些引用去查看原文细节。

对于一份 100 页的技术文档,从提问到获得答案通常只需要几秒钟。首次运行需要加载模型,可能需要等待十几秒。后续提问会快很多,因为模型已经驻留在内存中。

进阶优化

上面的代码是一个最小可行产品,实际使用中还可以进行多项优化。

  • 一是调整分块策略。不同类型的文档适合不同的分块方式。对于论文,可以按段落分块;对于书籍,可以按章节分块;对于表格较多的文档,可能需要专门的表格提取器。
  • 二是优化检索参数。可以通过调整 k 值(返回多少个相关文档)、添加过滤条件、使用混合搜索等方式提升检索质量。
  • 三是改用更强大的模型。如果电脑配置允许,可以尝试 qwen2.5:14b 或者混合专家模型 MoE,效果会有明显提升。
  • 四是添加流式输出。对于长回答,可���启��流式输出让用户提前看到部分答案,改善体验。
  • 五是支持多文档问答。可以把所有文档都放入同一个向量库,也可以按目录分组创建多个向量库实现跨文档检索。

总结

通过 LangChain + Ollama,我们可以在个人电脑上构建一个完全本地化的 PDF 智能问答系统。整个方案的优势在于:数据完全离线,保障隐私安全;无需付费 API,使用成本为零;响应速度快,交互体验流畅;定制灵活,可以根据具体需求调整。

这个系统特别适合需要处理大量技术文档的开发团队、研究人员,以及对数据隐私有要求的企业的内部使用。掌握了这项技能之后,你就拥有了一个随时可用的 AI 文档助手。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇