Claude Code 的 Context Window 管理与 Compaction 机制深度解析
适合读者:有 LLM 应用开发经验的前端/全栈工程师
核心问题:为什么 Claude Code 能在超长编码会话中不丢失上下文?它是怎么做到的?
1. 背景:为什么 Context Window 是 AI 编码工具的核心挑战
大语言模型(LLM)有一个固有限制:上下文窗口(Context Window)是有限的。对于一个 AI 编码助手来说,一次完整的工作会话可能包含:
- 数十轮对话
- 多个文件的读取结果
- Bash 命令的输出
- 工具调用的返回值
- 系统提示、技能描述、MCP 工具 schema
这些内容叠加起来,很容易超出模型的 token 上限。如果处理不当,要么会话中断,要么模型"失忆"——忘记之前做过的事情。
Claude Code 通过一套完整的Context Window 管理 + Compaction(压缩)机制,实现了理论上无限长度的会话。
2. 核心概念:Token 是怎么被消耗的
在 Claude Code 中,上下文由以下几类内容共同占用 token:
| 内容类型 | Token 消耗特征 | 优化策略 |
|---|---|---|
| 系统提示 | 固定开销,每轮都发送 | 日期字段移出系统提示以提升缓存命中率 |
| 用户消息 | 随对话轮次线性增长 | — |
| 助手消息(含 Thinking Blocks) | 可能很大,Thinking 也计入 | 默认不生成 Thinking 摘要 |
| 工具结果(Read/Bash/Search) | 大文件读取是主要消耗源 | Read 工具截断大文件,显示PARTIAL view |
| 图片 / PDF | 高消耗 | 压缩前自动剥离 |
| MCP 工具描述 | 随接入服务器数量增长 | 超过上下文 10% 时自动延迟加载(ToolSearch) |
| 技能(Skill)描述 | 可控 | 限制为 250 字符 |
有效上下文窗口的计算公式:
有效上下文窗口 = 模型总上下文窗口 - max_output_tokens(为响应预留)状态栏实时暴露两个字段供 UI 消费:context_window.used_percentage和context_window.remaining_percentage。
3. 整体架构:Context Window 管理系统
4. 自动压缩(Auto-Compaction):触发与执行流程
4.1 触发条件
当 token 使用量达到有效上下文窗口的约 98%时,自动压缩触发。
关键工程细节:
熔断机制:连续 3 次压缩失败后,系统停止重试并给出可操作的错误提示,避免无限消耗 API 调用。 3
防 Thrash Loop:如果压缩后上下文立即再次填满(连续 3 次),系统检测到这一模式并停止,给出明确错误。 4
大会话优化:压缩时首次摘要请求会基于溢出大小来初始化,避免浪费一次接近满上下文的重试。 5
4.2 内容预处理
在发送给压缩 API 之前,系统会:
- 剥离所有图片和 PDF 文档块,避免触发维度限制错误
- 保留文本内容,包括工具调用记录和助手回复
- 处理空文本块,防止 API 400 错误 6
5. 手动压缩(/compact):用户主动控制
用户可以在任何时候通过/compact命令主动触发压缩,流程与自动压缩相同,但有以下特点:
注意:从 v2.1.69 起,压缩后恢复会话不再产生前言式的内容回顾,直接继续。
相关命令:
/context:查看详细 token 用量,并给出优化建议(识别高消耗工具、内存膨胀等)/usage:查看 token 和费用统计
6. 状态保留:压缩后会话连续性保障
这是 Compaction 机制中最容易被忽视、也最重要的部分。压缩会替换历史消息,但以下关键状态必须完整保留:
| 状态类型 | 说明 | 相关修复版本 |
|---|---|---|
| 会话名称 | 自定义标题通过压缩后依然保留 | v2.1.47 |
| Plan 模式 | 压缩后不会从规划模式切换到执行模式 | v2.1.47 |
| 子代理 CWD | 子代理的工作目录在恢复时显式还原 | v2.1.116 |
| 模型选择 | 恢复的会话保持压缩前使用的模型 | — |
| Hook 上下文 | saved_hook_context跨压缩边界保留 | — |
PostCompactHook:从 v2.1.76 起,压缩完成后会触发PostCompactHook,允许开发者在压缩后执行自定义逻辑(如通知、日志记录)。 9
7. 工具输出管理:从源头控制 Token 消耗
除了压缩,Claude Code 还在工具输出层面做了大量优化:
7.1 Read 工具截断
大文件读取不再返回完整内容,而是返回截断的第一页并附带PARTIAL view提示。这个截断视图同样满足"编辑前必须读取"的检查,避免 Agent 重复读取大文件。 10
7.2 MCP 工具描述延迟加载
当 MCP 工具描述超过上下文窗口的10%时,自动切换为延迟发现模式(ToolSearch),工具不再预先加载到上下文中。 11
7.3 其他限制
- MCP 工具描述和服务器指令:单条上限2KB
- 技能描述:上限250 字符
- Hook 输出超过 50K 字符时保存到磁盘,仅注入文件路径和预览 12 13 14
8. 工程实践建议
8.1 监控上下文用量
在状态栏配置中读取context_window.used_percentage,当超过 80% 时主动提示用户考虑/compact。
8.2 合理配置 MCP 工具
接入大量 MCP 服务器时,确保每个工具描述控制在 2KB 以内,避免工具描述本身占满上下文。可以通过/context命令查看各 MCP 工具的 token 占用。
8.3 利用DISABLE_COMPACT环境变量
在调试场景下,可以设置DISABLE_COMPACT=1禁用自动压缩,观察原始上下文增长情况。 15
8.4 使用PostCompactHook 做监控
// .claude/settings.json{"hooks":{"PostCompact":[{"type":"command","command":"echo 'Compaction triggered' >> ~/.claude/compact.log"}]}}8.5 长会话的 idle 提示
Claude Code 在用户离开 75 分钟后返回时,会提示执行/clear,避免在陈旧会话上浪费 token 重新缓存。 16
9. 常见问题排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
/compact报 “context exceeded” | 会话已大到压缩请求本身都放不下 | 已在 v2.1.85 修复;升级版本 |
| 压缩后 Plan 模式丢失 | 旧版本 bug | 升级到 v2.1.47+ |
| 压缩后会话名称消失 | 旧版本 bug | 升级到 v2.1.47+ |
| 自动压缩反复触发(thrash loop) | 压缩后上下文立即再次填满 | 升级到 v2.1.89+;考虑/clear开新会话 |
| Opus 4.7 过早触发压缩 | 旧版本错误地按 200K 而非 1M 计算 | 升级到 v2.1.117+ |
| 压缩后工具 schema 丢失 | 延迟加载工具在压缩后丢失 input schema | 升级到 v2.1.76+ |
总结
Claude Code 的 Context Window 管理是一个多层次的工程系统:
理解这套机制,能帮助你在构建基于 Claude Code 的 AI 工程工作流时,做出更合理的架构决策——无论是控制 MCP 工具数量、设计 Hook 逻辑,还是在 CI/CD 中管理长时间运行的 Agent 会话。