乐于分享
好东西不私藏

AI Agent 开发 03 | LangChain RAG 实战

AI Agent 开发 03 | LangChain RAG 实战

模型知道莎士比亚,但不知道你的产品手册。RAG 就是给模型装上"外部知识库"的标准方案。这篇文章带你走完完整流程:从加载 PDF 到向量检索,最后让模型基于你自己的文档回答问题。

文档 → 切分 → 向量化 → 检索 → 生成,RAG 的完整链路

 做过 AI 客服的人都有这个经历:用户问了一个公司内部的问题,模型要么说"我不知道",要么开始瞎编。原因很简单,训练数据里没有你公司的产品手册。 

 最直接的想法是把文档整段塞进 Prompt。但一试就发现,手册稍微长一点(比如几十页),Prompt 就超出 Token 限制了。就算没超,把所有信息堆在一起,模型也分不清哪段是重点。 

 RAG(Retrieval-Augmented Generation,检索增强生成)就是标准解法[1]。流程分两步走:先把文档切碎存进知识库再根据用户的问题只找出相关片段交给模型。模型不需要读整本书,只需要看那几段相关的就够了。 

RAG 五步走

 LangChain 把 RAG 拆成五个步骤,每一步都有对应的组件: 

步骤组件说明
1 加载
Document Loaders
读取 PDF、Word、网页、数据库等 200+ 数据源
2 切分
Text Splitters
把长文档切成语义完整的小段,控制每段长度
3 向量化
Embeddings
将文本转换成向量,存进向量数据库
4 检索
Retriever
收到用户问题后,去向量库里找最相关的段落
5 生成
Chain + LLM
把检索结果和问题一起交给模型,生成最终回答

左边是硬塞所有文档,右边是 RAG 只检索相关段落

动手搭建 RAG 管道

1加载文档

 LangChain 提供了几十种 Document Loader[2]。最常用的是 PDF 和网页抓取。下面以加载一个 PDF 文件为例: 

Python - 加载 PDF
from langchain_community.document_loaders importPyPDFLoaderloader = PyPDFLoader("产品手册.pdf")docs = loader.load()print(f"共加载了 {len(docs)} 页")# docs 是 Document 对象列表,每个包含 page_content 和 metadata

Document 对象有两个字段:page_content 是文本内容,metadata 记录了来源信息(页码、文件名等),检索时可以用 meta 数据做过滤。 

2切分文档

 一整页 PDF 可能包含多个主题,直接整页做向量化会导致检索不准确。需要用 Text Splitter 把文档切成语义完整的片段。 

Python - 文本切分
from langchain.text_splitter importRecursiveCharacterTextSplittersplitter = RecursiveCharacterTextSplitter(chunk_size=500,chunk_overlap=50,)chunks = splitter.split_documents(docs)print(f"切分成 {len(chunks)} 个片段")

chunk_size 和 chunk_overlap 怎么设?chunk_size 是每个片段的字符数,常用 500-1000。chunk_overlap 是相邻片段之间的重叠字数(50-200),用来避免某个关键句恰好被切分线切到两段里。模型上下文越大,chunk_size 可以设得越大。

3向量化并存入数据库

 切好的片段需要转换成向量才能做语义搜索。LangChain 支持多种 Embedding 模型和向量数据库。下面用 OpenAI Embedding + FAISS[3](本地内存数据库)演示: 

Python - 构建向量索引
from langchain_openai importOpenAIEmbeddingsfrom langchain_community.vectorstores importFAISSembeddings = OpenAIEmbeddings()vectorstore = FAISS.from_documents(documents=chunks,embedding=embeddings,)# 保存到本地,下次直接加载不用重新计算vectorstore.save_local("faiss_index")

from_documents 一步完成了向量化和入库。保存到本地后,下次启动不用重新计算 Embedding,直接加载即可。 

4检索 + 生成

 前面三步是"建索引"(一次性工作),这一步是"问答"(每次用户提问时执行)。把检索器和模型串成一条 LCEL 管道: 

Python - RAG 问答链
from langchain_core.prompts importChatPromptTemplatefrom langchain_core.output_parsers importStrOutputParserfrom langchain_core.runnables importRunnablePassthroughretriever = vectorstore.as_retriever(search_kwargs={"k"5})template = ChatPromptTemplate.from_messages([    ("system""根据以下资料回答问题:\n{context}"),    ("human""{question}")])chain = ({"context": retriever, "question"RunnablePassthrough()}    | template    | model    | StrOutputParser)answer = chain.invoke("产品的退换货政策是什么?")print(answer)

 这段代码的核心是 {"context": retriever, "question": RunnablePassthrough()}。它的意思:用户的问题同时流向两个地方,原样传给模板(作为 question),以及传给检索器去查资料(结果作为 context)。模板把两者拼在一起送给模型,模型就有了上下文来回答。 

提升检索质量的高级技巧

 基础 RAG 已经能跑了,但生产环境中你会遇到两个问题:检索不准确(搜到的内容不相关)和信息过载(搜到太多无关内容干扰模型)。LangChain 提供了两个高级检索器来解决: 

基础检索 vs 多路召回 + 压缩,检索精度差距明显

MultiQueryRetriever,用户问一个问题,它自动生成多个不同角度的问法,分别去检索,最后汇总结果。比如用户问"怎么退款",它会同时搜"退货流程"、"取消订单"、"退款政策"等变体,覆盖率更高。

ContextualCompressionRetriever,先大范围检索,再用一个 LLM 或 Embedding 模型对结果做压缩和重排序,只保留与问题最相关的几段。适合文档片段本身很长、需要精炼的场景。

性能提示:FAISS 是内存数据库,适合原型开发和数据量较小的场景。生产环境建议用 Qdrant、Milvus 或 Pinecone 等独立部署的向量数据库,支持水平扩展和持久化。

总结

 RAG 的核心思路很朴素:不要让模型读整本书,只给它看相关的那几页。LangChain 把整个链路封装成了 5 步可组合的组件,核心代码不超过 20 行。

 加载 → 切分 → 向量化 → 检索 → 生成,每一步都有多种实现可选,你可以根据数据类型、查询场景和性能要求灵活组合。

参考资料

[1]
LangChain RAG 入门教程,https://python.langchain.com/docs/tutorials/rag/(2026 年 7 月)
[2]
LangChain Document Loaders 文档,https://python.langchain.com/docs/how_to/#document-loaders(2026 年 7 月)
[3]
FAISS 向量数据库文档,https://github.com/facebookresearch/faiss(2026 年 7 月)

墨羽鸿明 | AI Agent 开发专栏 | 原创文章