Context Rot:长上下文不是长期记忆

用 AI 做长一点的编程任务时,很容易产生一种误会:只要上下文窗口够大,就可以放心把所有东西都塞进去。

需求说明、代码片段、测试日志、搜索结果、旧方案、会议结论、刚才的失败尝试,全都给它。模型不是能看很长吗?那它应该会记得更多,理解得更完整,最后做得更稳。

我现在越来越觉得,这个想法危险的地方在于:它把“能放下”误认为“能用好”。

长上下文确实有价值。它让模型能一次读更多材料,也让复杂任务少一些来回搬运。但长上下文不是长期记忆,更不是天然干净的工作台。很多时候,Agent 不是因为看不见信息而失败,而是因为看见了太多旧的、相似的、过期的、未经验证的信息,最后在一堆上下文里拿错了权重。

我把这种现象称为 Context Rot:上下文还在窗口里,但已经开始变质。

不是忘了,而是记住了太多不该记的东西

context window 解决的是容量问题:一次请求里最多能放多少可被模型回看的内容。Anthropic 的文档把它描述成模型生成文本时能够回看并引用的文本总量。[1]

但容量不是记忆质量。

你可以把一整张桌子铺满资料,但这不等于桌面更适合工作。桌上有当前需求,也有三轮之前废弃的方案;有刚跑出来的测试失败,也有已经被修复过的旧报错;有真正相关的文件,也有名字相似但语义不同的模块。它们都在“可见范围”里,却不应该拥有同样的地位。

这就是 Context Rot 的核心:问题不是模型完全忘了,而是上下文里的信号密度、时效性和证据身份开始下降。模型仍然能看到文字,但更难稳定判断哪些是当前事实、哪些是旧计划、哪些只是失败路径,哪些只是临时猜测。

所以它经常表现得很迷惑:明明前面已经改过方向,它后面又沿用旧方案;明明读过正确文件,它总结时却引用了相似但错误的上下文;明明用户补充了新约束,它实现时还是被早期目标牵着走。

它不是没有记忆。

它是记忆太脏。

长上下文本身也会退化

这不是纯经验感受。Lost in the Middle 研究观察到,模型处理长输入时,相关信息的位置会影响使用效果;信息放在开头或结尾通常比放在中间更容易被利用。[2]

Chroma 的 Context Rot 技术报告进一步讨论了输入变长以后模型表现的退化。他们关注的不只是简单的“针在草堆里”检索,而是更接近真实应用的情况:上下文里有干扰项、语义相似项、结构化输入和不同相似度的问题。报告的一个重要提醒是,长上下文能力不能只用“能不能找回一个明确字符串”来代表。[3]

真实的 Coding Agent 任务通常比这些实验更乱。

因为编程任务里的上下文不是一份干净文档,而是一条不断滚动的工作流。它会混入:

  • 代码搜索结果
  • 文件全文
  • 测试日志
  • 构建失败
  • 网页资料
  • 临时计划
  • 已经废弃的假设
  • 用户中途补充的新目标
  • Agent 自己写过但还没有验证的解释

这些材料都可能有用,但它们的有效期不一样。测试日志可能只在定位阶段有用;旧计划一旦被推翻,就不应该继续参与实现;搜索结果如果没有打开原文验证,只能算候选线索;模型自己的总结如果没有证据,只能算假设。

一旦这些身份被混在一起,上下文就开始腐烂。

Coding Agent 里最常见的五种腐烂源

第一种是旧计划残留。

长任务一开始可能走 A 方案,后来发现不合适,改成 B 方案。但 A 方案的理由、文件路径、设计草图和半成品解释还留在对话里。后面 Agent 写代码或总结时,又把 A 方案当成有效背景拿回来用。

第二种是失败路径残留。

排障时会尝试很多假设。假设本来应该被证据淘汰,但如果没有明确标记“这条路已排除”,它会变成上下文里的幽灵状态。后续推理可能继续围着它转。

第三种是工具结果堆积。

rg 输出、测试日志、网页正文、API 响应、stack trace 都很有价值,但它们多数是短期证据。定位完成后,大段原始输出应该被压缩成“命令、结果、关键证据、可重取路径”。如果一直留在 active context 里,它们会持续占用注意力预算。

Anthropic 的 context engineering 资料也把 compaction、tool-result clearing、external memory、sub-agent/context isolation 等放在一起讨论,本质上都是在治理 active context,而不是迷信窗口容量。[4]

第四种是相似干扰项。

最危险的上下文不一定是完全无关的东西,而是“看起来相关但不是这次答案”的东西。比如相似模块、相似错误、旧版本接口、同名概念、另一个分支里的实现。它们会给模型一个很自然的错误抓手。

第五种是规则膨胀。

把所有偏好、禁忌、工具说明、写作风格和边界条件都塞进 always-on prompt,看起来很保险,实际可能稀释真正关键的规则。AGENTS.md、skill、项目文档都应该是索引和高频约束的载体,而不是百科全书。

Context Rot 的症状

日常使用里,可以从几个现象判断上下文已经不干净了。

Agent 开始重复已经否定过的方案。

它不断调用更多工具,但判断质量没有提升。工具调用越来越像是在给旧假设找理由,而不是寻找能区分假设的证据。

它读了很多文件,却引用错了文件。尤其是当仓库里有多个相似模块、相似命名、旧实现和新实现并存时,这种情况很常见。

它在总结里混入早期探索结论。明明中途已经改了方向,最后交付说明还是把旧方案、旧目标或旧报错带进来。

它开始忽略新约束。用户刚刚说了“不改这个模块”“只做本地验证”“不要动生成文件”,后面实现时却又被前面的大目标牵走。

还有一个很有意思的信号:压缩、重开任务或把当前事实整理成短摘要之后,模型表现突然变好了。

这说明问题可能不是能力不够,而是工作现场太乱。

更大的窗口不能根治它

更大的上下文窗口能推迟一部分问题,但不能消除 Context Rot。

因为 Context Rot 的核心不是“空间不够”,而是“上下文身份混乱”。窗口变大以后,旧计划、失败日志、相似干扰项和未经验证的总结也能放得更多。它们不会因为窗口变大就自动变成低权重,也不会自动被标记为过期。

所以大窗口更像一间更大的工作室。空间变大以后,确实可以放更多材料;但如果没有整理规则,它也可以更快变成仓库。

工程上真正要管理的是几件事:

  • 当前任务到底是什么
  • 当前阶段需要什么证据
  • 哪些内容已经过期
  • 哪些结论有来源
  • 哪些工具结果可以重取
  • 哪些规则应该常驻
  • 哪些资料应该按需加载

OpenAI 的 Codex best practices 强调给 Agent 明确目标、上下文、约束和完成标准,也建议把重复出现的项目指导沉淀到 AGENTS.md,并让 Agent 通过测试、lint、review 等方式验证结果。[5] 这背后的逻辑也是一样的:好的 Agent 工作流不是让模型背更多,而是让它在每一步拿到更正确的工作现场。

怎么治理 Context Rot

第一,按阶段切上下文。

研究阶段可以宽一点,多读文件、多搜索、多列假设。计划阶段应该收窄,只留下关键事实、取舍、风险和验收方式。实现阶段更应该窄,只保留当前文件、邻近接口和确定的设计决策。验证阶段需要的是新鲜证据,而不是早期信心。

第二,压缩工具结果。

工具输出不要默认长期驻留。大段日志读完以后,应该变成:

1
2
3
4
5
命令:npm run generate
结果:失败
关键错误:某篇文章 frontmatter 解析失败
证据位置:完整输出可重新运行命令获得
下一步假设:检查该文章 YAML

这比把完整日志一直放在上下文里更有用。

第三,显式废弃旧假设。

不要只追加“现在改用 B 方案”。最好写清楚:

1
2
3
已废弃:A 方案,因为测试 X 证明它不能覆盖 Y 场景。
当前方案:B 方案。
仍待验证:B 方案是否影响旧接口。

这能帮模型把历史状态和当前状态分开。

第四,把稳定结论外存。

如果某个结论下次还会用,就不要只留在聊天记录里。项目规则进 AGENTS.md 或文档;通用知识进 wiki;验证方式进脚本或 CI;可复用流程进 skill;一次性移交进 handoff。对话应该是临时工作台,不应该承担知识库的职责。

第五,保留证据指针,而不是保留全文。

很多内容是可重取的:文件路径、行号、命令、URL、测试名、日志路径。对模型来说,当前阶段通常不需要所有原文,只需要知道证据在哪里、结论是什么、是否仍然有效。

第六,把外部内容当证据,不当指令。

网页、issue、邮件、PDF、搜索结果都可能进入上下文,但它们不能越权改变任务规则。它们可以提供 claim,可以提供线索,可以被总结;但是否采纳,要看来源、时间、权限和当前目标。

一个简单检查清单

当一个 Agent 任务变长时,我会问这几个问题:

当前目标还能不能一句话说清楚?

当前阶段是研究、计划、实现、验证,还是沉淀?

现在窗口里最占地方的内容,还是不是当前阶段需要的?

有没有已经被否定但还没有标记废弃的方案?

有没有一大段工具输出可以压缩成摘要和指针?

关键结论有没有来源?来源是文件、命令、测试、文档,还是模型自己的猜测?

新约束有没有覆盖旧目标?旧目标是否需要明确失效?

完成判断有没有新鲜证据?

如果这些问题回答不上来,继续往上下文里塞材料通常不会让 Agent 更聪明,只会让它更容易把垃圾加工成一套看起来完整的方案。

长上下文应该被使用,而不是被迷信

我不是反对长上下文。

相反,长上下文是 AI 编程真正好用的重要原因之一。没有它,很多跨文件理解、长文档阅读、复杂需求梳理都会变得很麻烦。

但长上下文应该被管理,而不是被崇拜。

它适合承载当前任务所需的高信号材料,不适合永久保存所有历史痕迹。它适合帮助模型理解工作现场,不适合替代文档、测试、脚本、wiki 和人工判断。它适合让 Agent 少猜一点,不适合让我们把证据边界、任务边界和责任边界都交给模型自己整理。

如果说 AI 上下文工程:把正确的信息放到正确的位置 讲的是“要把正确的信息放到正确的位置”,那么 Context Rot 这篇想补上的就是另一半:

错误的位置、过期的信息和未清理的历史,本身也会变成一种输入。

Agent 的输出不是只由模型能力决定,也由它所在的工作现场决定。上下文越长,越要认真整理现场。否则它不是长期记忆,而是一张越来越乱的桌子。

参考与延伸阅读


  1. Anthropic, Context windows。这里引用它对 context window 作为模型当前可回看文本范围的解释。 ↩︎

  2. Nelson F. Liu et al., Lost in the Middle: How Language Models Use Long Contexts。这篇研究支持“相关信息在窗口内不等于模型会稳定利用它”的判断。 ↩︎

  3. Kelly Hong, Anton Troynikov, Jeff Huber, Context Rot: How Increasing Input Tokens Impacts LLM Performance,Chroma Technical Report, 2025。这里引用它来支持“长输入、干扰项和任务形式会让模型表现不均匀退化”的判断。 ↩︎

  4. Anthropic, Effective context engineering for AI agents,以及 Anthropic Cookbook, Context engineering: memory, compaction, and tool clearing。这里引用它们对 active context、compaction、tool-result clearing、external memory 和上下文隔离的工程实践。 ↩︎

  5. OpenAI, Codex best practices。这里引用的是任务目标、项目上下文、AGENTS.md、验证命令和 review 对 Coding Agent 工作质量的影响。 ↩︎