Claude Code 的 Prompt 工程:从静态分离到缓存优化的深度解析

📅 2026/7/8 1:57:06 👁️ 阅读次数 📝 编程学习
Claude Code 的 Prompt 工程:从静态分离到缓存优化的深度解析

Claude Code 的 Prompt 工程:从静态分离到缓存优化的深度解析

揭秘一个 AI 编程助手如何在每次请求都发送完整提示词的情况下,依然保持惊人的响应速度和低廉的成本

作为一款基于 Claude 模型的命令行编程助手,Claude Code 在效率与成本控制上的表现令人印象深刻。它能够在每次 API 调用都发送完整系统提示词的前提下,依然保持极快的响应速度和较低的使用成本。这背后的秘密,是一套精心设计的 Prompt 工程体系。

本文将深入解析 Claude Code 的提示词管理系统,从架构设计到缓存策略,带你看懂这套“既要又要”的精妙机制。


一、核心设计思想:静态与动态的分离

Claude Code 最核心的设计理念,是将系统提示词切分为静态段动态段

在源码中,二者通过一个特殊的标记SYSTEM_PROMPT_DYNAMIC_BOUNDARY明确分隔。

📌 静态段:不变的“宪法”

静态段位于边界之上,定义的是 AI 的核心身份、基本能力、安全准则和通用工作流

关键特征:

  • ✅ 内容稳定不变
  • ✅ 对所有用户、所有会话保持一致
  • ✅ 可以被全局缓存

具体包含的模块包括:

模块名作用
身份介绍“你是 Claude Code,Anthropic 的官方 CLI…”
系统能力说明具备读写文件、执行命令等能力
任务执行指南“先读代码再修改”、“找到根本原因”等原则
安全与操作规范强调操作的可逆性,高风险操作需确认
工具使用指南建议使用 FileRead 而非 cat 等技巧
语气与风格“不使用 emoji”、保持专业

📌 动态段:灵活的“任务书”

动态段位于边界之下,包含与当前会话、项目和用户强相关的实时信息。

关键特征:

  • 🔄 因会话而异
  • 🔄 可能每轮变化
  • 🔄 无法被全局缓存

具体包括:

模块名加载时机说明
会话特定指南会话级子代理合约等
项目记忆(CLAUDE.md)会话级启动时加载逐层加载并拼接
环境信息每轮更新当前目录、操作系统、日期时间等
Git 状态每轮更新git status输出,通过特殊机制加载
MCP 指令会话级来自 MCP 服务器的指令
语言设置会话级指定回复语言
Token 预算按需大上下文模式下的 +500k 指令

二、动态段如何加载用户指令?

用户指令主要通过以下方式进入动态段:

1.CLAUDE.md— 最主要的用户入口

  • 加载机制:会话启动时,从根目录向下遍历到当前目录,沿途加载所有CLAUDE.mdCLAUDE.local.md.claude/CLAUDE.md
  • 内容处理:原样拼接(verbatim),无摘要或截断
  • 层级覆盖:子目录配置与父目录共同生效,形成配置层叠

2.settings.json— 用户/项目级配置

配置文件中的设置内容也会作为用户指令的一部分加载到动态段。

3. 启动参数 — 一次性指令

通过--system-prompt--append-system-prompt参数追加自定义指令。

4. 输出风格(Output Styles)

通过修改系统提示词改变回复风格,自定义指令会被追加到系统提示词末尾。

⚠️ 重要提示:静态段(Anthropic 官方指令)拥有最高优先级。如果用户指令与官方指令冲突,官方指令会优先生效。


三、每次调用都完整发送,但依然飞快?

是的,Claude Code 每次 API 调用都会发送完整的系统提示词。然而它之所以仍能保持低延迟和低成本,全靠提示词缓存(Prompt Caching)机制。

缓存的工作原理

基于“严格前缀匹配”原则:

  1. API 会缓存请求的“前缀”部分
  2. 只要新请求的开头与缓存内容匹配,就能复用处理结果
  3. 只有新增或变化的部分需要全新处理

三层内容的缓存策略

层级内容变更频率缓存策略
System Prompt核心指令、工具定义很少变更✅ 高缓存命中,静态部分全局缓存
Project ContextCLAUDE.md、项目规则会话级✅ 会话内缓存
Conversation用户消息、对话历史每轮都变❌ 不被缓存,每次全新处理

缓存命中率的实际效果

这种设计可节省约80%的 Token 成本,并显著降低响应延迟。

你可以通过 API 返回头中的anthropic-organization-cache-creationanthropic-organization-cache-read字段来确认缓存命中情况。


四、DANGEROUS_uncachedSystemPromptSection:一场“主动牺牲”的缓存博弈

在 Claude Code 源码中,有一个命名极为直白的函数:DANGEROUS_uncachedSystemPromptSection

它的设计初衷

“与其让一个易变的内容破坏掉整个巨大的缓存前缀,不如主动将它标记为‘不缓存’,从而牺牲小我,保全大我。”

典型应用场景

  • MCP 指令:内容随服务器连接状态变化
  • Git 状态git status随文件改动频繁变化
  • 环境信息:CWD、时间戳等每轮可能不同

同级的其他部分

DANGEROUS_uncachedSystemPromptSection同级的是systemPromptSection()。二者的核心区别:

systemPromptSection()DANGEROUS_uncachedSystemPromptSection()
缓存策略内容可缓存❌ 不缓存,每轮重新计算
变更频率稳定或低频变化⚡ 频繁变化
典型用途会话级指令、项目记忆MCP 指令、Git 状态
设计目的最大化缓存复用保护主缓存不被破坏

💡 Git 状态会被加载吗?

会的。Git 状态正是通过DANGEROUS_uncachedSystemPromptSection来加载的。

由于git status的输出会随每次文件修改、暂存或提交而变化,将其放入可缓存部分会导致整个 Prompt Cache 频繁失效。因此,通过“不缓存”机制加载是一种务实的工程选择。

你也可以通过settings.json中的includeGitInstructions: false来控制是否包含 Git 状态指令。


五、缓存失效陷阱:开发者需要注意什么?

以下操作会破坏前缀匹配,导致缓存失效:

操作影响
切换模型不同模型的缓存相互独立
修改effort级别每个级别独立缓存
升级 Claude Code 版本系统提示词变化,缓存全部失效
工具集变化工具定义属于缓存前缀的一部分
提示词中的动态时间戳时间戳每轮变化会破坏前缀匹配

⚠️常见误解:中途修改CLAUDE.md会立即生效。实际上,出于缓存考量,CLAUDE.md的变更只会在新会话中生效


六、完整组装顺序:一切如何串联?

最终的系统提示词按以下顺序组装(由getSystemPrompt()驱动):

[静态段] 1. Intro (身份介绍) 2. Output style (输出风格) 3. System rules (系统规则) 4. Doing tasks (任务执行指南) 5. Actions (安全规范) ─── __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__ ─── [动态段] 6. Environment (环境信息) 7. Git status (Git 状态) 8. Project context (项目上下文) 9. CLAUDE.md (用户指令) 10. Runtime config (运行时配置)

最终示例(简化):

You are Claude Code, Anthropic's official CLI... # Your capabilities... # Doing tasks - In general, do not propose changes... # Executing actions with care... __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__ - Model: claude-3-opus-20240229 - CWD: /Users/me/my-project - Date: 2026-07-07 - Git status: On branch main, nothing to commit... - From CLAUDE.md: Always use ES modules...

七、总结:设计的哲学

Claude Code 的 Prompt 系统体现了三种核心设计哲学:

  1. 静态与动态分离:稳定的“骨架”与灵活的“血肉”各司其职
  2. 缓存优先:通过精细的缓存策略,在功能完整性与运行效率之间取得平衡
  3. 可观测性:通过 API 头和源码设计,让开发者能清晰理解系统行为

这套体系不仅让 Claude Code 能在每次请求都发送完整上下文的前提下保持高性能,也为其他 AI 应用的 Prompt 工程提供了优秀的参考范式。