管理 Claude Code 会话的核心在于有意识地控制上下文窗口的使用。当上下文累积到约 300-400k tokens 时,会出现 Context Rot,模型性能开始下降。通过合理运用 Continue、Rewind、Compact、New Session 和 Subagent 这五种操作,可以优化上下文质量、提升任务效率并避免性能劣化。

Thariq 的会话管理指南:Context Rot、Rewind、Compact vs Fresh Session

Claude Code 拥有高达一百万 token 的上下文窗口,使其能够处理更长、更复杂的任务。然而,窗口越大,不管理会话所带来的风险也越大。Thariq 的指南强调,上下文管理不再是可选项,而是决定输出质量的关键实践。

上下文与 Context Rot

上下文窗口是模型生成下一条回复时所能“看到”的所有信息,包括系统提示、整个对话历史、每一次工具调用及其输出,以及所有读取过的文件内容。Claude Code 的上下文窗口为一百万 token。

使用上下文有一个代价:Context Rot。随着上下文增长,模型的性能会下降,因为注意力需要分散到更多的 token 上,而旧的、不相关的内容会干扰当前任务的处理。对于百万 token 上下文,Context Rot 通常在上下文使用量达到 约 300-400k tokens 时开始显现,但这高度依赖于具体任务,并非绝对阈值。

当上下文即将耗尽时,需要通过总结任务并在新窗口中继续,这个过程称为压缩(Compaction)。你也可以主动触发压缩。

每个回合都是决策点

在 Claude 完成一个回合后,你有多达五种选择来决定下一步操作:

  1. Continue(继续):在同一个会话中发送下一条消息。
  2. Rewind(回溯) (/rewind 或双击 Esc):跳回之前的某条消息,并从那里重新开始。
  3. /clear:开始一个全新的会话,通常基于你从当前会话中提炼出的简要说明。
  4. Compact(压缩):将会话历史总结为一个摘要,并基于该摘要继续。
  5. Subagent(子代理):将下一块工作委派给一个拥有独立、干净上下文的代理,然后仅将结果拉回主会话。

虽然最自然的反应是直接继续,但其他四种选项的存在都是为了更好地管理你的上下文。

这五种选择在保留旧上下文信息方面有显著差异:

Fresh Session (新会话) Compact (压缩) Subagent (子代理) Rewind (回溯) Continue (继续)
仅保留你的简要说明 有损的总结 保留所有上下文 + 子代理结果 保留前缀,截断后续 保留所有内容
无旧上下文 完整旧上下文

何时开始新会话

新的百万 token 上下文窗口让长任务(例如从头构建一个全栈应用)更加可靠。但模型尚未耗尽上下文,不意味着你不应该开始新会话。

通用法则:开始新任务时,就应该开始新会话。

灰色地带出现在执行相关任务时,部分上下文仍然有用,但并非全部。例如,为你刚刚实现的功能编写文档。虽然可以开新会话,但 Claude 需要重新读取文件,这会更慢且成本更高。由于文档编写可能不是高度依赖智力的任务,保留旧上下文的效率收益或许值得。

优先使用 Rewind 而非修正

如果说哪个习惯最能体现优秀的上下文管理,Thariq 认为是 Rewind

在 Claude Code 中,双击 Esc 或运行 /rewind 可以让你跳回到任何一条历史消息,并从那里重新提示。该消息之后的所有内容都会从上下文中移除。

修正(Correcting)(在一次失败尝试 A 后说“不,试试 B”)会将失败的尝试保留在上下文中:

上下文 = 读取的文件 + 2次失败尝试 + 2次修正 + 最终修复

回溯(Rewinding)(回退到失败尝试之前,并基于学到的信息重新提示)则更干净:

上下文 = 读取的文件 + 一个基于充分信息的提示 + 最终修复

Rewind 通常是更好的方法。例如,Claude 读取了五个文件,尝试了一种方法但无效。你的本能可能是输入“这不行,试试 X。”但更好的做法是回溯到文件读取之后,用你学到的信息重新提示:“不要用方法 A,foo 模块不支持那个功能——直接使用 B。”

你还可以使用 “summarize from here” 让 Claude 总结其学习到的内容并创建交接信息,这就像来自尝试过但失败了的未来 Claude 写给过去 Claude 的一条消息。

压缩 vs 新建会话

当会话变得冗长时,你有两种减负方式:/compact/clear(并重新开始)。它们感觉相似但行为迥异。

压缩(Compact) 要求模型总结到目前为止的对话,然后用该摘要替换历史记录。这是一个有损过程——你相信 Claude 能判断什么重要,但无需自己动手。Claude 可能会更全面地包含重要的学习成果或文件。你也可以通过传递指令来引导它(例如 /compact 重点放在 auth 重构上,忽略测试调试部分)。

  • 适用场景:任务进行中,需要保持势头;细节可以模糊;成本较低,可继续推进。

新建会话并附带简要说明(Fresh + brief) (/clear) 意味着由你来写下什么是重要的(例如“我们正在重构 auth 中间件,约束条件是 X,重要的文件是 A 和 B,我们已经排除了方法 Y”),然后从干净的上下文开始。这需要更多工作,但产生的上下文完全由你决定其相关性。

  • 适用场景:下一步是高风险操作;在10万 token 的探索中只发现了一个关键事实;需要更多工作,但更精确。

是什么导致了糟糕的压缩?

如果你经常运行长时间会话,可能会注意到某些时候压缩效果特别差。当模型无法预测你后续工作的方向时,糟糕的压缩就会发生。

例如,自动压缩在一次长调试会话后触发,并总结了调查过程。你的下一条消息是“现在修复我们在 bar.ts 中看到的那个其他警告。”但由于会话一直专注于调试,这个“其他警告”可能已经在摘要中被丢弃了。

这尤其棘手,因为根据 Context Rot 的原理,模型在压缩时正处于智能最弱的状态。在拥有百万 token 上下文的情况下,你有更多空间来主动进行压缩,并在压缩指令中描述你接下来打算做什么,从而预防此类问题。

子代理与干净的上下文窗口

子代理(Subagent)是一种上下文管理形式,适用于当你事先知道某块工作会产生大量后续不再需要的中间输出时。

当 Claude 通过 Agent 工具生成子代理时,该子代理会获得自己独立的、干净的上下文窗口。它可以进行任意多的工作,然后综合其结果,因此只有最终报告会返回给父级。

判断标准:我需要的是这些工具输出,还是只需要结论?

当子代理退出时,探索性的噪音会被垃圾回收——20次文件读取、12次grep、3条死胡同——只有最终报告会返回父级上下文。

虽然 Claude Code 会自动调用子代理,但你可能想明确指示它这样做。例如:

  • “启动一个子代理,根据以下规范文件验证这项工作的结果。”
  • “分拆一个子代理去通读这个其他代码库,总结它如何实现了 auth 流程,然后用相同的方式在这里实现。”
  • “分拆一个子代理,根据我的 git 变更编写这个功能的文档。”

要深入了解如何定义和使用子代理,可以参考 Claude Code Subagents 指南

总结:决策框架

当 Claude 结束一个回合,你即将发送新消息时,你面临一个决策点。未来 Claude 可能会自行处理,但目前,这是引导 Claude 输出的关键方式之一。

场景 选择 原因
同一任务,上下文仍然相关 Continue 窗口中的所有信息仍有用——不必为重建它付出代价
Claude 误入歧途 Rewind (双击 Esc) 保留有用的文件读取结果,丢弃失败的尝试,用你学到的信息重新提示
任务进行中,但会话因过时的调试/探索而臃肿 /compact <提示> 低成本;由 Claude 决定什么重要。必要时用提示引导它
开始一个真正的新任务 /clear 零 Context Rot;你完全控制哪些信息被携带过去
下一步将产生大量你只需要结论的输出 Subagent 中间工具噪音留在子级上下文中;只有结果返回

对于想要将这些模式系统化、构建更复杂工作流的用户,可以进一步探索编排工作流实战

FAQ

Q: Context Rot 的 300-400k token 阈值是固定的吗? A: 不是。这是一个大致的参考范围,具体何时出现性能下降高度依赖于任务类型和上下文中的信息密度。

Q: 如何在压缩时避免丢失重要信息? A: 最有效的策略是主动压缩,并在指令中明确接下来要做什么(例如 /compact 我们接下来要重构 auth 模块,请保留相关文件路径和之前排除的方案)。这比依赖自动压缩并在事后发现信息丢失要好。

Q: 何时应该使用子代理而不是直接在主会话中工作? A: 当一项子任务预计会产生大量中间输出(如多次文件读取、搜索、试错),而你最终只需要其结论时,就应该使用子代理。这能保持主会话上下文的清洁。