第 10 · RAG · 9 min
读取你的文档
大语言模型如何在不记忆的情况下访问数千页内容。嵌入、语义搜索、注入上下文。
上下文窗口解决不了的问题
设想你想构建一个助手,能够回答关于公司全部内部文档的问题——五万页,每周更新。
即便有 100 万 Token 的上下文窗口,也装不下这些内容。退一步说,就算装得下,成本也将高不可攀,而且回复质量会急剧下降:模型在极长上下文中提取精确信息的能力是有限的。
你需要一种不同的方案。这就是 RAG——检索增强生成(Retrieval-Augmented Generation)。
核心思想
不是把整份文档塞给模型,而是只给它与当前问题相关的片段。为此,你需要两样东西:
- 一个索引:所有文档的向量表示,提前构建好。
- 一个语义搜索引擎:当问题到来时,找到语义上最接近的片段。
检索到的片段,随后与问题一起注入大语言模型的上下文。模型基于这些摘录来生成回答。
这正是我们在第 03 章已经了解的语义搜索——只不过应用到了真实文档上。
三步流水线
1. 索引(一次性完成)
文档被切割成片段(Chunk)——每段几百个 Token(相邻片段之间有少量重叠,以避免在边界处截断语义)。
每个片段被一个嵌入模型转换成一个向量,存入向量数据库(Pinecone、Chroma、pgvector……)。
这一步只需执行一次,或在文档更新时重新执行。
2. 检索(每次问答时)
问题到来时,用同一个嵌入模型将它转换成向量。
计算这个问题向量与数据库中所有片段向量的余弦相似度,检索出最近的 k 个片段——通常是 3 到 5 个。
这是语义搜索:"接近"并不意味着"包含相同的词",而是意味着"表达相似的意思"。
3. 生成
检索到的片段被拼装成一个提示词:
文档摘录:
[摘录 1 — ……]
[摘录 2 — ……]
[摘录 3 — ……]
问题:{用户的问题}
这个提示词被发送给大语言模型,模型基于摘录生成回答。模型没有记忆这份文档——它是在被提问的那一刻才读到它的。
流水线可视化
下面是这个系统在一个小型星球科学语料库上运行的样子。选择一个问题——观察哪些片段在向量空间中被检索,以及它们如何被组装进上下文。
选一个问题:它会被 embedded,与语料库的 chunks 比较,最相关的几个会在生成前被注入到 prompt 里。正是这一道弯路让 LLM 能回答它在训练时从未见过的文档相关的问题。
分块大小:一个真实的工程决策
将文档切割成片段并不简单。它往往是 RAG 系统中问题的首要来源。
片段太小:每个片段的信息量不足。我们检索到的碎片,脱离上下文后无法支撑模型给出正确回答。
片段太大:超出了嵌入模型的表达精度。一个代表 2,000 个 Token 的向量是一个模糊的平均——它会在某些问题上被检索到,但相关内容可能被淹没在大段文本中。
实践经验:200 到 500 个 Token 的片段,加上 10–15% 的重叠。合适的参数取决于你的文档结构。
该选哪个嵌入模型?
不是所有问题在同一个嵌入模型下都能命中正确的片段。一个在通用英文上训练的模型,检索 Python 代码时表现会很差;一个在代码上训练的模型,处理医疗对话时也会很差。
实践中常见的几种选择:
text-embedding-3-small/-large(OpenAI)—— 质量稳定,通用,多语言。刚开始时的默认选项。bge-large/bge-m3(BAAI)—— 开源,多语言表现极佳,2024 年 MTEB 排行榜的头部。all-MiniLM-L6-v2(Sentence-Transformers)—— 体积小,速度快,可以本地部署。在简单场景下质量与成本的性价比很高。- 领域专用模型(代码、生物医学、法律)—— 在自己的领域里总是更强,但出了领域就明显变弱。
实践经验:拿两三个模型在你自己的数据和你自己的问题上跑一遍。MTEB 排行榜对你具体的使用场景说明不了太多。
Reranker:第二轮筛选
向量检索有一个缺陷:快,但是粗。一个几百维的嵌入是一段文本的一个模糊平均。许多"大致相关"的片段会浮上来,真正最好的那些有时反而被淹没。
正因如此,认真做的 RAG 系统里逐渐出现了一个标配的步骤:reranker(重排器)。
思路分两步:
- 第一轮(向量检索)—— 取回距离最近的 50 或 100 个片段。快。
- 第二轮(重排)—— 用一个小模型(通常是一个 cross-encoder)把每一对
(问题, 片段)一起送进去打分,输出一个更精确的得分,保留前 5–10 个。每个片段处理起来很慢,但只在第一轮挑出来的那 50 个候选上做。
reranker 同时看到问题和片段,这是嵌入做不到的。它能捕捉到向量检索漏掉的语义细节。Cohere、Jina AI、BAAI 都提供开箱即用的 reranker。
没有 reranker,你的 RAG 会很快遇到天花板。加上它,整体质量能上一个台阶,而流水线的其他部分都不用动。
为什么不用全文搜索
一个合理的疑问:为什么不直接用关键词搜索,就像传统搜索引擎那样?
向量搜索是对关键词搜索的补充,而不是替代。它能找到语义相似的段落,即便措辞完全不同。"哪颗行星自转最慢?"可以找到一个谈论"公转周期"的片段,即便那个词没有出现在问题里。
实践中,最好的系统将两者结合:混合搜索——同时计算向量相似度和关键词匹配(BM25)的综合得分。
RAG 的局限
RAG 不是魔法。以下是最常见的问题:
切割位置不当。 如果一个答案横跨两个片段,而切割恰好发生在关键位置,那两个片段单独来看都不足以支撑正确回答。
片段内部的"迷失在中间"。 如果片段过长,重要信息可能落在中间而被模型忽视。
问题措辞模糊。 如果问题含糊,问题向量与大多数相关片段的距离都会偏远。解决方案:改写问题,或生成多个变体。
对摘录的幻觉。 大语言模型可能在片段内容之外进行推断。RAG 减少了幻觉,但没有消除它。
RAG 在实践中意味着什么
RAG 是今天将大语言模型连接到私有数据或最新数据的参考技术。几乎所有企业聊天机器人、文档助手和知识库工具都依赖它。
但这仍然是一种"被动"架构:模型接收问题,找到片段,给出回答。对于更复杂的任务——搜索,再根据结果行动,再搜索——你需要更进一步。这就是我们在前一章已经见过的智能体架构。
两者结合,才是当今最强大的应用系统的基础。
更新于