如何使用LangChain 构建 RAG 应用
Langchain构建RAG(Retrieval Augmented Generation)
LangChain 构建 RAG 应用学习笔记
最近在学习和实践 LangChain 构建 RAG 应用,整理了一份学习笔记,内容包括 RAG 核心概念、LangChain 组件体系、实战项目以及一些经验总结。
一、RAG 技术概述
1.1 什么是 RAG
RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合检索系统与生成模型的技术架构。其核心流程是:用户提问 → 检索相关文档 → 将文档与问题组合 → LLM 生成答案。
1.2 RAG 的优势
RAG 技术具有以下显著优势:
- 知识时效性:可接入最新文档数据,解决 LLM 知识截止问题
- 可解释性:答案来源于检索文档,便于追溯和验证
- 成本效益:更新知识无需重新训练模型,降低维护成本
- 减少幻觉:基于检索内容生成,降低 LLM 胡编乱造的风险
1.3 RAG 流程图
用户提问 → 向量检索 → 上下文组装 → LLM 生成 → 最终回答
二、LangChain 核心组件详解
LangChain 将 RAG 流程拆解为多个独立模块,主要包括以下组件:
2.1 文档加载器(Document Loader)
LangChain 支持多种文档格式的加载:
from langchain_community.document_loaders import TextLoader, PyPDFLoader, WebBaseLoader
# 文本文件加载
loader = TextLoader("document.txt")
docs = loader.load()
# PDF 文件加载
loader = PyPDFLoader("document.pdf")
docs = loader.load()
# 网页内容加载
loader = WebBaseLoader("https://example.com/article")
docs = loader.load()
提示:文件较多时,可使用 DirectoryLoader 一次性处理整个目录。
2.2 文本分割器(Text Splitter)
长文档需要切割成小块以适应向量检索和 LLM 上下文限制:
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每段字符数
chunk_overlap=50, # 相邻段重叠字符数
length_function=len
)
chunks = splitter.split_documents(docs)
参数设置建议:
chunk_size:推荐 500-1000 字符,过大会降低检索精度,过小会丢失上下文chunk_overlap:建议设为 chunk_size 的 10-20%,保证语义连贯
2.3 嵌入模型(Embedding)
文本向量化是计算语义相似度的基础:
from langchain_community.embeddings import OpenAIEmbeddings, HuggingFaceEmbeddings
# OpenAI 方案
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")
# 本地方案
embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-MiniLM-L6-v2"
)
选型建议:
- 正式项目推荐使用 OpenAI Embedding,效果更好
- 数据敏感场景可使用 HuggingFace 本地模型
2.4 向量数据库(Vector Store)
存储向量并支持高效相似度检索:
from langchain_community.vectorstores import Chroma, FAISS
# Chroma:轻量级,适合原型开发
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
# FAISS:高性能,适合大规模数据
vectorstore = FAISS.from_documents(
documents=chunks,
embedding=embeddings
)
vectorstore.save_local("./faiss_index")
向量数据库对比:
| 数据库 | 特点 | 适用场景 |
|---|---|---|
| Chroma | 轻量、易用 | 原型开发、小规模数据 |
| FAISS | 高性能、多索引 | 大规模数据、实时检索 |
| Milvus | 分布式、可扩展 | 企业级应用 |
| Pinecone | 云原生、托管服务 | 不想管理基础设施 |
2.5 检索器(Retriever)
从向量库中检索相关文档:
# 基础相似度检索
retriever = vectorstore.as_retriever(
search_kwargs={"k": 3} # 返回最相关的3个文档
)
# MMR 策略:增加结果多样性
retriever = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={"k": 3, "fetch_k": 10}
)
MMR(最大边际相关性):先从数据库取出多个候选,再选择多样性结果,避免返回内容过于相似。
2.6 问答链(Chain)
组装各组件形成完整 RAG 流程:
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # 将文档拼接到 prompt
retriever=retriever,
return_source_documents=True # 返回源文档
)
result = qa_chain({"query": "RAG 是什么?"})
chain_type 类型说明:
stuff:将所有文档拼接到一起,简单高效,文档多时可能超出上下文refine:迭代优化答案,适合处理长文档map_reduce:分别处理后合并,适合大量检索结果
三、实战项目:构建完整 RAG 应用
3.1 项目结构
rag_app/
├── main.py # 主程序
├── requirements.txt # 依赖
└── docs/ # 知识库文档
├── intro.txt
└── guide.txt
3.2 完整代码实现
import os
from langchain_community.document_loaders import TextLoader
from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
class RAGApp:
def __init__(self, docs_path):
self.docs_path = docs_path
self.embeddings = OpenAIEmbeddings()
# 加载并处理文档
docs = self._load_docs()
chunks = self._split_docs(docs)
# 构建向量索引
self.vectorstore = Chroma.from_documents(
documents=chunks,
embedding=self.embeddings,
persist_directory="./chroma_db"
)
# 初始化 LLM 和检索链
self.llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
self.qa_chain = RetrievalQA.from_chain_type(
llm=self.llm,
chain_type="stuff",
retriever=self.vectorstore.as_retriever(search_kwargs={"k": 3}),
return_source_documents=True
)
def _load_docs(self):
docs = []
for fname in os.listdir(self.docs_path):
if fname.endswith('.txt'):
path = os.path.join(self.docs_path, fname)
loader = TextLoader(path)
docs.extend(loader.load())
return docs
def _split_docs(self, docs):
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50
)
return splitter.split_documents(docs)
def ask(self, question):
result = self.qa_chain({"query": question})
return {
"answer": result["result"],
"sources": [doc.page_content for doc in result["source_documents"]]
}
if __name__ == "__main__":
app = RAGApp("./docs")
while True:
q = input("\n请输入问题(quit 退出): ").strip()
if q.lower() == 'quit':
break
if not q:
continue
res = app.ask(q)
print("\n回答:", res["answer"])
print("\n参考来源:")
for i, src in enumerate(res["sources"], 1):
print(f" {i}. {src[:150]}...")
3.3 依赖配置
# requirements.txt
langchain
langchain-community
langchain-openai
chromadb
openai
安装依赖:pip install -r requirements.txt
四、高级技巧与最佳实践
4.1 检索策略优化
问题:单独使用向量检索对专有名词、缩写等识别不准确。
解决方案:使用 Ensemble Retriever 结合多种检索方法。
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
# 向量检索 + BM25 关键词检索
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
bm25_retriever = BM25Retriever.from_documents(chunks)
ensemble = EnsembleRetriever(
retrievers=[vector_retriever, bm25_retriever],
weights=[0.5, 0.5]
)
4.2 自定义提示词模板
根据实际需求调整提示词:
from langchain.prompts import PromptTemplate
template = """基于以下参考资料回答问题。如果找不到相关信息,请如实说明。
参考内容:
{context}
问题: {question}
回答:"""
prompt = PromptTemplate(
template=template,
input_variables=["context", "question"]
)
4.3 常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 答案重复 | chunk_overlap 太小 | 增大 chunk_overlap |
| 答非所问 | chunk_size 太小或 k 值不合适 | 调整参数或增加检索数量 |
| 检索不准确 | Embedding 模型不匹配 | 更换或微调 Embedding |
4.4 调试方法
- 设置
return_source_documents=True查看实际检索到的文档 - 检查文档是否正确加载
- 验证切分方式是否符合预期
五、生产环境部署注意事项
5.1 性能优化
- 选择高效的向量索引类型(如 FAISS 的 IndexIVFFlat)
- 对 Embedding 结果进行缓存,避免重复计算
- 考虑使用异步处理提升并发能力
5.2 安全考虑
- API Key 通过环境变量管理,禁止硬编码
- 对用户输入进行校验,防止注入攻击
- 控制输入长度,避免资源耗尽
5.3 监控与日志
建议记录以下信息:
- 查询内容和响应时间
- 检索到的文档信息
- 异常情况和错误日志
六、总结
本文系统介绍了使用 LangChain 构建 RAG 应用的核心知识点:
- RAG 原理:检索增强生成的基本流程和优势
- 组件体系:文档加载、分割、嵌入、存储、检索、生成的完整链路
- 实战项目:从零构建完整的 RAG 应用
- 优化技巧:检索策略、提示词调整、问题排查
- 生产部署:性能、安全、监控要点
后续学习方向:
- 向量数据库索引算法优化
- RAG 系统性能评估方法
- 多模态 RAG(支持图片、音频等)
- Agent 与 RAG 的结合应用
如果有问题或建议,欢迎在评论区交流。
4.1 检索策略优化
问题:单独使用向量检索对专有名词、缩写等识别不准确。
解决方案:使用 Ensemble Retriever 结合多种检索方法。
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
# 向量检索 + BM25 关键词检索
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
bm25_retriever = BM25Retriever.from_documents(chunks)
ensemble = EnsembleRetriever(
retrievers=[vector_retriever, bm25_retriever],
weights=[0.5, 0.5]
)
4.2 自定义提示词模板
根据实际需求调整提示词:
from langchain.prompts import PromptTemplate
template = """基于以下参考资料回答问题。如果找不到相关信息,请如实说明。
参考内容:
{context}
问题: {question}
回答:"""
prompt = PromptTemplate(
template=template,
input_variables=["context", "question"]
)
4.3 常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 答案重复 | chunk_overlap 太小 | 增大 chunk_overlap |
| 答非所问 | chunk_size 太小或 k 值不合适 | 调整参数或增加检索数量 |
| 检索不准确 | Embedding 模型不匹配 | 更换或微调 Embedding |
4.4 调试方法
- 设置
return_source_documents=True查看实际检索到的文档 - 检查文档是否正确加载
- 验证切分方式是否符合预期
五、生产环境部署注意事项
5.1 性能优化
- 选择高效的向量索引类型(如 FAISS 的 IndexIVFFlat)
- 对 Embedding 结果进行缓存,避免重复计算
- 考虑使用异步处理提升并发能力
5.2 安全考虑
- API Key 通过环境变量管理,禁止硬编码
- 对用户输入进行校验,防止注入攻击
- 控制输入长度,避免资源耗尽
5.3 监控与日志
建议记录以下信息:
- 查询内容和响应时间
- 检索到的文档信息
- 异常情况和错误日志
六、总结
本文系统介绍了使用 LangChain 构建 RAG 应用的核心知识点:
- RAG 原理:检索增强生成的基本流程和优势
- 组件体系:文档加载、分割、嵌入、存储、检索、生成的完整链路
- 实战项目:从零构建完整的 RAG 应用
- 优化技巧:检索策略、提示词调整、问题排查
- 生产部署:性能、安全、监控要点
后续学习方向:
- 向量数据库索引算法优化
- RAG 系统性能评估方法
- 多模态 RAG(支持图片、音频等)
- Agent 与 RAG 的结合应用
如果有问题或建议,欢迎在评论区交流。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)