跳到主要内容

RAG:给模型接上外部知识

这一章讲三件事: RAG 到底解决什么问题——以及为什么「上下文越长越不需要它」是错觉; 它的两条检索路线(数关键词的、算意思距离的)各自怎么运转、怎么取舍、怎么合体; 让检索真正好用的四门手艺:切块、精排、改写问题、上下文加工,外加两条延伸线(图像、表格)。 它在全书的位置:这是第二种适配技术——不改权重,但改「每次给模型看什么」;下一章把检索器装进会自己决策的智能体。

1. 顶层全景:问题不是「知道多少」,是「递多少」

模型的内部知识有两个死穴:训练截止日之后的事它不知道,你的私有数据它更没见过。RAG(retrieval-augmented generation,检索增强生成)的解法名字里就写着:先从外部数据源检索相关信息,再把检索结果连同问题一起递给模型去生成回答。术语出自 Lewis 等 2020 年的论文,他们的动机一句话说尽:知识密集型任务没法把所有知识塞进模型;而拿到相关信息,既让回答更详实,也减少幻觉1

常见的反对意见是「上下文窗口越来越长,把整个知识库塞进去不就行了?」书里用两条理由否掉了这个想法2:

  • 内容会膨胀到占满窗口——作者拿帕金森定律自嘲:应用的上下文会扩展到占满模型支持的长度上限;

  • 装得下不等于用得上:上下文越长,模型越可能关注到错误的部分(第 07 章的 Lost in the Middle),而且每个 token 都在花钱花时间。RAG 反其道行之:每个查询,只递最相关的那一点

所以 RAG 是长期方案,不是权宜之计。真有分界线吗?Anthropic 给过一个实用口径:知识库小于 20 万 token(约 500 页)时,可以直接整库进提示词,无须 RAG3

RAG 的两半:
┌────────────┐ ①索引(离线):文档切块 → 转可检索形态
│ 检索器 │ ②查询(在线):接住查询 → 取回最相关的 k 块
└─────┬──────┘
│ 相关上下文

┌────────────┐
│ 生成器 │ 把(查询 + 检索到的块)交给模型作答
└────────────┘
图说:两半通常独立训练、各自更换——这正是工程上的好处。

顺带一个书里的视角转换:为模型组装上下文,扮演的是传统模型开发流程里「造输入」的那门手艺——决定把现实世界的哪些信息喂给模型,让模型有料可用4

2. 主走查:词项检索——数关键词的三层进化

第一条检索路线按「关键词出现没出现」打分。它的底层表示很朴素:每个词项(切分后的检索单位)对应一个独热向量——只有一位是 1、其余全是 0 的向量。书里的走查:词典 {"food": 0, "banana": 1, "slug": 2} 里,三个词分别表示成 [1,0,0]、[0,1,0]、[0,0,1]5

只数「出现次数」太糙,进化有三层:

第一层:词频(TF)。 一个词项在文档里出现得越多,文档大概率越相关。但「for」「at」这种到处都是的词会把账搅乱6

第二层:逆文档频率(IDF)。 出现在越多文档里的词,信息量越少——重要性应与覆盖面成反比。算法朴素:文档总数 ÷ 含该词的文档数;10 篇文档里 5 篇含某词,它的 IDF 就是 10/5 = 2。两者相乘得到的老牌评分,名字叫 TF-IDF(词频 × 逆文档频率)7

第三层:工程化产品。 把 TF-IDF 装进生产系统要一个加速结构——倒排索引(从「词项」反查「哪些文档含它」的字典),Elasticsearch 就靠它起家。

评分公式则升级为 BM25:长文天然更容易命中关键词,它把这份天然优势扣除后再比——这道修正工序叫归一化。Perplexity 的 CEO 有句被广泛引用的实话:「要在 BM25 或全文搜索的基础上实现真正的改进是很困难的」8

还有一道预处理工序:分词——把查询拆成词项。直接按单词切会切碎固定搭配:「hot dog」拆成 hot 和 dog 就都没了热狗的意思;对策是把常见的搭配(n-gram)当作整体词项,再统一小写、去标点、删「the/and/is」这类停止词9

3. 第二条路线:嵌入检索与向量数据库

第 04 章埋的地基在这里兑现:与其数字面关键词,不如比「意思的距离」。做法分两步——索引时给每个数据块生成嵌入向量,存进向量数据库;查询时把查询也转成嵌入,取最近的 k 个10

「取最近」在百万级数据上不能全库硬算,于是有了一族近似最近邻(ANN)算法——用一点点准确率换大量速度。书里点名的四位选手,思路各不相同11:

表里会出现一个易混词,量化:把数值压成更粗的表示来省算力——跟第 03 章的采样温度没有关系。

算法一句话思路
LSH全名「局部敏感哈希」:把相似的向量赶进同一个桶,牺牲一点准确性换速度
HNSW(分层可导航小世界)建多层图,节点是向量,顺着边走找近邻
乘积量化把向量拆成子向量,先在低维算距离(位宽更小,算得更快)

| IVF(倒排文件索引) | 先做聚类:把相近的向量圈成簇(每簇 100–10000 个),查询时只搜最近的几簇 |

工程上不必自研:FAISS、ScaNN、Annoy、Milvus 这些库都实现了上述算法。选型的核心权衡是一对此消彼长——建索引越慢、越占内存的(如 HNSW),查询越快越准;反之亦然12

4. 怎么选:一张对照表加四个数

两条路线的取舍,书里收成一张对照表13:

词项检索嵌入检索
速度快,开箱即用取决于 ANN 配置
上限调优空间小可持续微调,性能上限更高
死穴换个说法就抓瞎关键词会丢——错误码 EADDRNOTAVAIL 这类字串,嵌入后没了辨识度

注意「死穴互补」这行:这正是混合检索(两条路线同时跑)存在的理由。而组合方式有两种14:

  • 顺序合:便宜的先粗筛,贵的再精挑——第二步行话叫重排序;

  • 并行合:两条路线各排一份榜单,再用倒数排名融合(RRF)合成:排名第 1 记 1 分(1/1),第 2 记 0.5(1/2),各文档把两条线的分数相加——一边第 1 一边第 2 就是 1 + 0.5 = 1.5,总分排序出最终榜单。

评检索好坏的尺子也有讲究15。第一把叫上下文精度:检回来的内容有多相关。

第二把叫上下文召回率:该检回来的检回了多少。它听着更根本,生产里却常常只算上一把——因为算召回率得给库里的所有文档标注「与这条查询相不相关」,成本爆炸;精度只要拿检回的那几条比一比,还能外包给 AI 裁判。若关心排序质量(相关的要排前面),再看 NDCG、MAP、MRR 这组指标;检索领域也有综合考卷 BEIR(14 个常见检索基准)16

最后是账本:嵌入不是免费的——要是每天为 1 亿个文档重新生成嵌入呢?书里引用的行情是,向量数据库的花费占到模型 API 总支出的五分之一甚至一半并不罕见17

5. 四门手艺:让检索真正好用

手艺一:切块

文档要先切成块才能建索引,书里把这步叫分块:切块的刀法直接影响检索成败18:

  • 等长切:按 2048 字符或 512 词一刀切,最简单,容易拦腰斩断语义;

  • 递归:章 → 段 → 句逐级换刀,直到每块够小,减少「切在半句话上」;

  • 专用切:代码用语法感知工具(py-tree-sitter),问答对文档一问一答一块;

  • 重叠切:相邻块留 20 个字符的重叠,专治边界截断——书里的例子:「I left my wife a note」若切成「I left my wife」和「a note」,两块都丢了关键信息;

  • 按分词器切:用生成模型(即负责最终作答的那个模型)自带的分词器定边界,模型吃得顺口;代价是换生成模型就得重建索引。

手艺二:重排序与时间权重

除两路合体外,排序本身还能加料:对时效敏感的场景(新闻、邮件、股票)给新文档加权19

手艺三:先把问题改写成人话

这套工序行话叫查询重写:把用户口语改成完整、可检索的问句,通常请另一个模型代笔。「那 Emily Doe 呢?」缺主语,得先补成自成一体的完整问题。

若查询里带指代,还有一道前置工序,行话叫解析:把「他」换回具体的人。查不出来就老实承认,别编一个来改写20

手艺四:上下文加工

给每块资料配「能被检索到的钩子」:加元数据(标签、错误码);把文档改写成问答对,一块资料附上它可能回答的全部问法(「如何重置密码」「我忘了密码」「救命」);Anthropic 的「上下文检索」做法是用 AI 给每块生成 50–100 token 的位置说明,再一并嵌入21

6. 两条延伸线:图像与表格

图像入库:若生成模型本身懂图,检索器可以同时取回文本和图片——查询「《飞屋环游记》里房子是什么颜色?」,检回一张剧照辅助作答。要让「文字查询」对上「图片」,需要 CLIP 这类能同时编码两种模态的嵌入模型(第 04 章的联合嵌入在此上岗):所有文本和图片统一生成嵌入存进向量数据库,查询时按距离取22

表格入库:结构化数据别硬转文字,标准做法是文本转 SQL——把查询翻译成 SQL 语句,在数据库上执行,把结果交给模型生成回答。书里的例子是一家虚构的猫咪时尚电商 Kitty Vogue:用户问「Fruity Fedora 这款卖了多少件」,系统生成 SELECT SUM(units)… 执行后作答23。注意一个伏笔:当问题变成「预测未来三个月的销量」,SQL 就不够了——系统得先补一次营销活动查询、再做推算,这种「自己决定走几步」的形态,正是下一章的智能体24

7. 作者的判断与证据

  • 「RAG 过时论」被正面驳回:两条结构性理由(内容膨胀、长上下文利用率低)都是机制层面的,不依赖某代模型的能力快照。
  • 检索是百年老手艺的新皮肤:书里顺带考据了信息检索一个世纪的历史(1920 年代的「统计机器」专利),提醒读者 BM25 这类「老」算法久经考验。
  • 成本数据是行业访谈级的:向量数据库支出占 API 总支出 1/5–1/2 出自从业者案例,作者标明了来源性质,未当普查数据。

判断(我们的,不是书里的): 「词项检索 vs 嵌入检索」的正确姿势几乎总是「都上」——因为它们的失败模式恰好互补:词项检索死在「换个说法」,嵌入检索死在「专有字串」。先问「我的语料里哪类查询更多」,再决定谁是粗筛、谁是精排。 如果错,会错在: 若嵌入模型在特定语料上足够强(如代码检索场景的错误码已进过训练分布),单路嵌入的丢词问题可能不复存在,混合的工程负担就不值当。

8. 边界与局限

  • 本章讲的是「检索器 + 生成器」的经典 RAG;检索器与生成模型联合训练、以及从检索器一路调到生成模型的所谓端到端:全流程联合微调,虽被提及能显著提效,书中未给做法。
  • 各类 ANN 算法只有概念级介绍,参数调优(簇数、图层数、 efSearch)不在本书范围。
  • 表格 RAG 只覆盖「文本转 SQL」一型;多表 join、权限过滤等真实数仓问题未展开。

9. 可带走的

  1. RAG 的本质是分配:每个查询只递最相关的信息——长上下文不会淘汰它,只会改变分界线(Anthropic:20 万 token 以下可不用);

  2. 词项检索三层进化:词频 → 逆文档频率(TF-IDF)→ BM25(长文归一化);加速靠倒排索引;

  3. 分词要保住固定搭配(hot dog 用 n-gram),再统一小写、去停止词;

  4. 嵌入检索 = 建索引时转嵌入 + 查询时取最近 k 个;大数据靠 ANN 算法族(LSH/HNSW/乘积量化/IVF)换速度;

  5. 两路死穴互补——词项怕「换个说法」,嵌入丢「专有字串」——所以才有混合检索:顺序合叫重排序,并行合用 RRF(第 1 名记 1,第 2 名记 0.5,求和);

  6. 评估记两尺:上下文精度(便宜,可外包 AI 裁判)与上下文召回率(要全库标注,生产常只算前者);

  7. 分块五法:等长、递归、专用、重叠、按分词器——重叠切专治边界截断;

  8. 查询先重写(「那 Emily Doe 呢?」→ 完整问句;解析不出身份就承认),资料块要预埋「钩子」(问答化、元数据、上下文说明);

  9. 图表都能入 RAG:图像靠 CLIP 联合嵌入,表格走文本转 SQL(Kitty Vogue)——要「多走几步」时,下一章的智能体接棒。

10. 原文地图

主题原书章原文位置
RAG 术语与动机、减幻觉第6章text/13-ch06.txt:67(搜「知识密集型」)
特征工程类比第6章text/13-ch06.txt:81(搜「特征工程」)
反驳长上下文、帕金森第6章text/13-ch06.txt:84(搜「帕金森」) · text/13-ch06.txt:84(搜「占满」)
Anthropic 500 页口径第6章text/13-ch06.txt:98(搜「200,000」)
检索器+生成器、独立训练第6章text/13-ch06.txt:122(搜「独立训练」)
独热向量走查第6章text/13-ch06.txt:162(搜「独热」) · text/13-ch06.txt:165(搜「[1, 0, 0]」)
TF 与 IDF、10/5=2第6章text/13-ch06.txt:180(搜「词频」) · text/13-ch06.txt:186(搜「10/5=2」)
倒排索引与 Elasticsearch第6章text/13-ch06.txt:206(搜「倒排索引」)
BM25 归一化、Perplexity 引言第6章text/13-ch06.txt:220(搜「归一化」) · text/13-ch06.txt:223(搜「真正的改进」)
分词、hot dog、停止词第6章text/13-ch06.txt:231(搜「hot dog」) · text/13-ch06.txt:234(搜「停止词」)
向量数据库与查询两步第6章text/13-ch06.txt:246(搜「向量数据库」)
k-NN 与 ANN、库第6章text/13-ch06.txt:278(搜「k近邻」) · text/13-ch06.txt:293(搜「FAISS」)
LSH / HNSW / 乘积量化 / IVF第6章text/13-ch06.txt:305(搜「哈希到同一个桶」) · text/13-ch06.txt:311(搜「多层图」) · text/13-ch06.txt:317(搜「子向量」) · text/13-ch06.txt:323(搜「100到10,000」)
词项 vs 嵌入取舍、丢关键词第6章text/13-ch06.txt:350(搜「EADDRNOTAVAIL」)
上下文精度与召回率第6章text/13-ch06.txt:353(搜「上下文精度」) · text/13-ch06.txt:371(搜「标注数据库中所有文档」)
NDCG/MAP/MRR、BEIR第6章text/13-ch06.txt:374(搜「NDCG」) · text/13-ch06.txt:431(搜「BEIR」)
成本:1 亿文档、五分之一第6章text/13-ch06.txt:386(搜「1亿个文档」) · text/13-ch06.txt:386(搜「五分之一」)
顺序合:重排序第6章text/13-ch06.txt:452(搜「重排序」)
RRF:1+0.5=1.5第6章text/13-ch06.txt:461(搜「倒数排名融合」) · text/13-ch06.txt:464(搜「1.5」)
分块:等长 2048/512第6章text/13-ch06.txt:499(搜「2048个字符」)
递归切、专用切第6章text/13-ch06.txt:502(搜「递归拆分」) · text/13-ch06.txt:505(搜「py-tree-sitter」)
重叠切:I left my wife第6章text/13-ch06.txt:508(搜「I left my wife」)
按分词器切、换模型重建第6章text/13-ch06.txt:514(搜「重新对数据进行索引」)
时间权重第6章text/13-ch06.txt:538(搜「时间」;若定位失败搜「新闻聚合」)
查询重写:Emily Doe第6章text/13-ch06.txt:556(搜「Emily」;若定位失败搜「查询重写」)
上下文检索与钩子第6章text/13-ch06.txt:490(搜「上下文检索」;若定位失败搜「元数据」)
多模态 RAG、飞屋环游记第6章text/13-ch06.txt:674(搜「飞屋环游记」) · text/13-ch06.txt:686(搜「CLIP」)
表格 RAG:Kitty Vogue第6章text/13-ch06.txt:704(搜「Kitty Vogue」)
伏笔:Fruity Friedman 三个月预测第6章text/13-ch06.txt:830(搜「Fruity Fedora」)

Footnotes

  1. 出处:「第6章」第 67 段(text/13-ch06.txt:67,搜「知识密集型」)。

  2. 出处:「第6章」第 84 段(text/13-ch06.txt:84,搜「占满」)与第 92 段(text/13-ch06.txt:92,搜「最相关的信息」)。

  3. 出处:「第6章」第 98 段(text/13-ch06.txt:98,搜「200,000」)。

  4. 出处:「第6章」第 81 段(text/13-ch06.txt:81,搜「特征工程」)。

  5. 出处:「第6章」第 162 段(text/13-ch06.txt:162,搜「独热」)与第 165 段(text/13-ch06.txt:165,搜「[1, 0, 0]」)。

  6. 出处:「第6章」第 180 段(text/13-ch06.txt:180,搜「词频」)。

  7. 出处:「第6章」第 186 段(text/13-ch06.txt:186,搜「10/5=2」)与第 189 段(text/13-ch06.txt:189,搜「TF-IDF」)。

  8. 出处:「第6章」第 206 段(text/13-ch06.txt:206,搜「倒排索引」)、第 220 段(text/13-ch06.txt:220,搜「归一化」)与第 223 段(text/13-ch06.txt:223,搜「真正的改进」)。

  9. 出处:「第6章」第 231 段(text/13-ch06.txt:231,搜「hot dog」)与第 234 段(text/13-ch06.txt:234,搜「停止词」)。

  10. 出处:「第6章」第 246 段(text/13-ch06.txt:246,搜「向量数据库」)。

  11. 出处:「第6章」第 293 段(text/13-ch06.txt:293,搜「FAISS」)、第 305 段(text/13-ch06.txt:305,搜「哈希到同一个桶」)、第 311 段(text/13-ch06.txt:311,搜「多层图」)、第 317 段(text/13-ch06.txt:317,搜「子向量」)与第 323 段(text/13-ch06.txt:323,搜「100到10,000」)。

  12. 出处:「第6章」第 125 段(text/13-ch06.txt:125,搜「索引」;若定位失败搜「权衡」)。

  13. 出处:「第6章」第 350 段(text/13-ch06.txt:350,搜「EADDRNOTAVAIL」)。

  14. 出处:「第6章」第 452 段(text/13-ch06.txt:452,搜「重排序」)、第 461 段(text/13-ch06.txt:461,搜「倒数排名融合」)与第 464 段(text/13-ch06.txt:464,搜「1.5」)。

  15. 出处:「第6章」第 353 段(text/13-ch06.txt:353,搜「上下文精度」)。

  16. 出处:「第6章」第 371 段(text/13-ch06.txt:371,搜「标注数据库中所有文档」)、第 374 段(text/13-ch06.txt:374,搜「NDCG」)与第 431 段(text/13-ch06.txt:431,搜「BEIR」)。

  17. 出处:「第6章」第 386 段(text/13-ch06.txt:386,搜「1亿个文档」)。向量数据库占比见同段(搜「五分之一」)。

  18. 出处:「第6章」第 499 段(text/13-ch06.txt:499,搜「2048个字符」)、第 502 段(text/13-ch06.txt:502,搜「递归拆分」)、第 505 段(text/13-ch06.txt:505,搜「py-tree-sitter」)、第 508 段(text/13-ch06.txt:508,搜「I left my wife」)与第 514 段(text/13-ch06.txt:514,搜「重新对数据进行索引」)。

  19. 出处:「第6章」第 538 段(text/13-ch06.txt:538,搜「新闻聚合」)。

  20. 出处:「第6章」第 556 段(text/13-ch06.txt:556,搜「Emily」;若定位失败搜「查询重写」)。

  21. 出处:「第6章」第 490 段(text/13-ch06.txt:490,搜「上下文检索」;若定位失败搜「元数据」)。

  22. 出处:「第6章」第 674 段(text/13-ch06.txt:674,搜「飞屋环游记」)与第 686 段(text/13-ch06.txt:686,搜「CLIP」)。

  23. 出处:「第6章」第 704 段(text/13-ch06.txt:704,搜「Kitty Vogue」)。

  24. 出处:「第6章」第 830 段(text/13-ch06.txt:830,搜「Fruity Fedora」)。