年份与会议
2020 · NeurIPS
从经典 RAG 论文出发,梳理检索、重排序、上下文组装到生成的完整链路,解释为什么“把文档塞进模型”远远不够。
年份与会议
2020 · NeurIPS
作者
Patrick Lewis、Ethan Perez、Aleksandara Piktus、Fabio Petroni、et al.
主题
RAG
阅读时长
约 4 分钟
收录时间
2020/05/22
当通用大模型真正进入业务场景后,团队很快发现一个现实问题:模型再强,也不可能只靠参数记住一切,而且静态参数里的知识还会过时。
于是出现了一个非常自然的方向:
让模型在回答前先去外部知识库找资料,再把找到的证据喂给它。
这就是 Retrieval-Augmented Generation,也就是 RAG 的核心直觉。它之所以重要,不只是因为“能查资料”,而是因为它把大模型从一个封闭参数系统,改造成了一个可连接外部知识、可更新、可解释的系统。
对很多企业和产品来说,RAG 不是可选增强,而是把大模型真正落地的必要基础设施。
Lewis 等人的经典 RAG 论文提出的是一个相对早期、但非常关键的框架:在生成过程中,把参数化知识和非参数化外部知识结合起来。
它的重要意义有三层:
虽然今天的 RAG 实现比原始论文复杂得多,但“检索先行、证据进入生成环节”的主线,依然来自这里。
很多刚接触 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 的第一步不是检索算法,而是文档工程。你到底把知识切成什么单位,会直接影响后面所有召回与生成质量。
RAG 最常被讨论的一层是检索。主流方法通常包括:
不同方法各有优劣:
这里最容易被忽视的一点是:召回率高并不等于最终回答好。因为模型是否真正使用这些证据,还要看后续几环做得如何。
实际系统里,第一轮召回通常会拿到一批候选 chunk,但其中很多并不值得直接喂给模型。因此常见做法是加一层 reranker:
这一步非常关键。因为如果直接把召回结果按相似度原样拼接,常常会出现两个问题:
这也是为什么 RAG 工作常常和 Lost in the Middle 一起看。后者提醒我们:即使正确证据被召回了,模型也未必会在最终提示中有效利用它。
很多失败的 RAG 项目并不是输在检索,而是输在 prompt 组织。上下文组装至少要考虑:
如果把这一步做得粗糙,模型可能面对一坨长文本却抓不到重点。真正高质量的 RAG 系统,往往在这一步投入很多细节设计。
生成不是把文档塞进去就结束。最终输出至少还涉及:
也就是说,RAG 的价值并不只是提升正确率,还包括提升回答的可解释性和可追溯性。很多产品真正需要的不是“更会编”,而是“能说清自己凭什么这么答”。
RAG 在企业环境里尤其常见,原因很简单:
因此,RAG 实际上解决的是三个企业级核心问题:
这也是为什么今天很多“企业大模型应用”本质上首先是“企业 RAG 应用”。
RAG 很强,但也经常被过度神化。它的边界包括:
即便检索到了正确材料,模型也可能忽视、误解或错误组合。
召回过多会引入噪声,成本更高,也可能降低有效利用率。
如果知识库本身混乱、过时或互相冲突,再好的模型也难给出稳定答案。
例如需要复杂规划、长期记忆或外部执行的任务,RAG 往往只是系统的一部分,而不是全部。
因此,RAG 不是“给 LLM 装数据库”就结束,而是一整套需要持续调优的知识系统。
随着应用深入,大家很快发现简单 RAG 不够,于是逐渐出现:
这说明 RAG 的演化方向和大模型本身很像:从一个简单原型,逐步发展成多模块协作系统。真正成熟的 RAG,往往已经不再是“检索 + 生成”二段式,而是更长的决策链。
如果你只带走四点,请记住:
理解这四点后,你再去做企业知识库问答或文档助手,会更容易把力气用在真正关键的位置。
RAG 系统搭建实战 这类教程内容。沿着相近主题继续阅读,加深对方法边界与实践场景的理解。