第 11 讲:[客座] 检索增强生成(RAG)

Large Language Models: Methods and Applications · Lecture 11。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应原课:CMU 11-667 Fall 2025 · Lecture 11 · Tue 30-Sep-2025 · Retrieval-augmented generation(客座:Akari Asai,CMU / Ai2) 原课 slides:Retrieval and Retrieval-Augmented Generation(改编自 ACL 2023 教程 Retrieval-based Language Models and Applications(Asai、Min、Zhong、Chen),以及 Graham Neubig 的 Advanced NLP Fall 2024) 阅读材料:Lewis et al. (2020), Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks;Khandelwal et al. (2020), Generalization through Memorization: Nearest Neighbor Language Models(kNN-LM);Mallen et al. (2023), When Not to Trust Language Models: Investigating Effectiveness of Parametric and Non-Parametric Memories;Asai et al. (2024), Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection 配套代码:code/lecture11/(1 个模块 + 5 个演示脚本;第一次运行要训练 5 个模型,共约 3 分钟) 本讲的写法:骨架来自原课 slides 的三部分(文档库、检索器、语言模型与流水线);“花园百科”是补充的,对应原课 HW3 的后半(训练检索器、搭建 RAG)。所有数字都来自配套代码的实际输出。


目录


0. 本讲导读

0.1 这一讲要回答的问题

第 10 讲最后的法律例子说明:给 LLM 接上检索,能大幅减少”编造”。这一讲把这件事讲透:

  • 语言模型把知识存在参数里,哪些知识它记得住、哪些记不住?不知道时它会怎样?
  • 一个检索增强的语言模型由哪三部分组成?每一部分有哪些设计选择?
  • 检索器有哪几类(稀疏、稠密、重排序)?怎样训练、怎样评估?它们各自栽在哪里?
  • 检索到的段落怎样交给语言模型——拼进输入、在中间层融合、还是在输出端插值?
  • 检索什么时候帮忙、什么时候反而有害?模型能不能自己判断”该不该检索""资料有没有用”?

0.2 学完这一讲你应该能

  • 用”知识在预训练语料里出现的次数”解释参数化知识的长尾问题,说出幻觉和知识过时的来源;
  • 画出 RAG 的三个部件(文档库、检索器、语言模型),说出 RAG 的三个好处;
  • 计算 BM25 和 nDCG@10,写出稠密检索的对比学习损失,比较稀疏、稠密、交叉编码器重排序;
  • 区分输入增强(RAG)、中间融合(RETRO)、输出插值(kNN-LM),写出 RAG 的边缘化公式和 kNN-LM 的插值公式;
  • 说出简单 RAG 的四个局限(不必要的检索、被无关上下文带偏、输出缺少引用支持、延迟),以及自适应检索和 Self-RAG 怎样应对。

0.3 本讲的实验平台:花园百科

rag_world.py 造了一个”知道每条知识在语料里出现了几次”的世界:

  • 400 位园丁,名字是”名 + 独一无二的造词姓氏”(例如 Ines Ronus、Tova Sur);20 个名字被很多人共用,姓则一人一个。每位园丁有三条事实:住在哪个镇(16 个镇,大镇更常见,最大的 Ashby 约占 20%)、种什么(35 种植物)、养什么(8 种动物)。
  • 流行度服从 Zipf 定律:排第 r 位的园丁被提到的概率 ∝ r−1.2r^{-1.2}。最热门的 Ines Ronus 的住址出现在 2732 篇文档里,排第 100 位的 20 篇,排第 399 位的 4 篇。
  • 预训练语料(“网页”):18000 篇传记 + 24000 篇新闻,随机打乱:
传记:Tova Zind grows fig . Tova Zind keeps dog .
新闻:Rosa Gek sold pumpkin to Ada Kamen .
新闻:Jude Zemal walked rabbit with Ines Ronus . Jude Zemal walked rabbit with Ines Ronus .

新闻里的镇、植物、动物都是随机的,和谁住哪儿、种什么无关——它们是天然的”干扰项”;一半的新闻把那句话原样再说一遍(§5.1 会解释为什么需要它)。COUNTS 记录每条事实出现在几篇传记里,这就是本讲的”流行度”(Kandpal et al. 2023 的做法:数相关文档)。

  • 文档库(“百科全书”):85% 的园丁有一篇百科条目(三条事实都在,16 个 token),外加 3000 篇新闻。
  • 测试:每 4 位园丁取 1 位(共 100 位)留作”读者训练集”,其余 300 位 × 3 个关系 = 900 条测试事实。按流行度分桶:0 次 23 条、1~2 次 153 条、3~9 次 462 条、10~29 次 166 条、≥30 次 96 条。

模型是第 2 讲的因果 Transformer:small(d=64、2 层,约 10 万参数)和 large(d=128、4 层,857,088 个参数)。和真实 LLM 预训练一样,每篇文档只看一遍,所以”出现几次”就是”见过几次”。


1. 参数里的知识:热门的记得住,冷门的记不住

1.1 参数化语言模型

slides 从最熟悉的图开始:语言模型 θ\theta 在预训练数据上学会 pθ(x5∣x1,…,x4)p_\theta(x_5 \mid x_1, \dots, x_4)。问它 “ChatGPT is developed by”,它给 OpenAI 0.52、Google 0.31……知识全部存在参数里——这叫参数化记忆(parametric memory)。

问题是,参数里的知识有三个毛病:

  1. 幻觉(hallucination):slides 里,ChatGPT-4o(2025 年 2 月)被问到 Akari Asai 的论文,列出的论文”不是我的”、发表的会议也是错的;问 “Who is Akari Asai?”,模型可能回答”一位日本声优”(同名的人)。
  2. 长尾知识:Mallen et al. (2023) 的 PopQA 发现,LM 在冷门实体上的准确率很低——越不出名,越答不对。
  3. 知识过时:参数停留在训练数据截止的那一刻。问 “Who developed GPT4o?”,2023 年收集数据的模型回答”没有叫 GPT4o 的模型”(RealTimeQA,Kasai et al. 2023)。

1.2 实验:准确率 vs 流行度

代码 01 §2:闭卷问法是给模型 “Ines Ronus lives in”,看它接下来说哪个词(和 LAMA 探针一样)。

模型总体0 次1~2 次3~9 次10~29 次≥30 次
small(约 10 万参数)35.9%8.7%14.4%23.6%57.8%97.9%
large(约 85 万参数)59.8%8.7%22.2%53.9%94.6%100.0%

这就是 Mallen et al. 那张图的形状:一条事实见过 30 次以上,两个模型都几乎全对;见过 1~2 次,大模型也只答对两成多。把模型做大,主要提升的是中间几档(3~29 次)。Kandpal et al. (2023) 统计了真实预训练语料里”问题和答案同时出现的文档数”,看到同样的单调关系,并外推出:要把只出现几次的知识学好,模型得大好几个数量级。

代码 01 §5:多训练几遍呢?

large总体0 次1~2 次3~9 次10~29 次≥30 次
1 遍59.8%8.7%22.2%53.9%94.6%100.0%
3 遍96.2%13.0%90.8%100.0%100.0%100.0%

训练 3 遍 = 每条事实多见两次,“见过 1~2 次”那一档从 22% 跳到 91%——决定记不记得住的是”见过几次”。但从没出现过的事实(0 次)怎么训练都学不会,而真实世界里这样的知识要多少有多少(新闻、私有文档、昨天发生的事)。

我写代码时的第一版在同一份语料上训练了 10 遍,结果只出现过一次的事实也全都答对——那其实是”见过 10 次”。真实的 LLM 预训练大多只过一遍数据,才有长尾问题。(代码 README 第 1 条)

1.3 实验:它知道自己不知道吗?

代码 01 §3(large):

流行度准确率平均置信度答错且置信度 > 0.5
0 次8.7%0.3117.4%
1~2 次22.2%0.339.2%
3~9 次53.9%0.413.9%
10~29 次94.6%0.700.0%
≥30 次100.0%0.940.0%

两件事同时成立:

  • 置信度随流行度下降,模型多少”感觉到”自己不熟——这是 §5.4”按置信度决定要不要检索”的依据;
  • 但它永远会给出一个答案。见过 0~2 次的住址答错时,它最常说 Ashby(28%)——最大的镇。没见过的事实,它按先验猜,说出来和真的一样流利。例:Rosa Muxol keeps ▶ goat(置信度 0.42;正确答案 cat)。

这就是幻觉的来源:语言模型的训练目标是”预测最可能的下一个词”,里面没有”我不知道”这个选项。

1.4 实验:世界变了

代码 01 §4:两成园丁搬了家(World.updated(0.2))。测试集里搬了家的 54 位园丁,模型说出旧地址 68.5%、新地址 1.9%。要更新参数里的知识,得重新训练或编辑参数(知识编辑,例如 ROME);而 RAG 只要更新文档库——§7.3 会检验读者是否真的”信”新资料。


2. 检索增强:文档库 + 检索器 + 语言模型

2.1 直觉

slides 的直觉例子:问 “Who is Akari Asai?”,闭卷的 LM 回答”日本声优”;先检索到一段资料(“Akari Asai is a Ph.D. student in the Paul G. Allen School…”),再回答,就说对了。RAG 的三个好处:

  1. 减少幻觉:答案有资料可依;
  2. 不重新训练就能更新知识:更新文档库即可(GPT4o 的例子);
  3. 可验证:答案可以附上出处,用户能核对。

工业界已经大量采用:slides 引用 Databricks 的数据——60% 的 LLM 应用用了某种形式的 RAG。

2.2 三个部件

x  →检索器  D=Top-kd∈文档库 Sim(d∣x)  →语言模型  yx \;\xrightarrow{\text{检索器}}\; \mathcal{D} = \mathrm{Top}\text{-}k_{d \in \text{文档库}}\, \mathrm{Sim}(d \mid x) \;\xrightarrow{\text{语言模型}}\; y
  • 文档库(datastore):大量文档的集合——维基百科、代码、论坛……(§3)
  • 检索器(retriever):按相似度 Sim(⋅∣x)\mathrm{Sim}(\cdot \mid x) 从文档库里取出前 k 篇(§4)
  • 语言模型:读 xx 和 D\mathcal{D},生成 yy(§5–7)

slides 的例子:问 “Which company developed GPT4o?”,三篇文档的相似度分别是 0.9(GPT-4o is a pre-trained transformer developed by OpenAI)、0.1(Transformers 系列电影)、0.8(GPT4o was released by OpenAI in May 2024),取前两篇交给 LM,回答 OpenAI。

下面三节按这三个部件展开。


3. 文档库:来源、切块、规模

3.1 用什么做文档库

选对文档库很重要。问”哪家公司开发了 GPT4o”,英文维基百科(Chen et al. 2017、Lewis et al. 2020 等大量工作的选择)就够了;问”怎样用 LlamaIndex 实现 RAG”,需要的是代码片段、官方文档、社区论坛(CodeRAG-Bench,Wang et al. 2025)。

规模:MassiveDS(Shao et al. 2024)把文档库从维基百科的 50 亿 token 扩到 1.4 万亿 token(22 TB),检索增强的语言模型随文档库变大而持续变好——但存储、索引、检索的工程挑战也随之而来。

3.2 怎样处理文档

slides 的三步:

  1. 整理与预处理:HTML → 纯文本(第 3 讲的清洗流水线);
  2. 切块(chunking):按段落(换行符)切,或每 k 个词切一块(常见 100~250 个词);
  3. 后处理:去掉太短的块、去重、过滤乱码。

3.3 实验:同一个文档库,三种切法

代码 02 §1:查询是测试集里有条目的园丁 × 3 个关系 = 768 个问题(例如 “where does Ines Ronus live ?”);“正确的块”= 完整包含答案那句话的块;检索器都是 BM25。

切块方式块数平均长度没有正确块的问题R@1R@5nDCG@10MRR
整篇文档33408.801.0001.0001.0001.000
按句子40207.300.3330.9900.7070.608
每 8 个词36808.02560.3330.6590.5330.489
  • 整篇文档:问题里的姓只在这位园丁的条目里出现三次,BM25 一找一个准。代价是每块更长,读者要读的字更多。
  • 按句子:这位园丁的三句话都含有名字,BM25 分不出哪句讲”住址”——问题里的 live 和句子里的 lives 不是同一个词(练习 1 会算出为什么 R@1 恰好是三分之一)。
  • 每 8 个词:不顾句子边界,三分之一的问题根本没有完整的答案块。

切块是检索的单位,它决定了检索器能找到什么、读者要读多少。块太碎,相关性信号不够;块太大,读者被块里的其他内容干扰、上下文也更贵(§5.5)。


4. 检索器:稀疏、稠密、重排序

4.1 三类检索器

稀疏检索器稠密检索器重排序器
相似度基于词频的向量预训练 LM 编码的稠密向量查询和文档一起编码后打分
训练不需要需要*需要*
例子TF-IDF、BM25DPR、Contriever、ColBERT交叉编码器(cross-encoder)

(*也有无监督训练的版本。)

4.2 稀疏检索:TF-IDF 与 BM25

最简单的表示是独热向量:每个维度是一个词,查询或文档里出现了就是 1。接着用词频代替 0/1,再用 IDF 给罕见的词更大的权重:

TF-IDF(t,d)=TF(t,d)×log⁡Nnt\text{TF-IDF}(t, d) = \text{TF}(t, d) \times \log \frac{N}{n_t}

NN 是文档总数,ntn_t 是含有词 tt 的文档数。BM25(Robertson & Zaragoza 2009)在此基础上加了词频饱和和长度归一化:

BM25(q,d)=∑t∈qIDF(t)⋅f(t,d)⋅(k1+1)f(t,d)+k1⋅(1−b+b⋅∣d∣avgdl)\text{BM25}(q, d) = \sum_{t \in q} \text{IDF}(t) \cdot \frac{f(t, d) \cdot (k_1 + 1)}{f(t, d) + k_1 \cdot \left(1 - b + b \cdot \frac{|d|}{\text{avgdl}}\right)}
  • f(t,d)f(t,d) 从 1 到 2 的提升大于从 10 到 11(k1k_1 控制饱和得多快,常取 1.2);
  • 长文档的词频要打折扣(bb 控制打多少,常取 0.75)。

稀疏检索的局限:它是”词袋”——不懂语义相似(live 和 lives、pet 和 keeps 对它来说毫无关系)。

4.3 稠密检索

把查询和文档各自编码成一个向量,用内积排序:

zi=Encoder(zi),x=Encoder(x),(z1,…,zk)=arg⁡Top-k  x⋅z\mathbf{z}_i = \text{Encoder}(z_i), \quad \mathbf{x} = \text{Encoder}(x), \quad (z_1, \dots, z_k) = \arg\text{Top-}k\; \mathbf{x} \cdot \mathbf{z}

编码器常取掩码 LM 的 [CLS] 输出(DPR,Karpukhin et al. 2020),或对全部输出向量做均值 / 最大池化(SBERT、SGPT)。文档向量可以预先算好存进索引,查询时只编码查询。

快速近邻搜索:千万级以内,精确搜索(矩阵乘法)仍然很快;再大就用近似搜索(FAISS 的倒排、HNSW 图),用量化压缩索引——拿一点精度换速度和内存。

训练:对比学习(第 10 讲 §5):

L(q,p+,p1−,…,pn−)=−log⁡exp⁡(sim(q,p+))exp⁡(sim(q,p+))+∑j=1nexp⁡(sim(q,pj−))\mathcal{L}(q, p^+, p_1^-, \dots, p_n^-) = -\log \frac{\exp(\mathrm{sim}(q, p^+))}{\exp(\mathrm{sim}(q, p^+)) + \sum_{j=1}^{n} \exp(\mathrm{sim}(q, p_j^-))}

负例来自同一批里其他查询的正例(批内负例),以及同一个或另一个模型检索到的困难负例(DPR 用 BM25 的结果)。

无监督训练:Contriever(Izacard et al. 2022)不需要标注的(问题, 段落)对——从同一篇文档里随机截两段(independent cropping)当正例。BEIR 上,无监督训练的检索器在训练分布之外更稳健。

指令微调的检索器(TART,Asai et al. 2023):把任务说明写进查询(“找一段回答这个问题的维基百科段落” vs “找一段相似的代码”),同一个检索器按指令检索不同的东西。

4.4 重排序:交叉编码器

双编码器(bi-encoder)分别编码查询和文档,两者只在最后做一次内积,交互是”浅”的;交叉编码器把查询和文档拼在一起送进模型,每一层都能互相注意,打分更准,但每个(查询, 文档)对都要跑一次模型,无法预先算好。所以实践中是两阶段:稀疏 / 稠密检索召回几百篇,交叉编码器重排序前几十篇。

4.5 评估

  • 无序的检索结果:精确率、召回率;
  • 有序的结果:Recall@k、MRR,以及 BEIR 的主要指标 nDCG@10:
DCG@10=∑i≤10,  di 相关1log⁡2(i+1),nDCG@10=DCG@10理想排序的 DCG@10\text{DCG@10} = \sum_{i \le 10,\; d_i \text{ 相关}} \frac{1}{\log_2(i + 1)}, \qquad \text{nDCG@10} = \frac{\text{DCG@10}}{\text{理想排序的 DCG@10}}
  • 基准:BEIR(Thakur et al. 2021,18 个零样本检索数据集)、MTEB(Muennighoff et al. 2022,嵌入模型的综合基准,有公开排行榜)。slides 总结 BEIR 的结果:加交叉编码器重排序有帮助;稠密检索器在分布外可能很吃力;无监督训练有助于分布外。

4.6 实验:BM25 vs 稠密 vs 混合

代码 02 §2:按句子切块(BM25 最吃亏的那种)。稠密检索器用第 10 讲的 BowEncoder(词向量平均 → 线性层),在 84 位”读者训练集”园丁的 504 个(问题, 正确句子)对上做 InfoNCE 训练,每个关系用两种问法(“where does … live ?”、“which town is home to … ?”)。测试的是另外那些园丁——名字从没在检索器的训练里出现过——分两种问法:训练里见过的第一种,和从没见过的第三种(“in which town does … live ?”、“what animal is kept by … ?”)。

检索器新园丁·见过的问法 R@1 / nDCG@10新园丁·没见过的问法 R@1 / nDCG@10
BM250.333 / 0.7070.661 / 0.875
稠密(64 维)0.993 / 0.9970.384 / 0.568
混合(标准化后相加)1.000 / 1.0000.915 / 0.967
  • 见过的问法:稠密检索器学会了 live ↔ lives in、grow ↔ grows,知道问的是哪个关系;对没见过的名字也找得准——查询和句子里是同一个姓,两边用同一个词向量,点积里天然有”自己和自己”的相似度。
  • 没见过的问法:“kept by""planted by”里的新词带着从没训练过的随机词向量,冲淡了名字的信号:稠密检索器有 34% 的问题找到了”讲同一个关系的句子”,却是别的园丁的。BM25 反而变好了:in which town 里的 in 恰好和 lives in 字面重合。
  • 两者的错误互补:BM25 锁定了是哪位园丁,稠密检索器补上”问的是哪个关系”,混合检索远好于任何一个。这就是 BEIR 上反复看到的现象:稠密检索器在训练分布之外常常不如 BM25;稀疏 + 稠密的混合是最常用的稳健做法。

第一版实验里,测试问题和训练问题用的是同一种问法,稠密检索器看起来近乎完美(99%)。换成没见过的问法,才看到它的脆弱。评估检索器时,测试查询的分布和训练查询一样重要。(代码 README 第 3 条)

4.7 实验:向量的瓶颈

代码 02 §3:问法都是训练里见过的那种,区别只在于这位园丁有没有在检索器的训练里出现过。

向量维度训练集里的园丁 R@1新园丁 R@1新园丁:混合 R@1
887.7%52.1%91.4%
1698.8%80.2%97.3%
3299.6%91.0%98.4%
64100.0%99.3%100.0%

一个定长向量要装下整段话的意思。维度够大时,每个姓都能保留自己的方向;维度小了,检索器训练时专门拉开过的名字还分得清,没见过的名字就开始互相混淆。这对应真实世界的观察:稠密检索器在以冷门实体为中心的问题上常常输给 BM25(Sciavolino et al. 2021,“Simple Entity-Centric Questions Challenge Dense Retrievers”)。真实的稠密检索器要把几百个 token 压进 768 维,冷门实体的名字(往往被切成好几个子词)更容易被”挤掉”。


5. 先检索、再阅读

5.1 怎样使用检索结果:三个问题

slides 把检索增强 LM 按三个问题分类:

  • 检索什么:文本块(段落)?token?别的东西?
  • 什么时候检索:每个问题一次?每隔几个 token?每个 token?
  • 怎样使用:
输入增强中间融合输出插值
做法把检索结果拼进 LM 的输入修改 LM,在中间层融入检索结果直接修改输出的 token 分布
优点容易使用(不训练也行)、有效能扩展到很多段落不需要训练*
缺点难以使用很多段落需要重新训练在一些任务上效果有限
例子RAGRETRO、InstructRETROkNN-LM

这一节讲输入增强,§6 讲另外两种。

5.2 RAG(Lewis et al. 2020)与它的训练

“RAG”这个名字来自 Lewis et al. (2020):检索器(DPR)取出 top-k 段落 zz,生成器(BART)在每个段落的条件下生成,按检索分数边缘化:

pRAG(y∣x)≈∏i∑z∈top-k(pη(⋅∣x))pη(z∣x)  pθ(yi∣x,z,y1:i−1)p_{\text{RAG}}(y \mid x) \approx \prod_{i} \sum_{z \in \text{top-}k(p_\eta(\cdot \mid x))} p_\eta(z \mid x)\; p_\theta(y_i \mid x, z, y_{1:i-1})

(这是 RAG-Token 的形式:每个 token 都对段落求和;RAG-Sequence 对整个输出序列求和一次。)训练时最小化 −∑jlog⁡pRAG(yj∣xj)-\sum_j \log p_{\text{RAG}}(y_j \mid x_j),检索器的查询编码器和生成器一起更新——检索器从”哪个段落让答案更好生成”里得到信号,不需要段落级的标注。

slides 把 RAG 的训练方式分成三类:

  • 独立训练:检索器和 LM 各练各的(DrQA、DPR + 任意阅读器);
  • 顺序训练:先固定一个、再训练另一个(REPLUG 用 LM 的反馈训练检索器;Evidentiality Generator);
  • 联合训练:RAG、REALM(文档向量异步更新)。

今天人们说”RAG”,多半指”检索 + 现成的 LLM”:不训练任何东西,把检索到的段落写进提示。这之所以可行,是因为大模型本来就会”读”。

5.3 实验:先教会小模型”读”

我们的小模型不会”读”。读者(reader)= 闭卷模型(large)在 7200 条”检索到的资料 + 问题 → 答案”上微调(只用 100 位读者训练集园丁,只在答案上算损失),同时回放 4000 篇预训练文档。输入长这样:

<ctx> Jude Riskem lives in Pebworth . Jude Riskem grows poppy . Jude Riskem keeps pony . <sep> Jude Zemal walked cat with Jude Riskem . </ctx> Jude Riskem lives in  ▶ Pebworth

读者起初怎么也学不会读:给了正确条目,准确率也只有 73%。原因是基座没有复制能力(第 6、10 讲反复出现的主题)。先在传记里加”把事实再说一遍”的回顾句——没用,因为事实本来就能从记忆里预测,复制不是必需的;改成让内容随机的新闻带回顾句,预测回顾句就只能靠照抄,基座这才学会复制。只有一种新闻模板(met … in 镇)时,它只学会了抄镇名,于是新闻改成了三种模板。(代码 README 第 2 条)

5.4 实验:RAG 帮了谁

代码 03 §1(BM25 按问题检索整篇文档):

总体0 次1~2 次3~9 次10~29 次≥30 次
闭卷(预训练模型)59.8%8.7%22.2%53.9%94.6%100.0%
闭卷(读者)54.4%17.4%21.6%47.2%86.1%95.8%
开卷:BM25 第 1 篇88.0%91.3%85.6%85.9%91.6%94.8%
开卷:BM25 前 3 篇81.0%87.0%77.8%79.0%84.3%88.5%
开卷:直接给正确条目99.6%95.7%99.3%99.6%100.0%100.0%
  • 给了正确条目,读者几乎全对,不管这条知识多冷门——它是在”读”而不是在”记”。
  • 开卷让冷门知识的准确率翻了几倍;可最热门那一档,开卷反而比闭卷低——正是 Mallen et al. (2023) 的图(slides:“RAG 在长尾上持续带来提升”,但热门实体上 GPT-3 + 检索不如 GPT-3 自己)。
  • 读者的闭卷成绩比预训练模型低了 5.3 个百分点:微调成读者时,参数里的一部分知识被冲掉了(回放预训练文档也没能完全避免——第 6 讲的灾难性遗忘)。

5.5 简单 RAG 的局限

slides 列出四个:

  1. 不必要的检索:问 “Who is Sam Altman?”,检索器取回了 Samuel Adams(美国开国元勋)的资料,模型照着说”他是美国的开国元勋”——本来模型自己知道答案。
  2. LM 很容易被无用的上下文带偏(Shi et al. 2023)。
  3. 输出常常得不到引用的支持:Liu et al. (2023) 评估生成式搜索引擎,相当一部分句子得不到所附引用的支持。
  4. 延迟:要编码长得多的上下文(RAGCache 等工作专门优化这部分)。

代码 03 §2 演示前两个。测试题里有 132 道题的园丁在文档库里没有条目,BM25 返回的是提到这位园丁的新闻:

资料:Nia Gaskan met Jude Riskem in Larkhill .
问:Nia Gaskan lives in ▶ 读者答 Larkhill(正确答案 Coveton;同一个模型闭卷时答 Coveton)

这些题,读者开卷只答对 21.2%,而它闭卷能答对 40.9%。其中 44 道题的新闻里恰好有一个同类的词(问住址时新闻里有镇名)——读者照抄它的比例 90.9%。热门的(≥10 次)33 道:开卷 42.4%,闭卷 72.7%。读者在训练时”资料里总有答案”,于是学会了几乎无条件地照抄资料里看起来像答案的词。

代码 03 §4:多给几篇资料呢?

检索篇数 k正确条目在资料里准确率平均输入长度(token)
0(闭卷)—54.4%4.3
185.3%88.0%21.2
285.3%85.0%30.4
385.3%81.0%40.5
585.3%71.4%63.4

BM25 第 1 篇就找到了正确条目;多给的几篇只是提到这位园丁的新闻,里面的随机值全是干扰项,准确率随 k 下降,输入长度却成倍增加(自注意力的计算量和长度的平方成正比)。在检索质量更差的场景里,多给几篇能提高”正确资料被检索到”的概率,那时 k 的取舍就是召回率和干扰之间的权衡。

代码 03 §6:答案有资料支持吗?“有支持”= 检索到的资料里有一句”这位园丁 + 这个关系 + 这个答案”。

有支持没支持
答对84.9%3.1%
答错0.0%12.0%

有支持的答案全是对的,所有错误都没有支持——如果系统检查”引用是否真的支持答案”,就能把错误挑出来。另有少数答对的答案没有支持:资料没用,读者凭记忆或碰巧答对了。

5.6 实验:自适应检索

Mallen et al. (2023) 的建议:热门知识信模型自己,冷门的才去查。代码 03 §3,每道题二选一:闭卷回答,或检索 1 篇后由读者回答。闭卷那一支可以用读者自己,也可以用没被微调冲掉知识的预训练模型。

策略闭卷用读者:检索比例 / 准确率闭卷用预训练模型:检索比例 / 准确率
从不检索(闭卷)0.0% / 54.4%0.0% / 59.8%
总是检索100.0% / 88.0%100.0% / 88.0%
按流行度:出现 < 10 次才检索70.9% / 87.1%70.9% / 89.1%
按流行度:出现 < 30 次才检索89.3% / 88.1%89.3% / 88.6%
按置信度:闭卷置信度 < 0.533.2% / 74.9%54.3% / 88.6%
按置信度:闭卷置信度 < 0.860.4% / 85.1%77.4% / 88.8%
按置信度:闭卷置信度 < 0.9583.2% / 88.2%92.1% / 88.1%
先知(只在闭卷会答错时检索)45.6% / 91.4%40.2% / 93.8%
  • 闭卷用预训练模型时,“置信度 < 0.5 才检索”只检索一半的题,准确率还略高于总是检索。
  • 闭卷用读者时,自适应检索只能和总是检索打平:读者忘掉了一部分热门知识,闭卷那一支不再可靠。
  • 真实系统往往不知道一个问题有多”热门”(这里我们作弊地数了预训练语料);用模型自己的置信度来决定(FLARE,Jiang et al. 2023 在生成到低置信度的 token 时才检索)不需要这个信息。

代码 03 §5:文档库的覆盖率(自适应检索 = 闭卷用预训练模型、置信度 < 0.5 才检索):

有条目的园丁比例总是检索自适应检索
25%42.1%62.8%
50%62.9%74.4%
85%88.0%88.6%
100%99.6%95.6%

文档库每多覆盖一位园丁,开卷就能多答对他的问题(MassiveDS 的结论)。覆盖率低时,总是检索甚至不如闭卷(59.8%),自适应检索要好得多;覆盖率 100%、检索永远可靠时,总是检索几乎全对,自适应检索反而吃亏——它相信了闭卷时”有把握”却答错的那些题。要不要检索,取决于检索有多可靠。


6. 其他用法:中间融合与输出插值(kNN-LM)

6.1 RETRO:在中间层融合

RETRO(Borgeaud et al. 2022)把输入切成每 64 个 token 一块,每块用冻结的 BERT 向量去一个两万亿 token 的文档库里检索近邻,再在 Transformer 的中间层用块交叉注意力(chunked cross-attention)融入这些近邻。好处是能用很多段落(交叉注意力的开销比把它们全拼进输入小);代价是要重新训练模型。Borgeaud et al. 报告,7.5B 参数的 RETRO 在多个语言建模基准上能和大二十多倍的模型相当。

6.2 kNN-LM:在输出端插值

kNN-LM(Khandelwal et al. 2020)完全不改模型:

PkNN-LM(y∣x)=(1−λ) PLM(y∣x)+λ PkNN(y∣x)P_{\text{kNN-LM}}(y \mid x) = (1 - \lambda)\, P_{\text{LM}}(y \mid x) + \lambda\, P_{\text{kNN}}(y \mid x)
  • 数据库:对语料里每个位置,键 = 模型在该位置的最后一层隐藏状态(“上文的表示”),值 = 那里的下一个词;
  • 查询:用当前上文的表示找 k 个最近的键,按 exp⁡(−距离2)\exp(-\text{距离}^2) 加权它们的值,得到 PkNNP_{\text{kNN}};
  • λ\lambda:超参数,“信模型”还是”信数据库”。

检索的是 token(每个 token 检索一次),用的方式是输出插值——§5.1 那张表的最右一列。

6.3 实验:把”见过但没记住”的找回来

代码 04 §1:预训练语料 42000 篇、508,729 个 token → 数据库 508,729 条,每个键 128 维。例子:

'Tova Sur lives in'(这条事实在语料里只出现过 1 次;正确答案 Redcliff)
  语言模型:Ashby(概率 0.96;正确答案的概率 0.00)
  4 个最近邻(距离平方 → 存的下一个词):
     0.00  …Tova Sur lives in → Redcliff
    46.01  …Jude Stuman lives in → Ashby
    46.01  …Jude Stuman lives in → Ashby
    46.54  …Jude Stuskin lives in → Ashby

最近的键就是语料里那唯一一次提到这条事实的位置(那篇传记也以 “Tova Sur lives in” 开头,上文一字不差,距离为 0)。语言模型训练时只见过这句话一次,参数没记住;数据库却原样存着它。

代码 04 §2(k = 16):

总体0 次1~2 次3~9 次10~29 次≥30 次
语言模型59.8%8.7%22.2%53.9%94.6%100.0%
kNN-LM λ = 0.2591.3%4.3%84.3%93.3%99.4%100.0%
kNN-LM λ = 0.597.7%8.7%100.0%100.0%100.0%100.0%
只用 kNN97.7%8.7%100.0%100.0%100.0%100.0%

只要事实在语料里出现过,哪怕一两次,kNN 就能把它找回来;从没出现过的事实,数据库里也没有——kNN-LM 能”记住”的上限就是它的数据库。论文的标题”Generalization through Memorization”:把记忆交给数据库,模型只负责把上文表示好。

闭卷问答上的效果好得出奇,一部分原因是查询和语料里的上文一字不差。下面在留出文本上看更公平的数字。(代码 README 第 6 条)

6.4 实验:留出文本的困惑度

代码 04 §3:1000 篇新文档(同分布、没参加训练),11,963 个 token。

λ全部传记里的事实新闻里的随机值其他词
0.002.361.366.142.36
0.102.331.246.122.36
0.252.331.176.162.37
0.502.401.096.462.46
0.752.591.047.302.69

整体困惑度只小幅下降(最好在 λ ≈ 0.1~0.25),收益集中在”传记里的事实”——Khandelwal et al. 也发现 kNN-LM 主要帮助罕见的模式(事实、专有名词)。新闻里的随机值本来就不可预测,数据库里”相似上文”后面的词和这里无关,λ 越大越糟;λ 太大时连普通词也变差。slides 说输出插值”在一些任务上效果有限”,正是这个原因。

6.5 实验:换数据库,更新知识

代码 04 §4:两成园丁搬了家;用”新世界”的语料重建数据库,语言模型本身不动。测试集里搬了家的 54 位(热门的 17 位):

说出新地址说出旧地址热门的:新 / 旧
语言模型1.9%68.5%0% / 100%
kNN-LM λ = 0.2529.6%61.1%6% / 94%
kNN-LM λ = 0.5100.0%0.0%100% / 0%
只用新数据库100.0%0.0%100% / 0%

不用训练,换掉数据库就更新了知识。但插值时,参数里的旧知识还在”投票”:热门园丁的旧地址模型很有把握,λ 小时旧地址赢。

代价(代码 04 §5):模型 857,088 个参数(3.4 MB),数据库 6500 万个浮点数(260 MB),是模型的 76 倍;而且每生成一个 token 都要做一次近邻搜索(RAG 每个问题只检索一次)。Khandelwal et al. 的数据库有 1 亿多条、每条 1024 维,只能用 FAISS 的近似搜索。


7. 近期进展:让模型自己决定检索和批判

7.1 Self-RAG

slides 把简单 RAG 的根本问题概括为两条:LM 没有在检索的条件下训练过;固定的两阶段流水线(总是检索、总是用)。Self-RAG(Asai et al. 2024)训练 LM 生成反思 token(reflection tokens):

反思 token问的问题取值
Retrieve需要检索吗?是 / 否 / 继续用已有的证据
IsRel这个段落和问题相关吗?相关 / 无关
IsSup生成的内容有段落支持吗?完全支持 / 部分支持 / 不支持
IsUse回答有用吗?1~5 分

推断时:模型先决定要不要检索;要的话,对每个检索到的段落并行生成一段输出,同时生成 IsRel、IsSup;再按反思 token 的概率给各个候选打分、挑最好的那段,进入下一句。slides 的例子:问”推荐展示 LLM 帮助科学家综合文献的论文”,第一句”Certainly!”不需要检索;第二句检索到三个段落,两个被判为无关,相关的那个生成的句子被判为”完全支持”(0.9),另一个”部分支持”(0.5)。

训练数据的反思 token 由一个”批评者”模型标注(批评者本身是用 GPT-4 的判断蒸馏出来的),然后生成器在带反思 token 的数据上做普通的语言模型训练——推断时不需要批评者。

7.2 实验:会说”这份资料没用”的读者

代码 05:一个最简版本,只实现 IsRel。同样的 100 位园丁、同样的 7200 条,四成的资料里没有正确条目:

<ctx> Jude Riskem lives in Pebworth . … </ctx> Jude Riskem lives in  ▶ <rel> Jude Riskem lives in Pebworth
<ctx> Jude Zemal met Jude Riskem in Oakridge . </ctx> Jude Riskem lives in  ▶ <irr>

推断:先看 P(<rel>)/(P(<rel>)+P(<irr>))P(\texttt{<rel>}) / (P(\texttt{<rel>}) + P(\texttt{<irr>}))。≥ 0.5 就接上”<rel> + 复述的问题”照资料回答;否则丢掉资料、闭卷回答。

反思 token 的判断(BM25 第 1 篇):资料里有正确条目时判为”有用” 99.6%,没有时判为”有用” 0.0%。

总体有条目没条目0 次1~2 次3~9 次10~29 次≥30 次
普通读者:闭卷54.4%56.8%40.9%17.4%21.6%47.2%86.1%95.8%
普通读者:BM25 第 1 篇88.0%99.5%21.2%91.3%85.6%85.9%91.6%94.8%
会反思的读者:闭卷55.1%57.2%43.2%4.3%26.1%48.1%83.7%97.9%
会反思的读者:BM25 第 1 篇91.6%99.9%43.2%95.7%87.6%89.6%95.8%99.0%

资料没用时,普通读者照抄新闻里的随机值;会反思的读者识别出来、退回闭卷,正确率翻了一倍(正好是它自己闭卷的水平)。热门知识不再被检索失败拖累,总体 91.6%,超过了 §5.6 里除”先知”以外的所有自适应检索策略。

这个读者改了三版(代码 README 第 5 条),两次失败都很有教益。第一版在 <irr> 后面直接说出正确答案——读者把 100 位训练园丁的事实背了下来,读新园丁的资料时会说出同名训练园丁的住址。第二版在 <rel> 后面直接给答案,读资料的准确率从 99.6% 掉到 92%:照抄靠的是”找到上文里和当前词相同的位置、抄它后面的词”(induction head,第 6 讲),答案紧跟在 in 后面时,资料里恰好有 “lives in Pebworth” 可以对照;紧跟在 <rel> 后面就没有了。第三版在 <rel> 后面先复述问题——和 Self-RAG 在 IsRel 之后生成完整的输出句一样——读资料回到 99.8%。输出格式会影响模型能不能用上它已有的本事。

7.3 实验:逐篇判断 vs 拼在一起

代码 05 §2:检索 3 篇。

做法准确率每次前向的输入长度
普通读者:3 篇拼在一起81.0%39.5
会反思的读者:3 篇拼在一起80.2%39.5
会反思的读者:逐篇判断,挑 P(<rel>) 最高的90.1%20.2(× 3 次)

拼在一起时,多出来的新闻是干扰项;逐篇判断每次只读一篇、挑出”有用”的那篇——Self-RAG 的做法。不过这里它还略低于只读第 1 篇(91.6%):排在第 2、3 位的常常是同名不同姓的园丁的条目,反思 token 偶尔会把它误判为有用、而且打分比正确条目还高。检索器越不可靠,逐篇判断的价值越大;检索器很可靠时,多看的那几篇只是多了几次犯错的机会。

7.4 实验:资料和记忆冲突时,信谁?

代码 05 §3:把正确条目里被问到的那条事实换成一个错误的值,其余不动。

跟着资料坚持记忆资料被判为有用跟着资料:0 次 / 1~2 / 3~9 / 10~29 / ≥30
普通读者98.9%0.3%—100 / 98.7 / 98.7 / 98.8 / 100.0
会反思的读者98.2%0.8%99.7%100 / 98.7 / 98.5 / 97.0 / 97.9

两个读者都几乎总是跟着资料走,连它们最熟悉的热门知识也一样。反思 token 也照样判为”有用”——它学会的是”这段资料是不是在讲这位园丁”(相关性),不是”这段资料说得对不对”(真实性)。

  • 好的一面:世界变了,只要更新文档库,读者就会跟着变——搬了家的 45 位园丁,两个读者闭卷都说出新地址 0.0%,开卷分别 100.0% 和 95.6%。
  • 坏的一面:文档库里混进了错误或恶意的内容,读者会照单全收(数据投毒、间接提示注入,第 16 讲)。

真实 LLM 介于两者之间:Longpre et al. (2021) 发现模型常常固执于参数里的记忆、无视上下文里的新知识;Xie et al. (2024) 发现资料连贯可信时,LLM 又很容易被说服。

7.5 工具增强的 LM 与深度研究

  • 工具增强(第 10 讲):Toolformer 让模型在需要时通过 API 调用搜索,能灵活扩展到其他工具;
  • 深度研究(deep research):把推理模型和搜索结合起来,用 SFT / RL 教它规划、多轮搜索、阅读、再推理(例如 WebThinker,Li et al. 2025)。slides 指出它的局限:不能扩展到很多文档(需要”上下文工程”来决定放什么进上下文),输出不严格基于资料。

8. 小结、常见误区、练习

8.1 小结

  1. 参数化知识的局限:能否闭卷答对,由”在语料里见过几次”决定。见过 30 次以上几乎全对,见过 1~2 次只答对两成(大模型主要提升中间档)。不知道时按先验流利地编(幻觉);知识停在训练截止的那一刻。
  2. RAG 的三个部件:文档库(来源、切块、规模)、检索器、语言模型;好处是减少幻觉、不重新训练就能更新知识、可验证。
  3. 检索器:BM25 精确匹配罕见的词但不懂同义;稠密检索器学会改写,但对训练分布之外的问法和冷门实体脆弱;两者互补,混合 + 交叉编码器重排序是常用做法;nDCG@10、BEIR、MTEB。
  4. 先检索再阅读:读者给了正确资料几乎全对,冷门知识成倍提升;但检索失败时,只在”资料总有答案”的数据上训练的读者照抄无关文档(90.9%),热门知识反被拖累。自适应检索(按置信度)用一半的检索达到同样或更好的准确率,前提是闭卷那一支可靠;多给资料不一定更好。
  5. kNN-LM:输出插值,把见过但没记住的事实从数据库里找回来;整体困惑度改进小、对不可预测的内容有害;换数据库就能更新知识;代价是巨大的数据库和每个 token 一次搜索。
  6. Self-RAG:让模型生成反思 token 判断检索和相关性;能识别检索失败、退回记忆;但”相关”不等于”正确”,读者仍会照单全收错误的资料。

8.2 常见误区

  • “把模型做大就能记住所有知识”:模型变大主要帮助中间档的知识;从没见过或只见过一两次的事实,靠规模很难补上(§1.2)。
  • “模型答得流利,说明它知道”:没见过的事实它照样流利地回答,置信度只是略低(§1.3)。
  • “检索总是有帮助”:检索失败时,模型会被无关资料带偏,连本来会的热门知识也答错(§5.5、§5.6)。
  • “给的资料越多越好”:多出来的段落是干扰项,还让上下文成倍变长(§5.5)。
  • “稠密检索器比 BM25 先进,所以更好”:它在训练分布之外、在冷门实体上常常不如 BM25;两者互补(§4.6、§4.7)。
  • “评估检索器时,用和训练一样的问法就够了”:同一个稠密检索器,见过的问法 99%、没见过的问法 38%(§4.6)。
  • “RAG 系统会核实资料的真伪”:读者(包括会判断相关性的读者)几乎总是相信资料(§7.4)。
  • “kNN-LM 能让模型知道新东西”:它只能找回数据库里有的;数据库里没有的,它和模型一样不知道(§6.3)。

8.3 练习

练习 1(BM25 为什么恰好是三分之一):按句子切块时,“where does Ines Ronus live ?” 只和三句话里的 ines、ronus 两个词匹配。分词时句号被去掉,三句话的长度是 5(lives in Larkhill)、4(grows turnip)、4(keeps cat),avgdl = 6.32,idf(ines) = 1.057、idf(ronus) = 1.127,k1=1.2k_1 = 1.2、b=0.75b = 0.75。算出三句的 BM25 分数,并解释为什么 R@1 恰好是 1/3。如果给 BM25 加上最简单的词干还原(去掉词尾的 s),R@1 会变成多少?

参考答案(用 rag_world 验证)

每个匹配词的 tf 部分是 1×2.21+1.2×(0.25+0.75×L/6.32)\frac{1 \times 2.2}{1 + 1.2 \times (0.25 + 0.75 \times L / 6.32)}。L = 5:分母 1+1.2×0.843=2.0121 + 1.2 \times 0.843 = 2.012,得 1.0935;L = 4:分母 1+1.2×0.725=1.8701 + 1.2 \times 0.725 = 1.870,得 1.1768。分数 = (1.057 + 1.127) × tf 部分:lives 那句 2.389,grows、keeps 两句都是 2.570。所以住址那句永远排第三;grows 和 keeps 并列,稳定排序取文档库里在前面的那句(条目里 grows 在 keeps 之前)。于是:问住址 R@1 = 0,问植物 R@1 = 1,问动物 R@1 = 0,平均恰好 1/3(实测:town 0.0、plant 1.0、animal 0.0)。加上词干还原后,live/lives、grow/grows、keep/keeps 都能匹配上,三个关系的 R@1 都是 1,总体 1.000。真实的 BM25 系统(如 Lucene)默认带词干还原,正是为了缓解这种字面不匹配。

练习 2(手算 nDCG@10):一个查询有 2 篇相关文档,检索器把它们排在第 2 和第 5 位。算 R@1、R@5、MRR 和 nDCG@10。

参考答案(用 multi_metrics 验证)

R@1 = 0(第 1 位不相关),R@5 = 1(前 5 里有相关的),MRR = 1/2 = 0.5(第一个相关的在第 2 位)。DCG@10 = 1/log⁡23+1/log⁡26=0.631+0.387=1.0181/\log_2 3 + 1/\log_2 6 = 0.631 + 0.387 = 1.018;理想排序把两篇放在第 1、2 位:IDCG = 1+0.631=1.6311 + 0.631 = 1.631;nDCG@10 = 0.624。和 R@k、MRR 相比,nDCG 同时考虑了”有几篇相关的”和”它们排得多靠前”。

练习 3(RAG 的边缘化):问 “Ada Brask lives in”,检索到两个段落,pη(z1∣x)=0.7p_\eta(z_1 \mid x) = 0.7、pη(z2∣x)=0.3p_\eta(z_2 \mid x) = 0.3。生成器在 z1z_1 下给 Coveton 0.9,在 z2z_2 下给 Coveton 0.1。(a) 算 p(Coveton∣x)p(\text{Coveton} \mid x)。(b) 联合训练时,最小化 −log⁡p(Coveton∣x)-\log p(\text{Coveton} \mid x) 会让检索器怎样变化?为什么这不需要”哪个段落是对的”的标注?

参考答案

(a) 0.7×0.9+0.3×0.1=0.660.7 \times 0.9 + 0.3 \times 0.1 = 0.66。(b) 对检索器的分数求导:∂log⁡p∂pη(zi∣x)∝pθ(y∣x,zi)\frac{\partial \log p}{\partial p_\eta(z_i \mid x)} \propto p_\theta(y \mid x, z_i),z1z_1 下答案的概率更高,所以梯度会提高 pη(z1∣x)p_\eta(z_1 \mid x)、降低 z2z_2——“哪个段落让正确答案更好生成,就把它排得更靠前”。监督信号来自答案本身,段落的好坏由生成器”投票”决定,这就是 RAG、REALM 和 REPLUG 都不需要段落标注的原因。代价是:如果生成器能不看段落就答对(热门知识),这个信号就很弱。

练习 4(kNN-LM 的温度与插值):§6.3 的例子里,4 个最近邻的距离平方是 0、46.0、46.0、46.5,存的词分别是 Redcliff、Ashby、Ashby、Ashby;语言模型给 Redcliff 0.0004、Ashby 0.959。权重 ∝ exp⁡(−d2/T)\exp(-d^2 / T)。(a) 分别取 T = 1 和 T = 50,算 PkNN(Redcliff)P_{\text{kNN}}(\text{Redcliff})。(b) λ = 0.5 时,两种温度下 kNN-LM 各输出哪个词?λ = 0.25 呢?

参考答案(代码验证:k = 16 时结论相同)

(a) T = 1:e−46≈10−20e^{-46} \approx 10^{-20},Redcliff 的权重几乎是全部,PkNN(Redcliff)≈1.00P_{\text{kNN}}(\text{Redcliff}) \approx 1.00。T = 50:权重 1,e−0.92,e−0.92,e−0.93=1,0.399,0.399,0.3951, e^{-0.92}, e^{-0.92}, e^{-0.93} = 1, 0.399, 0.399, 0.395,总和 2.19,Redcliff 0.456、Ashby 0.544。(b) λ = 0.5,T = 1:Redcliff 0.5×1+0.5×0.0004=0.5000.5 \times 1 + 0.5 \times 0.0004 = 0.500,Ashby 0.5×0.959=0.4800.5 \times 0.959 = 0.480,输出 Redcliff(险胜);T = 50:Redcliff 0.5×0.456=0.2280.5 \times 0.456 = 0.228,Ashby 0.5×0.544+0.5×0.959=0.7520.5 \times 0.544 + 0.5 \times 0.959 = 0.752,输出 Ashby。λ = 0.25,T = 1:Redcliff 0.250、Ashby 0.719,输出 Ashby。温度决定”只信最近的那一个”还是”让一群相似的上文投票”;λ 决定数据库的票有多重。模型越有把握(这里 0.96),需要的 λ 越大——这就是 §6.5 里热门园丁在 λ = 0.25 时仍说旧地址的原因。

练习 5(自适应检索的阈值):闭卷用预训练模型,“置信度 < τ 才检索”的检索比例和准确率(代码 03 的数据):τ = 0.3:31.9% / 80.7%;0.4:44.4% / 85.7%;0.5:54.3% / 88.6%;0.6:63.3% / 89.6%;0.7:69.6% / 89.6%;总是检索:100% / 88.0%。假设一次检索的成本相当于答错一题的 1/20,哪个 τ 的总成本最低?

参考答案

总成本 = 错误率 + 0.05 × 检索比例:τ = 0.3:0.193 + 0.016 = 0.209;0.4:0.143 + 0.022 = 0.165;0.5:0.114 + 0.027 = 0.141;0.6:0.104 + 0.032 = 0.136;0.7:0.104 + 0.035 = 0.139;总是检索:0.120 + 0.050 = 0.170。τ = 0.6 最好:它比总是检索准确率更高(89.6% vs 88.0%)、检索少三分之一以上。检索越贵(例如要调用付费的搜索 API、或者延迟要求很严),最优的 τ 越小。注意准确率在 τ = 0.6 之后不再上升:置信度 0.6~0.95 的那些题,闭卷和开卷差不多。

练习 6(切块大小):把 §3.3 的”每 k 个词”换成 k = 8、12、24、48,预测”没有正确块的问题数”和 R@1 的变化,再说说块变大的代价。

参考答案(实测)
k块数没有正确块R@1nDCG@10
836802560.3330.533
1224542560.5610.622
241227810.7840.843
4861400.9840.991

块越大,句子被切断的概率越小、名字在块里重复的次数越多,检索越准。(注意:条目恰好 16 个 token,k = 16 时窗口和条目完全对齐、全部命中——这是巧合,不说明 16 是好的选择。)代价是:读者要读的上下文变长(延迟、计算量),而且一个 48 词的块里有好几位园丁的事实,读者更容易被块里的其他内容带偏(§5.5 的干扰问题)。所以真实系统常常”检索时用小块、阅读时扩展到周围的大块”,或者按段落 / 句子边界切块再合并到目标长度。

练习 7(思考:为什么普通读者会照抄):§5.5 里,检索到的新闻有同类的词时,普通读者 90.9% 照抄它。从训练数据的角度解释原因,并设计两种不同的修正办法,说出各自的代价。

参考答案

普通读者的 7200 条训练样例里,资料总是含有正确条目,所以”抄资料里看起来像答案的那个词”永远是对的——它没有任何理由学会检查”这段资料讲的是不是我问的那个人”。修正:(1) 鲁棒训练:训练数据里混入没用的资料,目标仍是正确答案(Yoran et al. 2024),让模型学会忽略无关资料;代价是答案要靠记忆给出,模型会被迫背下训练实体的事实(本讲的第一版 robust 读者就因此学会了按名字乱套)。(2) 显式批判(Self-RAG):先输出 <rel> / <irr>,无关时丢掉资料、走闭卷;代价是需要相关性标注(Self-RAG 用 GPT-4 蒸馏的批评者),多一步推断,而且只判断相关性、不判断真伪(§7.4)。另一个思路是在检索端加一个独立的重排序器 / 相关性过滤器,读者不变。

练习 8(思考:RAG 还是微调):一家公司要让 LLM 回答关于自家产品的问题,产品文档每周更新。比较三种做法:(a) 在文档上继续预训练 / 微调;(b) RAG;(c) kNN-LM。用本讲的实验结果支持你的论证。

参考答案

(a) 微调把知识写进参数:§1.2 显示一条事实要见好几次才记得住(见过 1~2 次只对 22%,多训练两遍才到 91%),需要对每条新知识做数据增强(换说法、多次出现);每周更新就要每周重新训练,还有灾难性遗忘(§5.4 读者丢了 5.3 个百分点);答案无法溯源。Ovadia et al. (2024) 的实验也发现,注入新知识时 RAG 明显好于无监督微调。(b) RAG:更新文档库即可(§7.4 搬家实验 100%),答案可以附出处(§5.5 的支持分析),对冷门知识效果最好;代价是检索质量决定上限(覆盖率实验)、检索失败时可能被带偏、上下文更长。(c) kNN-LM:同样能换库更新(§6.5),但每个 token 都要检索、数据库巨大、需要访问模型的隐藏状态(闭源 API 做不到),对问答这类任务不如直接给资料。实践中常见的组合是:用 RAG 提供知识,用(少量)微调教模型怎样读资料、怎样按公司的风格回答——也就是本讲读者微调做的事。

练习 9(思考:文档库的风险与机会):RAG 把知识从参数里搬到了文档库里。列举这带来的两个风险和两个机会(提示:投毒、隐私、版权、可删除性)。

参考答案

风险:(1) 投毒与间接提示注入——§7.4 显示读者几乎总是相信资料,攻击者只要往文档库(网页、维基、共享文档)里写入错误事实或藏着指令的文字,就能操纵输出(第 16 讲讲防御);(2) 隐私泄露——文档库里的个人信息会被原样检索出来交给模型,任何能提问的人都可能拿到。机会:(1) 可删除、可追溯——要删掉一条有版权或隐私问题的资料,从文档库里删掉即可,不用重新训练;每个答案都能指向来源(SILO,Min et al. 2024:参数只在许可宽松的数据上训练,高风险数据只放在推断时的文档库里,可以随时移除并给出归属);(2) 访问控制——不同用户检索不同的文档库(按权限过滤),同一个模型能服务权限不同的人,这是把知识写进参数做不到的。

8.4 延伸阅读

  • 原课阅读:Lewis et al. (2020), RAG;Khandelwal et al. (2020), kNN-LM;Mallen et al. (2023), When Not to Trust Language Models(PopQA、自适应检索);Asai et al. (2024), Self-RAG
  • 教程与综述:Asai, Min, Zhong & Chen (2023), ACL 教程 Retrieval-based Language Models and Applications(slides 的来源);Gao et al. (2024), Retrieval-Augmented Generation for Large Language Models: A Survey
  • 长尾与知识:Kandpal et al. (2023), Large Language Models Struggle to Learn Long-Tail Knowledge;Allen-Zhu & Li (2023), Physics of Language Models: Part 3.1
  • 检索器:Karpukhin et al. (2020), DPR;Izacard et al. (2022), Contriever;Khattab & Zaharia (2020), ColBERT;Asai et al. (2023), Task-aware Retrieval with Instructions(TART);Thakur et al. (2021), BEIR;Muennighoff et al. (2022), MTEB;Sciavolino et al. (2021), Simple Entity-Centric Questions Challenge Dense Retrievers
  • 架构:Guu et al. (2020), REALM;Borgeaud et al. (2022), RETRO;Shi et al. (2023), REPLUG;Izacard & Grave (2021), Fusion-in-Decoder
  • 局限与改进:Shi et al. (2023), Large Language Models Can Be Easily Distracted by Irrelevant Context;Yoran et al. (2024), Making Retrieval-Augmented Language Models Robust to Irrelevant Context;Liu et al. (2023), Evaluating Verifiability in Generative Search Engines;Jiang et al. (2023), Active Retrieval Augmented Generation(FLARE);Longpre et al. (2021), Entity-Based Knowledge Conflicts in Question Answering;Xie et al. (2024), Adaptive Chameleon or Stubborn Sloth
  • 规模与数据:Shao et al. (2024), Scaling Retrieval-Based Language Models with a Trillion-Token Datastore(MassiveDS);Min et al. (2024), SILO Language Models
  • 本仓库的相关内容:第 6 讲(复制能力与 induction head、灾难性遗忘);第 10 讲(BM25、稠密检索、ANCE);CMU17-630 的 RAG 相关讲次

8.5 下一讲预告

这一讲里,“把模型做大”对长尾知识帮助有限,而 RETRO、MassiveDS 都在问”把参数换成数据库值不值”。第 12 讲回到 LLM 的核心问题:规模定律。给定算力预算,模型该多大、数据该多少?损失能不能在训练之前就预测出来?为什么每家公司都在追逐最大的模型——以及 Chinchilla 怎样证明 GPT-3 时代的模型”太大、数据太少”。我们会在花园世界里训练一系列小模型,亲手拟合幂律、画出 IsoFLOP 曲线。

← 返回课程目录