大模型知道很多,但不知道你公司的内部文档、上周的产品公告、你个人笔记里的那条备忘。直接问它,它要么坦白不知道,要么一本正经地编一个答案——后者就是臭名昭著的幻觉。RAG(Retrieval-Augmented Generation,检索增强生成)给出的解法是:回答之前先查资料——把相关的私有知识实时检索出来,塞进上下文,再让模型基于资料作答。这是当前企业级 AI 应用采用率最高的架构,没有之一。本文按“原理流程 → 关键组件 → 最小实现 → 质量优化 → 技术选型 → 总结”组织全文。
1、概述
RAG 的思想并不新鲜,它的原型来自 2020 年 Meta 研究团队的论文,首次提出“生成前先从外部知识库检索相关片段”,见 RAG 原始论文。真正让它爆发的,是大模型落地时绕不开的三个现实问题。
第一个是知识截止。模型的知识冻结在训练数据截止的那一刻,之后的世界它一无所知。第二个是私有数据。企业内部文档、数据库、聊天记录从未进入训练集,模型天然不知道。第三个是可溯源。合规场景要求每个结论都能给出处,模型参数里的知识无法引用,RAG 的“先检索后生成”让每个回答都可以标注来源。
与另外两条路线相比,RAG 的位置很清晰。微调改变模型“会什么”,RAG 改变模型“能看到什么”;微调成本高、更新慢,RAG 知识库分钟级就能更新。直接把所有文档塞进长上下文窗口则受限于成本与注意力稀释——上下文越长,模型对中段内容的利用率越低。三者的适用边界在第五节展开。
RAG 的典型落地场景包括:
- 企业知识库问答:员工手册、内部 Wiki、技术文档
- 智能客服:基于产品帮助文档回答用户问题
- 个人知识管理:把笔记变成可对话的资产
- 代码助手:从团队代码规范与历史方案中检索参考
2、核心流程
RAG 系统分两条链路:离线的索引链路与在线的查询链路。前者把原始文档加工成可检索的形态,后者处理用户提问。整体流程如下:
两条链路的分工值得注意:索引链路是重活,一次投入、持续受益,通常做在后台;查询链路决定用户体验,延迟敏感——检索通常要求在几百毫秒内完成,Embedding 与检索的质量直接决定最终回答质量。
一句话概括本质:RAG 用检索换取知识的实时性与可溯源性,用向量相似度逼近语义相关性。模型不再需要“记住”所有知识,只需要“会查”。
3、关键组件详解
3.1、解析与分块
文档进来第一步是把 PDF、Word、网页、Markdown 解析成纯文本或结构化文本,第二步是把长文本切成块(Chunk)。分块是 RAG 质量的第一道分水岭:块太大,检索粒度粗、上下文浪费;块太小,语义被切断,检索命中了也读不懂。
常见分块策略对比如下:
| 策略 | 原理 | 适用场景 |
|---|---|---|
| 固定长度 | 按字符数硬切,带重叠 | 快速原型 |
| 递归分割 | 优先按段落、句子等自然边界切 | 通用首选 |
| 结构感知 | 按标题、章节、代码函数切 | Markdown、代码 |
| 语义分块 | 按相邻句向量相似度变化点切 | 对质量要求高时 |
实践中最常用的是递归分割,典型参数:块大小 256~1024 token,相邻块重叠 10%~20%。重叠的意义是防止关键句恰好被切断在两个块的边界上。分块没有万能参数,最佳值与文档类型强相关——表格多的文档、代码、聊天记录各有各的切法。
3.2、Embedding 与向量数据库
Embedding 模型把文本映射成高维向量,语义相近的文本在向量空间中距离也近。用户的提问与文档块本来不是同一种文本,但各自的向量都落在“语义空间”里,相似度即可计算——这就是“语义检索”的全部原理。
向量数据库负责存储这些向量并支撑高速近邻检索。FAISS 是 Meta 开源的向量检索库,适合本地与研究场景;生产环境则常用带服务能力的方案。选型时主要看四个维度:
| 维度 | 关注点 |
|---|---|
| 规模 | 百万级以下本地库即可,亿级需分布式 |
| 过滤 | 是否支持先按元数据过滤再检索 |
| 混合检索 | 是否原生支持关键词与向量混合 |
| 运维 | 部署形态、备份、权限、成本 |
3.3、重排序
向量检索负责“从百万块里粗筛出几十个候选”,重排序(Rerank)负责“从候选里精选出真正相关的几个”。粗筛追求速度,用向量近似;精排追求精度,用交叉编码器对“问题—文档对”逐对深度打分。加不加重排,回答质量常常差一个档次,而成本只增加一次小模型调用。“召回看向量,精度看重排”,这六个字是检索质量的工程口诀。
4、从零实现最小 RAG
理解一个 RAG 系统最快的方式是亲手写一个。下面用 Python 实现最小可用版本,不依赖任何框架,只用到 OpenAI SDK 与 FAISS。
第一步,把文档切块并向量化入库:
import faiss, numpy as np
from openai import OpenAI
client = OpenAI()
def embed(texts: list[str]) -> np.ndarray:
resp = client.embeddings.create(model="text-embedding-3-small", input=texts)
return np.array([d.embedding for d in resp.data], dtype="float32")
docs = ["RAG 是检索增强生成的缩写,先检索后生成。",
"分块大小影响检索粒度,常见 256 到 1024 token。",
"重排序用交叉编码器对候选结果精排。"]
vectors = embed(docs)
index = faiss.IndexFlatL2(vectors.shape[1])
index.add(vectors) # 向量入库,真实系统需同时保存原文与向量 ID 的映射
faiss.write_index(index, "kb.index")
解读:IndexFlatL2 是暴力检索,百万级以下规模完全够用;真实系统要用 IndexIVFFlat 或 IndexHNSWFlat 换取速度。入库时必须维护“向量行号 → 原文 + 元数据”的映射,否则检索到向量也拿不回文本。
第二步,检索并生成:
def retrieve(query: str, k: int = 3) -> list[str]:
index = faiss.read_index("kb.index")
qv = embed([query])
_, ids = index.search(qv, k)
return [docs[i] for i in ids[0]]
def answer(query: str) -> str:
hits = retrieve(query)
context = "\n".join(f"[{i+1}] {t}" for i, t in enumerate(hits))
resp = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content":
f"仅依据以下资料回答问题,并标注引用编号:\n{context}\n\n问题:{query}"}])
return resp.choices[0].message.content
print(answer("重排序是做什么的"))
解读:answer 的提示词里有两条关键约束:“仅依据以下资料”压幻觉,“标注引用编号”保溯源。这两条正是 RAG 相对裸模型对话的价值所在。四十行代码,已经具备一个生产系统的骨架——剩下的都是工程强化。
不想从零造轮子的,主流框架都能把这个流程缩到十行以内:LlamaIndex 主打数据接入与索引抽象,LangChain 主打全链路编排与组件生态。
5、质量问题与优化
RAG 上线的头号痛点不是“搭不起来”,而是“答不准”。失败要分层归因——检索没找到(检索失败),还是找到了没用好(生成失败)。治理手段对应展开:
- 治检索:加混合检索(向量 + BM25 关键词,术语、编号、人名类查询关键词更可靠)
- 治分块:按文档结构调整切分,给块附上“所属章节”等元数据
- 治排序:加交叉编码器重排,把最相关的块顶到最前
- 治生成:提示词强约束“资料里没有就回答不知道”,宁可拒答不可编造
- 治评估:建评测集,用命中率、MRR 等指标量化,别靠肉眼感觉
评估是所有优化的前提。一个务实的起步做法:从真实用户提问里采样上百条,人工标注“应该命中哪些文档块”,之后每次调参都跑一遍命中率。没有度量的调优,和闭眼调参没有区别。
RAG 的幻觉有很强的隐蔽性:检索质量 90% 的系统,用户感知到的是“十次里错一次,不知道哪次错”——信任一旦崩塌,再建起来非常贵。
6、RAG 与长上下文微调之争
“上下文窗口都到百万 token 了,RAG 还有必要吗?”——这是高频争论。答案藏在成本、延迟与注意力三个维度:百万 token 的单次调用成本远高于检索几 KB 的片段;超长上下文的推理延迟显著上升;且长文本中段的利用率衰减是模型固有的注意力问题,塞进去不等于看得见。
微调的边界同样清晰:它适合改变模型的行为模式(风格、格式、领域话术),不适合注入频繁更新的知识——每更新一次知识就要重新训练,成本与时效都无法接受。
三种方式的定位对比如下:
| 方式 | 改变什么 | 更新成本 | 典型场景 |
|---|---|---|---|
| RAG | 模型能看到什么 | 分钟级 | 知识问答、可溯源场景 |
| 微调 | 模型的行为习惯 | 天级 | 风格、领域话术、格式 |
| 长上下文 | 单次输入的信息量 | 无需更新 | 单文档深度分析 |
三者不互斥。生产系统的成熟做法是组合拳:长上下文模型打底、私有知识走 RAG、输出风格靠微调或提示词约束。
7、总结
回顾全文:RAG 通过“离线索引 + 在线检索生成”两条链路,解决了模型知识截止、私有数据与可溯源三大问题;分块、Embedding、向量库、重排四个组件决定检索质量,“召回看向量、精度看重排”;最小实现几十行代码即可跑通,工程强化无上限;优化必须建立在分层归因与量化评估之上;在与长上下文、微调的选型中,RAG 胜在知识更新成本与溯源能力。
对于准备上手 RAG 的开发者,建议按三步走:先用最小实现跑通全链路,建立直觉;再用真实数据建评测集,让质量可度量;最后按“检索 → 重排 → 生成”的顺序逐层优化——把力气花在刀刃上,大多数质量问题都出在检索层。

