上下文压缩管理
2026/7/31 17:27:47 · 更新于 2026/7/31 17:33:24
Claude Code 通过多层递进的分级压缩管线(工具预算裁剪、snip、microcompact、context collapse、autocompact 与 reactive compact 兜底),在保障长程工程任务连续性的同时最大化保留细粒度上下文结构,而非依赖单一的全局摘要机制。
Claude Code 的长上下文能力并非单纯依赖模型窗口大小,而是基于一套精密的多阶段分级压缩管线。在主查询链路中,它串联了预算裁剪、细粒度瘦身、视图折叠、自动摘要与报错兜底等六层机制,并深度结合会话持久化与 Prompt Cache 协同,确保在长期工程任务中实现结构优先、延后信息损失的运行时上下文管理。
为什么 Claude Code 必须做上下文压缩
Claude Code 的任务不是一次性问答,而是持续执行复杂的工程操作:
- 读取多个文件
- 搜索代码库
- 运行 Bash 命令
- 写文件和补丁
- 调用子 Agent
- 与 MCP / LSP 交换结果
这些行为会不断把新消息和工具结果追加进会话历史。如果没有压缩,模型很快就会被旧消息、长工具输出和文件附件塞满。
Anthropic 在系统提示词中甚至直接明确指出了这一机制:
自动摘要承诺
The conversation has unlimited context through automatic summarization.(这段对话会通过自动摘要获得“近似无限”的上下文。)
压缩触发条件
The system will automatically compress prior messages in your conversation as it approaches context limits.(当对话接近上下文限制时,系统会自动压缩更早的消息。对应中文即为:当对话接近上下文限制时,系统会自动压缩更早的消息。)
从产品承诺到运行时实现,Claude Code 都将“自动压缩”视为基础设施,而非事后打补丁的逻辑。
主链路与分级管线架构
真正的压缩主链位于 /Users/xuanyuan/Downloads/claude-code-src/query.ts。从源码顺序可以看出,它并非只做一次 compact(),而是多层串联:
messagesForQuery = await applyToolResultBudget(...)
const snipResult = snipModule!.snipCompactIfNeeded(messagesForQuery)
messagesForQuery = snipResult.messages
const microcompactResult = await deps.microcompact(
messagesForQuery,
toolUseContext,
querySource,
)
messagesForQuery = microcompactResult.messages
const collapseResult = await contextCollapse.applyCollapsesIfNeeded(
messagesForQuery,
toolUseContext,
querySource,
)
messagesForQuery = collapseResult.messages
const { compactionResult } = await deps.autocompact(
messagesForQuery,
toolUseContext,
...
)
最值得注意的不是函数名本身,而是严格的执行顺序:
- 先裁掉过大的工具结果
- 再做
snip(局部瘦身) - 再做
microcompact(结构化微压缩) - 投影
context collapse(折叠视图) - 最后才尝试
autocompact(全局摘要)
这意味着 Claude Code 并不急着把旧历史粗暴压成一段摘要,而是优先尝试保留更多细节与结构。整个上下文管理本质上是一个多阶段管线,而非单点能力。

六层分级压缩机制详解
第 1 层:工具结果预算裁剪
最先运行的是 applyToolResultBudget(...)。
messagesForQuery = await applyToolResultBudget(
messagesForQuery,
toolUseContext.contentReplacementState,
...,
new Set(
toolUseContext.options.tools
.filter(t => !Number.isFinite(t.maxResultSizeChars))
.map(t => t.name),
),
)
核心目标:在进入真正的上下文压缩之前,先把明显过大的工具结果做替换或裁剪。这非常关键,因为很多时候最占空间的不是用户消息,而是:
BashTool打出来的大段终端输出- 搜索工具返回的长结果
- 文件读取工具读到的大文件片段
如果这类结果不先处理,后续的压缩管线会被低价值的超长文本拖累。
第 2 层:snip 细粒度裁剪
源码注释明确标注了它的定位:
// Apply snip before microcompact (both may run — they are not mutually exclusive).
这说明两点:
snip和microcompact不是互斥关系,可叠加执行。snip更靠前,属于更轻量的局部瘦身。
对应代码逻辑:
const snipResult = snipModule!.snipCompactIfNeeded(messagesForQuery)
messagesForQuery = snipResult.messages
snipTokensFreed = snipResult.tokensFreed
if (snipResult.boundaryMessage) {
yield snipResult.boundaryMessage
}
从返回值可以看出其作用:产出新消息数组、记录释放的 token 数、必要时注入边界提示。可以将 snip 理解为:
在不破坏主要会话结构的前提下,先对低价值部分做局部裁剪。
第 3 层:microcompact 微压缩
microcompact 比 snip 深入一层,但尚未进入“整段历史总结”阶段。源码注释指出:
// Apply microcompact before autocompact
// cached MC operates purely by tool_use_id
这说明它的核心设计目标是围绕工具调用记录(tool_use_id)做细粒度压缩。特别适合以下场景:
- 工具调用链很长
- 部分工具结果内容极长
- 但工具调用的元数据/结构信息仍值得保留
与 snip 的粗略对比:
| 机制 | 作用范围 | 核心策略 |
|---|---|---|
snip | 局部轻量裁剪 | 削减低价值文本 |
microcompact | 结构化微压缩 | 保留 tool_use_id 链路,压缩冗余 Payload |

这一层体现了 Claude Code 极强的工程判断:只要还能保留结构化上下文,就不要急着把它们全变成一段摘要。
第 4 层:context collapse 折叠视图
这是源码中容易被忽视、但极其巧妙的一层。注释原文精准描述了其存在意义:
// Project the collapsed context view and maybe commit more collapses.
// Runs BEFORE autocompact so that if collapse gets us under the
// autocompact threshold, autocompact is a no-op and we keep granular
// context instead of a single summary.
核心逻辑:在进入自动压缩前,先投影一个折叠后的上下文视图。如果折叠之后已经回到阈值以下,自动压缩将直接跳过(no-op),从而保留更细粒度的原始上下文,而非合成一段大摘要。
调用入口:
const collapseResult = await contextCollapse.applyCollapsesIfNeeded(
messagesForQuery,
toolUseContext,
querySource,
)
messagesForQuery = collapseResult.messages
关键设计思想不是“删除历史”,而是**“重新投影视图”**。底层日志未必被彻底抹除,但当前喂给模型的视图已被折叠。这与后续 sessionStorage.ts 中的 contextCollapseCommits 和 contextCollapseSnapshot 完美呼应:
const contextCollapseCommits: ContextCollapseCommitEntry[] = []
let contextCollapseSnapshot: ContextCollapseSnapshotEntry | undefined
说明 collapse 的处理不仅是临时内存操作,而是具备提交记录与快照版本的持久化概念。
第 5 层:autocompact 自动摘要压缩
真正对应大众认知的“自动摘要”,在源码中为 deps.autocompact(...)。
const { compactionResult, consecutiveFailures } = await deps.autocompact(
messagesForQuery,
toolUseContext,
{
systemPrompt,
userContext,
systemContext,
toolUseContext,
forkContextMessages: messagesForQuery,
},
querySource,
tracking,
snipTokensFreed,
)
若压缩成功,会立即重建消息链:
const postCompactMessages = buildPostCompactMessages(compactionResult)
for (const message of postCompactMessages) {
yield message
}
messagesForQuery = postCompactMessages
关键点:
- 不只是生成摘要文本,还会重建完整的 post-compact 消息序列。
- 压缩结果会真正回写进当前对话执行链,后续模型请求基于此继续。
- 它不是旁路日志记录,而是实际改变主循环所能看到的上下文状态。
第 6 层:reactive compact 报错恢复兜底
如果主动压缩管线依然无法释放足够空间,Claude Code 设有一条兜底链路:reactive compact。该逻辑位于 query.ts 流式返回的后半段:
if ((isWithheld413 || isWithheldMedia) && reactiveCompact) {
const compacted = await reactiveCompact.tryReactiveCompact({
hasAttempted: hasAttemptedReactiveCompact,
querySource,
aborted: toolUseContext.abortController.signal.aborted,
messages: messagesForQuery,
cacheSafeParams: {
systemPrompt,
userContext,
systemContext,
toolUseContext,
forkContextMessages: messagesForQuery,
},
})
}
主要用于处理两类 runtime 失败:
prompt too long(API 返回 413)- 媒体内容超限(大图片 / PDF / 多图输入)
设计本质:当真实 API 调用已经报错时,触发一次恢复性压缩把任务“救回来”。

这体现了工程的成熟度:不假设“主动压缩一定成功”,而是将失败恢复纳入主循环设计。
压缩的持久化与会话边界管理
压缩不仅发生在内存中,还严格影响会话持久化与恢复逻辑。QueryEngine.ts 专门处理 compact_boundary:
if (
persistSession &&
message.type === 'system' &&
message.subtype === 'compact_boundary'
) {
const tailUuid = message.compactMetadata?.preservedSegment?.tailUuid
...
}
在回放时,它同样被视为必须确认的系统消息:
(msg.type === 'system' && msg.subtype === 'compact_boundary')
这说明 compact_boundary 的作用绝非 UI 提示,而是:
- 标记压缩边界:明确一次摘要在会话链条中的物理/逻辑位置。
- 告知 Transcript:哪一段历史已被总结,哪些仍需保留。
- 提供恢复锚点:让下游系统能准确重新拼接
preserved segment。
为什么 sessionStorage.ts 如此复杂
如果只做“摘要替换”,会话恢复逻辑会非常简单。但 Claude Code 采用了更精细的策略,因此在 sessionStorage.ts 中出现了大量处理压缩边界和保留段的逻辑:
核心注释
Splice the preserved segment back into the chain after compaction.
以及 applyPreservedSegmentRelinks(...) 中的关键说明:
Only the LAST seg-boundary is relinked — earlier segs were summarized into it.
这揭示了一个重要设计原则:
- 压缩后并非所有旧消息都彻底消失。
- 关键片段会以
preserved segment形式保留。 - 会话恢复时,必须将这些片段精确重新接回链上。
这也是 Claude Code 的上下文管理不同于普通聊天产品“把前文总结成一段文字”的根本原因。
与 Prompt Cache 的协同设计
在 constants/prompts.ts 中定义了一个关键边界常量:
export const SYSTEM_PROMPT_DYNAMIC_BOUNDARY =
'__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'
源码注释直言不讳:
Everything BEFORE this marker in the system prompt array can use scope: 'global'. Everything AFTER contains user/session-specific content and should not be cached.
将其与上下文压缩结合来看,能更清晰理解 Claude Code 的总体架构策略:
- 静态系统提示:尽量缓存(提升推理速度/降低成本)
- 动态用户上下文:分层压缩管理(保障可持续性)
- 历史消息管理:通过
boundary标记与snapshot机制控制恢复正确性
因此,它解决的不仅是“如何缩小 token 数”,而是同时统筹:
- Token 成本控制
- 长上下文任务可持续性
- Prompt Cache 命中率
/resume会话恢复的正确性
实际体验与架构总结
这套分级管线最终转化为以下用户可感知的效果:
- 容错性强:长任务不会因为读了太多文件/代码立刻崩溃。
- 延迟稳定:对话可持续多轮,不会随着历史增长而明显迟钝。
- 具备自救能力:在触达硬界限时有主动与被动双重压缩机制。
- 恢复保真度高:
/resume恢复出的会话能无缝接上前文逻辑。 - 结构保留优先:优先折叠视图与局部瘦身,不轻易将历史压成模糊摘要。
总结
Claude Code 的上下文压缩,远非“接近上限时做一次摘要”的简单逻辑。从源码审视,它更像一套分层内存管理系统:
- 前端层:优先轻量裁剪与结构化微压缩。
- 中端层:通过视图折叠保留关键调用链,阻断不必要的摘要。
- 后端层:触发全局自动摘要,并在 API 报错时启动恢复性兜底。
若仅将 Claude Code 视为“模型 + 工具”,会严重低估其复杂度。真正支撑它持续完成复杂工程任务的,正是这套运行时级别的上下文架构与资源编排能力。
Key takeaways
- 多阶段管线优先于单点摘要:
applyToolResultBudget→snip→microcompact→context collapse→autocompact→reactive compact,按顺序执行,层层递进释放空间。 - 结构保留 > 粗暴压缩:通过
tool_use_id追踪与视图投影(Collapse),最大限度保留工具调用上下文,避免核心逻辑被摘要抹除。 - 边界与快照机制保障持久化:
compact_boundary与preserved segment设计确保会话在跨轮次加载时能精确还原逻辑链路。 - 与缓存策略深度耦合:引入
SYSTEM_PROMPT_DYNAMIC_BOUNDARY严格分割静态系统提示与动态对话历史,兼顾 Prompt Cache 命中率与会话管理安全性。 - 工程兜底思维:不依赖单一压缩路径成功,内置
reactive compact应对413等运行时失败,体现高可用架构设计。

学习地图
🗺️ 学习路线:掌握 Claude Code 上下文压缩机制
阶段一:基础原理认知
- 理解 LLM Context Window 的底层限制与 Token 成本关系
- 区分“固定摘要替换”与“分级增量压缩”的设计哲学差异
- 熟悉主查询链路各压缩阶段的触发阈值与作用范围
阶段二:源码机制与运行时流转
- 追踪
query.ts核心调用栈,掌握 6 层压缩管线的执行顺序 - 分析 Bash/文件/搜索等工具输出对上下文的污染路径及裁剪策略
- 理解
context collapse的视图投影思想与compact_boundary的持久化边界逻辑
阶段三:工程配置与 Prompt Cache 协同
- 结合
SYSTEM_PROMPT_DYNAMIC_BOUNDARY划分静态/动态区,提升缓存命中率 - 自定义工具时合理设置
maxResultSizeChars以适配预算裁剪机制 - 观察 Session Storage 如何重组 Preserved Segment 并完成会话恢复
阶段四:架构扩展与实战避坑
- 横向对比同类 Agent 工具的上下文管理差异
- 设计支持
/resume恢复的结构化工作流,规避长任务片段断裂风险 - 结合实际场景调优压缩管线参数,平衡信息保留率与推理延迟
动手实践——分步指南
- 环境准备:使用
npm create @anthropic-ai/claude-code@latest初始化本地工程目录,并通过 CLI 启动交互式会话。 - 观察工具预算裁剪:创建一个包含大段冗余内容(如日志文件或大型 JSON)的测试文件,要求模型读取并分析,在终端输出中关注超长内容的自动替换与截断提示。
- 触发完整压缩管线:进行多轮代码重构任务(连续读写文件、运行命令、调用子 Agent),每轮结束后记录 Token 计数变化及上下文流转状态,观察从 snip 到 autocompact 的渐进过程。
- 测试结构化工具配置:在 CLI 参数或工具定义中调整
maxResultSizeChars阈值,对比不同大小限制下 Claude Code 裁剪粒度的差异。 - 验证 Prompt Cache 协同效果:将 System Prompt 拆分为“静态全局指令(边界前)”与“动态会话指令(边界后)”,通过官方诊断工具或代码注释查看缓存命中情况。
- 长任务恢复演练:主动触发上下文超限场景,使用
/compact清理并执行/resume,验证 Preserved Segment 是否被正确保留并重新拼接进主循环。
三大推荐资源
- 1Anthropic 官方提示工程指南(上下文窗口管理)
官方文档详解 Context Window 工作原理、Windowing 策略及长对话优化的核心原则,是理解 Anthropic 压缩机制的基础。
https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/context-windows-and-windowing
- 2Claude Code 官方 GitHub 仓库
提供 Claude Code 的完整源码、架构文档与实践示例,便于直接阅读 `query.ts` 与 `sessionStorage.ts` 等核心上下文管理模块。
https://github.com/anthropics/claude-code
- 3Prompt Engineering Guide(开源实战库)
涵盖 Prompt Cache、长文本压缩策略及大模型工程化交互模式,提供大量可直接复用的架构设计与优化模板。
https://www.promptingguide.ai/zh/
链接由 AI 推荐——使用前建议快速核实。