检索增强生成(RAG)¶
RAG(Retrieval-Augmented Generation) 是将信息检索与 LLM 生成相结合的技术框架。它让 LLM 在回答问题前,先从外部知识库中检索相关信息,然后基于检索到的内容生成答案——从根本上缓解了 LLM 的"幻觉"和知识过时问题。
为什么需要 RAG?¶
LLM 虽然强大,但存在三个根本性的局限:
| 局限 | 说明 | 示例 |
|---|---|---|
| 知识截止 | 训练数据有截止日期,不知道之后发生的事 | "2026 年世界杯冠军是谁?"→ 无法回答 |
| 幻觉问题 | 不知道时会"一本正经地胡说八道" | 编造不存在的论文、虚构的统计数据 |
| 缺乏私有知识 | 不了解企业内部文档、个人笔记等 | 无法回答"公司报销流程是什么?" |
RAG 的解决思路很简单:让模型开卷考试——回答问题前先查资料。
一句话理解
RAG = 搜索引擎 + LLM。先搜,再答。
RAG 的基本流程¶
graph LR
A["用户提问"] --> B["检索器<br>Retriever"]
B --> C["知识库<br>向量数据库"]
C --> B
B --> D["构建 Prompt<br>问题 + 检索结果"]
D --> E["LLM 生成<br>答案"]
完整流程分三步¶
第 1 步:索引(Indexing)——建设知识库
将文档预处理后存入向量数据库,这是一次性的离线操作:
第 2 步:检索(Retrieval)——找到相关信息
用户提问时,将问题也转换为向量,在向量数据库中搜索最相似的文档块:
第 3 步:生成(Generation)——基于检索结果回答
将检索到的文档块和用户问题一起喂给 LLM:
核心组件详解¶
文本切块(Chunking)¶
长文档需要被切分为适当大小的块(Chunk),因为:
- Embedding 模型有长度限制(通常 512~8192 Token)
- 检索时需要精确定位到具体段落,而非整篇文档
- LLM 的上下文窗口有限,不能塞入所有内容
常见切块策略:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 固定长度切块 | 按固定 Token 数切分(如每 512 Token) | 简单场景 |
| 重叠切块 | 相邻块有重叠部分(如重叠 50 Token) | 避免关键信息被截断 |
| 语义切块 | 按段落、章节、句子等语义边界切分 | 结构化文档 |
| 递归切块 | 先按大标题切,再按段落切,逐层递归 | 长文档、书籍 |
块大小的权衡
- 块太小:缺少足够的上下文,检索结果可能不完整
- 块太大:包含太多无关信息,稀释了关键内容
- 通常推荐:256~1024 Token,根据文档类型调整
Embedding(向量化)¶
Embedding 模型将文本映射到高维向量空间,使得语义相似的文本在向量空间中距离更近。
"猫喜欢在阳光下睡觉" → [0.23, -0.45, 0.87, ...] (768 维)
"小猫爱晒太阳" → [0.21, -0.42, 0.85, ...] (768 维) ← 向量非常接近!
"量子力学的基本原理" → [-0.56, 0.78, -0.12, ...] (768 维) ← 向量差异很大
常用的 Embedding 模型:
| 模型 | 维度 | 特点 |
|---|---|---|
| OpenAI text-embedding-3-large | 3072 | 效果好,需 API 调用 |
| BGE-large-zh | 1024 | 中文效果优秀,开源 |
| E5-mistral-7b | 4096 | 大模型做 Embedding,效果强 |
| GTE-Qwen2 | 多种 | 阿里开源,多语言 |
向量数据库¶
专门用于存储和高效检索向量的数据库:
| 数据库 | 特点 |
|---|---|
| FAISS | Meta 开源,纯本地,速度极快 |
| Milvus | 开源分布式向量数据库,适合大规模部署 |
| ChromaDB | 轻量级,适合快速原型开发 |
| Pinecone | 云服务,全托管,易上手 |
| Weaviate | 支持混合搜索(向量 + 关键词) |
相似度计算¶
检索时需要计算用户问题向量与知识库中所有文档块向量的相似度:
余弦相似度(最常用):
值域为 \([-1, 1]\),1 表示完全相同,0 表示无关。
进阶 RAG 技术¶
查询改写(Query Rewriting)¶
用户的原始问题可能不适合直接用于检索。查询改写让 LLM 先优化查询:
常见策略: - HyDE(Hypothetical Document Embedding):让 LLM 先生成一个"假想的答案",用这个答案去检索(因为答案和文档的语义更接近) - 多查询生成:将一个问题拆成多个不同角度的子查询,分别检索后合并结果
重排序(Re-ranking)¶
向量检索返回的 Top-K 结果中,排序可能不够精确。Re-ranker 对检索结果进行二次排序:
Re-ranker 通常使用交叉编码器(Cross-Encoder),它将查询和文档拼接输入,能捕捉更细粒度的语义关系,精度显著高于向量检索的双塔模型。
混合搜索(Hybrid Search)¶
单纯的向量搜索可能会遗漏关键词精确匹配的结果。混合搜索结合两种方式:
- 向量搜索(语义):捕捉语义相似性。"汽车" 能匹配 "轿车"
- 关键词搜索(BM25):捕捉精确匹配。专有名词、代码变量名
多跳 RAG¶
有些问题需要多步检索才能回答:
问题:"OpenAI CEO 的妻子是哪年出生的?"
第 1 跳检索:"OpenAI CEO" → Sam Altman
第 2 跳检索:"Sam Altman 妻子" → 无公开信息
答:根据检索到的信息,无法确认该问题的答案。
RAG vs 微调:如何选择?¶
| 对比维度 | RAG | 微调 |
|---|---|---|
| 知识更新 | ✅ 只需更新知识库 | ❌ 需要重新训练 |
| 成本 | 低(只需 Embedding + 向量数据库) | 高(GPU 训练) |
| 幻觉控制 | ✅ 答案有据可查 | 一般(仍可能幻觉) |
| 私有知识 | ✅ 天然支持 | 需要私有数据训练 |
| 深度理解 | 一般(依赖检索质量) | ✅ 模型内化知识 |
| 适用场景 | 知识库问答、客服、文档助手 | 特定风格/格式、专业领域 |
实践建议
- 优先尝试 RAG:成本低、见效快、易维护
- RAG 效果不好时再考虑微调:当任务需要深度理解特定领域的"语感"或风格
- 最佳方案往往是两者结合:用微调让模型掌握领域知识和回答风格,再用 RAG 补充最新信息
简易 RAG 实现思路¶
一个最小可用的 RAG 系统只需要:
1. 准备文档 → 切块
2. 调用 Embedding API → 向量化
3. 存入 FAISS / ChromaDB
4. 用户提问 → 向量化 → 检索 Top-K
5. 拼接 Prompt → 调用 LLM → 返回答案
主流框架:
| 框架 | 特点 |
|---|---|
| LangChain | 生态丰富,组件多,适合快速原型 |
| LlamaIndex | 专注于 RAG,索引和检索能力强 |
| Haystack | 端到端 RAG 框架,生产级 |