30 秒快速回答

上下文腐烂(Context Rot)指的是:模型的输入越长,它在同一个任务上的准确率就越低——哪怕答案就在上下文里,哪怕窗口远没装满。

这个现象由向量数据库公司 Chroma 在 2025 年 7 月的技术报告《Context Rot: How Increasing Input Tokens Impacts LLM Performance》正式命名并量化。他们测了 18 款主流模型(含 GPT-4.1、Claude 4、Gemini 2.5、Qwen3),约 19.4 万次调用,结论是没有一款模型幸免。

核心价值一句话:上下文窗口大小说的是”能装多少”,上下文腐烂说的是”装进去之后还用得动多少”——这是两个完全不同的数字,而后者永远不会出现在产品参数页上。

一、先分清四个容易混的概念

概念 本质 典型表现 该怎么治
上下文溢出(Overflow) 超过窗口上限 报错或截断,非常明显 换大窗口、切片
中间信息丢失(Lost in the Middle) 位置问题:中段召回差 把答案挪到开头/结尾就恢复 重排提示词
上下文腐烂(Context Rot) 长度问题:token 越多越不准 静默变差,不报错、不截断 必须”剪”,重排无效
幻觉(Hallucination) 输出没有依据 编造事实 校验、RAG、结构化输出

最常踩的坑是把上下文腐烂当成”中间信息丢失”来治:重排一遍提示词,看起来清爽了,但一个顺序完全正确、内容依旧臃肿的 prompt 照样会烂。位置和体积是两条独立的失效轴,只能靠削减来解决体积问题。

二、证据:三个实验,一个结论

Chroma 的实验设计很克制:固定任务难度,只改输入长度,这样准确率的变化只能归因于长度本身。

实验 1:语义化大海捞针

经典 NIAH 是逐字匹配,”针”和问题用的是同一批词,前沿模型基本满分,于是长上下文看起来”已解决”。Chroma 做了三处加难:把针换成需要语义匹配的版本、加入看起来合理的干扰项、降低问题与答案的相似度。结果准确率随长度明显下滑,相似度越低掉得越陡。

实验 2:LongMemEval 对话记忆

同一个答案给模型看两遍:一份是约 300 token 的聚焦提示,一份是约 113,000 token 的完整历史(里面完整包含那 300 token)。每个模型家族都是聚焦版更高,而且不少模型是以”拒答”而不是”答错”的形式失败。信息在不在,不是唯一变量。

实验 3:重复词复制

这个任务完全不需要推理,只要求原样复述一串重复词加一个不同的词。长度上去之后,所有模型开始错位、随机替换,个别模型直接拒绝任务。连”复制”都做不好,说明问题不在理解能力,而在注意力被摊薄。

另外两个反直觉的发现值得记住:

  • 干扰项比长度更毒。一个”看起来像答案”的段落就能拉低准确率,四个会进一步叠加,而且杀伤力不均匀。
  • 连贯的文档反而更差。18 款模型上一致出现:在乱序的 haystack 里找针,比在逻辑连贯的文章里更容易。连贯文本给了模型更多”貌似合理”的错误线索。

三、为什么会烂:三个机制

1. 注意力预算被摊薄。 Softmax 权重要分给每一个 token,多一个 token 就多一个竞争者。Anthropic 的说法很形象:注意力是一份有限预算,每个 token 都在花它。

2. 干扰项累积。 真正致命的是”相似但不对”的内容,而 Agent 的工具返回、搜索结果里恰恰遍地都是。

3. 上下文惯性(Context Inertia)。 这是 2026 年 10 月 Drew Breunig 在 AGNTCon 演讲《The State of Context Engineering》里新增的失败模式:Agent 在长步骤里会形成一个”工作假设”,之后倾向于继续细化它而不是推翻它——即使新证据已经要求转向。典型症状是 50 步计划走到第 40 步,还在挖同一个坑。

顺带记住他归纳的四种老失败模式,排错时很好用:中毒(幻觉进了上下文被反复引用)、分心(历史太长,模型跟着自己的旧行为走)、混淆(无关的工具和文档影响判断)、冲突(新旧信息互相打架)。

他给的操作建议非常朴素:上下文到 20 万 token 就该清。”Delete your context. I’m not joking.”

四、五种修复(按杠杆大小排序)

手法 一句话做法 能解决什么
少而准(augmentation) 检索 top-k 相关片段,而不是贴整篇文档 直接降体积,杠杆最大
按需装载工具(tool loadout) 只暴露这一步需要的工具与技能 治”混淆”,30 个以上工具描述开始重叠
剪枝 + 卸载(pruning/offloading) 旧工具结果只留一行结论,原文落盘 治”分心”,顺带省钱
子代理隔离(quarantine) 子 Agent 用干净窗口探索,只回传摘要 治”冲突”,父窗口保持小
定期清空(strategic forgetting) 写一条笔记 → 清空上下文 → 保留环境 治”惯性”,最反直觉但最有效

一个可直接抄的上下文装配器:

BUDGET = 60_000  # 可用预算,不是窗口上限

def assemble(system, retriever, tools, history, task):
    ctx = [system]
    # 1) 工具按需装载:只给这一步要用的
    loadout = [t["name"] for t in tools.loadout(task)]
    ctx.append({"role": "system", "content": f"可用工具: {loadout}"})
    # 2) 检索少而准:拿片段,不拿整篇
    ctx.append({"role": "system", "content": retriever.top_k(task, k=5)})
    # 3) 剪枝:旧工具结果只留结论,原文已落盘
    for turn in history:
        if turn.kind == "tool_result":
            ctx.append({"role": "user", "content": f"[落盘 {turn.path}] {turn.one_line}"})
        else:
            ctx.append(turn.raw)
    # 4) 超预算就从最旧的非关键轮次开始压
    while tokens(ctx) > BUDGET:
        ctx = compact_oldest(ctx, keep=ctx[:3])
    return ctx

一个容易忽略的细节:prompt caching 对腐烂没用。缓存改变的是你为这些 token 付多少钱,并不改变它们占不占窗口。

关于定期清空,有两个真实参考:Anthropic 的 Memento harness 让 Agent 每隔约一个半小时写一条简短笔记,然后清空上下文,环境(文件、仓库状态)原样保留;微软研究院的 Fork-and-Flush 是同类思路。

五、怎么确认是”腐烂”而不是”提示词写坏了”

写个二十行的消融脚本,同一任务跑三种上下文:

def ablation(task, build_ctx, model):
    variants = {
        "full_history": build_ctx(task, mode="full"),
        "curated":      build_ctx(task, mode="curated"),
        "minimal":      build_ctx(task, mode="minimal"),
    }
    for name, ctx in variants.items():
        acc = run_eval(model, task, ctx, n=30)
        print(f"{name:14s} tokens={tokens(ctx):>7d} acc={acc:.1%}")

判读方法:

  • curated 明显高于 full_history → 你在付”腐烂税”,去剪枝;
  • 三者都低 → 不是腐烂,是提示词、工具或检索本身的问题;
  • minimal 反而最低 → 上下文削过头了,缺关键前提。”少”是方向,不是教条,稀疏同样会失败。

六、总结

  • 窗口大小不等于可用长度:200K 窗口的模型,可能 50K 就开始掉准。
  • 腐烂是静默的:不报错、不截断,模型还很自信,所以只能靠消融测出来。
  • 治它靠”剪、换、隔、卸、清”五个动作,重排位置没用。
  • 记一个数字:约 20 万 token 是值得主动清空上下文的警告线。
  • 下一阶段的难点是策略性遗忘——决定丢什么、什么时候丢、按什么标准丢。

延伸阅读

  • Chroma《Context Rot: How Increasing Input Tokens Impacts LLM Performance》(2025-07)
  • Drew Breunig《The State of Context Engineering》(2026-10-24,AGNTCon 演讲整理稿)
  • Anthropic《Effective context engineering for AI agents》
  • 本站延伸:《什么是上下文工程?》《什么是 Agent 上下文压缩?》《什么是 Agent 记忆修订?》