构建智能问答系统:从零开始实现 RAG 应用
1. 什么是 RAG?
RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合信息检索与文本生成的技术,旨在提升大型语言模型(LLM)在特定领域或私有数据上的表现。其核心流程分为两部分:
- Indexing(索引):将源数据(如文档、网页内容)加载、拆分并存储为向量数据库。
- Retrieval & Generation(检索与生成):在运行时根据用户查询从数据库中检索相关片段,并通过 LLM 生成答案。
RAG 的优势在于:
- 动态更新知识:无需重新训练模型即可利用最新数据。
- 减少幻觉:通过外部数据验证,避免模型生成错误信息。
- 适应特定场景:适用于企业知识库、学术研究、客服系统等场景。
2. RAG 的典型架构
一个完整的 RAG 应用通常包含以下组件:
- 数据加载与预处理
- Document Loaders:加载原始数据(如 PDF、网页、文本文件)。
- Text Splitters:将长文档拆分为小块(Chunks),便于检索和模型处理。
- 向量存储与检索
- VectorStore:将文本块嵌入为向量并存储(如 Chroma、FAISS)。
- Retriever:根据用户查询检索最相关的文档片段。
- 生成答案
- Prompt Template:将检索结果与用户问题结合,构造输入提示。
- LLM:生成最终答案。
3. 实现 RAG 应用的完整流程
以下通过代码示例逐步演示如何构建一个基于 RAG 的问答系统。
步骤 1:环境准备
安装 LangChain 及相关依赖:
pip install langchain langchain-text-splitters langchain-community langgraph langchain-chroma
步骤 2:加载并预处理数据
从网页加载内容并拆分文本:
from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter# 加载网页内容
loader = WebBaseLoader(web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),bs_kwargs=dict(parse_only=bs4.SoupStrainer(class_=("post-content", "post-title", "post-header")))
)
docs = loader.load()# 拆分文本为小块
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
all_splits = text_splitter.split_documents(docs)
步骤 3:构建向量数据库
使用 Chroma 存储文本块的向量表示:
# 初始化嵌入模型(需通义千问API-KEY)
from langchain_community.embeddings import DashScopeEmbeddings# 初始化嵌入模型
embed_model = DashScopeEmbeddings(model="text-embedding-v2",dashscope_api_key="sk-712a634dbaa7444d838d20b25eb938xx"
)# 构建向量数据库
from langchain_chroma import Chromavector_store = Chroma(collection_name="example_collection",embedding_function=embed_model,persist_directory="./chroma_langchain_db", # Where to save data locally, remove if not necessary
)
步骤 4:定义检索与生成逻辑
使用 LangGraph 编排流程,并通过 LLM 生成答案:
from langchain.chat_models import init_chat_model
from langchain_core.prompts import PromptTemplate
from langgraph.graph import StateGraph, START
from typing_extensions import TypedDict, List
from langchain_openai import ChatOpenAI# 初始化 LLM(以 OpenAI 为例)
llm = ChatOpenAI(model="deepseek-chat",api_key="sk-e3f022d1746f415c9b0f4bc9a52a43xx", # todo 替换deepseek API Key https://platform.deepseek.com/api_keystemperature=0.7,max_tokens=512,timeout=30,max_retries=3,base_url="https://api.deepseek.com"
)# 定义状态结构
class State(TypedDict):question: strcontext: List[Document]answer: str# 检索函数
def retrieve(state: State):retrieved_docs = vector_store.similarity_search(state["question"])return {"context": retrieved_docs}# 生成函数
def generate(state: State):docs_content = "\n\n".join(doc.page_content for doc in state["context"])prompt = PromptTemplate.from_template("Question: {question}\nContext: {context}\nAnswer:")messages = prompt.invoke({"question": state["question"], "context": docs_content})response = llm.invoke(messages)return {"answer": response.content}# 构建流程图
graph_builder = StateGraph(State)
graph_builder.add_edge(START, "retrieve")
graph_builder.add_sequence([retrieve, generate])
graph = graph_builder.compile()
步骤 5:测试 RAG 应用
运行流程并验证输出:
response = graph.invoke({"question": "What is Task Decomposition?"})
print(response["answer"])
示例输出:
4. 关键技术点解析
-
文本拆分策略
- 使用
RecursiveCharacterTextSplitter
按字符递归拆分,确保上下文连贯性。 - 调整
chunk_size
和chunk_overlap
以平衡检索效果与模型输入限制。
- 使用
-
向量数据库优化
- 选择适合的嵌入模型(如
text-embedding-3-large
)提升检索精度。 - 持久化存储数据(如
./chroma_langchain_db
)以便后续扩展。
- 选择适合的嵌入模型(如
-
Prompt 设计
- 通过模板将检索结果与用户问题结合,引导 LLM 生成更准确的答案。
- 可尝试不同的 Prompt 结构(如 Chain-of-Thought)优化生成效果。
5. 扩展与进阶方向
- 支持对话式交互:在 Part 2 中,将 RAG 扩展为支持多轮对话的系统。
- 多阶段检索:结合
map_reduce
或refine
等链式结构处理复杂查询。 - 性能优化:通过缓存机制减少重复计算,或使用本地部署模型降低 API 成本。
- 监控与调试:集成 LangSmith 追踪流程,分析各环节性能瓶颈。
6. 应用场景与案例
-
企业知识库问答
- 场景:员工快速检索公司政策、产品手册。
- 实现:将内部文档构建为向量数据库,结合 RAG 提供实时答案。
-
学术研究辅助
- 场景:研究人员快速获取论文关键结论。
- 实现:从论文数据库中检索相关段落,生成摘要。
-
个性化推荐系统
- 场景:根据用户历史行为推荐相关内容。
- 实现:检索用户相似行为记录,生成个性化推荐理由。
7. 常见问题与解决方案
-
Q1:如何处理大文件加载失败?
- A:使用分页加载或分块处理(如
TextSplitter
),避免内存溢出。
- A:使用分页加载或分块处理(如
-
Q2:检索结果不相关怎么办?
- A:优化嵌入模型选择,调整向量相似度阈值,或引入多路召回策略。
-
Q3:如何部署为生产环境服务?
- A:使用 FastAPI 或 Streamlit 封装为 Web API,并通过 Docker 容器化部署。
8. 总结
通过 LangChain 的 RAG 框架,你可以高效构建一个结合外部知识的智能问答系统。从数据加载、向量存储到检索生成,LangChain 提供了完整的工具链,大幅降低了开发复杂度。无论你是企业开发者、研究人员,还是 AI 爱好者,RAG 都能帮助你释放 LLM 的潜力。
下一步建议:尝试将 RAG 应用于你的实际项目!例如,为你的团队搭建一个基于内部文档的智能助手,或者为网站添加实时客服问答功能。通过实践,你会发现 RAG 在提升效率和准确性上的巨大价值。