一、前言
最近系统学习了 LangChain 最新版本 RAG 检索增强生成 技术,从零实现了一套「PDF 本地知识库问答系统」。
本次实战我完全使用 新版 LangChain(0.3+),摒弃网上大量过时教程,解决了大量新版本兼容报错、模型下载卡死、向量检索失效、Prompt 不生效等经典问题。
本文记录我今日完整学习成果:PDF解析 → 文本分块 → BGE 向量化 → Chroma 向量数据库 → 自定义Prompt → 大模型问答 全套链路。
二、项目技术栈
PDF解析:pymupdf(新版fitz)
文本切分:RecursiveCharacterTextSplitter 智能中文分块
嵌入模型:BAAI/bge-small-zh-v1.5(最强开源中文Embedding模型)
向量数据库:Chroma(langchain-chroma 新版独立包)
大模型调用:通义千问 DashScope 兼容 OpenAI 接口
问答链路:RetrievalQA 经典RAG链路(适配新版LangChain)
三、RAG核心原理简述
RAG(检索增强生成)解决的是大模型幻觉、知识滞后、私有数据无法问答的问题。
整体流程:
文档解析:读取本地PDF全文
文本分块:长文本切分成适合向量检索的小块
文本向量化:BGE模型将文本转为向量
向量入库:存入Chroma向量数据库
语义检索:用户问题向量匹配最相似文档块
大模型生成:根据检索到的真实文档,严格依据上下文回答
四、今日重点踩坑总结(全网最实用)
本次实战最大的收获不是代码,而是 新版LangChain 各种坑的彻底解决:
1. langchain-community 弃用警告 #674
新版 LangChain 彻底拆分包,Chroma 不再属于 community,必须安装独立包:langchain-chroma,否则持续警告、未来直接报错。
2. HuggingFace 模型下载卡死 / 401 报错
很多人混淆模型仓库:
❌ 错误:sentence-transformers/bge-small-zh-v1.5(401无权限)
✅ 正确:BAAI/bge-small-zh-v1.5
同时必须配置国内镜像或代理,否则 Python 进程无法下载模型。
3. BGE模型必须开启归一化
BGE系列模型官方要求:normalize_embeddings=True
关闭归一化会导致向量相似度错乱,检索完全失效!
4. 文本分块过小导致RAG回答“不知道”
最初我设置 chunk_size=50,文本被切得支离破碎,语义断裂,检索召回残缺片段,LLM 直接触发兜底话术。
✅ 修正:中文最佳参数 chunk_size=600,chunk_overlap=120
5. RetrievalQA 新版调用方式变更
废弃 qa_chain({}),必须使用 qa_chain.invoke({})
6. 自定义Prompt不生效问题
必须在 RetrievalQA 传入 chain_type_kwargs={"prompt": prompt},否则永远使用系统默认提示词,自定义规则完全失效。
五、完整可运行工程代码
以下是我今日最终调试通过、无报错、检索精准的完整代码:
import os
import pymupdf
from langchain_chroma import Chroma
from langchain_core.documents import Document
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_classic.chains.retrieval_qa.base import RetrievalQA
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate
from dotenv import load_dotenv
load_dotenv() # 读取项目下的.env文件
def extract_text_pdf(pdf, start=1, end=None):
'''加载pdf文件的内容'''
text = ''
page_numbers = []
for pn, page in enumerate(pdf):
if pn < start: # 跳过前几页
continue
if end is not None and pn == end: # 控制读取的页数
break
extract_text = page.get_text("text")
if extract_text:
text += extract_text
page_numbers.extend([pn] * len(extract_text.split('\n')))
return text, page_numbers
# 线上加载BGE中文嵌入模型(新版标准写法)
embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh-v1.5",
model_kwargs={'device': 'cpu'},
encode_kwargs={'normalize_embeddings': True} # BGE必须开启归一化
)
print("✅线上模型加载完成")
# 通义千问大模型初始化(兼容OpenAI接口)
llm = ChatOpenAI(
model=os.getenv("DASHSCOPE_MODEL"),
base_url=os.getenv("DASHSCOPE_BASE_URL"),
api_key=os.getenv("DASHSCOPE_API_KEY"),
temperature=0,
)
# 自定义RAG提示词(严格限制只能根据文档回答)
prompt_template = '''
你是一个问答机器人。
你的任务是根据下述给定的已知信息回答用户问题。
已知信息:
{context} # 检索出来的原始文档
用户问题:
{question} # 用户的问题
如果已知信息中不包含用户问题的答案,或者已知信息无法回答用户问题,请直接返回"俺不知道!你找别的人吧!"。
请不要输出已知信息中不包含的信息或者答案。
请用中文回答用户问题。
'''
prompt = PromptTemplate(
template=prompt_template,
input_variables=["context", "question"]
)
if __name__ == "__main__":
# 1.读取PDF
pdf = pymupdf.open('43-显存优化策略篇.pdf')
text, page_numbers = extract_text_pdf(pdf)
# 2.封装文档对象
documents = [Document(page_content=text,
metadata={'source': '43-显存优化策略篇.pdf'})]
# 3.中文智能分块(最优参数)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=600,
chunk_overlap=120,
separators=["\n\n", "\n", "。", ",", "!", "?"]
)
splits = text_splitter.split_documents(documents)
print(f"分块总数量:{len(splits)}")
# 4.向量化并入库
db = Chroma.from_documents(
documents=splits,
embedding=embeddings,
persist_directory="./chroma_db4"
)
# 5.构建RAG问答链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=db.as_retriever(search_kwargs={"k": 3}),
return_source_documents=True,
chain_type_kwargs={'prompt': prompt}
)
# 6.提问测试
query = "介绍一下 gradient checkpointing 显存优化方式?"
result = qa_chain.invoke({'query': query})
print('答案: ', result['result'])
# 打印检索上下文,用于调试
print("\n=======召回的文档片段======")
for idx, doc in enumerate(result["source_documents"]):
print(f"【片段{idx}】\n{doc.page_content}\n")
六、核心代码解析
1. PDF文本解析
使用 pymupdf 替代废弃的 fitz,逐页提取文本,支持自定义跳过前页、截止页,适配教程PDF、书籍PDF。
2. BGE嵌入模型加载
采用工业级中文向量模型 bge-small-zh-v1.5,开启归一化,保证语义相似度计算精准。
3. 文本分块策略
针对中文句号、逗号、换行进行切割,配合重叠分块,解决知识点被切割断裂问题,是RAG效果好坏的核心关键。
4. 自定义Prompt约束
强制模型只能基于检索到的文档回答,无对应知识直接兜底回复,彻底杜绝大模型幻觉。
5. 多路检索增强
设置 k=3,一次召回3条相似文本,丰富上下文,大幅提升问答准确率。
七、最终效果
✅ 成功解析 PDF 显存优化技术文档
✅ 精准召回 gradient checkpointing 梯度检查点原理文档
✅ 严格依据文档内容回答,无幻觉
✅ 未知问题自动兜底,符合预期
✅ 完全适配最新 LangChain 版本,无弃用报错
八、学习总结
本次实战让我彻底吃透了 新版LangChain RAG 完整落地流程,不再被过时教程误导。
RAG 项目效果好坏,模型权重占20%,文本分块+检索策略+Prompt工程占80%。
后续可以继续扩展:
自动判断向量库是否存在,避免重复入库
接入本地 Ollama 开源大模型,完全离线部署
实现对话记忆、多轮问答
支持多PDF文件知识库
九、环境依赖安装命令
pip install langchain langchain-core langchain-text-splitters langchain-community langchain-chroma langchain-huggingface langchain-classic chromadb pymupdf sentence-transformers transformers torch python-dotenv langchain-openai