<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>集异璧之大成</title><description>Rediscory the beauty of typography</description><link>https://astro-theme-typography.vercel.app/</link><item><title>[译] 使用 Claude Code：会话管理与 100 万上下文</title><link>https://astro-theme-typography.vercel.app/posts/cc-session-management/</link><guid isPermaLink="true">https://astro-theme-typography.vercel.app/posts/cc-session-management/</guid><description>Claude Code 工程师 Thariq 分享会话管理最佳实践：何时开新会话、rewind vs 纠正、compact vs clear、以及如何用 subagents 管理上下文。</description><pubDate>Thu, 16 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;原文：&lt;a href=&quot;https://x.com/trq212/status/2044548257058328723&quot;&gt;Using Claude Code: Session Management &amp;amp; 1M Context&lt;/a&gt;
原作者：Thariq（&lt;a href=&quot;https://x.com/trq212&quot;&gt;@trq212&lt;/a&gt;）— Claude Code 工程师。曾就职 YC W20、MIT Media Lab。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;今天，我们为 &lt;code&gt;/usage&lt;/code&gt; 命令推出了一项全新更新，旨在帮助你更清晰地了解自己在 Claude Code 中的使用情况。这个决定的背后，是我们近期与用户进行的多次深入交流。&lt;/p&gt;
&lt;p&gt;在这些交流中，一个反复浮现的话题是：不同用户管理会话的方式差异极大，尤其是在 Claude Code 新增 100 万上下文之后。&lt;/p&gt;
&lt;p&gt;你是只在终端里保持一两个会话常驻？还是每次提示词都开一个新会话？什么时候该用 compact、rewind 或 subagents？什么会导致一次糟糕的 compact？&lt;/p&gt;
&lt;p&gt;这里面的门道比想象中多得多，而且会切实影响你使用 Claude Code 的体验。而几乎所有这些问题，本质上都归结为对上下文窗口的管理。&lt;/p&gt;
&lt;h2&gt;上下文、压缩与上下文腐化速览&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;images/cc-session-management/HF-nqWCbEAE3Oan.jpeg&quot; alt=&quot;上下文窗口示意&quot; /&gt;&lt;/p&gt;
&lt;p&gt;上下文窗口是模型在生成下一次回复时能一次性&quot;看见&quot;的全部内容，包括系统提示词、到目前为止的对话、每一次工具调用及其输出，以及所有被读取过的文件。Claude Code 的上下文窗口为 100 万 token。&lt;/p&gt;
&lt;p&gt;不过，使用上下文本身是有代价的——这种现象通常被称为上下文腐化（context rot）。简单来说，随着上下文不断膨胀，模型的注意力被摊薄到更多 token 上，早期那些不再相关的内容开始干扰当前任务，性能因此下降。&lt;/p&gt;
&lt;p&gt;上下文窗口存在硬性上限。当你快要触顶时，就需要将当前工作浓缩为一段更精简的描述，然后在新的上下文窗口中继续——这就是压缩（compaction）。你也可以手动触发压缩。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/cc-session-management/HF-ntaxboAAZuCm.jpeg&quot; alt=&quot;压缩示意&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;每一轮都是一个分岔点&lt;/h2&gt;
&lt;p&gt;假设你刚让 Claude 做了一件事，它也已经完成了。此时你的上下文里已经有了一些信息：工具调用、工具输出、你的指令。接下来你其实有相当多的选择：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;继续：在同一个会话里再发一条消息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/rewind&lt;/code&gt;（Esc Esc）：跳回到之前某条消息，从那里重新尝试&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/clear&lt;/code&gt;：开启新会话，通常附上一段你从刚才的工作中提炼出的简要说明&lt;/li&gt;
&lt;li&gt;Compact：总结到目前为止的会话，然后基于这份总结继续&lt;/li&gt;
&lt;li&gt;Subagents：把下一段工作委派给一个拥有干净上下文的代理，只把它的结果带回当前会话&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最自然的做法当然是继续发消息，但另外四个选项存在的目的，都是帮助你管理上下文。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/cc-session-management/HF-n6mMbEAEImhv.jpeg&quot; alt=&quot;会话分岔点&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;什么时候该开始新会话&lt;/h2&gt;
&lt;p&gt;什么时候该保留一个长会话，什么时候又该另起炉灶？我们的经验法则是：新任务，新会话。&lt;/p&gt;
&lt;p&gt;100 万上下文窗口确实意味着你现在可以更可靠地完成更长的任务，比如从零开始构建一个完整的全栈应用。&lt;/p&gt;
&lt;p&gt;但有时你会处理一些相关任务，其中一部分上下文仍然必要，但并非全部。例如，为你刚实现的功能编写文档。虽然你可以开启新会话，但 Claude 需要重新读取你刚实现的那些文件，这会更慢，也更贵。&lt;/p&gt;
&lt;h2&gt;用回退代替纠正&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;images/cc-session-management/HF-oDqjbEAI94h5.jpeg&quot; alt=&quot;回退 vs 纠正&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果只能推荐一个体现良好上下文管理的习惯，那就是 rewind。&lt;/p&gt;
&lt;p&gt;在 Claude Code 中，双击 Esc（或运行 &lt;code&gt;/rewind&lt;/code&gt;）可以让你跳回任意一条之前的消息，并从那里重新输入提示词。该时间点之后的消息会从上下文中移除。&lt;/p&gt;
&lt;p&gt;相比直接纠正，rewind 往往是更好的选择。举个例子：Claude 读取了五个文件，尝试了一种方案，但没有成功。你的直觉可能是输入&quot;这不行，换成 X 试试&quot;。但更好的做法是回退到刚读完文件之后的位置，然后带着你刚学到的信息重新提示：&quot;不要用方案 A，foo 模块没有暴露那个接口，直接走 B。&quot;&lt;/p&gt;
&lt;p&gt;你也可以使用 &quot;summarize from here&quot;，让 Claude 总结它的发现并创建一条交接消息——有点像未来的 Claude 给过去的自己留了张纸条：&quot;我试过了，这条路走不通。&quot;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/cc-session-management/HF-oKwBbEAAdb6I.jpeg&quot; alt=&quot;Rewind 流程&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;压缩与全新会话&lt;/h2&gt;
&lt;p&gt;当一个会话变得很长时，你有两种方式可以减负：&lt;code&gt;/compact&lt;/code&gt; 或 &lt;code&gt;/clear&lt;/code&gt;（然后重新开始）。它们感觉相似，但行为非常不同。&lt;/p&gt;
&lt;p&gt;Compact 会让模型总结到目前为止的对话，然后用这份总结替换掉历史记录。这是一个有损过程——你把&quot;什么值得保留&quot;的判断权交给了 Claude。好处是你不需要动手写任何东西，而且 Claude 在纳入关键发现和文件方面可能比你更全面。你也可以通过传入指令来引导它，例如：&lt;code&gt;/compact focus on the auth refactor, drop the test debugging&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/cc-session-management/HF-oPtxaAAAUKMr.jpeg&quot; alt=&quot;Compact 示意&quot; /&gt;&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;/clear&lt;/code&gt; 时，你需要亲手写下重要内容：&quot;我们正在重构 auth middleware，约束是 X，相关文件是 A 和 B，我们已经排除了方案 Y&quot;——然后干净地重新开始。这更费事，但最终上下文中保留的内容完全由你决定。&lt;/p&gt;
&lt;h2&gt;什么会导致糟糕的 Compact？&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;images/cc-session-management/HF-oy22bEAE_Jd8.jpeg&quot; alt=&quot;糟糕的 Compact&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果你经常跑长会话，可能已经遇到过压缩效果特别差的情况。我们发现，糟糕的压缩往往发生在模型无法预判你接下来要做什么的时候。&lt;/p&gt;
&lt;p&gt;比如，自动压缩在一次漫长的调试会话之后触发，总结了这次排查过程。而你的下一条消息是：&quot;现在修一下我们在 bar.ts 里看到的另一个 warning。&quot;&lt;/p&gt;
&lt;p&gt;但由于这个会话之前聚焦在调试上，那个&quot;另一个 warning&quot;可能已经从总结中被丢掉了。&lt;/p&gt;
&lt;p&gt;这尤其棘手——受上下文腐化影响，模型在执行压缩时恰好处于它最不聪明的状态。好在有了 100 万上下文之后，你会有更充裕的时间主动使用 &lt;code&gt;/compact&lt;/code&gt;，并附带说明你接下来想做什么。&lt;/p&gt;
&lt;h2&gt;Subagents 与全新的上下文窗口&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;images/cc-session-management/HF-o6v1bQAA7pS6.jpeg&quot; alt=&quot;Subagents 示意&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Subagents 本质上也是一种上下文管理手段，适用于你提前知道某段工作会产生大量中间输出、而这些输出之后不再需要的场景。&lt;/p&gt;
&lt;p&gt;当 Claude 通过 Agent 工具派生出一个 subagent 时，这个 subagent 会获得自己的全新上下文窗口。它可以按需完成大量工作，然后综合结果，只将最终报告返回给父会话。&lt;/p&gt;
&lt;p&gt;我们的判断标准很简单：之后还需要这些工具输出本身，还是只需要结论？&lt;/p&gt;
&lt;p&gt;虽然 Claude Code 会自动调用 subagents，但你也可以主动要求它这样做。例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;启动一个 subagent，根据下面这个 spec 文件验证这项工作的结果&quot;&lt;/li&gt;
&lt;li&gt;&quot;派生一个 subagent，阅读另一个代码库并总结它是如何实现 auth flow 的，然后你自己用同样方式实现&quot;&lt;/li&gt;
&lt;li&gt;&quot;派生一个 subagent，根据我的 git changes 为这个功能编写文档&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;总之，每当 Claude 结束一轮回复、而你准备发送下一条消息时，你就站在了一个决策点上。&lt;/p&gt;
&lt;p&gt;未来，我们预期 Claude 能自主处理这些决策。但就目前而言，主动管理上下文仍然是你引导 Claude 产出更好结果的重要手段。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/cc-session-management/HF-qwt9bEAEa1eq.jpeg&quot; alt=&quot;总结&quot; /&gt;&lt;/p&gt;
</content:encoded><category>AI Agent</category><author>Shelven Zhou</author></item><item><title>Claude Code Context Engineering 拆解: Snip、MicroCompact 与 AutoCompact</title><link>https://astro-theme-typography.vercel.app/posts/cc-context-engineering/</link><guid isPermaLink="true">https://astro-theme-typography.vercel.app/posts/cc-context-engineering/</guid><description>深入 Claude Code 源码，拆解其三层递进式 context window 管理机制——Snip 拦截冗余输出、MicroCompact 外科手术式清理 tool results、AutoCompact LLM 驱动总结——以及它们如何配合 prompt cache 实现成本与能力的双重优化。</description><pubDate>Tue, 14 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;目前 Agent 的能力天花板往往不是模型本身，而是 context window 的管理质量。一个百万 token 的窗口看似宽裕，但在真实的 coding agent 场景下——动辄几十次 tool call、成百上千行的文件读取和 shell 输出——填满它只是时间问题。填满之后怎么办？粗暴截断会丢失关键上下文，导致 agent &quot;失忆&quot;；放任不管又会让模型淹没在噪音中，注意力被稀释，决策质量下降。&lt;/p&gt;
&lt;p&gt;Claude Code 对此做了三层递进式压缩：&lt;strong&gt;Snip → MicroCompact → AutoCompact&lt;/strong&gt;。这套机制不仅在省 token，降低模型端的服务压力，更直接提升了 agent 的任务完成质量——更少的噪音意味着更精准的注意力分配。本文基于 2026 年 3 月 31 日泄露的 Claude Code 源码（文末可免费下载）和开源社区项目，拆解这三层机制的设计与实现。&lt;/p&gt;
&lt;h2&gt;全局视角：三层压缩的执行链路&lt;/h2&gt;
&lt;p&gt;在 Claude Code 的 query 主循环中，三层压缩按以下顺序执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 1. Snip: 在输出进入 context 之前拦截
const snipResult = snipModule.snipCompactIfNeeded(messagesForQuery)
messagesForQuery = snipResult.messages
snipTokensFreed = snipResult.tokensFreed

// 2. MicroCompact: 精准清理旧的 tool results
const microcompactResult = await microcompactMessages(messagesForQuery, ...)
messagesForQuery = microcompactResult.messages

// 3. AutoCompact: 超过阈值时，用 LLM 总结整个对话
const shouldCompact = await shouldAutoCompact(
  messages, model, querySource, snipTokensFreed
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三者不是互斥的，而是逐级递进——Snip 做源头拦截，MicroCompact 做存量清理，AutoCompact 是最后防线。整体设计哲学是：&lt;strong&gt;能不调 LLM 就不调 LLM&lt;/strong&gt;。Snip 和 MicroCompact 都是纯本地操作，零额外成本；只有当前两层都不够用时，才启动代价最高的 LLM 总结。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/cc-context-engineering/three-layers.svg&quot; alt=&quot;三层压缩执行链路&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Layer 1: Snip — 在输出进入 context 之前就拦截&lt;/h2&gt;
&lt;p&gt;Claude Code 内部有一个 &lt;code&gt;snipCompact&lt;/code&gt; 模块，由 &lt;code&gt;feature(&apos;HISTORY_SNIP&apos;)&lt;/code&gt; 控制，其代码并未包含在公开的源码中。但从调用方式可以看出它的定位：&lt;strong&gt;在 MicroCompact 之前执行，返回 &lt;code&gt;tokensFreed&lt;/code&gt; 供后续阈值判断使用。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由于原始代码不可用，这里参考 &lt;a href=&quot;https://github.com/edouard-claude/snip&quot;&gt;edouard-claude/snip&lt;/a&gt; 的实现来分析 snip 的设计思路。该项目是社区基于 Claude Code hook 机制构建的独立 shell 输出过滤工具，Claude Code 内部的 snip 逻辑在策略和细节上可能有所不同。&lt;/p&gt;
&lt;h3&gt;代理与拦截模式&lt;/h3&gt;
&lt;p&gt;Snip 的核心思想是在 AI Agent 和操作系统 Shell 之间建立一个拦截层：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Claude Code → [PreToolUse Hook] → snip → Shell → [过滤输出] → Claude Code
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过 Claude Code 的 &lt;code&gt;PreToolUse&lt;/code&gt; 钩子，当 Claude 准备执行 &lt;code&gt;bash&lt;/code&gt; 工具时，hook 脚本会将命令改写为 &lt;code&gt;snip -- &amp;lt;original_command&amp;gt;&lt;/code&gt;，让 snip 代理执行并过滤输出。&lt;/p&gt;
&lt;h3&gt;命令变换与参数注入&lt;/h3&gt;
&lt;p&gt;Snip 不只是被动过滤，还会主动改造命令以获得更好的结构化输出。例如，对于 &lt;code&gt;go test&lt;/code&gt;，snip 会自动注入 &lt;code&gt;-json&lt;/code&gt; 参数，强制产生 JSON 格式的输出，便于后续精确过滤：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- action: &quot;aggregate&quot;
  patterns:
    passed: &apos;&quot;Action&quot;:&quot;pass&quot;&apos;
    failed: &apos;&quot;Action&quot;:&quot;fail&quot;&apos;
  format: &quot;{{.passed}} passed, {{.failed}} failed&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;原本几百行的测试日志，经过 aggregate action 聚合后，变成一行 &lt;code&gt;12 passed, 0 failed&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;各类命令的压缩效果&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;过滤策略&lt;/th&gt;
&lt;th&gt;压缩率&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;分类统计文件状态，仅显示摘要&lt;/td&gt;
&lt;td&gt;~85%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;提交信息重写为单行摘要&lt;/td&gt;
&lt;td&gt;~85%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;go test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;注入 JSON 参数，聚合 Pass/Fail&lt;/td&gt;
&lt;td&gt;~97%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cargo test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;捕获进度条，仅保留失败堆栈&lt;/td&gt;
&lt;td&gt;~99%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git diff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;仅保留统计信息，截断超长 diff&lt;/td&gt;
&lt;td&gt;~80%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;优雅降级&lt;/h3&gt;
&lt;p&gt;Snip 的一个重要设计原则是&lt;strong&gt;绝不破坏主链路&lt;/strong&gt;。如果过滤器内部出错、找不到匹配的过滤器、或环境配置不全，它会自动退化为 passthrough 模式，原样返回输出。这确保了它作为黑盒代理的安全性。&lt;/p&gt;
&lt;h2&gt;Layer 2: MicroCompact — 外科手术式清理 tool results&lt;/h2&gt;
&lt;p&gt;如果说 Snip 是在源头减少输入，MicroCompact 则是对已经进入 context 的历史消息做精准清理。它只针对特定工具的结果进行处理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const COMPACTABLE_TOOLS = new Set([
  FILE_READ_TOOL_NAME,    // 文件读取
  ...SHELL_TOOL_NAMES,    // Shell 命令
  GREP_TOOL_NAME,         // 搜索
  GLOB_TOOL_NAME,         // 文件匹配
  WEB_SEARCH_TOOL_NAME,   // 网页搜索
  WEB_FETCH_TOOL_NAME,    // 网页获取
  FILE_EDIT_TOOL_NAME,    // 文件编辑
  FILE_WRITE_TOOL_NAME,   // 文件写入
])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键设计：&lt;strong&gt;清理时保留 tool_use 的 ID 和结构，只移除 content&lt;/strong&gt;。这确保模型知道「曾经执行过这个操作」，但不再为其内容占据 token 空间。&lt;/p&gt;
&lt;h3&gt;双轨机制：Cold Cache vs Warm Cache&lt;/h3&gt;
&lt;p&gt;要理解 MicroCompact 为什么要分两条路径，需要先了解 Prompt Caching 的工作方式。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Prompt Caching 快速回顾&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当你向 Claude API 发送请求时，模型需要对 prompt 中的每个 token 计算 KV（Key-Value）对。Prompt Caching 的核心思想是：&lt;strong&gt;如果两次请求的 prompt 共享相同的前缀，那么这些前缀 token 的 KV 对可以被缓存和复用，无需重新计算。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对于 Claude Code 这种多轮对话场景，每一轮新请求都会携带完整的对话历史作为前缀，只要前缀不变，后续请求就能享受 cache read 的低成本——&lt;strong&gt;cache read 的价格仅为 cache write（首次写入）的 1/10&lt;/strong&gt;。但反过来，&lt;strong&gt;任何对历史消息的修改都会破坏前缀匹配，导致修改位置之后的所有缓存失效。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;images/cc-context-engineering/prompt-cache.svg&quot; alt=&quot;Prompt Caching 原理示意&quot; /&gt;&lt;/p&gt;
&lt;p&gt;理解了这个约束，MicroCompact 的双轨设计就顺理成章了——本质上就是在回答一个问题：&lt;strong&gt;当前的 prompt cache 是热的还是冷的？&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;Time-based 路径（Cold Cache）&lt;/h4&gt;
&lt;p&gt;当对话停顿超过一定时间（Claude Code 默认阈值为 60 分钟），系统判定 prompt cache 已失效（注：Anthropic API 的标准 cache TTL 为 5 分钟，这里的 60 分钟是 Claude Code 自定义的触发阈值，采用更保守的策略来决定何时执行 time-based 清理）。既然下次请求注定要完整重发所有 token，不如趁机&quot;瘦身&quot;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function maybeTimeBasedMicrocompact(messages, querySource) {
  const trigger = evaluateTimeBasedTrigger(messages, querySource)
  if (!trigger) return null

  // 保留最近 N 个 tool results，清理其余
  const keepSet = new Set(compactableIds.slice(-keepRecent))
  const clearSet = new Set(compactableIds.filter(id =&amp;gt; !keepSet.has(id)))

  // 直接替换内容为占位符
  return messages.map(message =&amp;gt; {
    // ...
    if (clearSet.has(block.tool_use_id)) {
      return { ...block, content: &apos;[Old tool result content cleared]&apos; }
    }
    // ...
  })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逻辑直白：cache 反正冷了，直接改消息内容，物理减少发送的 token 量。&lt;/p&gt;
&lt;h4&gt;Cached MC 路径（Warm Cache）&lt;/h4&gt;
&lt;p&gt;活跃对话中，cache 仍然有效。如果此时直接修改历史消息，会破坏前缀匹配，导致之前所有 cache 失效——代价太大。&lt;/p&gt;
&lt;p&gt;Cached MC 的解法是&lt;strong&gt;将「缓存存储」与「模型可见性」解耦&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;发送完整的历史消息到 API（保持 cache 命中）&lt;/li&gt;
&lt;li&gt;附带 &lt;code&gt;cache_edits&lt;/code&gt; 指令，告诉模型在推理时忽略特定 tool result 的内容&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;async function cachedMicrocompactPath(messages, querySource) {
  // 注册和追踪 tool results
  const toolsToDelete = mod.getToolResultsToDelete(state)

  if (toolsToDelete.length &amp;gt; 0) {
    // 创建 cache_edits 指令（不修改本地消息！）
    const cacheEdits = mod.createCacheEditsBlock(state, toolsToDelete)
    pendingCacheEdits = cacheEdits

    // 消息原样返回，cache_edits 在 API 层注入
    return { messages, compactionInfo: { pendingCacheEdits: { ... } } }
  }
  return { messages }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这实现了一个看似矛盾的目标：&lt;strong&gt;在不破坏已有 cache 的前提下，减少模型实际处理的 token 数量。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cache_edits&lt;/code&gt; 支持两类操作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;clear_tool_uses&lt;/code&gt;：屏蔽特定 tool call 的输入或输出&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clear_thinking&lt;/code&gt;：清除旧的思维链（除最近 1-2 次外，早期推理过程通常已无必要）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;cache_edits：Agent 与 Model 的协同优化&lt;/h3&gt;
&lt;p&gt;值得注意的是，&lt;code&gt;cache_edits&lt;/code&gt; 不是纯客户端的技巧——它要求模型推理引擎在底层配合，能够在保持 KV cache 完整的前提下，根据客户端指令在推理时跳过特定内容。这是一个 &lt;strong&gt;agent 端和 model 端协同优化&lt;/strong&gt;的典型案例，也是 Anthropic 作为同时掌控模型和 agent 产品的厂商的核心竞争力之一。目前 &lt;code&gt;cache_edits&lt;/code&gt; 是 Claude Code 内部使用的能力，尚未作为公开 API 提供。&lt;/p&gt;
&lt;p&gt;横向对比来看，各家在缓存管理上的深度差异很大：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;提供商&lt;/th&gt;
&lt;th&gt;缓存触发方式&lt;/th&gt;
&lt;th&gt;是否支持缓存编辑&lt;/th&gt;
&lt;th&gt;缓存失效机制&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Anthropic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;显式标记 (&lt;code&gt;cache_control&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;是&lt;/strong&gt; (&lt;code&gt;cache_edits&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;按 TTL 或手动覆盖&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Google&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;显式创建 (&lt;code&gt;CachedContent&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;仅管理（TTL/删除）&lt;/td&gt;
&lt;td&gt;固定 TTL（默认 1h）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DeepSeek&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;自动触发&lt;/td&gt;
&lt;td&gt;否（仅前缀匹配）&lt;/td&gt;
&lt;td&gt;动态过期（硬盘存储）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OpenAI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;自动触发&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;精确匹配失效&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;大多数提供商的 prompt cache 是&quot;只读&quot;的——你只能通过保持前缀不变来利用它，一旦中间有修改就全部失效。Anthropic 的 &lt;code&gt;cache_edits&lt;/code&gt; 打破了这个限制，允许在不破坏缓存的前提下对 context 做&quot;外科手术式&quot;编辑。这使得 Claude Code 能在活跃对话中实现 MicroCompact，而其他提供商上的 agent 只能等 cache 过期后才能清理。&lt;/p&gt;
&lt;h3&gt;Token 估算的保守策略&lt;/h3&gt;
&lt;p&gt;由于无法在发送前获得精确的 API token 计数，MicroCompact 对本地估算的 token 数做了 4/3 的加权处理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export function estimateMessageTokens(messages: Message[]): number {
  // ... 遍历所有 block 累加 token
  // 4/3 加权，确保在接近上限时提前触发压缩
  return Math.ceil(totalTokens * (4 / 3))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;宁可多压缩一点，也不能让请求因溢出而失败。&lt;/p&gt;
&lt;h2&gt;Layer 3: AutoCompact — 最后防线&lt;/h2&gt;
&lt;p&gt;当 Snip 和 MicroCompact 都不够用时，AutoCompact 作为最后一道防线介入。它的触发条件是 token 使用量超过 &lt;code&gt;effectiveContextWindow - 13K buffer&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export const AUTOCOMPACT_BUFFER_TOKENS = 13_000

export function getAutoCompactThreshold(model: string): number {
  const effectiveContextWindow = getEffectiveContextWindowSize(model)
  return effectiveContextWindow - AUTOCOMPACT_BUFFER_TOKENS
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;优先级：Session Memory &amp;gt; LLM Summarization&lt;/h3&gt;
&lt;p&gt;AutoCompact 并不直接调用 LLM 总结。它先尝试一个更轻量的方案：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export async function autoCompactIfNeeded(messages, ...) {
  // 优先尝试 Session Memory Compaction
  const sessionMemoryResult = await trySessionMemoryCompaction(
    messages, agentId, autoCompactThreshold
  )
  if (sessionMemoryResult) {
    return { wasCompacted: true, compactionResult: sessionMemoryResult }
  }

  // fallback: 传统 LLM 总结
  const compactionResult = await compactConversation(messages, ...)
  return { wasCompacted: true, compactionResult }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Session Memory Compaction&lt;/strong&gt; 利用 Claude Code 在对话过程中持续维护的 session memory（一个结构化的会话记忆文件）。当需要压缩时，直接用这个已有的记忆作为摘要，保留最近 10K-40K tokens 的原始消息，无需额外 LLM 调用。&lt;/p&gt;
&lt;p&gt;只有当 session memory 不可用（未启用、内容为空、或压缩后仍超阈值）时，才 fallback 到传统的 LLM 总结。&lt;/p&gt;
&lt;h3&gt;传统 Compaction：fork agent 做总结&lt;/h3&gt;
&lt;p&gt;传统路径会 fork 一个 agent，用专门设计的 prompt 总结对话。这个 prompt 要求生成 9 个结构化 section：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. Primary Request and Intent
2. Key Technical Concepts
3. Files and Code Sections（含代码片段）
4. Errors and fixes
5. Problem Solving
6. All user messages（完整保留用户原话）
7. Pending Tasks
8. Current Work
9. Optional Next Step（含原文引用，防止任务漂移）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中两个设计值得注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;analysis + summary 两阶段&lt;/strong&gt;：prompt 要求先在 &lt;code&gt;&amp;lt;analysis&amp;gt;&lt;/code&gt; 标签中整理思路，再在 &lt;code&gt;&amp;lt;summary&amp;gt;&lt;/code&gt; 中给出最终总结。&lt;code&gt;&amp;lt;analysis&amp;gt;&lt;/code&gt; 部分在使用时会被 &lt;code&gt;formatCompactSummary&lt;/code&gt; 函数剥离——它只是用来提升总结质量的 &quot;草稿纸&quot;，不会进入后续 context&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partial Compact&lt;/strong&gt;：支持只总结旧消息、保留近期消息原文。这比全量总结保留了更多细节&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;安全机制&lt;/h3&gt;
&lt;p&gt;AutoCompact 有两个关键的安全设计：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Circuit Breaker&lt;/strong&gt;：连续 3 次压缩失败后，停止重试。这防止了 context 不可恢复地超限时，无意义的 API 调用风暴：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3
// BQ 2026-03-10: 1,279 sessions had 50+ consecutive failures (up to 3,272)
// in a single session, wasting ~250K API calls/day globally.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;PTL Retry&lt;/strong&gt;：当 compact 请求本身因为 prompt 过长而失败时，逐步从最旧的消息组开始截断，直到请求能通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export function truncateHeadForPTLRetry(messages, ptlResponse) {
  const groups = groupMessagesByApiRound(messages)
  // 根据 token gap 计算需要丢弃的组数，或 fallback 到 20%
  const dropCount = tokenGap !== undefined
    ? /* 精确计算 */ ...
    : Math.max(1, Math.floor(groups.length * 0.2))
  return groups.slice(dropCount).flat()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;对于 agent 开发者来说，这篇文章的核心 takeaway 不只是&quot;怎么压缩 context&quot;，而是 &lt;strong&gt;context 管理本身就是 agent 能力的一部分&lt;/strong&gt;。具体来说：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;分层设计优于单一策略&lt;/strong&gt;——零成本的本地操作（Snip、MicroCompact）覆盖绝大多数场景，LLM 总结只是最后防线。不是每次都需要动用最重的工具&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache-aware 是关键约束&lt;/strong&gt;——在有 prompt cache 的系统中，&quot;压缩 context&quot;和&quot;保持 cache 命中&quot;是一对张力。MicroCompact 的双轨设计展示了如何在这个约束下做工程权衡&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;精心管理的 context = 更好的任务完成质量&lt;/strong&gt;——更少的噪音意味着更精准的注意力分配，这直接影响 agent 的决策质量，而不仅仅是省钱&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本文所引用的 Claude Code 源码包含在下方附件中，欢迎自行探索更多细节。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;附件&lt;/strong&gt;：&lt;a href=&quot;/downloads/claude-code-main.zip&quot;&gt;claude-code-main.zip&lt;/a&gt; — 2026 年 3 月 31 日泄露的 Claude Code 源码（用于本文分析）&lt;/p&gt;
</content:encoded><category>AI Agent</category><author>Shelven Zhou</author></item></channel></rss>