检索增强生成(RAG)基础
一句话
检索增强生成(RAG)通过在查询时获取相关外部知识,解决了大语言模型(LLM)的有限上下文和静态知识两大限制,为LLM提供上下文特定的信息增强其回答。
什么时候翻这页
当你需要了解RAG的基本概念、构建知识库、理解不同RAG架构(2-Step RAG、Agentic RAG、Hybrid RAG)以及实现检索管道时。
核心概念
LLM的限制
- 有限上下文:无法一次性处理整个语料库
- 静态知识:训练数据在某个时间点被冻结
检索与RAG
检索通过在查询时获取相关外部知识来解决上述问题,这是**检索增强生成(RAG)**的基础:使用上下文特定信息增强LLM的回答。
知识库
知识库是检索过程中使用的文档或结构化数据存储库。如果已有知识库(如SQL数据库、CRM或内部文档系统),无需重建,可以:
- 作为工具连接到代理系统中
- 查询并将检索内容作为上下文提供给LLM(2-Step RAG)
检索管道
典型的检索工作流程包括:
- 从来源加载文档
- 将文档分割成块
- 将文档转换为嵌入
- 存储到向量存储
- 查询时生成嵌入
- 使用检索器获取相关文档
- LLM使用检索信息生成回答
构建块
- Document loaders:从外部源(如Google Drive、Slack、Notion等)摄取数据,返回标准化的Document对象
- Text splitters:将大文档分割成小块,便于单独检索并适合模型的上下文窗口
- Embedding models:将文本转换为数字向量,使语义相似的文本在向量空间中彼此接近
- Vector stores:专门用于存储和搜索嵌入的数据库
- Retrievers:给定非结构化查询返回文档的接口
RAG架构比较
| 架构 | 描述 | 控制性 | 灵活性 | 延迟 | 示例用例 |
|---|---|---|---|---|---|
| 2-Step RAG | 检索总是在生成之前执行。简单且可预测 | ✅ 高 | ❌ 低 | ⚡ 快 | FAQ、文档机器人 |
| Agentic RAG | LLM驱动的代理决定何时以及如何在推理过程中检索 | ❌ 低 | ✅ 高 | ⏳ 可变 | 具有多工具访问权限的研究助手 |
| Hybrid | 结合两种方法的特点,包含验证步骤 | ⚖️ 中等 | ⚖️ 中等 | ⏳ 可变 | 需要质量验证的领域特定问答 |
怎么做
2-Step RAG
在2-Step RAG中,检索步骤总是在生成步骤之前执行。这种架构简单且可预测,适合许多应用场景。
graph LR
A[用户问题] --> B["检索相关文档"]
B --> C["生成回答"]
C --> D[向用户返回回答]
Agentic RAG
Agentic RAG结合了检索增强生成和基于代理的推理的优势。代理(LLM驱动)逐步推理并决定何时以及如何在交互过程中检索信息。
graph LR
A[用户输入/问题] --> B["代理(LLM)"]
B --> C{需要外部信息?}
C -- 是 --> D["使用工具搜索"]
D --> H{信息足够回答?}
H -- 否 --> B
H -- 是 --> I[生成最终回答]
C -- 否 --> I
I --> J[返回给用户]
实现示例:
import requests
from langchain.tools import tool
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent
@tool
def fetch_url(url: str) -> str:
"""从URL获取文本内容"""
response = requests.get(url, timeout=10.0)
response.raise_for_status()
return response.text
system_prompt = """\
当需要从网页获取信息时使用fetch_url;引用相关片段。
"""
agent = create_agent(
model="claude-sonnet-4-6",
tools=[fetch_url], # 用于检索的工具
system_prompt=system_prompt,
)
Hybrid RAG
Hybrid RAG结合了2-Step和Agentic RAG的特点,引入了中间步骤如查询预处理、检索验证和后生成检查。
典型组件包括:
- 查询增强:修改输入问题以提高检索质量
- 检索验证:评估检索到的文档是否相关且充分
- 回答验证:检查生成回答的准确性、完整性和与源内容的一致性
graph LR
A[用户问题] --> B[查询增强]
B --> C[检索文档]
C --> D{信息足够?}
D -- 否 --> E[优化查询]
E --> C
D -- 是 --> F[生成回答]
F --> G{回答质量OK?}
G -- 否 --> H{尝试不同方法?}
H -- 是 --> E
H -- 否 --> I[返回最佳回答]
G -- 是 --> I
I --> J[返回给用户]
命令 / API 速查
文档加载器
from langchain.document_loaders import YourLoaderClass
loader = YourLoaderClass()
documents = loader.load()
文本分割器
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
chunks = text_splitter.split_documents(documents)
嵌入模型
from langchain.embeddings import OpenAIEmbeddings
embeddings = OpenAIEmbeddings()
向量存储
from langchain.vectorstores import Chroma
vectorstore = Chroma.from_documents(documents=chunks, embedding=embeddings)
检索器
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
2-Step RAG链
from langchain.chains import RetrievalQA
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever
)
Agentic RAG
from langchain.agents import create_agent, Tool
tools = [
Tool(
name="retriever",
func=retriever.get_relevant_documents,
description="检索相关文档"
)
]
agent = create_agent(llm=llm, tools=tools)
与 Hello-Agents / LangGraph / 本博客 handbook 索引的联系
本博客的handbook已使用Chroma作为向量库构建了RAG系统,这与官方文档中推荐的向量存储实现一致。在Hello-Agents的记忆与检索章节中,我们学习了如何构建基本的检索系统,而本页内容扩展了这一概念,介绍了不同的RAG架构和实现方式。LangGraph中的代理系统可以与RAG结合,实现更复杂的推理和检索流程,如Agentic RAG示例所示。
初学者易错点
- 过度依赖单一检索策略:不同场景可能需要不同的RAG架构,2-Step RAG适合简单任务,而Agentic RAG更适合复杂推理。
- 忽视查询优化:原始查询可能不够精确,需要通过查询增强提高检索质量。
- 忽略检索验证:检索到的文档可能不相关或不充分,需要验证机制确保信息质量。
- 向量存储选择不当:不同的向量存储有不同的特点和性能,应根据需求选择合适的实现。
- chunk大小设置不合理:chunk太大可能超出模型上下文窗口,太小可能丢失上下文信息。