跳转至

2.1 Context Management

本节摘要

从State Management角度看,Context Management回答的核心问题是:每次 LLM 调用时Context 由什么组成、怎么保持稳定不变的部分尽量缓存、Context 快满时怎么丢弃、丢弃后怎么恢复关键信息? 本节按「组成 → 稳定性 → 丢弃 → 恢复」的主线展开。


一、Context 由什么组成

每次 API 调用时,LLM 收到的Context 由以下部分构成,各自有不同的变化频率

组成部分 变化频率 说明
System Prompt 静态区域 不变(跨组织共享缓存) 身份、安全指令、工具规范、风格等 7 个 Section
System Prompt 动态区域 会话级(/clear/compact 时重算) 环境信息、CLAUDE.md、Skill 指导、MCP 指令等 11+ Section
对话历史 每 turn 增长 进程内 messages[] 数组,用户消息 + 助手回复 + 工具调用/结果
Attachment 每 turn 重算 <system-reminder> 包裹的动态 Context(详见 2.6 Attachment 系统
工具定义 会话级(偶尔变化) 工具 JSON Schema 数组(详见 2.3 Tool Management

对话历史是Context 中增长最快的部分——每次工具调用都会产生 tool_use + tool_result 消息对,在 agentic 场景下增速很快。


二、怎么保持稳定:Prompt Cache 策略

Context 中不变的部分越多,API 的 Prompt Cache 命中率越高(省成本、降延迟)。Claude Code 围绕这一目标做了三层缓存设计。

System Prompt 的静态/动态分区

getSystemPrompt()SYSTEM_PROMPT_DYNAMIC_BOUNDARY 常量将系统提示切成两半:

区域 Section 数量 缓存行为 包含内容
静态 7 个 scope: 'global',跨组织共享 身份、安全、工具规范、风格等
动态 11+ 个 会话级客户端缓存 环境、CLAUDE.md、Skill 指导、MCP 等

静态区域约占系统提示的 60-70%。Anthropic API 对这部分做服务端缓存,每次 API 调用都命中

Section 的两种缓存类型

类型 行为 何时使用
systemPromptSection(name, compute) 计算一次后缓存,/clear/compact 才重算 大多数 Section
DANGEROUS_uncachedSystemPromptSection(name, compute, reason) 每轮重算 MCP 指令等必须实时更新的内容

DANGEROUS_ 前缀是故意的命名约定——提醒维护者「这个 Section 会破坏 Prompt Cache」。

环境 Context 的 memoize

getSystemContext()(git 状态)和 getUserContext()(CLAUDE.md + 日期)通过 memoize 缓存,单次会话仅执行一次。CLAUDE.md 作为 user context 前缀注入,不放进 system prompt 静态区——保护缓存。


三、怎么丢弃:六层渐进式压缩

当Context 接近窗口上限时,Claude Code 通过六层渐进式压缩来丢弃旧状态。核心原则:能不破坏缓存就不破坏,能不丢信息就不丢

graph LR
    A["L1: 清除旧结果\n无损"] -->|"不足"| B["L2: API 缓存编辑\n保持缓存"]
    B -->|"不足"| C["L3: API 原生裁剪\n委托 API"]
    C -->|"不足"| D["L4: Session Memory\n缓存失效⚠️"]
    D -->|"不足"| E["L5: LLM 摘要\n有损"]
    E -->|"不足"| F["L6: 紧急折叠\n核弹选项"]
层级 触发条件 做了什么 丢弃了什么 破坏缓存?
L1 Time-Based 消息 > 60 分钟未引用 清除旧 tool_result 文本,保留调用骨架 过时的工具输出
L2 Cached 工具调用超阈值 API cache_edits 清理 API 端缓存消息
L3 API MC input > 180K (90%) 委托 API 原生 context_management API 自主裁剪
L4 Session Memory > 167K (83.5%) 用已提取的 Session Memory 替代完整历史 全部旧消息 ⚠️
L5 Legacy L4 失败 fallback LLM 生成 9 章节结构化摘要 全部旧消息(摘要替代) ⚠️
L6 Collapse ~90% / 95% 阻断 紧急压缩(与 autocompact 互斥) 最大范围丢弃 ⚠️

关键分界线在 L3 和 L4 之间:L1-L3 在保持缓存的前提下尽量释放空间;L4 开始完全重建Context,缓存失效。

精确阈值(200K 窗口)

阈值 占比 设计原因
有效窗口 180,000 90% 预留 20K 给输出(p99.99 = 17,387)
自动压缩 167,000 83.5% 留 ~13K 给当前 turn 完成
警告 147,000 73.5% 给用户反应时间
阻断 177,000 88.5% 防止 API 400 错误

熔断器

MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3——连续失败 3 次后停止尝试。源码记录:1,279 sessions had 50+ consecutive failures, wasting ~250K API calls/day globally


四、丢弃后怎么恢复:Rehydration

L4/L5 压缩会清空全部旧消息。压缩后系统自动恢复关键状态,防止模型「失忆」到无法继续:

恢复项 预算 来源
最近操作的文件 5 个文件 × 5K tokens ≈ 50K readFileState
活跃 Skill 全文 每个 5K tokens,总 ≈ 25K invoked_skills attachment
CLAUDE.md 全层级重加载 磁盘文件
AGENTS.md 关键段落 Session Startup + Red Lines postCompactCleanup

恢复顺序compact.ts):

boundaryMarker → summaryMessages → messagesToKeep → attachments → hookResults

缓存清理:压缩后清除 getUserContext 缓存 + resetGetMemoryFilesCache + 执行 processSessionStartHooks('compact')——确保重新读取可能已变化的文件。


关键文件索引

文件 职责
src/constants/prompts.ts getSystemPrompt() + 静态/动态分区
src/constants/systemPromptSections.ts Section 两种缓存类型
src/context.ts getSystemContext() / getUserContext() + memoize
src/services/compact/autoCompact.ts 六层压缩调度 + 阈值 + 熔断器
src/services/compact/compact.ts Rehydration 重注入逻辑
src/services/compact/postCompactCleanup.ts 压缩后缓存清理