Skip to content

Claude Code 提示词工程架构深度分析

本文档深入分析 Claude Code 系统提示词的工程架构,涵盖组装流程、缓存边界设计、优先级系统、内外部差异化和 Feature Flag 体系。


getSystemPrompt() 是提示词的主入口函数,位于 src/constants/prompts.ts。它按以下顺序组装系统提示词数组:

getSystemPrompt(tools, model, additionalWorkingDirectories?, mcpClients?)
├── [特殊路径] CLAUDE_CODE_SIMPLE 环境变量 → 最小化提示词(仅 CWD + Date)
├── [特殊路径] Proactive 模式激活 → 自主 Agent 专用提示词
└── [标准路径] 以下为默认组装顺序:
├── ─── 静态内容(可跨用户缓存)───
│ 1. getSimpleIntroSection()
│ 角色:身份定义与开场白
│ 内容:定义 Claude Code 为交互式软件工程助手
│ 包含:Cyber Risk 指令、URL 生成限制
│ 依赖:outputStyleConfig(非 null 时改变角色描述)
│ 2. getSimpleSystemSection()
│ 角色:系统规则
│ 内容:6 条核心规则 — Markdown 渲染、权限模式、
│ system-reminder 标签、prompt injection 检测、
│ hooks 系统、自动压缩
│ 3. getSimpleDoingTasksSection()
│ 角色:任务执行准则
│ 条件:outputStyleConfig 为 null 或 keepCodingInstructions 为 true
│ 内容:编码风格(反过度工程三连)、安全编码、忠实报告(ant-only)、
│ 评论哲学(ant-only)、bug 报告指导(ant-only)
│ 4. getActionsSection()
│ 角色:谨慎执行操作
│ 内容:可逆性与爆炸半径评估框架、高风险操作分类与确认流程
│ 5. getUsingYourToolsSection()
│ 角色:工具使用指南
│ 依赖:enabledTools(工具集合影响具体输出内容)
│ 内容:专用工具 > Bash、并行调用策略、任务管理工具
│ 分支:REPL 模式下只保留任务管理工具指引
│ 6. getSimpleToneAndStyleSection()
│ 角色:语气和风格
│ 内容:反 emoji、代码位置引用格式、GitHub 链接格式
│ 差异:外部用户多一条"responses should be short and concise"
│ 7. getOutputEfficiencySection()
│ 角色:输出效率
│ 内容:内外部双轨制
│ - 内部(ant):长段落,强调"理解 > 简短",倒金字塔结构
│ - 外部:短指令,"Go straight to the point"
├── ═══ SYSTEM_PROMPT_DYNAMIC_BOUNDARY ═══
│ 条件:仅当 shouldUseGlobalCacheScope() 为 true(1P provider)
└── ─── 动态内容(通过 systemPromptSection 注册制管理)───
│ 以下通过 resolveSystemPromptSections() 批量解析:
│ 8. session_guidance(systemPromptSection)
│ getSessionSpecificGuidanceSection()
│ 内容:AskUserQuestion 指引、!命令提示、
│ Agent 工具使用策略(Fork vs 传统)、
│ Explore Agent 分流指引、Skill 系统、
│ Verification Agent 对抗式验证
│ 9. memory(systemPromptSection)
│ loadMemoryPrompt()
│ 内容:CLAUDE.md 文件链 + Agent 记忆
│ 10. ant_model_override(systemPromptSection)
│ getAntModelOverrideSection()
│ 内容:内部模型特定的系统提示词后缀
│ 条件:仅 ant 用户 + 非 undercover 模式
│ 11. env_info_simple(systemPromptSection)
│ computeSimpleEnvInfo()
│ 内容:工作目录、git 状态、平台、Shell、OS 版本、
│ 模型名称/ID、知识截止日期、模型家族信息
│ 12. language(systemPromptSection)
│ getLanguageSection()
│ 内容:语言偏好设定(如 "Always respond in Chinese")
│ 13. output_style(systemPromptSection)
│ getOutputStyleSection()
│ 内容:用户自定义输出风格配置
│ 14. mcp_instructions(DANGEROUS_uncachedSystemPromptSection)
│ getMcpInstructionsSection()
│ 原因:"MCP servers connect/disconnect between turns"
│ 内容:已连接 MCP 服务器的使用指导
│ 15. scratchpad(systemPromptSection)
│ getScratchpadInstructions()
│ 内容:会话专用临时目录的使用说明
│ 16. frc(systemPromptSection)
│ getFunctionResultClearingSection()
│ 内容:旧工具结果自动清理机制说明
│ 条件:CACHED_MICROCOMPACT feature + 模型支持
│ 17. summarize_tool_results(systemPromptSection)
│ 常量字符串
│ 内容:提醒记录重要信息(原始结果可能被清除)
│ 18. numeric_length_anchors(systemPromptSection,ant-only)
│ 内容:"工具调用之间文本 <=25 词,最终回复 <=100 词"
│ 19. token_budget(systemPromptSection,TOKEN_BUDGET feature)
│ 内容:Token 预算追踪指引
│ 20. brief(systemPromptSection,KAIROS feature)
│ getBriefSection()
│ 内容:Brief 工具使用指引

这种模块化组装设计有几个关键优势:

  1. 按需加载:每个 Section 独立,可根据工具集、Feature Flag、用户类型条件性加载
  2. 缓存友好:静态部分不变,动态部分独立变化,最大化 prompt cache 命中率
  3. 可测试性:每个 get*Section() 都是纯函数(或近似纯函数),可独立单元测试
  4. 渐进增强:新功能通过添加 section 而非修改现有 section 引入,降低回归风险

export const SYSTEM_PROMPT_DYNAMIC_BOUNDARY =
'__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'

这个字符串标记是一个缓存分水岭。在 getSystemPrompt() 返回的字符串数组中,它将内容分为两部分:

  • 边界之前:使用 cacheScope: 'global' 进行跨组织缓存。这些内容对所有用户完全相同(不含任何用户/会话特定信息),可以在 Anthropic API 层面实现全局缓存复用。
  • 边界之后cacheScope: null,不参与全局缓存。包含用户环境、语言偏好、MCP 服务器等会话特定信息。

splitSysPromptPrefix() 函数(位于 src/utils/api.ts)消费这个标记,将系统提示词拆分为最多 4 个 block:

1. Attribution header (cacheScope=null)
2. System prompt prefix (cacheScope=null)
3. Static content 静态内容 (cacheScope='global') ← 跨用户缓存
4. Dynamic content 动态内容 (cacheScope=null)

systemPromptSection() vs DANGEROUS_uncachedSystemPromptSection()

Section titled “systemPromptSection() vs DANGEROUS_uncachedSystemPromptSection()”
// 计算一次,缓存到 /clear 或 /compact
function systemPromptSection(name, compute) {
return { name, compute, cacheBreak: false }
}
// 每个 turn 都重新计算,会破坏 prompt cache
function DANGEROUS_uncachedSystemPromptSection(name, compute, reason) {
return { name, compute, cacheBreak: true }
}

关键区别

特性systemPromptSectionDANGEROUS_uncachedSystemPromptSection
计算频率首次调用后缓存每个 turn 重新计算
缓存清除/clear/compact每次都是新的
Prompt cache 影响不破坏(值稳定)值变化时破坏缓存
使用场景环境信息、语言设置等MCP 指令(服务器随时连接/断开)
命名要求无特殊要求必须提供 reason 参数说明为何需要 uncached

为什么 MCP instructions 必须 uncached? MCP 服务器可以在任意两个 turn 之间连接或断开。如果缓存了旧的 MCP 指令,模型可能会尝试使用已断开的服务器工具,或者缺少新连接服务器的使用指南。DANGEROUS_ 前缀是有意的命名恫吓,提醒开发者谨慎使用。

全局缓存 scope 的 Blake2b hash 优化

Section titled “全局缓存 scope 的 Blake2b hash 优化”

shouldUseGlobalCacheScope() 判断是否启用全局缓存:

export function shouldUseGlobalCacheScope(): boolean {
return (
getAPIProvider() === 'firstParty' &&
!isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS)
)
}

仅 1P(firstParty)provider 启用。静态部分的 Blake2b hash 用于前缀匹配——相同的静态内容产生相同的 hash,API 层面可以直接复用缓存的 KV cache,而无需重新处理 40K+ tokens 的静态提示词。

Insight:缓存边界是成本优化的杠杆

Section titled “Insight:缓存边界是成本优化的杠杆”

一个单独的边界标记实现了巨大的成本优化——跨用户共享 ~30K tokens 的缓存前缀。设计关键在于:

  • 静态部分严格排除所有运行时变量(工具集影响 section 5,但在静态区域通过条件渲染处理)
  • 一个新的条件分支如果放错位置(静态区域),会指数级增加 hash 变体(2^N),彻底破坏缓存效果
  • PR #24490 和 #24171 修复的就是这类 bug——getSessionSpecificGuidanceSection() 正是因此被移到动态区域

buildEffectiveSystemPrompt() 位于 src/utils/systemPrompt.ts,实现了 6 层优先级:

优先级从高到低:
┌─────────────────────────────────────────────────────────────┐
│ 0. Override(overrideSystemPrompt) │
│ 触发条件:loop 模式设置 overrideSystemPrompt │
│ 行为:完全替换所有其他提示词,不追加 appendSystemPrompt │
│ 场景:自动化循环执行,需要完全控制提示词 │
├─────────────────────────────────────────────────────────────┤
│ 1. Coordinator(COORDINATOR_MODE feature flag) │
│ 触发条件:feature('COORDINATOR_MODE') && │
│ CLAUDE_CODE_COORDINATOR_MODE env && │
│ !mainThreadAgentDefinition │
│ 行为:使用 getCoordinatorSystemPrompt() 替换默认提示词 │
│ 追加:appendSystemPrompt 仍然追加 │
├─────────────────────────────────────────────────────────────┤
│ 2. Agent(mainThreadAgentDefinition) │
│ 触发条件:存在 mainThreadAgentDefinition │
│ 行为(标准模式):Agent 的 getSystemPrompt() 替换默认 │
│ 行为(Proactive 模式):Agent 指令追加到默认提示词之后 │
│ 设计:Proactive 模式下 Agent 是"增强"而非"替换", │
│ 类似 teammate 在基础自主 Agent 之上叠加领域指令 │
├─────────────────────────────────────────────────────────────┤
│ 3. Custom(customSystemPrompt,来自 --system-prompt 参数) │
│ 触发条件:无 Agent 定义且指定了 --system-prompt │
│ 行为:替换默认提示词 │
├─────────────────────────────────────────────────────────────┤
│ 4. Default(defaultSystemPrompt) │
│ 触发条件:无以上任何自定义 │
│ 行为:使用 getSystemPrompt() 生成的标准提示词 │
├─────────────────────────────────────────────────────────────┤
│ 5. Append(appendSystemPrompt) │
│ 行为:始终追加到最终结果尾部 │
│ 例外:Override 模式下不追加 │
│ 场景:额外指令叠加,不影响基础提示词选择 │
└─────────────────────────────────────────────────────────────┘

这个优先级链体现了几个设计原则:

  1. 完全替换 vs 追加:Override 是唯一不允许追加的层级,体现了”完全控制或完全默认”的二元思维
  2. 模式互斥:Coordinator 模式和 Agent 模式互斥(协调器不允许 mainThreadAgentDefinition)
  3. Proactive 的特殊性:Proactive 模式下 Agent 不替换而是追加——因为自主工作需要基础能力(内存管理、tick 处理、sleep 控制),Agent 只提供领域增强
  4. Append 的粘性:appendSystemPrompt 除 Override 外始终生效,适合跨模式的通用指令

Claude Code 通过 process.env.USER_TYPE === 'ant' 控制内部用户(Anthropic 员工)专属内容。由于 USER_TYPE 是构建时 --define 注入的常量,bundler 可以在外部构建中进行常量折叠和死代码消除。

差异点内部版(ant)外部版
评论写作”默认不写评论。只在 WHY 不明显时写” + 不解释 WHAT + 不删除已有评论无此指导
完成验证”报告完成前先验证:跑测试、执行脚本、检查输出”无此指导
协作主动性”如发现用户基于误解,或相邻 bug,主动说出来”无此指导
忠实报告明确禁止虚假阳性和虚假谦虚无此指导
bug 上报推荐 /issue/share 命令无此指导
输出风格长段落,强调理解和清晰(~300 词指导)短指令,“Go straight to the point”(~100 词)
数值锚点”工具调用之间 <=25 词,最终回复 <=100 词”无此指导
简洁性指引无”responses should be short”(因为已有详细输出风格指导)有”Your responses should be short and concise”

isUndercover() 是 ant-only 的安全机制,用于在公开/开源仓库中隐藏所有内部信息:

激活逻辑:
1. CLAUDE_CODE_UNDERCOVER=1 → 强制开启
2. 否则自动模式:除非确认在内部仓库列表中,默认开启
3. 没有强制关闭选项(安全默认)

Undercover 模式下的行为:

  • 系统提示词中不包含模型名称和 ID
  • 不包含最新模型家族信息
  • 不包含 Claude Code 的产品描述
  • 不包含 Fast mode 说明
  • 提交信息和 PR 描述中不包含任何 Anthropic 内部信息
  1. 内部版更严格:反直觉地,面向开发者的内部版约束更多——因为 Anthropic 开发者频繁使用 Claude Code 进行实际工程工作,需要更精确的行为校准
  2. 数值 > 定性:内部版使用具体数字(<=25 词、<=100 词)而非定性描述(“be concise”),研究表明前者减少约 1.2% output tokens
  3. 安全默认:Undercover 模式没有强制关闭选项,体现了”宁可误杀不可泄漏”的安全思维

Claude Code 使用 GrowthBook A/B 测试平台管理 Feature Flag,通过 feature() 函数(Bun 构建时宏)进行编译时门控,以及 getFeatureValue_CACHED_MAY_BE_STALE() / checkStatsigFeatureGate_CACHED_MAY_BE_STALE() 进行运行时门控。

Flag控制内容说明
PROACTIVE自主工作模式启用后 Claude Code 变为自主 Agent,通过 tick 驱动唤醒,主动探索和执行任务
COORDINATOR_MODE协调器模式使 Claude Code 成为协调器角色,通过 Worker Agent 并行执行任务
CACHED_MICROCOMPACT缓存微压缩启用 Function Result Clearing(旧工具结果自动清除以释放上下文空间)
KAIROS / KAIROS_BRIEFBrief 工具启用 Brief 工具用于简洁化输出
VERIFICATION_AGENT验证 Agent启用对抗式验证——非平凡实现完成后必须通过独立验证 Agent
FORK_SUBAGENTFork 子 Agent启用 Fork 模式,子 Agent 继承父上下文和工具池
TOKEN_BUDGETToken 预算启用 token 预算追踪,用户可指定目标消耗量
EXPERIMENTAL_SKILL_SEARCH技能搜索启用 DiscoverSkills 工具自动发现和推荐技能
TRANSCRIPT_CLASSIFIER转录分类器启用 Auto Mode 所需的安全分类器
编译时门控(feature()):
├── 优势:死代码消除(DCE),不引入运行时开销
├── 用法:条件性 require(),避免拉入不需要的模块
└── 示例:proactiveModule 仅在 PROACTIVE/KAIROS 启用时加载
运行时门控(GrowthBook):
├── 优势:无需重新部署即可调整
├── 特点:CACHED_MAY_BE_STALE 后缀表明值可能有延迟
└── 示例:tengu_hive_evidence 控制验证 Agent 是否激活
  1. 两层门控:编译时 + 运行时的双层设计,既保证构建体积最小(DCE),又支持灰度发布
  2. 互斥关系:Fork subagent 和 Coordinator mode 互斥——两者都涉及 Agent 编排,同时存在会产生冲突
  3. ant-only A/B:多个特性先在内部用户中 A/B 测试(如 Verification Agent、数值长度锚点),验证后再推向外部
  4. DANGEROUS_ 命名约定DANGEROUS_uncachedSystemPromptSection 的命名是有意识的恫吓设计,防止开发者随意使用会破坏缓存的 uncached section

feature('PROACTIVE')feature('KAIROS') 启用且 proactiveModule.isProactiveActive() 返回 true 时,getSystemPrompt() 走一条完全不同的路径:

Proactive 模式提示词组成:
1. 自主 Agent 身份 + Cyber Risk 指令
2. System reminders 处理规则
3. Memory prompt(CLAUDE.md 等)
4. 环境信息
5. 语言偏好
6. MCP 指令(如果非 delta 模式)
7. Scratchpad 指令
8. Function result clearing
9. Summarize tool results
10. Proactive section(tick 驱动、sleep 控制、终端焦点感知等)

Proactive 模式的提示词显著更精简——没有标准的”做任务”、“谨慎执行”、“工具使用”等 section,因为自主 Agent 需要更大的行动自由度。

Insight:模式切换是提示词架构的核心挑战

Section titled “Insight:模式切换是提示词架构的核心挑战”

Proactive 模式体现了一个根本性的设计张力:标准模式需要”谨慎、确认、最小变更”,自主模式需要”主动、果断、偏向行动”。解决方式不是在同一套提示词中加条件分支,而是走完全不同的组装路径。这避免了”当谨慎规则和主动规则同时存在”时模型的困惑。


当通过 Agent 工具创建子 Agent 时,enhanceSystemPromptWithEnvDetails() 会在 Agent 自身的系统提示词之后追加:

Agent 原始系统提示词
+ Notes(绝对路径、文件引用规范、反 emoji 等)
+ DiscoverSkills 指引(如果可用)
+ 环境信息(CWD、平台、模型名称等)

这确保了子 Agent 既有领域专属指引,又了解运行环境。


Claude Code 的提示词架构可以用三个核心设计选择概括:

  1. 缓存边界分离:一条线将 40K+ tokens 分为”所有人共享”和”每人不同”,实现了巨大的推理成本优化
  2. Section 注册制:每个提示词模块独立计算、独立缓存、独立刷新,实现了高度的可维护性和可组合性
  3. 优先级链 + 模式互斥:6 层优先级 + Proactive 独立路径,确保不同运行模式获得最适合的提示词组合,而不是一个臃肿的全能提示词