跳转至

第31章:当记忆装不下:压缩系统

生活类比:塞满的行李箱

行李箱快爆了,你通常有三种办法:自己整理、提前清理、快爆时紧急腾空间。Claude Code 的压缩系统,也差不多就是这三套思路。

这一章先回答一个问题

对话越来越长、工具结果越来越多、上下文快超限时,Claude Code 是怎么“瘦身”而不把关键任务线索一起删掉的?

它没有只靠一种压缩,而是做了一个组合拳:manual compact、auto compact、microcompact、reactive compact、context collapse、snip、tool summary


31.1 为什么“上下文压缩”是 Agent 系统的生死线

普通聊天机器人上下文满了,最多就是聊不下去。Claude Code 不一样,它在任务执行中还要保留:

  • 用户目标
  • 工具结果
  • 中间决策
  • 文件上下文
  • 记忆注入
flowchart TD
    A["用户消息"] --> E["上下文窗口"]
    B["工具结果"] --> E
    C["记忆注入"] --> E
    D["系统提示"] --> E
    E --> F{"接近上限?"}
    F -->|否| G["继续推理"]
    F -->|是| H["进入压缩路径"]

    style E fill:#e3f2fd,stroke:#1e88e5,color:#000
    style H fill:#fff3e0,stroke:#fb8c00,color:#000

所以压缩不是优化项,而是“能不能继续工作的前提”。


31.2 auto compact:提前减肥,而不是等到完全爆掉

autoCompact.ts 会根据模型上下文大小和阈值判断是否需要自动压缩。它的思路很像“提前做容量管理”:

  • 先看是否启用
  • 计算阈值
  • 到了阈值就提前压缩
  • 把 tracking 信息带回主循环
flowchart LR
    A["当前 token 使用量"] --> B{"超过 autoCompactThreshold?"}
    B -->|否| C["继续"]
    B -->|是| D["autoCompactIfNeeded()"]
    D --> E["生成 compaction result"]
    E --> F["buildPostCompactMessages()"]

这类压缩的优点,是它通常发生在系统还“比较从容”的时候,所以保真度更高。


31.3 microcompact 与 snip:优先删“最该删的部分”

Claude Code 并不是一上来就对整段历史做大摘要。microCompact.tssnipCompact.ts 更像精细手术:

  • 优先处理旧工具结果
  • 尽量保留最近和高价值片段
  • 在 API 调用前先做更细粒度瘦身
flowchart TD
    A["完整消息历史"] --> B["识别 compactable tool ids"]
    B --> C["microcompactMessages()"]
    A --> D["snipCompactIfNeeded()"]
    C --> E["更短的历史"]
    D --> E
    E --> F["再进入模型调用"]

这很重要,因为“粗暴摘要整段对话”太容易把任务骨架也丢掉。微压缩和 snip 的价值,就是先拿掉体积大但信息密度低的部分。


31.4 reactive compact:真的快爆了,才动用紧急策略

query.ts 里,reactiveCompactcontextCollapse.recoverFromOverflow() 出现在错误恢复链上。也就是说,这些手段更像应急逃生通道

  • 上下文已被 withheld
  • 或媒体/提示过大
  • 普通路径无法继续
  • 这时才触发更激进的紧急瘦身
sequenceDiagram
    participant Q as query.ts
    participant C as contextCollapse
    participant R as reactiveCompact

    Q->>Q: 发现 withheld / 413 / overflow
    Q->>C: recoverFromOverflow()
    C-->>Q: 尝试局部排水
    Q->>R: tryReactiveCompact()
    R-->>Q: compaction result
    Q->>Q: buildPostCompactMessages()
    Q->>Q: 重新发起下一轮

这类压缩保真度通常不如提前压缩,但胜在能救回一次本该失败的对话。


31.5 context collapse 与 tool summary:让“骨架”继续露在外面

有意思的是,Claude Code 并不总是选择“全部压成摘要”。contextCollapsegenerateToolUseSummary() 更像在做结构化保留:

  • 让一些片段折叠,而不是彻底消失
  • 把冗长工具结果改写成摘要
  • 保留边界消息和任务骨架
flowchart LR
    A["长工具输出"] --> B["toolUseSummary"]
    C["部分上下文"] --> D["contextCollapse"]
    B --> E["保留结论,压掉细节"]
    D --> F["保留骨架,折叠负担"]

这是一种很高级的“信息密度管理”思路:不只问“删掉什么”,还问“怎样删得更聪明”。


31.6 设计取舍:压缩系统为什么一定要多层

如果只有一种压缩策略,它迟早会在某种场景下失效。Claude Code 选择多层压缩,本质上是在处理不同级别的上下文压力:

flowchart TD
    A["轻度压力"] --> B["microcompact / snip"]
    B --> C["中度压力"]
    C --> D["auto compact"]
    D --> E["重度压力"]
    E --> F["context collapse / reactive compact"]

    style F fill:#ffebee,stroke:#e53935,color:#000

这背后的产品观也很清楚:

  • 平时少动大刀
  • 先删低价值负担
  • 真危险了再走激进路径

这样既能保住体验,也能保住任务连续性。

🔭 深水区(架构师选读)

上下文压缩最难的不是“压缩率”,而是“压完还能不能继续工作”。Claude Code 把压缩设计成一条渐进式流水线:先微调,再自动,再应急。这个层级结构,比单一摘要器要稳得多,也更适合 Agent 场景。

本章小结

Claude Code 的压缩系统不是单点功能,而是一套多层策略:microcompact 和 snip 负责精细减重,auto compact 负责提前管理,context collapse 和 reactive compact 负责应急救火。

关键源码索引

  • query.ts 引入 compact 体系:query.ts
  • Snip 预处理:query.ts
  • context collapse 应用:query.ts
  • overflow 恢复:query.ts
  • reactive compact 重试:query.ts
  • auto compact 阈值与入口:autoCompact.ts
  • autoCompactIfNeeded:autoCompact.ts
  • buildPostCompactMessages:compact.ts
  • microcompact 主入口:microCompact.ts
  • snipCompactIfNeeded:snipCompact.ts
  • recoverFromOverflow:index.ts

逆向提醒

压缩效果和模型行为强相关。源码能解释“什么时候压、怎么压、压后消息如何重建”,但不能保证任何一次压缩都保留了最优语义,这依然是运行时策略和模型质量共同决定的结果。