返回博客

主动压缩而非被动截断——AI 长会话的上下文管理心法

用 Claude Code 做过长任务的人,大多遇到过同一个现象:会话跑着跑着,模型的回答开始变得迟缓、前后矛盾,或者对之前说过的事情「失忆」。这时候往往想着「忍一忍,撑过去」,结果越撑越乱。

真正的问题不是上下文太长,而是压缩发生在错误的时机。自动压缩(auto-compaction)不认识任务边界,它只认 token 计数。当你正在啃一个复杂的实现阶段,它偏偏在中途触发,把你好不容易积累的变量名、文件路径、部分状态全部丢掉——留给你一个残缺的现场。

在逻辑边界主动出手

解决办法其实很朴素:把压缩时机的控制权收回来,在任务的自然换挡点手动执行 /compact

典型的换挡点:

  • 探索期 → 规划期:调研阶段积累了大量文档摘要和背景信息,但真正需要带入下一步的只是最终的计划。此时 compact,把「研究过程」换成「行动方案」。
  • 规划期 → 实施期:计划已经落进 TodoWrite 或某个文件,上下文里的推演过程可以清掉,给实现阶段腾出空间。
  • 调试结束 → 下一个功能:调试产生的错误栈、临时假设、走错的分支,对接下来的新功能毫无价值,反而是噪音。
  • 死路之后:当一个方向被证明走不通,那些用来论证「这条路不行」的推理,也可以一并清掉,用干净的上下文重新出发。

什么时候不该 compact?实现进行到一半时——此刻上下文里有你刚读的文件内容、还没写完的函数、彼此关联的修改点,断掉代价很高。

compact 前的一个习惯

执行 /compact 之前,先把关键中间产物落盘:重要的分析写进文件,计划列进 TodoWrite,口头约定存进 ~/.claude/memory/。因为 compact 之后,CLAUDE.md 和磁盘上的文件会保留,但对话里说过的一切都消失了。

什么在压缩后存活,什么消失

理解这张表,才能「带着信心压缩」:

| 压缩后保留 | 压缩后丢失 | |-----------|-----------| | CLAUDE.md 指令 | 对话中的中间推理 | | TodoWrite 任务列表 | 之前 Read 过的文件内容 | | 写到磁盘的文件 | 多步对话的上下文链 | | Memory 文件 | 口头表达的偏好和约定 | | Git 状态(commits、分支) | 工具调用历史与计数 |

这意味着:只要你养成「关键信息落盘」的习惯,压缩本身并不可怕。真正的损失,往往是「以为记住了,结果只在对话里」的那些东西。

工具辅助:让钩子提醒你

如果不想靠人工记忆来判断何时该压缩,可以用一个轻量的 PreToolUse 钩子来自动提示——在 Edit 或 Write 触发到一定次数后,钩子会打出建议,最终是否 compact 由你决定。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit",
        "hooks": [{ "type": "command", "command": "node ~/.claude/skills/strategic-compact/suggest-compact.js" }]
      }
    ]
  }
}

工具给你「时机信号」,你来做「是否」的判断——这个分工很合理。阈值也可以通过环境变量 COMPACT_THRESHOLD 自定义。

一句话心法

压缩是重置,不是失去——选对边界主动触发,每个新阶段都能以干净的上下文全力出发。