上下文腐化
上下文不是越长越好:注意力稀释、干扰信息与“中间遗忘”。
一句话理解:上下文窗口是容量,不是理解力;放进去的 Token 越多,模型对每一条信息的利用往往越差,这就是上下文腐化(Context Rot)。
模型的上下文窗口这几年增长得很快。以 Claude 为例,官方文档显示多款当前模型已支持 1M Token 的上下文窗口。于是很自然地出现一种想法:既然装得下,何必费心筛选?把所有文档、所有历史、所有工具结果都放进去,让模型自己找。
这种做法在 Demo 里常常看起来可行,在生产环境里却会以一种很难排查的方式失败:Agent 没有报错,只是越跑越“笨”——忘记早先确认过的约束、重复调用已经调用过的工具、在长报告里漏掉关键的一行。这一课解释背后的原因,以及产品上应该怎么应对。
直觉:注意力是有预算的
Anthropic 在关于 Context Engineering 的文章里用了一个比喻:模型和人一样,有一个有限的“注意力预算”,每多放入一个 Token,就会消耗一点这个预算。
从机制上看,Transformer 需要在所有 Token 之间建立关联。上下文越长,需要处理的关系越多,模型能分给任何一条具体信息的“关注”就越稀薄。这不是某个模型的缺陷,而是一种普遍的趋势:上下文长度增加时,准确性与召回能力会逐渐下降。 Claude 的官方文档在介绍上下文窗口时也直接写明了这一点,并把它称为 context rot。
可以把它想象成开会:会议材料 3 页时,每个人都能记住关键数字;材料 300 页时,大家都“看过了”,但很少有人记得第 147 页那条例外条款。
同一条关键条款,放在长短不同的上下文里,处境完全不同:
腐化的表现与研究证据
四种表现
| 表现 | 发生了什么 | 客服 / Coding 场景的例子 |
|---|---|---|
| 注意力稀释 | 关键信息被大量无关内容包围 | 3000 条支付流水里,“退款单已被驳回”那一条被忽略 |
| 干扰项误导 | 与问题 相似但不相关 的内容被当成答案依据 | 检索到了另一个订单号相近的订单的记录,Agent 用它下结论 |
| 中间遗忘 | 位于长上下文中部的信息更容易被忽略 | 会话初期用户说“只看企业版客户”,20 步之后被遗忘 |
| 错误累积 | 早期的错误假设留在上下文里,持续影响后续判断 | Coding Agent 一开始误判 Bug 在前端,后面的探索都围绕这个方向打转 |
最后一种在 Agent 中尤其危险。Chatbot 的错误通常停留在一次回复里,而 Agent 的上下文会把错误的中间结论一路带下去,后续每一步都在“被污染的文件袋”上做判断。
研究怎么说
这里只列经过核实、且对产品设计有直接启发的两项研究。
“Lost in the Middle”(Liu 等,发表于 TACL,2023):研究者把回答问题所需的关键文档放在长输入的不同位置,发现当关键信息位于开头或结尾时模型表现最好,位于中间时表现明显下降。这项研究基于当时的模型,具体程度会随模型迭代而变化,但“位置会影响利用率”这个直觉至今仍有参考价值。
这项发现可以画成一条示意曲线:
Chroma 的 Context Rot 报告(2025 年 7 月):测试了 18 个模型,得到几个反直觉的发现:
- 即使只加入 一个 干扰项,表现也会下降,而且不同干扰项造成的影响不同。
- 问题与答案之间的 语义相似度越低,输入变长时表现下降得越快。也就是说,需要“绕个弯”才能找到的信息,最怕长上下文。
- 在对话记忆类任务上,只给相关片段(约 300 Token)的表现显著好于给出完整历史(约 11 万 Token)。
一个值得注意的推论:常见的“大海捞针”测试通常是在无关文本里找一句字面高度相似的话,这是最简单的情形。模型在这类测试里表现很好,不代表 它在真实业务的长上下文里同样可靠。
对产品设计的五条启发
1. 以“最小充分”为目标,而不是“尽量完整”。 好的上下文是能支撑判断的最小信息集。多出来的部分不是免费的,它会拉低准确率。
2. 让工具返回“可用的结果”,而不是“全部的数据”。 支付流水查询默认返回程序计算好的摘要和异常点,需要时再取原文。这比让模型在几千行里自己找可靠得多。
3. 重要的东西放在显眼的位置,并在关键时刻重申。 固定规则放在系统指令里;当前目标和约束,可以通过持续更新的任务清单(Todo)让它们反复出现在上下文靠后的位置。很多 Coding Agent 在长任务中维护 Todo 列表,一部分作用就在于此。
4. 及时清理已经没用的内容。 旧的工具结果、被推翻的假设、失败的尝试,在完成使命后应当被清理或压缩成一句结论。具体方法见 长任务的上下文管理。
5. 相似但无关的内容比完全无关的内容更危险。 检索时召回了 10 份“看起来相关”的文档,其中 7 份是干扰项,效果可能不如只给 3 份准确的。这正是后面 混合检索与重排序 要解决的问题。
如何发现腐化
腐化很少直接报错,需要在评测和 Trace 里刻意寻找:
这些信号都可以转化为评测用例,放进评测集持续回归(参见 构建评测集)。
常见误区
- “窗口到了百万级,就不需要做上下文管理。” 窗口决定上限,不决定质量。长上下文还意味着更高的成本和延迟。
- “大海捞针测试满分,说明长上下文没问题。” 那是最简单的检索情形。真实任务需要推理、需要处理干扰项,难度高得多。
- “信息多给了,模型自己会忽略无关部分。” 研究显示,哪怕一个干扰项都可能降低表现。与其指望模型忽略,不如一开始就不放进去。
设计要点
- 评审方案时,问每一块大体积上下文:“去掉它,判断会变差吗?”答不上来就先去掉,用评测验证。
- 为长任务 Agent 设计“长度梯度”评测,而不仅是单步评测。
- 工具默认返回摘要与异常点,原文通过 ID 按需获取。
- 当前目标、关键约束、已排除项放进持续更新的任务状态,而不是只留在早期对话里。
- 检索宁缺毋滥:召回之后要重排与截断,不要把 Top 20 全塞进去。
练习
用你能调用的任意一个模型,做一个 30 分钟的小实验:
- 准备一个知识库问题,例如“根据以下资料,订单 ORD-1024 的退款为什么没有到账?”,以及 3 段真正相关的资料。
- 版本 A:只给 3 段相关资料。版本 B:3 段相关资料 + 20 段相似但无关的资料(例如其他订单的记录、旧版政策),并把相关资料放在中间。
- 各跑 5 次,记录正确率和答案中是否出现了“张冠李戴”。写一段话总结你观察到的差异。
延伸阅读
- Anthropic Engineering:Effective context engineering for AI agents
- Chroma Research:Context Rot
- Liu et al.:Lost in the Middle: How Language Models Use Long Contexts
下一步
既然上下文不能无限累积,长任务怎么办?下一课「长任务的上下文管理」会讲摘要压缩、外置笔记、清理旧工具结果与子任务隔离。