Claude Code 提示词缓存的核心启示
整理时间: 2026-02-20
来源: 群聊消息(来自 Claude Code 开发者 @trq212)
整理人: AI助手
摘要
对于 Claude Code 这种需要长时间运行、进行多次往返交互的智能体工具,提示词缓存是决定其经济成本和响应延迟可行性的核心技术。本文整理了提示词缓存的底层原理、最佳实践架构、以及复杂场景下的优化方案,为构建高效 AI Agent 提供工程实践指导。
一、核心技术原理
1.1 前缀匹配机制
| 特性 | 说明 |
|---|---|
| 缓存方式 | 前缀匹配 |
| 缓存范围 | 从请求起始位置到指定的 cache_control 断点 |
| 关键特性 | 前缀中任何细微改变,都会导致该位置之后的所有缓存失效 |
1.2 缓存的重要性
- 经济成本:缓存命中 vs 未命中,成本差异巨大
- 响应延迟:缓存命中 = 极速响应
- 可行性:没有缓存,长会话 Agent 根本无法落地
二、最佳实践架构(从静到动)
2.1 缓存分层原则
Claude Code 的架构遵循“静态内容在前,动态内容在后”的原则:
| 层级 | 内容 | 缓存范围 |
|---|---|---|
| 第 1 层 | 全局静态系统提示词 & 工具定义 | 全局共享 |
| 第 2 层 | 项目级上下文(如 CLAUDE.md) | 项目内共享 |
| 第 3 层 | 会话级上下文 | 会话内共享 |
| 第 4 层 | 具体对话消息记录 | 每次不同 |
2.2 排列顺序的重要性
[静态系统提示词 + 工具定义] → [项目上下文] → [会话上下文] → [对话消息]
↑ ↑
缓存起点 缓存终点(动态)
核心原则: 越静态的内容越靠前,越动态的内容越靠后
三、工程实践中的「反直觉」经验
3.1 状态更新:使用「系统消息」而非「修改系统提示词」
| 场景 | 错误做法 | 正确做法 |
|---|---|---|
| 外部状态变化 | 更新系统提示词(如时间改变) | 使用 |
原因: 更新系统提示词会破坏整个会话的缓存
正确做法:
# 错误 ❌
system_prompt = f"当前时间: {datetime.now()}" # 破坏缓存!
# 正确 ✅
messages.append({
"role": "system-reminder",
"content": f"当前时间: {datetime.now()}" # 不破坏缓存
})
3.2 避免中途切换模型
| 场景 | 错误做法 | 正确做法 |
|---|---|---|
| 会话中切换模型 | 从 Opus 切换到 Haiku | 使用子代理交接 |
原因: 缓存与具体模型绑定,切换模型会导致缓存完全失效
正确做法:
- 主会话保持 Opus
- 让 Opus 生成任务交接消息给 Haiku
- Haiku 作为子代理处理简单任务
- 主会话缓存保持完整
3.3 绝对不要中途添加或移除工具
| 场景 | 错误做法 | 正确做法 |
|---|---|---|
| 优化工具数量 | 只给模型当前需要的工具 | 工具集保持静态 |
原因: 工具定义缓存在前缀中,增减工具会立刻破坏缓存
正确做法: 工具集必须在整个会话中保持不变
四、复杂场景下的缓存优化方案
4.1 规划模式的设计
需求: 进入只读模式(不修改代码)时,如何避免缓存失效?
方案: 保留所有工具,引入模式切换工具
| 工具 | 功能 |
|---|---|
| EnterPlanMode | 进入规划模式 |
| ExitPlanMode | 退出规划模式 |
实现:
- 开启规划模式时:发送系统消息 “你现在处于规划模式,只能探索代码”
- 不移除任何工具
- 缓存零破坏
额外优势: AI 可以自主决定何时进入规划模式
4.2 延迟加载解决海量工具问题
问题: 几十个 MCP 工具,全部加载太贵,中途移除破坏缓存
方案: 工具存根 + 延迟加载
# 轻量级存根(永远在缓存中)
tools = [
{
"name": "search_files",
"defer_loading": True, # 延迟加载标记
"schema": {...}
},
# ... 更多存根
]
# 模型需要时,通过 ToolSearch 动态发现并加载完整 Schema
优势:
- 前缀中永远只有不变的存根
- 缓存前缀绝对稳定
- 按需加载完整工具
4.3 上下文压缩的「缓存安全分叉」
问题: 对话历史超限时,需要总结压缩
错误做法:
# 直接用新请求总结,会导致缓存完全失效 ❌
response = api.chat_completion(
messages=[{"role": "user", "content": "请总结以上对话"}]
)
# 缓存未命中!需支付全额费用
正确方案:
| 步骤 | 操作 |
|---|---|
| 1 | 复用与主会话完全相同的系统提示词 |
| 2 | 复用相同的工具定义 |
| 3 | 复用历史消息 |
| 4 | 仅在末尾追加 “请进行总结” |
# 正确做法 ✅
response = api.chat_completion(
messages=[
*system_prompt, # 完全相同
*tool_definitions, # 完全相同
*conversation_history, # 完全相同
{"role": "user", "content": "请进行总结"} # 追加指令
]
)
# 完美命中缓存!
关键: 在设计时预留”压缩缓冲区”
五、一句话总结
不要随意改变前缀,用状态机(消息和工具调用)来代替环境改变,把缓存机制当作第一性原理来设计系统。
六、核心原则汇总
| 原则 | 说明 |
|---|---|
| 静态在前,动态在后 | 系统提示词 → 项目上下文 → 会话 → 对话 |
| 前缀不可变 | 任何前缀改动都破坏缓存 |
| 状态用消息传递 | 不用修改提示词来更新状态 |
| 模型不要中途切换 | 用子代理代替 |
| 工具集保持静态 | 全程不变,模式切换用工具 |
| 压缩要复用前缀 | 总结时保持系统提示词和工具不变 |
整理备注
本文档基于 Claude Code 开发者 @trq212 的实战分享整理,包含提示词缓存的核心原理、最佳实践及复杂场景优化方案。