Claude Code Wiki
首页 深入解析 服务层

压缩服务:上下文压缩与内存优化策略

中级 服务层

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 中拥有 SkillToolinvoked_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

相关页面