{"notes":[{"id":"retrieval-augmented-generation/rag","category":"retrieval-augmented-generation","legacyPath":"","legacySlug":"","legacyPaths":[],"title":"RAG","subtitle":"怎么是块抹布？","author":"Z. Yuan","paperDate":"2020-05-22","publishedOn":"2026-05-17","world":"external/rag","paperTitle":"Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks","paperUrl":"https://arxiv.org/abs/2005.11401","bibliography":{"title":"Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks","authors":["Patrick Lewis","Ethan Perez","Aleksandra Piktus","Fabio Petroni","Vladimir Karpukhin","Naman Goyal","Heinrich Küttler","Mike Lewis","Wen-tau Yih","Tim Rocktäschel","Sebastian Riedel","Douwe Kiela"],"url":"https://arxiv.org/abs/2005.11401","pdfUrl":"https://arxiv.org/pdf/2005.11401v4","codeUrl":null,"preprint":{"id":"2005.11401","submittedOn":"2020-05-22","url":"https://arxiv.org/abs/2005.11401"},"publication":{"venue":"NeurIPS","year":2020,"kind":"conference","url":"https://proceedings.neurips.cc/paper/2020/hash/6b493230205f780e1bc26945df7481e5-Abstract.html"},"citation":"@misc{retrievalaugmentedgenerationrag2020,\n  title = {{Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks}},\n  author = {Patrick Lewis and Ethan Perez and Aleksandra Piktus and Fabio Petroni and Vladimir Karpukhin and Naman Goyal and Heinrich Küttler and Mike Lewis and Wen-tau Yih and Tim Rocktäschel and Sebastian Riedel and Douwe Kiela},\n  year = {2020},\n  eprint = {2005.11401},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/2005.11401}\n}\n","citationPath":"/content/papers/citations/retrieval-augmented-generation/rag.85ab2502cd0c.bib"},"thumbnail":{"src":"/content/papers/assets/05c7bcd1d2c3f13c0726dfa7180e85f043b7cd64a0c61fa595b954d979a6550e.png","width":1122,"height":358},"locale":"zh-hans","path":"/content/papers/zh-hans/retrieval-augmented-generation/rag.6843079b4840.md","headings":[{"id":"定义问题","text":"定义问题","depth":2},{"id":"解决问题","text":"解决问题","depth":2},{"id":"模型架构","text":"模型架构","depth":3},{"id":"外部记忆2100-万段维基百科","text":"外部记忆：2,100 万段维基百科","depth":3},{"id":"文档是一个随机变量","text":"文档是一个随机变量","depth":3},{"id":"没有标注检索器怎么学","text":"没有标注，检索器怎么学？","depth":3},{"id":"推理时怎么解码","text":"推理时怎么解码？","depth":3},{"id":"讨论","text":"讨论","depth":2},{"id":"开放域问答","text":"开放域问答","depth":3},{"id":"jeopardy-出题拼装两份文档","text":"Jeopardy 出题：拼装两份文档","depth":3},{"id":"学出来的检索比较好吗","text":"学出来的检索，比较好吗？","depth":3},{"id":"换一份索引知识就更新了","text":"换一份索引，知识就更新了","depth":3},{"id":"几个没那么顺利的地方","text":"几个没那么顺利的地方","depth":3},{"id":"结论","text":"结论","depth":2}],"anchorAliases":{},"guide":null,"relatedReading":[]}],"text":"这几年只要聊到「让语言模型读公司文档」，十之八九会听到 RAG 这个词。\n\n这个名字的出处，就是这篇 2020 年的论文。\n\n不过 rag 这个英语单词，原意是抹布、破布。一个后来红遍整个 AI 圈的技术，名字直译过来就是「抹布」，实在让人哭笑不得。\n\n第一作者 Patrick Lewis 后来在 [**NVIDIA 的访谈**](https://blogs.nvidia.com/blog/what-is-retrieval-augmented-generation/)里，也为这个不太好听的缩写道歉：早知道会流传这么广，他们一定会多花点心思取名字；原本也打算想个好听的，只是写论文时没有人想到更好的。\n\n名字就这样留了下来。\n\n但如果你是从 ChatGPT 之后才认识 RAG，读这篇论文可能会有点意外。现在常说的 RAG，多半是「找几段文本，贴进提示词，交给大型语言模型回答」。这篇论文里的 RAG，用的是 4 亿参数的 BART，检索器和生成器一起训练，而检索到的文档被当成一个**随机变量**来处理。\n\n这篇笔记，我们就回到这个名字最初指的东西。\n\n## 定义问题\n\n2020 年前后，预训练语言模型已经被发现能在参数里记住不少事实知识。像 T5 这样的模型，不给任何参考数据，直接问它问题，也能答对一部分。\n\n这种做法叫做 **closed-book**，像是闭卷考试：知识全在脑袋里。\n\n闭卷有几个麻烦：\n\n1. **知识难以更新**。世界变了，模型参数里的知识不会跟着变，只能重新训练。\n2. **说不出依据**。模型答对了，你也不知道它是从哪里学到的。\n3. **会一本正经地编造**。也就是后来大家常说的「幻觉」。\n\n另一条路是让模型带着外部数据应试，也就是 **open-book**。在这之前，REALM、ORQA 已经把可微分的检索器接上掩码语言模型，但只用在**抽取式问答**：答案必须是原文中的一段文本，模型负责把它框出来。\n\n作者想做的事更广：\n\n- **能不能让一般的生成模型（seq2seq）也带着一份可检索的外部记忆，而且用同一套方法微调到各种任务上？**\n\n还有一个条件让这件事变得困难：训练数据只有「问题」和「答案」，没有人标注「该去找哪一份文档」。\n\n那检索器要怎么学？\n\n## 解决问题\n\n### 模型架构\n\n[![RAG 架构总览：Query Encoder 把输入编码成 q(x)，以 MIPS 从 Document Index 找出 top-K 文档，再交给 Generator 并对文档边缘化](/content/papers/assets/05c7bcd1d2c3f13c0726dfa7180e85f043b7cd64a0c61fa595b954d979a6550e.png)](/content/papers/assets/05c7bcd1d2c3f13c0726dfa7180e85f043b7cd64a0c61fa595b954d979a6550e.png)\n\n*原论文 Figure 1，取自 [**v4 PDF 第 2 页**](https://arxiv.org/pdf/2005.11401v4#page=2)。左侧为三种任务的输入，右侧为对应输出。*\n\n这张图由左往右读。\n\n最左边是输入 $x$，可以是一个问题（「定义中耳」）、一句待查核的陈述，或是 Jeopardy 出题用的答案词（「神曲」）。\n\n绿色框是**检索器** $p_\\eta$。Query Encoder 先把输入转成向量 $q(x)$；Document Index 里存着每份文档预先算好的向量 $d(z)$。MIPS 从里面挑出最相关的几份文档 $z_1,\\dots,z_4$。\n\n蓝色框是**生成器** $p_\\theta$，把输入和每份文档分别串起来，产生答案。最后的「Marginalize」把多份文档的结果合成一个预测。\n\n图顶那条虚线箭头写着「End-to-End Backprop through **q** and $p_\\theta$」：训练时，梯度会一路传回 Query Encoder 和生成器。注意，这里没有写到 Document Index。这点等一下会再提。\n\n作者把这两块称为两种记忆：\n\n- **参数记忆（parametric memory）**：生成器的参数，也就是 BART 自己记住的知识。\n- **非参数记忆（non-parametric memory）**：外部的文档索引，可以直接替换。\n\n### 外部记忆：2,100 万段维基百科\n\n外部知识只有一份：2018 年 12 月的英文维基百科。\n\n每篇条目切成不重叠的 100 个词（word）段落，总共约 2,100 万份「文档」。每份文档用文档编码器算出向量，存进 FAISS 建好的索引里。\n\n检索器采用 [**DPR**](https://arxiv.org/abs/2004.04906)（Dense Passage Retriever）。它有两个 BERT-base 编码器，一个编问题、一个编文档，相关程度就是两个向量的内积：\n\n$$\np_\\eta(z\\mid x)\\propto \\exp\\!\\left(d(z)^\\top q(x)\\right),\\quad d(z)=\\text{BERT}_d(z),\\ q(x)=\\text{BERT}_q(x)\n$$\n\n从 2,100 万个向量里找出内积最大的前 $K$ 个，就是 **MIPS**（Maximum Inner Product Search，最大内积搜索）问题。\n\n\n> [!TIP]\n> \n> **2,100 万个向量，每次都要全部算一遍吗？**\n> \n> 不用。作者用 FAISS 搭配 HNSW（Hierarchical Navigable Small World）近似搜索：先把向量组成多层的邻近图，查询时沿着图往目标靠近，不必和每个向量都算内积。代价是结果可能不是精确的前 $K$ 名，换来的是次线性的查询时间。\n> \n> 附录还提到，整份索引有 153 亿个数值，可以用 8 比特精度存放，降低内存和硬盘用量。\n\n\n生成器用 BART-large，约 4 亿参数。把输入 $x$ 和文档 $z$ 接起来，交给它生成答案，做法就这么简单。\n\n### 文档是一个随机变量\n\n接下来是这篇论文最关键的部分。\n\n前面说过，训练数据没有标注「哪份文档才是对的」。作者的处理方式是：**不决定**。把检索到的文档 $z$ 当成一个看不到的隐变量（latent variable），对可能的文档全部加权平均。\n\n检索器给出每份文档的概率 $p_\\eta(z\\mid x)$；生成器在每份文档的条件下，给出答案的概率 $p_\\theta(y\\mid x,z)$。两者相乘再加总，就是答案的概率。\n\n至于「怎么加总」，作者给了两个版本。\n\n**RAG-Sequence**：整个答案绑定同一份文档。先算每份文档条件下整句的概率，再对文档加权：\n\n$$\np_{\\text{RAG-Sequence}}(y\\mid x)\\approx\\sum_{z\\in\\text{top-}k}p_\\eta(z\\mid x)\\prod_{i}^{N}p_\\theta(y_i\\mid x,z,y_{1:i-1})\n$$\n\n**RAG-Token**：每个 token 都可以参考不同的文档。每一步先对文档加权，得到这个 token 的概率，再把所有 token 连乘：\n\n$$\np_{\\text{RAG-Token}}(y\\mid x)\\approx\\prod_{i}^{N}\\sum_{z\\in\\text{top-}k}p_\\eta(z\\mid x)\\,p_\\theta(y_i\\mid x,z,y_{1:i-1})\n$$\n\n两条式子只差在 $\\sum$ 和 $\\prod$ 的顺序。顺序不同，结果差在哪里？\n\n我们用一组小数字算一次。\n\n假设检索器找到两份文档，给 doc1 的概率是 0.6，doc2 是 0.4。答案有两个 token：\n\n- 在 doc1 条件下，生成器给第 1 个 token 0.9、第 2 个 token 0.2。\n- 在 doc2 条件下，正好反过来：第 1 个 token 0.3、第 2 个 token 0.8。\n\n也就是说，答案前半段的信息在 doc1，后半段的信息在 doc2。\n\n```python\n# 检索器给两份文档的概率\np_z = {\"doc1\": 0.6, \"doc2\": 0.4}\n\n# 生成器在各文档条件下，产生两个答案 token 的概率\np_y = {\n    \"doc1\": [0.9, 0.2],  # 第 1 个 token 很像 doc1 的内容，第 2 个不像\n    \"doc2\": [0.3, 0.8],  # 反过来\n}\n\n# RAG-Sequence：整句绑定同一份文档，再对文档加权\nseq = sum(p_z[z] * p_y[z][0] * p_y[z][1] for z in p_z)\n\n# RAG-Token：每个 token 各自对文档加权，再连乘\ntok = 1.0\nfor i in range(2):\n    tok *= sum(p_z[z] * p_y[z][i] for z in p_z)\n\nprint(f\"RAG-Sequence: {seq:.4f}\")\nprint(f\"RAG-Token:    {tok:.4f}\")\n\n# RAG-Sequence: 0.2040\n# RAG-Token:    0.2904\n```\n\nRAG-Sequence 要求同一份文档撑起整个答案：doc1 撑得起前半、撑不起后半，doc2 反之，两边都打折。\n\nRAG-Token 则是第 1 个 token 主要靠 doc1，第 2 个 token 主要靠 doc2，所以这个「拼装」答案的概率比较高。\n\n这也是后面实验里，RAG-Token 在 Jeopardy 出题表现较好的原因，我们到讨论时会看到实际的例子。\n\n\n> [!NOTE]\n> \n> **分类任务呢？**\n> \n> 若把分类标签当成长度为 1 的答案，例如事实查核的「支持」、「反驳」、「信息不足」，只有一个 token，$\\sum$ 和 $\\prod$ 的顺序就没差了，两种 RAG 完全相同。\n\n\n### 没有标注，检索器怎么学？\n\n训练目标很单纯：让正确答案的边缘概率越大越好，也就是最小化 $-\\log p(y\\mid x)$。\n\n回头看上面的式子。$p_\\eta(z\\mid x)$ 出现在加总里，所以梯度会传到它。如果某份文档让生成器更容易产生正确答案，增加这份文档的概率，就能提高整体的边缘概率。训练下来，检索器就学会多给这类文档一点分数。\n\n没有人告诉它哪份文档是对的，它从「哪份文档有帮上忙」学到了。\n\n不过，作者只更新**问题编码器** $\\text{BERT}_q$ 和 BART，**文档编码器和索引保持冻结**。\n\n原因很实际：文档编码器一改，2,100 万份文档的向量都要重算、索引要重建。REALM 在预训练时会定期重建索引，作者发现不做这一步，成绩也够好。\n\n\n> [!TIP]\n> \n> **「端到端训练检索器」的常见误解**\n> \n> 有些介绍会说 RAG 把检索器端到端训练了。精确地说，训练时更新的是问题那一侧；文档那一侧从 DPR 初始化后就没动过。而 DPR 本身已经用 Natural Questions 和 TriviaQA 的检索标注训练过，作者在结果段落也主动提醒了这一点。\n\n\n### 推理时怎么解码？\n\nRAG-Token 每一步都会算出下一个 token 的概率，可以直接套进一般的 beam search。\n\nRAG-Sequence 比较麻烦：整句的概率没办法拆成每个 token 的概率。作者的做法是对每份文档各跑一次 beam search，收集所有候选答案，再补算每个候选在其他文档下的概率，最后加权加总，称为「Thorough Decoding」。\n\n候选一多，补算的前向计算会很可观，所以另有一个近似版本「Fast Decoding」：某份文档的 beam 里没出现过的候选，就当作在那份文档下概率为 0，省掉补算。\n\n## 讨论\n\n### 开放域问答\n\n作者在四个开放域问答数据集上测试：Natural Questions（NQ）、TriviaQA（TQA）、WebQuestions（WQ）与 CuratedTrec（CT），指标是答案完全相符的比例（Exact Match）。\n\n[![原论文 Table 1：闭卷的 T5、开卷的 REALM 与 DPR，以及 RAG-Token、RAG-Sequence 在 NQ、TQA、WQ、CT 的测试分数](/content/papers/assets/e4210dd8d6a0578d12df7e28472ad4aec7137a2aa87c895aad1e7044d0bfcdd6.png)](/content/papers/assets/e4210dd8d6a0578d12df7e28472ad4aec7137a2aa87c895aad1e7044d0bfcdd6.png)\n\n*原论文 Table 1，取自 [**v4 PDF 第 6 页**](https://arxiv.org/pdf/2005.11401v4#page=6)。TQA 左列为标准开放域测试集，右列为 TQA-Wiki 测试集。*\n\n表分成三段。上面是闭卷的 T5，中间是开卷的 REALM 和 DPR，最下面是 RAG。\n\n在 NQ 上，RAG-Sequence 拿到 44.5，闭卷的 T5-11B 是 34.5。\n\n这个比较要看一下参数量。T5-11B 有 110 亿个可训练参数；RAG 全部加起来约 6.26 亿（两个 BERT-base 编码器各 1.1 亿，其中文档编码器其实没有训练，加上 BART 的约 4 亿）。附录提到，参数量最接近的 T5-large（7.7 亿）在 NQ 只有 28.9。\n\n另一个比较对象是 DPR 的问答系统，它还多用了一个 cross-encoder 重排序和抽取式阅读器。RAG 不用这两样，NQ 还高出 3 分。\n\n生成式的答案还有一个抽取式做不到的好处：文档里只有线索、没有答案原文时，模型仍可能生成正确答案。在 NQ 上，正确答案不在任何检索文档里的题目，RAG 仍答对了 11.8%；抽取式模型在这种情况必然是 0%。\n\n### Jeopardy 出题：拼装两份文档\n\nJeopardy 是美国的益智节目，题目形式比较特别：给一个答案，要写出对应的提示句。例如答案是「The World Cup」，提示可能是「1986 年，墨西哥成为第一个两度主办这项国际赛事的国家」。\n\n这种提示句常常把两件事放在一起，正好可以检验 RAG-Token 的拼装能力。下图是输入「Hemingway」、检索五份文档时，每生成一个 token，模型认为是哪份文档在帮忙：\n\n[![RAG-Token 为输入 Hemingway 生成 Jeopardy 题目时，各 token 对五份文档的后验概率热图](/content/papers/assets/bc3d0fd74e0299ec9fc8eae15768959cef1e43472643f9449c1f7002164a42db.png)](/content/papers/assets/bc3d0fd74e0299ec9fc8eae15768959cef1e43472643f9449c1f7002164a42db.png)\n\n*原论文 Figure 2，取自 [**v4 PDF 第 7 页**](https://arxiv.org/pdf/2005.11401v4#page=7)。横轴为生成的 token，纵轴为五份检索文档；颜色越深，后验概率越高。*\n\n左边列出两份文档：Document 1 提到《永别了，武器》（A Farewell to Arms），Document 2 提到《太阳照常升起》（The Sun Also Rises）。\n\n看右边的热图。生成「Sun」的时候，Doc 2 那一行特别深；生成「A」、开始写「A Farewell to Arms」的时候，换成 Doc 1 最深。\n\n这就是我们刚才手算的情况：一句话的前后段，分别由不同文档支撑。\n\n还有一个有趣的细节：书名的第一个 token 生出来之后，热图就变淡了。作者的解读是，后面的字 BART 自己就会接。他们把「\"The Sun」单独喂给没有检索的 BART，它真的接出了完整书名。作者说这是两种记忆在合作：检索到的文档把模型带到对的方向，参数里的知识负责把话说完。\n\n人工评估在 452 组 BART 与 RAG-Token 的出题中比较事实正确性：认为 BART 较正确的只有 7.1%，认为 RAG 较正确的有 42.7%（依原论文 Table 4）。\n\n### 学出来的检索，比较好吗？\n\n作者做了两组消融：把检索器冻结不训练，以及直接换成 BM25 关键字检索。\n\n以 NQ 开发集的 RAG-Sequence 为例（Table 6）：\n\n1. **换成 BM25**：31.8。\n2. **冻结检索器**：41.2。\n3. **一起训练**：44.0。\n\n学出来的检索在问答任务上帮助很大。\n\n但 FEVER 事实查核是例外：BM25 的三分类准确率 75.1，略高于学习检索的 74.5。作者推测，FEVER 的陈述大多围绕特定实体，名字一对上就找得到，很适合关键字比对。\n\n### 换一份索引，知识就更新了\n\n这个实验最能说明外部记忆的用处。\n\n作者另外用 2016 年 12 月的维基百科建了一份索引，再准备 82 位在 2016 到 2018 年间换人的世界领袖，用「Who is {position}?」问模型，例如「Who is the President of Peru?」。\n\n| 索引 | 问 2016 年的领袖 | 问 2018 年的领袖 |\n| --- | ---: | ---: |\n| 2016 年索引 | 70% | 4% |\n| 2018 年索引 | 12% | 68% |\n\n*整理自原论文 §4.5。*\n\n索引和问题的年份对上，大约七成答对；对不上，正确率就掉到个位数或一成出头。\n\n模型参数一个都没动，只换了外部记忆，答案就跟着换了。这正是闭卷模型做不到的事。\n\n### 几个没那么顺利的地方\n\n1. **检索不是越多越好**。NQ 上，RAG-Sequence 的成绩随测试时取回的文档数增加而上升；RAG-Token 则在 10 份左右达到高峰。\n2. **检索可能崩溃**。附录提到，在故事生成等任务的初步实验中，检索器会学到不管输入是什么都返回同一批文档；生成器接着学会忽略文档，整个模型退化成普通的 BART。作者推测，这类任务对事实知识的需求不明显，或是答案太长，传回检索器的梯度不够有用。\n3. **有些问题维基百科本来就答不了**。MS-MARCO 里有「加州 Volcano 现在天气如何？」这种题目。作者观察到，模型对这类较难从检索受益的问题，会固定取回某一组文档。\n\n## 结论\n\n这篇论文把一个预训练的生成模型和一份可检索的外部记忆接在一起，用同一套方法微调到问答、出题和事实查核上。\n\n它最有说服力的几件事：\n\n1. **小模型加外部记忆，打赢大很多的闭卷模型**。NQ 上 6.26 亿参数的 RAG-Sequence 拿到 44.5，110 亿参数的 T5-11B 是 34.5。\n2. **不需要标注该找哪份文档**。把文档当成隐变量边缘化，检索器就能从答案的概率学到该找什么。\n3. **换索引就能更新知识**。2016 和 2018 年的索引互换，领袖问题的答案跟着改变，模型参数不用动。\n\n回头看现在常说的 RAG，「先检索、再把文档交给生成器」与「外部记忆可以替换」这两个想法一路留了下来。另一半，也就是检索器和生成器一起训练、对文档做边缘化，在后来以提示词拼接为主的大型语言模型应用里就少见多了；模型大到难以微调，检索器也常换成现成的 embedding 模型或搜索引擎。\n\n这是后来的发展，不是这篇论文的主张。\n\n名字倒是一直没换。\n","imageSizes":{"/content/papers/assets/05c7bcd1d2c3f13c0726dfa7180e85f043b7cd64a0c61fa595b954d979a6550e.png":{"width":1122,"height":358},"/content/papers/assets/e4210dd8d6a0578d12df7e28472ad4aec7137a2aa87c895aad1e7044d0bfcdd6.png":{"width":561,"height":375},"/content/papers/assets/bc3d0fd74e0299ec9fc8eae15768959cef1e43472643f9449c1f7002164a42db.png":{"width":1122,"height":210}}}
