Claude Code 的压缩服务是一个关键的性能优化系统,负责在对话上下文接近模型上下文窗口限制时,智能地压缩历史消息,同时保留核心上下文信息。该系统通过多层压缩策略、精确的 token 估算和智能缓存管理,确保长时间运行的会话能够持续进行,而不会因上下文窗口限制而中断。
核心价值与设计目标
压缩服务的设计围绕三个核心目标:上下文连续性(保留关键决策和代码模式)、内存效率(通过多级压缩策略最小化 token 占用)以及 用户体验(透明执行,自动触发)。系统通过分层策略实现这些目标:微型压缩进行轻量级清理,完整压缩生成结构化摘要,而会话记忆压缩则提供语义化的长期记忆。
Sources: compact.ts, autoCompact.ts
架构概览:多级压缩管道
压缩服务采用责任链模式,按照从轻到重的顺序尝试不同级别的压缩策略,优先选择成本最低且保留最多上下文的方案。
flowchart TD
A[压缩触发检查] --> B{时间基准微型压缩?}
B -->|是| C[清除旧工具结果]
B -->|否| D{缓存编辑微型压缩可用?}
D -->|是| E[注册缓存编辑]
D -->|否| F{会话记忆压缩?}
F -->|是| G[提取语义记忆]
F -->|否| H{手动/自动压缩?}
H --> I[生成结构化摘要]
C --> J[返回压缩结果]
E --> J
G --> J
I --> K[创建压缩附件]
K --> L[执行清理钩子]
L --> J
style A fill:#e1f5ff
style J fill:#d4edda
style C fill:#fff3cd
style E fill:#fff3cd
style G fill:#fff3cd
style I fill:#f8d7da
这个流程图展示了压缩服务的决策链:系统首先尝试最轻量的时间基准微型压缩(基于缓存过期时间),然后是缓存编辑微型压缩(保持缓存前缀),接着是会话记忆压缩(基于语义提取),最后才执行完整的对话摘要压缩。每一级都有明确的触发条件和上下文保留策略。
Sources: microCompact.ts, compact.ts
压缩策略详解
微型压缩:轻量级上下文清理
微型压缩是最轻量的压缩形式,专注于清除可丢弃的工具结果而不生成摘要。它包含两种模式:
时间基准微型压缩:基于服务器端缓存的生命周期(5分钟),当检测到距离最后一个 assistant 消息的时间超过阈值时,自动清除旧工具结果。这种策略避免了缓存过期后的全量重写,提前清理以减少 API 调用成本。
Sources: microCompact.ts, timeBasedMCConfig.ts
缓存编辑微型压缩:利用 Anthropic 的 cache_edits API,在不破坏缓存前缀的情况下删除工具结果。系统追踪可压缩工具(文件读取、Bash 命令、搜索操作等)的结果,当累积数量超过阈值时,通过缓存编辑操作删除它们。这种方法保持缓存前缀有效,避免全量缓存重建。
Sources: microCompact.ts, apiMicrocompact.ts
| 工具类型 | 是否可压缩 | 理由 |
|---|---|---|
| FileReadTool | ✓ | 文件内容可通过重新读取恢复 |
| BashTool/PowerShellTool | ✓ | 命令输出通常是临时的 |
| GrepTool/GlobTool | ✓ | 搜索结果可重新生成 |
| WebSearchTool/WebFetchTool | ✓ | 网络内容可重新获取 |
| FileEditTool/FileWriteTool | ✓ | 编辑结果已持久化到磁盘 |
| AskUserQuestionTool | ✗ | 用户反馈必须保留 |
| AgentTool | ✗ | 子代理结果包含关键决策 |
Sources: microCompact.ts
完整压缩:结构化对话摘要
当微型压缩无法满足需求时,系统执行完整压缩,生成包含九个关键部分的结构化摘要。这个过程通过 compactConversation 函数实现,它使用一个独立的 API 调用来生成摘要。
sequenceDiagram
participant User
participant CompactCommand
participant Microcompact
participant CompactEngine
participant API
participant PostCleanup
User->>CompactCommand: /compact 触发
CompactCommand->>Microcompact: 尝试微型压缩
Microcompact-->>CompactCommand: 返回部分清理的消息
CompactCommand->>CompactEngine: compactConversation()
CompactEngine->>CompactEngine: 执行 PreCompact 钩子
CompactEngine->>CompactEngine: 构建压缩提示词
CompactEngine->>API: 流式请求摘要
API-->>CompactEngine: 返回结构化摘要
CompactEngine->>CompactEngine: 创建压缩边界标记
CompactEngine->>CompactEngine: 生成附件(文件、计划、技能)
CompactEngine->>PostCleanup: 执行清理钩子
PostCleanup->>PostCleanup: 清除缓存和状态
CompactEngine-->>CompactCommand: 返回 CompactionResult
CompactCommand-->>User: 显示压缩完成
这个序列图展示了完整压缩的执行流程:从命令触发到微型压缩预处理,再到 API 调用生成摘要,最后执行清理钩子并返回结果。整个过程确保了压缩的原子性和一致性。
Sources: compact.ts, compact.ts
压缩提示词的结构化设计:压缩提示词强制模型生成包含九个部分的详细摘要,每个部分都有明确的格式要求。提示词首先要求模型在 <analysis> 标签中进行时间顺序分析,识别用户请求、技术决策、代码模式和错误修复,然后在 <summary> 标签中输出结构化结果。
Sources: prompt.ts
摘要的九个核心部分包括:主要请求和意图(用户的明确需求)、关键技术概念(框架、库和模式)、文件和代码段(包含完整代码片段和重要性说明)、错误和修复(遇到的错误及解决方案)、问题解决(已解决和进行中的故障排查)、所有用户消息(非工具结果的用户输入)、待处理任务(明确要求的工作)、当前工作(最近正在处理的任务)以及可选的下一步(基于最近对话的直接引用)。
Sources: prompt.ts
会话记忆压缩:语义化长期记忆
会话记忆压缩是一个实验性功能,它利用预提取的语义记忆进行压缩,而不是通过 API 调用生成摘要。当系统检测到会话记忆文件存在且非空时,优先使用这种压缩方式,因为它避免了额外的 API 调用成本。
会话记忆压缩通过 truncateSessionMemoryForCompact 函数截断会话记忆文件,保留最近的语义信息(最少 10,000 tokens,最少 5 个文本块消息,最多 40,000 tokens),然后将截断后的记忆作为压缩摘要使用。这种方法特别适用于长时间运行的会话,其中语义记忆已经捕获了关键的上下文信息。
Sources: sessionMemoryCompact.ts, sessionMemoryCompact.ts
部分压缩:保留特定上下文段
部分压缩(通过 /compact up_to:<message_uuid> 或 /compact from:<message_uuid> 触发)允许用户保留特定的上下文段,只压缩指定边界之外的消息。up_to 模式保留从指定消息到最新的所有消息(压缩前缀),而 from 模式保留从开始到指定消息的所有消息(压缩后缀)。
部分压缩的实现通过 compactPartialConversation 函数完成,它根据方向参数计算分割点,然后对目标消息集应用标准的压缩流程。系统使用 annotateBoundaryWithPreservedSegment 函数在压缩边界上添加元数据,以便消息加载器能够正确重建消息链。
Sources: compact.ts
自动压缩:智能触发机制
自动压缩系统通过 shouldAutoCompact 函数在每次 API 调用后检查上下文压力,当 token 使用量超过阈值时自动触发压缩。
Token 阈值计算
系统计算有效上下文窗口时,会从模型的完整上下文窗口中减去为摘要输出预留的 token(最多 20,000 tokens)。然后,自动压缩阈值设置为有效窗口减去 13,000 tokens 的缓冲区。这个缓冲区确保在压缩完成后,仍有足够的空间继续对话。
// 简化的阈值计算逻辑
const MAX_OUTPUT_TOKENS_FOR_SUMMARY = 20_000
const AUTOCOMPACT_BUFFER_TOKENS = 13_000
function getEffectiveContextWindowSize(model: string): number {
const reservedTokensForSummary = Math.min(
getMaxOutputTokensForModel(model),
MAX_OUTPUT_TOKENS_FOR_SUMMARY
)
const contextWindow = getContextWindowForModel(model)
return contextWindow - reservedTokensForSummary
}
function getAutoCompactThreshold(model: string): number {
const effectiveWindow = getEffectiveContextWindowSize(model)
return effectiveWindow - AUTOCOMPACT_BUFFER_TOKENS
}
Sources: autoCompact.ts
警告状态管理
系统通过 calculateTokenWarningState 函数计算三级警告状态:警告阈值(有效窗口减去 20,000 tokens)、错误阈值(有效窗口减去 20,000 tokens)和自动压缩阈值(有效窗口减去 13,000 tokens)。当 token 使用量超过警告阈值时,系统会显示剩余上下文的百分比;当超过错误阈值时,系统会显示更紧急的警告。
Sources: autoCompact.ts
失败重试与熔断机制
自动压缩实现了熔断机制以防止无限重试:当连续压缩失败次数达到 3 次时,系统停止尝试自动压缩,避免浪费 API 调用。失败可能由于多种原因,包括 prompt_too_long 错误(压缩请求本身超出限制)或网络问题。
Sources: autoCompact.ts
消息分组:API 轮次边界
压缩系统使用 groupMessagesByApiRound 函数将消息按 API 轮次分组,每个组对应一次完整的 API 调用及其响应。分组的边界由 assistant 消息的 ID 决定:当遇到一个新的 assistant 消息(ID 与前一个不同)时,开始一个新的组。
这种分组策略确保了压缩操作不会破坏工具调用的配对关系:根据 API 契约,每个 tool_use 必须在下一个 assistant 轮次之前被解析,因此按 assistant ID 分组自然地保持了配对的有效性。对于格式错误的消息(例如恢复后的悬空 tool_use),fork 代理的 ensureToolResultPairing 函数会在 API 时间修复配对。
Sources: grouping.ts
Token 估算与分析
精确与估算模式
系统提供两种 token 计数方式:精确计数通过 API 的 count_tokens 端点获取准确值,而快速估算通过 roughTokenCountEstimation 函数基于启发式规则快速计算。估算模式在压缩决策时使用(避免额外的 API 调用),而精确计数用于压缩后的统计和监控。
Sources: tokenEstimation.ts, tokens.ts
上下文分析
analyzeContext 函数提供详细的上下文统计,包括:工具请求和结果的 token 分布(按工具名称分组)、人类和助手消息的 token 数量、本地命令输出的 token、附件的类型和数量、重复文件读取的统计(识别低效的文件访问模式)以及总 token 数。
这些统计信息用于生成用户可见的上下文分析报告,帮助用户理解上下文压力的来源,并优化他们的交互模式。
Sources: contextAnalysis.ts
压缩后清理:状态重置
压缩完成后,runPostCompactCleanup 函数执行一系列缓存和状态清理操作,释放被压缩操作无效化的内存结构。清理包括:
微型压缩状态重置:清除缓存编辑的追踪状态,为下一轮压缩做准备。
上下文折叠重置:如果启用了 CONTEXT_COLLAPSE 特性,重置上下文折叠引擎的状态(仅主线程)。
内存文件缓存重置:清除 getUserContext 的缓存和 getMemoryFiles 的一次性钩子标志,确保下一轮重新加载内存文件(仅主线程)。
系统提示段清除:清除动态系统提示段的缓存。
分类器批准清除:重置权限分类器的批准状态。
推测性检查清除:清除 Bash 工具的推测性权限检查缓存。
Beta 追踪状态清除:重置 beta 功能的追踪状态。
会话消息缓存清除:清除会话存储的消息缓存。
重要设计决策:系统故意不清除已发送技能名称(sentSkillNames),因为重新注入完整的 skill_listing(约 4,000 tokens)会产生纯缓存创建成本。模型仍然在 schema 中拥有 SkillTool,invoked_skills 附件保留了已使用技能的内容,动态添加由技能变更检测器处理。
Sources: postCompactCleanup.ts
压缩附件:关键状态恢复
压缩后,系统创建一系列附件消息以恢复关键状态,确保模型在压缩后立即拥有必要的上下文。附件的创建遵循严格的 token 预算:
文件附件:最多恢复 5 个最近读取的文件,每个文件最多 5,000 tokens,总预算 50,000 tokens。文件选择基于压缩前的文件状态缓存,优先选择最近访问的文件。
计划附件:如果会话中有活动计划,重新注入计划内容。
计划模式附件:如果当前处于计划模式,重新注入计划模式指令,确保模型继续在计划模式下操作。
技能附件:如果会话中调用了技能,重新注入技能内容(最多 5 个技能,每个最多 5,000 tokens,总预算 25,000 tokens)。
增量附件:重新声明工具、代理列表和 MCP 指令的增量,通过 delta 机制避免全量重传。
Sources: compact.ts, compact.ts
Prompt-Too-Long 重试机制
当压缩请求本身触发 prompt_too_long 错误时(这种情况在极端长的会话中可能发生),系统通过 truncateHeadForPTLRetry 函数从头部删除最旧的 API 轮次组,然后重试压缩。这个过程最多重试 3 次。
重试逻辑首先尝试基于 token 缺口精确计算需要删除的组数,累积每组的 token 估算值直到覆盖缺口。如果无法解析 token 缺口(某些 Vertex/Bedrock 错误格式),则回退到删除 20% 的组。删除后,如果第一个消息是 assistant 类型(这会被 API 拒绝),系统会插入一个合成的用户标记消息。
Sources: compact.ts, compact.ts
缓存共享:优化 API 成本
压缩系统通过 tengu_compact_cache_prefix 特性标志(默认启用)支持提示缓存共享。当启用时,forked-agent 路径重用主对话的提示缓存,显著降低压缩 API 调用的成本。实验数据表明,禁用缓存共享会导致 98% 的缓存未命中率,增加约 0.76% 的舰队缓存创建成本(每天约 380 亿 tokens)。
缓存共享在冷缓存环境(CCR/GHA/SDK)中尤其重要,这些环境中 GrowthBook 缓存被禁用或不可用。该特性作为熔断开关保留,可以在出现问题时快速禁用。
Sources: compact.ts
性能监控与遥测
压缩系统发出多个遥测事件用于监控和优化:
tengu_compact:记录成功压缩的详细信息,包括压缩前后的 token 数、压缩 API 调用的使用量、是否为自动压缩、提示缓存共享状态、重新压缩信息(是否为链式重新压缩、距上次压缩的轮次数)以及查询来源。
tengu_compact_ptl_retry:记录 prompt-too-long 重试的尝试次数、删除的消息数和剩余消息数。
tengu_compact_failed:记录压缩失败的原因(prompt_too_long、no_summary、api_error)和相关上下文。
tengu_cached_microcompact:记录缓存编辑微型压缩删除的工具数量和工具 ID。
tengu_partial_compact_failed:记录部分压缩失败的原因和方向。
这些事件用于分析压缩效率、识别瓶颈和优化压缩策略。
Sources: compact.ts, microCompact.ts
命令接口:手动控制
用户通过 /compact 命令手动触发压缩。命令支持可选的自定义指令参数,允许用户提供额外的上下文或特定要求。命令的实现首先尝试会话记忆压缩(如果可用),然后是微型压缩预处理,最后执行完整的压缩流程。
命令还支持响应式压缩模式(通过 REACTIVE_COMPACT 特性标志),在该模式下,压缩通过响应式路径执行,提供更细粒度的控制和更好的用户体验。
Sources: compact.ts
配置选项
压缩系统支持多个环境变量配置:
CLAUDE_CODE_AUTO_COMPACT_WINDOW:覆盖自动压缩的上下文窗口大小,用于测试或特殊场景。
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE:设置自动压缩阈值为上下文窗口的百分比(1-100),用于更容易地测试自动压缩。
CLAUDE_CODE_TIME_BASED_MC_THRESHOLD_MS:配置时间基准微型压缩的阈值(毫秒),默认为 5 分钟。
Sources: autoCompact.ts, autoCompact.ts
相关页面
- 查询引擎:QueryEngine 对话生命周期管理 — 了解压缩如何集成到查询引擎的生命周期中
- API 服务:认证、限流与 Anthropic API 客户端 — 深入了解提示缓存和缓存编辑 API
- 状态管理:AppState 与 React Context 体系 — 探索压缩状态如何集成到全局状态管理中
- 记忆系统:memdir 持久化与团队同步 — 了解会话记忆压缩与长期记忆系统的关系