Skip to main content

长上下文能取代检索吗

上下文窗口从几千涨到百万级之后,"RAG 是不是可以不要了"每隔一段时间就会重新争论一轮。诚实的结论是:对一部分场景可以,对大多数生产场景还不行——但真正的分界线不是窗口大小,而是另外四个变量。

这篇文章给一套可执行的判断顺序,以及两种做法各自的失败模式。判断依据以你自己的语料和任务为准,不引用任何"某某模型在某基准上赢了"作为裁决。

纯检索语料库混合召回只留 top-k生成带引用全塞进去语料库不做筛选整段进上下文注意力自己找混合语料库粗召回缩小重排保序长上下文合成纯检索输在召回漏,全塞输在成本与中间丢失,混合把「筛选」和「合成」拆成两步。
图:三种排布——先选后答、不选全塞、先粗筛再合成

1. 两种做法差在哪​

检索是"先选,再答"。 语料在外面,按问题挑出若干切片塞进提示词,提示词通常在几千 token 量级。

长上下文是"不选,全塞"。 把整个相关语料直接放进上下文,让注意力机制自己去找。

很多人以为差别在准确率,其实更关键的差别在你知不知道答案是从哪来的。检索系统知道它给了哪几个切片,所以引用是系统的属性,是结构性的;长上下文里模型同时看到了全部内容,引用只能靠模型自述——它说它参考了哪一段,你无法从系统侧验证。凡是要对外部用户负责出处的场景(客服答复、合规问答、医疗与法律),这一条比准确率更早成为决定因素,详见《答案要能追溯到出处》那一篇的取舍。

2. 四个变量决定选哪个​

2.1 语料有界还是无界​

有界——一份合同、一个模块的代码、一份已定稿的规格:两种都行。无界——全量工单、整个文档站、开放的网页:只能检索,任何窗口都装不下。

这条是硬约束,没有讨论空间。

2.2 任务要"通读全文"还是"找到那一段"​

需要通读的:总结一份 200 页文档、审计一份长合同、找出两份协议之间的冲突。这类问题的答案可能依赖文本里相距很远的两处之间的关系——而这种关系恰恰最容易被切片切断(见《切片决定检索上限》)。检索擅长找"相关段落",但有些问题根本没有单独的相关段落。

只需要定位的:"欧盟用户的退货政策是什么"。一段排好序的切片,效果通常好过让模型在 20 万 token 里扫一遍。

2.3 更新频率​

数据经常变(库存、工单队列、价格),检索赢:索引可以增量更新,每次查询都能看到新数据。长上下文每次都要重新组装整个载荷,语料一变就得重来。

数据稳定(定稿合同、冻结的规格、一篇论文),长上下文没问题,进上下文的成本每会话只付一次。

一条好记的规则:数据变化的速度快过你愿意重建上下文的速度,就检索。

2.4 单次成本与延迟​

这是最容易被低估的一项,因为它是乘法。用一份 15 万 token 的语料回答 1000 个问题:

  • 长上下文:每次为约 15 万输入 token 付费,合计 1.5 亿输入 token,还没算输出
  • 检索:每次取回约 4K 相关 token,合计 400 万,外加一次廉价的向量检索

差了一个数量级以上。单次问答"长上下文反正也不贵"是对的,但它是按次计价的,量一大就换了个量级。

3. 各自的失败模式​

检索的失败模式都在生成之前,且互不相似:

  • 召回漏:正确答案不在 top-k 里,模型只能凭空答,还答得很自信
  • 切片切断:表格、跨段落的条款被切开,两边都读不懂
  • 重排错序:相关的切片排到了后面,被截断(这一点《重排修不了召回》展开过)

长上下文的失败模式都不在"找不到",而在"找到了也没用好":

  • 中间丢失:相关内容放在超长上下文的中间位置,模型对它的注意力显著低于首尾
  • 噪声稀释:50 万 token 的无关内容,让那 500 个真正相关的 token 更难被注意到
  • 成本失控:一次意外的超长输入就能吃掉预算
  • 调试不透明:答错了,你无法定位它是从上下文的哪一段得出这个结论的

注意这两组失败模式不构成互补:检索不会修好中间丢失,长上下文也不会修好召回漏。选一个,就是接受那一组的失败模式。

4. 标称窗口不等于可用窗口​

这是实践里最常踩的一处。厂商标称 100 万 token,不代表这 100 万都能被同等质量地使用。检索类任务(大海捞针)的表现随上下文长度下降,越接近标称上限下降越明显。

所以正确的做法是自己测一条可用窗口曲线:把一份答案放在语料的不同位置、不同总长度下,看召回率在什么长度开始塌。你得到的那个数字,才是设计时的真实约束。拿标称值做容量规划,等于拿硬盘标称容量当可用容量。

5. 混合是多数团队的落点​

公开讨论里混合模式被讲得很玄,其实就一句话:让检索负责"把候选从很大缩到可控",让长上下文负责"在这批候选上做合成"。

落到管道上,是三个具体改动:

宽候选,然后重排,不要早截断。 经典 RAG 的问题是取得太少——三个紧切片,答案只要跨边界就没了。先取宽一点,靠重排把顺序排对。

总量按实测可用窗口封顶,不按标称窗口。 第 4 节那条曲线量出来的数字,是这里的上限。

切片可以切大一点。 激进切分本来就是小窗口时代的权宜之计。既然有空间,就保留段落之间的关系——这正是长上下文相对检索的优势所在。

混合的代价是管道更复杂:检索那一半仍然要好。一张撒得太宽的网里全是干扰项,比内容为空还糟,因为模型会把干扰项也读进去。

6. 缓存改变了成本那一项​

第 2.4 节的成本对比有个前提:每次都重新算一遍前缀。如果前缀稳定,提示缓存能让第二次起大幅降价——折扣按厂商和模型而定(Anthropic 读取约 0.1 倍、OpenAI 较新模型 90% off、Gemini 约 75% off,详见《提示缓存怎么才命中》),"一份长文档服务很多请求"因此变得划算,长上下文的成本劣势会被显著削平。

反过来,请求稀疏(间隔超过缓存有效期)或者前缀常变,缓存写入比省下的还多,那这个折扣就不存在。具体怎么算、哪些行为会打掉缓存,见《提示缓存怎么才命中》。

一句话:缓存能让长上下文变得可负担,但只在"重复读同一段"的流量形态下。

7. 别拿别人的基准当结论​

公开评测的结果是混的:有研究称长上下文在问答类基准上普遍优于 RAG,也有结果称 RAG 在对话类与通用查询上更好。这类结论互相矛盾不是因为谁做错了,而是因为结论高度依赖语料规模、切片方式与查询分布。

所以它们唯一的用途,是提醒你"该在自己数据上测一遍"。拿同一批真实问题,分别跑检索构造的提示词和长上下文构造的提示词,比成本、延迟、质量三项差值——这个结果才对你有效。

8. 一个可执行的判断顺序​

按顺序问,遇到"是"就停:

  1. 语料装不装得进实测可用窗口? 装不进 → 检索
  2. 数据是不是经常变? 常变 → 检索(增量更新的做法见《知识库的重灌与切换》)
  3. 任务是不是必须通读全文才能答? 是 → 长上下文
  4. 量大之后成本能不能接受? 不能 → 检索
  5. 需要精确到段落的引用吗? 需要 → 检索

五问都走完还拿不定,就上混合:粗召回缩到可控规模,重排保序,交给长上下文合成。

9. 两个默认值都是错的​

一类团队把 RAG 当默认值,语境里所有问题都先建索引;另一类把"反正能塞进去"当默认值,把所有东西都堆进上下文。两者都是默认值思维,区别只是默认值选了哪一边。

真正该做的是把它当成一个选项:按语料规模、更新频率、任务类型、成本四项来选,并且留一个开关——因为这四个变量里至少有三个会随时间变化。今天选长上下文的方案,两年后语料涨十倍就该换回检索;反过来,一个为小窗口做过激进切分的系统,在窗口变大之后反而应该把切片放大。

这条和《RAG 链路与失败模式》里说的是同一件事:先想清楚失败模式是什么,再选架构。