基于 LangChain 的 RAG(检索增强生成)

第一部分:导入模块

复制代码
from langchain_community.document_loaders import PyMuPDFLoader
from langchain_community.vectorstores import Chroma
from langchain_ollama import OllamaEmbeddings, ChatOllama
from langchain.indexes import VectorstoreIndexCreator

解析:

模块 作用
PyMuPDFLoader 用于加载 PDF 文件(基于 PyMuPDF,即 fitz 库)
Chroma 向量数据库,存储文本向量
OllamaEmbeddings 用于生成文本嵌入(embedding)的模型(如 qwen3-embedding)
ChatOllama 用于生成自然语言回答的大模型(如 qwen3:8b)
VectorstoreIndexCreator 自动化工具,简化"加载 → 分块 → 嵌入 → 存储"流程

第二部分:加载 PDF 并构建索引(方式1)

复制代码
from langchain_text_splitters import RecursiveCharacterTextSplitter

llm = ChatOllama(model="qwen3:8b")
pdf_loader = PyMuPDFLoader("docker_info.pdf")
pdf_pages = pdf_loader.load()

embed = OllamaEmbeddings(model="qwen3-embedding:0.6b")
text_splitter = RecursiveCharacterTextSplitter(
    separators=["\n\n", "\n", ". ", "? ", "! ", "; ", " ", '"'],
    chunk_size=50,
    chunk_overlap=10,
    length_function=len
)

inter_creator = VectorstoreIndexCreator(
    vectorstore_cls=Chroma,
    embedding=embed,
    text_splitter=text_splitter,
    vectorstore_kwargs={"persist_directory": "./test_db1"}
)

index = inter_creator.from_documents(pdf_pages)
res1 = index.query("Docker引擎主要有那两个版本", llm)
print(res1)

解析:

  1. 加载 PDF

    • PyMuPDFLoader("docker_info.pdf"):读取 PDF 内容。
    • load() 返回的是 Document 对象列表(每个页或段落是一个 Document)。
  2. 设置文本分块器

    • RecursiveCharacterTextSplitter:递归按字符分割文本。
    • 参数说明:
      • chunk_size=50:每块约 50 字符(中文),适合短句。
      • chunk_overlap=10:相邻块之间重叠 10 字符,避免断句。
      • separators:优先按换行、句号等切分。
  3. 创建向量化索引

    • VectorstoreIndexCreator 是一个自动化工具,整合了:
      • 分块
      • 嵌入
      • 存入 Chroma
    • persist_directory="./test_db1":持久化保存数据到本地磁盘,程序重启后仍可使用。
  4. 查询

    • index.query(...):调用 LLM + 检索,自动完成"检索 + 生成"。
    • 输出是 LLM 生成的回答。

注意:这种方式是 一键式流程,适合快速原型开发。


第三部分:手动构建 RAG 流程(方式2,推荐用于生产)

复制代码
from langchain.chains.retrieval_qa.base import RetrievalQA
from langchain_community.document_loaders import PyMuPDFLoader
from langchain_ollama import ChatOllama, OllamaEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 初始化模型
llm = ChatOllama(model="qwen3:8b")
embedding = OllamaEmbeddings(model="qwen3-embedding:0.6b")

# 加载 PDF
pdf_loader = PyMuPDFLoader("docker_info.pdf")
pdf_docs = pdf_loader.load()

# 关键步骤:分块!
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,        # 每块约 500 字符(中文)
    chunk_overlap=50,      # 块间重叠 50 字符,避免切断句子
    separators=["\n\n", "\n", ". ", "? ", "! ", "; ", " ", '"']
)
split_docs = text_splitter.split_documents(pdf_docs)  # 分块后的文档列表

# 创建向量库(使用分块后的文档)
db = Chroma.from_documents(split_docs, embedding=embedding)

# 构建 QA 链
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",  # 把检索结果拼接进 prompt
    retriever=db.as_retriever(search_kwargs={"k": 2}),  # 返回最相关的2个文档
    return_source_documents=True  # 可选:返回引用的原文
)

# 查询
result = qa_chain.invoke({"query": "2015年6月,Docker牵头成立了什么组织"})
print("回答:", result["result"])
print("\n引用来源:")
for doc in result["source_documents"]:
    print("-" * 50)
    print(doc.page_content[:200])

解析:

这是更 完整、可控、可调试 的 RAG 实现方式。

步骤详解:
  1. 初始化模型

    • llm: 大模型(qwen3:8b)用于生成答案。
    • embedding: 嵌入模型(qwen3-embedding:0.6b)用于向量化。
  2. 加载文档

    • PyMuPDFLoader 读取 PDF,得到原始 Document 列表。
  3. 分块(Chunking)

    • RecursiveCharacterTextSplitter 按规则切分文本。
    • 设置 chunk_size=500 更适合中文长句,避免切在中间。
    • chunk_overlap=50 保证上下文连贯。
  4. 构建向量库

    • Chroma.from_documents(...):将分块后的文档存入向量库。
    • 元数据(如页码、标题)会自动保留。
  5. 构建 QA 链

    • RetrievalQA 是标准 RAG 链。
    • chain_type="stuff":把所有检索到的文档内容拼接进 Prompt。
    • retriever.search_kwargs={"k": 2}:只取最相关的 2 个文档。
    • return_source_documents=True:返回原始文档内容,方便溯源。
  6. 查询与输出

    • 输入问题:"2015年6月,Docker牵头成立了什么组织?"
    • 输出:
      • 回答(LLM 生成)
      • 引用来源(原文片段)

总结对比

方式 特点 适用场景
VectorstoreIndexCreator 简单快捷,一键完成 快速原型、学习演示
手动构建 RAG 链 控制力强,可调试,支持复杂逻辑 生产环境、需要溯源、优化性能

建议与优化

  1. 调整 chunk_size

    • 中文建议 300~500 字符,避免句子被截断。
  2. 启用持久化

    复制代码
    db = Chroma.from_documents(..., persist_directory="./my_db")

    这样下次无需重新加载和分块。

  3. 增加过滤器

    • 可以通过 metadata 过滤特定章节或页码。
  4. 使用 rerankerhybrid search

    • 提升检索准确率。
  5. 部署为 API

    • 用 FastAPI + LangChain 封装成服务。
相关推荐
大模型RAG和Agent技术实践4 小时前
从零构建:基于 LangGraph 的医疗问诊智能体实战(完整源代码)
人工智能·langchain·agent·langgraph
3秒一个大7 小时前
LangChain 中的 Output 解析器与 Zod:用法与意义
javascript·langchain
kimi-22210 小时前
短期记忆中ChatMessageHistory()、 InMemoryChatMessageHistory()区别
langchain
SCBAiotAigc1 天前
langchain1.2学习笔记(一):安装langchain
人工智能·python·langchain
我想问问天1 天前
【从0到1大模型应用开发实战】02|用 LangChain 和本地大模型,完成第一次“可控对话
后端·langchain·aigc
韭菜炒大葱1 天前
LangChain 二:输出结果定制与历史管理能力详解
前端·langchain·openai
低调小一1 天前
LangChain 入门:把大模型“组装”成应用的那套乐高(5分钟用通义千问 + LCEL 跑通 Demo)
langchain
龙腾亚太1 天前
如何有效整合文本、图像等不同模态信息,提升模型跨模态理解与生成能力
langchain·多模态·dify·具身智能·智能体·vla
Coder_Boy_1 天前
基于SpringAI的智能平台基座开发-(五)
java·人工智能·spring boot·langchain·springai