RAG基础原理与LangChain实战
本文系统介绍RAG(检索增强生成)的基础原理、核心工作流程,并通过LangChain 1.0实战演示如何构建完整的RAG系统,包括文档加载、切分、向量存储和混合检索。
关于作者
- 深耕领域:大语言模型开发 / RAG 知识库 / AI Agent 落地 / 模型微调
- 技术栈:Python | RAG (LangChain / Dify + Milvus) | FastAPI + Docker
- 工程能力:专注模型工程化部署、知识库构建与优化,擅长全流程解决方案
「让 AI 交互更智能,让技术落地更高效」
欢迎技术探讨与项目合作,解锁大模型与智能交互的无限可能!
RAG基础原理与LangChain实战
摘要:本文系统介绍RAG(检索增强生成)的基础原理、核心工作流程,并通过LangChain 1.0实战演示如何构建完整的RAG系统,包括文档加载、切分、向量存储和混合检索。
一、RAG基础概念
1.1 什么是RAG
RAG = Retrieval(检索) + Augmented(增强) + Generation(生成)
RAG即检索增强生成,为LLM提供了从某些数据源检索到的信息,并基于此修正生成的答案。RAG基本上是Search + LLM提示,可以通过大模型回答查询,并将搜索所找到的信息作为大模型的上下文。查询和检索到的上下文都会被注入到发送到LLM的提示语中。
1.2 RAG工作原理
一个简单完整的RAG系统工作流程:
用户进行提问后,问题会先去知识库里检索答案,检索到相似度最高的前N个答案,然后和用户的提问一起放入到Prompt里,交给大语言模型,大语言模型根据用户的提问和检索的知识进行整理总结,最终输出返回给用户结果。
1.3 为什么需要RAG
| 问题 | 传统LLM | RAG解决方案 |
|---|---|---|
| 知识时效性 | 训练数据有截止日期 | 实时检索最新信息 |
| 幻觉问题 | 可能编造不存在的信息 | 基于检索到的真实文档生成 |
| 领域专业性 | 通用知识,缺乏专业深度 | 接入专业领域知识库 |
| 可解释性 | 黑盒生成 | 可追溯检索来源 |
二、RAG核心工作流程
RAG系统的工作流程分为两个阶段:
2.1 阶段一:准备阶段(建立知识库)
这个过程就像是为一个庞大的图书馆建立一本详尽的电子目录。
具体步骤:
- 数据接入:收集各种文档(PDF、Word、网页等)
- 文档解析:提取文本内容
- 文档分割:将长文档切分成小片段
- 向量化:将文本转换为数学向量(Embedding)
- 存储:将向量存入专门的向量数据库
2.2 阶段二:问答阶段(智能应答)
当用户提出问题时,系统开始工作。
具体步骤:
- 用户提问:输入问题
- 问题向量化:将问题也转换成向量
- 相似度检索:在向量数据库中寻找最相关的文档片段
- 构建增强提示:将检索到的文档+原始问题组合成新的提示
- 生成答案:大语言模型基于增强后的提示生成最终答案
三、企业RAG核心应用场景
3.1 企业知识库与智能问答
场景描述:企业拥有大量内部文档(员工手册、产品文档、技术规范、会议纪要等),员工需要快速找到准确信息。
实际案例:
- 新员工入职培训问答(降低培训成本)
- 产品技术规格查询(文档分散在不同系统中)
- 公司政策咨询(提升搜索效率)
3.2 专业客服与技术支持
场景描述:为客户提供准确、一致的技术支持和问题解答。
RAG优势:
- 基于最新产品文档和解决方案库
- 提供标准化的准确回答
- 减少培训时间,提高处理效率
四、LangChain 1.0 RAG实战
4.1 环境准备
依赖安装:
pip install langchain langchain-community langchain-openai langchain-chroma faiss-cpu rank_bm25
模型加载:
from langchain_deepseek import ChatDeepSeek
from langchain_openai.embeddings import OpenAIEmbeddings
from dotenv import load_dotenv
# 加载环境变量
load_dotenv(override=True)
# 使用DeepSeek模型
model = ChatDeepSeek(model="deepseek-chat", temperature=0)
# 使用OpenAI嵌入模型
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
4.2 文档加载
LangChain支持多种文档加载器:
from langchain_community.document_loaders import TextLoader, Docx2txtLoader
# 读取文本文件
loader = TextLoader("sample_document.txt", encoding="utf-8")
documents = loader.load()
# 读取Word文档
# loader = Docx2txtLoader("document.docx")
# documents = loader.load()
print(f"文档内容预览:\n{documents[0].page_content[:500]}")
4.3 文档切分
为什么需要切分?
- 大模型有上下文长度限制
- 细粒度切分提高检索精度
- 避免无关信息干扰
RecursiveCharacterTextSplitter使用:
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 定义文档切分器
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 切分文本块大小
chunk_overlap=50, # 文本块重叠大小
separators=["\n\n", "\n", " ", ""] # 按照换行符、空格等符号进行切分
)
# 执行切分
texts = text_splitter.split_documents(documents)
print(f"分割后的文本块数量: {len(texts)}")
print(f"第一个文本块内容:\n{texts[0].page_content}")
参数说明:
| 参数 | 说明 | 建议值 |
|---|---|---|
chunk_size |
每个文本块的最大字符数 | 500-1000 |
chunk_overlap |
相邻文本块的重叠字符数 | 50-100 |
separators |
切分优先级顺序 | [“\n\n”, “\n”, " ", “”] |
4.4 向量存储与检索
4.4.1 创建向量存储(FAISS)
from langchain_community.vectorstores import FAISS
# 创建向量数据库
vector_store = FAISS.from_documents(texts, embeddings)
# 保存到本地
vector_store.save_local("faiss_index")
# 从本地加载
vector_store = FAISS.load_local(
"faiss_index",
embeddings,
allow_dangerous_deserialization=True
)
4.4.2 创建检索器
# 创建基础检索器
retriever = vector_store.as_retriever(
search_type="similarity", # 相似度搜索
search_kwargs={"k": 3} # 返回top3结果
)
# 执行检索
query = "LangChain的主要特性是什么?"
results = retriever.invoke(query)
for i, doc in enumerate(results):
print(f"结果{i+1}:\n{doc.page_content}\n")
4.5 混合检索(向量检索 + 关键词检索)
为什么需要混合检索?
- 向量检索:语义相似度高,但可能遗漏关键词匹配
- 关键词检索(BM25):精确匹配关键词,但缺乏语义理解
- 混合检索:结合两者优势,提高召回率和准确率
EnsembleRetriever实现:
from langchain_community.retrievers import BM25Retriever
from langchain_classic.retrievers import EnsembleRetriever
# 1. 创建BM25检索器(基于关键词)
bm25_retriever = BM25Retriever.from_documents(texts)
bm25_retriever.k = 3
# 2. 创建向量检索器(基于语义)
faiss_retriever = vector_store.as_retriever(
search_type="similarity",
search_kwargs={"k": 3}
)
# 3. 创建混合检索器
ensemble_retriever = EnsembleRetriever(
retrievers=[faiss_retriever, bm25_retriever],
weights=[0.5, 0.5] # 权重分配
)
# 执行混合检索
results = ensemble_retriever.invoke("LangChain RAG工作流程")
检索方式对比:
| 检索方式 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| 向量检索 | 语义理解强,容错性好 | 对特定关键词不敏感 | 开放式问题、语义搜索 |
| BM25检索 | 关键词匹配精确 | 缺乏语义理解 | 特定术语、精确匹配 |
| 混合检索 | 兼具语义和关键词优势 | 计算成本略高 | 生产环境推荐 |
五、完整RAG链构建
5.1 基础RAG链
from langchain.chains import RetrievalQA
# 创建RAG链
qa_chain = RetrievalQA.from_chain_type(
llm=model,
chain_type="stuff", # 将所有文档拼接
retriever=ensemble_retriever, # 使用混合检索器
return_source_documents=True # 返回源文档
)
# 执行问答
query = "LangChain 1.0有哪些改进?"
result = qa_chain.invoke({"query": query})
print(f"答案:{result['result']}")
print(f"\n参考来源:")
for doc in result['source_documents']:
print(f"- {doc.page_content[:100]}...")
5.2 自定义Prompt的RAG
from langchain.prompts import PromptTemplate
# 自定义Prompt模板
custom_prompt = PromptTemplate(
template="""基于以下上下文信息回答问题。如果上下文不包含答案,请说"我无法从提供的文档中找到答案"。
上下文:
{context}
问题:{question}
请提供详细且准确的回答:""",
input_variables=["context", "question"]
)
# 创建自定义RAG链
qa_chain = RetrievalQA.from_chain_type(
llm=model,
chain_type="stuff",
retriever=ensemble_retriever,
chain_type_kwargs={"prompt": custom_prompt}
)
六、敏感数据处理
6.1 分离存储策略
对于包含敏感信息的数据,建议单独存储:
# 敏感数据文档切分
sensitive_texts = text_splitter.split_documents(sensitive_documents)
# 创建敏感数据向量库
sensitive_vector_store = FAISS.from_documents(sensitive_texts, embeddings)
sensitive_vector_store.save_local("sensitive_faiss_index")
# 加载敏感数据检索器
sensitive_retriever = sensitive_vector_store.as_retriever(
search_kwargs={"k": 3}
)
6.2 权限控制
def get_retriever(user_role):
"""根据用户角色返回对应的检索器"""
if user_role == "admin":
# 管理员可以访问所有数据
return ensemble_retriever
else:
# 普通用户只能访问公开数据
return public_retriever
七、总结
| 主题 | 核心内容 |
|---|---|
| RAG基础 | Retrieval + Augmented + Generation,解决知识时效性和幻觉问题 |
| 工作流程 | 准备阶段(文档处理+向量化)+ 问答阶段(检索+生成) |
| LangChain实战 | 文档加载、RecursiveCharacterTextSplitter切分、FAISS向量存储 |
| 混合检索 | EnsembleRetriever结合向量检索和BM25关键词检索 |
| 最佳实践 | 敏感数据分离存储、自定义Prompt、权限控制 |
通过本文介绍的基础RAG流程,开发者可以构建一个功能完整的检索增强生成系统。在下一篇文章中,我们将探讨更高级的Agentic RAG架构,让RAG系统具备自主规划和迭代优化的能力。
参考资源
- LangChain RAG文档:https://python.langchain.com/docs/use_cases/question_answering/
- FAISS官方文档:https://github.com/facebookresearch/faiss
- BM25算法详解:https://en.wikipedia.org/wiki/Okapi_BM25
更多推荐




所有评论(0)