RAG 综述:检索增强生成的系统主线

从经典 RAG 论文出发,梳理检索、重排序、上下文组装到生成的完整链路,解释为什么“把文档塞进模型”远远不够。

年份与会议

2020 · NeurIPS

作者

Patrick Lewis、Ethan Perez、Aleksandara Piktus、Fabio Petroni、et al.

主题

RAG

阅读时长

约 4 分钟

收录时间

2020/05/22

标签

原文链接

https://arxiv.org/abs/2005.11401

为什么 RAG 会成为大模型应用的基础设施

当通用大模型真正进入业务场景后,团队很快发现一个现实问题:模型再强,也不可能只靠参数记住一切,而且静态参数里的知识还会过时。

于是出现了一个非常自然的方向:

让模型在回答前先去外部知识库找资料,再把找到的证据喂给它。

这就是 Retrieval-Augmented Generation,也就是 RAG 的核心直觉。它之所以重要,不只是因为“能查资料”,而是因为它把大模型从一个封闭参数系统,改造成了一个可连接外部知识、可更新、可解释的系统。

对很多企业和产品来说,RAG 不是可选增强,而是把大模型真正落地的必要基础设施。

经典 RAG 论文到底解决了什么

Lewis 等人的经典 RAG 论文提出的是一个相对早期、但非常关键的框架:在生成过程中,把参数化知识和非参数化外部知识结合起来。

它的重要意义有三层:

  1. 把检索与生成不再视为两个独立模块,而是一个端到端系统。
  2. 证明外部知识能显著帮助知识密集型任务。
  3. 为后来几乎所有企业 RAG 系统提供了概念原型。

虽然今天的 RAG 实现比原始论文复杂得多,但“检索先行、证据进入生成环节”的主线,依然来自这里。

RAG 不是一个模块,而是一条链路

很多刚接触 RAG 的团队会把它理解成:

  • 建向量库
  • 做相似度检索
  • 把结果贴进 prompt

但真正可用的 RAG 系统远比这复杂。更准确地说,它通常至少包含五个环节:

  1. 数据准备与切块
  2. 索引与召回
  3. 重排序与过滤
  4. 上下文组装
  5. 生成与引用

任何一个环节做得不好,最终效果都可能显著下降。因此 RAG 更像一条完整生产线,而不是单一组件。

把这条主线压成一张图,会更容易看清“召回命中”为什么还远远不是终点:

RAG 综述中的检索增强主线 从知识库准备开始,经过切块和索引,在线阶段依次经过查询理解、召回、重排序、上下文组装和生成带引用回答,强调检索只是中间环节。 RAG 的关键不是“有检索器”,而是证据如何一路走到生成结果
  <rect x="34" y="74" width="912" height="114" rx="24" fill="#f6f9ff" stroke="#d7e2f1" />
  <text x="58" y="106" font-size="20" font-weight="700">离线知识准备</text>

  <g>
    <rect x="58" y="124" width="178" height="46" rx="14" fill="#e8f1ff" stroke="#98b7e1" />
    <text x="147" y="153" text-anchor="middle" font-size="18" font-weight="700">原始文档</text>
  </g>
  <g>
    <rect x="270" y="114" width="184" height="66" rx="16" fill="#eef6e8" stroke="#a8c48e" />
    <text x="362" y="142" text-anchor="middle" font-size="18" font-weight="700">切块与元数据</text>
    <text x="362" y="163" text-anchor="middle" font-size="13" fill="#4b5563">chunk / title / time / source</text>
  </g>
  <g>
    <rect x="488" y="114" width="194" height="66" rx="16" fill="#fff4dc" stroke="#e2c36f" />
    <text x="585" y="142" text-anchor="middle" font-size="18" font-weight="700">索引与召回器</text>
    <text x="585" y="163" text-anchor="middle" font-size="13" fill="#4b5563">BM25 / dense / hybrid</text>
  </g>
  <g>
    <rect x="716" y="124" width="196" height="46" rx="14" fill="#f4ebff" stroke="#c7afe8" />
    <text x="814" y="153" text-anchor="middle" font-size="18" font-weight="700">可更新知识库</text>
  </g>

  <line x1="236" y1="147" x2="270" y2="147" stroke="#5b6b7f" stroke-width="3" marker-end="url(#rag-survey-arrow)" />
  <line x1="454" y1="147" x2="488" y2="147" stroke="#5b6b7f" stroke-width="3" marker-end="url(#rag-survey-arrow)" />
  <line x1="682" y1="147" x2="716" y2="147" stroke="#5b6b7f" stroke-width="3" marker-end="url(#rag-survey-arrow)" />

  <rect x="34" y="220" width="912" height="146" rx="24" fill="#f9fafb" stroke="#e5e7eb" />
  <text x="58" y="252" font-size="20" font-weight="700">在线问答链路</text>

  <g>
    <rect x="52" y="280" width="120" height="60" rx="16" fill="#e8f1ff" stroke="#98b7e1" />
    <text x="112" y="316" text-anchor="middle" font-size="18" font-weight="700">用户问题</text>
  </g>
  <g>
    <rect x="200" y="270" width="132" height="80" rx="18" fill="#eef6e8" stroke="#a8c48e" />
    <text x="266" y="301" text-anchor="middle" font-size="18" font-weight="700">查询理解</text>
    <text x="266" y="323" text-anchor="middle" font-size="13" fill="#4b5563">rewrite / 澄清意图</text>
  </g>
  <g>
    <rect x="360" y="270" width="132" height="80" rx="18" fill="#fff4dc" stroke="#e2c36f" />
    <text x="426" y="301" text-anchor="middle" font-size="18" font-weight="700">第一轮召回</text>
    <text x="426" y="323" text-anchor="middle" font-size="13" fill="#4b5563">先求 recall,不求完美顺序</text>
  </g>
  <g>
    <rect x="520" y="270" width="132" height="80" rx="18" fill="#fce7ef" stroke="#e2a8bd" />
    <text x="586" y="301" text-anchor="middle" font-size="18" font-weight="700">重排序过滤</text>
    <text x="586" y="323" text-anchor="middle" font-size="13" fill="#4b5563">把噪声挡在模型外</text>
  </g>
  <g>
    <rect x="680" y="270" width="132" height="80" rx="18" fill="#dff4f0" stroke="#8dc7bd" />
    <text x="746" y="301" text-anchor="middle" font-size="18" font-weight="700">上下文组装</text>
    <text x="746" y="323" text-anchor="middle" font-size="13" fill="#4b5563">顺序 / 引用 / 摘要</text>
  </g>
  <g>
    <rect x="840" y="270" width="86" height="80" rx="18" fill="#ede9fe" stroke="#b7a8ea" />
    <text x="883" y="301" text-anchor="middle" font-size="18" font-weight="700">生成</text>
    <text x="883" y="323" text-anchor="middle" font-size="13" fill="#4b5563">答案 + 来源</text>
  </g>

  <line x1="172" y1="310" x2="200" y2="310" stroke="#5b6b7f" stroke-width="3" marker-end="url(#rag-survey-arrow)" />
  <line x1="332" y1="310" x2="360" y2="310" stroke="#5b6b7f" stroke-width="3" marker-end="url(#rag-survey-arrow)" />
  <line x1="492" y1="310" x2="520" y2="310" stroke="#5b6b7f" stroke-width="3" marker-end="url(#rag-survey-arrow)" />
  <line x1="652" y1="310" x2="680" y2="310" stroke="#5b6b7f" stroke-width="3" marker-end="url(#rag-survey-arrow)" />
  <line x1="812" y1="310" x2="840" y2="310" stroke="#5b6b7f" stroke-width="3" marker-end="url(#rag-survey-arrow)" />

  <line x1="814" y1="188" x2="426" y2="270" stroke="#94a3b8" stroke-width="2.5" stroke-dasharray="7 7" marker-end="url(#rag-survey-arrow)" />
  <text x="618" y="232" font-size="13" fill="#64748b">在线召回依赖离线构建好的索引</text>
</g>
RAG 的难点不是“接上向量库”这一瞬间,而是如何让正确证据以合适顺序、合适密度进入最终生成。

第一环:数据准备与切块

RAG 成败往往首先取决于你怎么处理原始文档。常见问题包括:

  • 文档切得太粗,召回到的 chunk 太长、噪声太大。
  • 切得太细,关键信息被切散,模型上下文不完整。
  • 标题、来源、时间戳等元数据没有保留,导致后续排序和引用困难。

这说明 RAG 的第一步不是检索算法,而是文档工程。你到底把知识切成什么单位,会直接影响后面所有召回与生成质量。

第二环:索引与召回

RAG 最常被讨论的一层是检索。主流方法通常包括:

  • 稀疏检索,例如 BM25
  • 稠密检索,例如 embedding 向量召回
  • 混合检索,把关键词和语义召回结合

不同方法各有优劣:

  • 关键词检索更擅长精确术语匹配。
  • 向量检索更擅长语义近邻。
  • 混合检索在很多真实业务里更稳。

这里最容易被忽视的一点是:召回率高并不等于最终回答好。因为模型是否真正使用这些证据,还要看后续几环做得如何。

第三环:重排序与过滤

实际系统里,第一轮召回通常会拿到一批候选 chunk,但其中很多并不值得直接喂给模型。因此常见做法是加一层 reranker:

  • 根据问题和候选文档更细粒度打分
  • 去掉噪声块
  • 调整最终输入顺序

这一步非常关键。因为如果直接把召回结果按相似度原样拼接,常常会出现两个问题:

  1. 有用证据被噪声淹没
  2. 正确证据在上下文里位置不理想

这也是为什么 RAG 工作常常和 Lost in the Middle 一起看。后者提醒我们:即使正确证据被召回了,模型也未必会在最终提示中有效利用它。

第四环:上下文组装不是简单拼接

很多失败的 RAG 项目并不是输在检索,而是输在 prompt 组织。上下文组装至少要考虑:

  • 文档顺序怎么排
  • 是否保留来源标签
  • 是否加小标题与编号
  • 是否需要先摘要再拼接
  • 用户问题应该放在前面还是后面

如果把这一步做得粗糙,模型可能面对一坨长文本却抓不到重点。真正高质量的 RAG 系统,往往在这一步投入很多细节设计。

第五环:生成阶段要不要“看起来像在用证据”

生成不是把文档塞进去就结束。最终输出至少还涉及:

  • 是否准确引用文档内容
  • 是否在不确定时明确说明证据不足
  • 是否给出来源链接或出处
  • 是否在多文档冲突时表达不确定性

也就是说,RAG 的价值并不只是提升正确率,还包括提升回答的可解释性和可追溯性。很多产品真正需要的不是“更会编”,而是“能说清自己凭什么这么答”。

为什么 RAG 对企业场景特别重要

RAG 在企业环境里尤其常见,原因很简单:

  • 企业知识更新快,不能只靠预训练参数。
  • 资料常常是私有的,闭源 API 模型也需要外部知识注入。
  • 业务方通常需要来源可追踪,而不是只要一段听起来顺的回答。

因此,RAG 实际上解决的是三个企业级核心问题:

  1. 知识时效性
  2. 私有知识接入
  3. 可解释与可审计

这也是为什么今天很多“企业大模型应用”本质上首先是“企业 RAG 应用”。

局限:RAG 不是万能补丁

RAG 很强,但也经常被过度神化。它的边界包括:

1. 检索成功不等于生成成功

即便检索到了正确材料,模型也可能忽视、误解或错误组合。

2. 上下文长度不是无限的

召回过多会引入噪声,成本更高,也可能降低有效利用率。

3. 文档质量决定上限

如果知识库本身混乱、过时或互相冲突,再好的模型也难给出稳定答案。

4. 某些任务本来就不适合只靠检索增强

例如需要复杂规划、长期记忆或外部执行的任务,RAG 往往只是系统的一部分,而不是全部。

因此,RAG 不是“给 LLM 装数据库”就结束,而是一整套需要持续调优的知识系统。

RAG 为什么会不断演化成更复杂的系统

随着应用深入,大家很快发现简单 RAG 不够,于是逐渐出现:

  • query rewrite
  • hybrid retrieval
  • reranker
  • citation grounding
  • 多跳检索
  • agentic retrieval

这说明 RAG 的演化方向和大模型本身很像:从一个简单原型,逐步发展成多模块协作系统。真正成熟的 RAG,往往已经不再是“检索 + 生成”二段式,而是更长的决策链。

读这条主线时最该抓住什么

如果你只带走四点,请记住:

  1. RAG 解决的是参数知识静态、过时和私有知识接入问题。
  2. RAG 的核心不是单一检索器,而是一整条数据到生成链路。
  3. 检索命中不等于模型真正利用了证据。
  4. 可用的 RAG 系统,往往重在数据工程、重排序和上下文设计,而不只是向量库本身。

理解这四点后,你再去做企业知识库问答或文档助手,会更容易把力气用在真正关键的位置。

延伸阅读

  • 想理解长上下文下证据为何可能被忽略,建议继续看 Lost in the Middle
  • 想把 RAG 放到应用实践里理解,后续最自然的延伸是 RAG 系统搭建实战 这类教程内容。
  • 如果你更关注评测问题,建议把 RAG 与 LLM 评测方法论:从 MMLU 到 MT-Bench 一起看,因为 RAG 系统评测远不止看检索命中率。

相关内容

沿着相近主题继续阅读,加深对方法边界与实践场景的理解。