Claude Code 提示词工程架构深度分析
本文档深入分析 Claude Code 系统提示词的工程架构,涵盖组装流程、缓存边界设计、优先级系统、内外部差异化和 Feature Flag 体系。
1. 提示词组装流程
Section titled “1. 提示词组装流程”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 工具使用指引Insight:模块化组装的价值
Section titled “Insight:模块化组装的价值”这种模块化组装设计有几个关键优势:
- 按需加载:每个 Section 独立,可根据工具集、Feature Flag、用户类型条件性加载
- 缓存友好:静态部分不变,动态部分独立变化,最大化 prompt cache 命中率
- 可测试性:每个
get*Section()都是纯函数(或近似纯函数),可独立单元测试 - 渐进增强:新功能通过添加 section 而非修改现有 section 引入,降低回归风险
2. 缓存边界设计
Section titled “2. 缓存边界设计”SYSTEM_PROMPT_DYNAMIC_BOUNDARY 的作用
Section titled “SYSTEM_PROMPT_DYNAMIC_BOUNDARY 的作用”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 或 /compactfunction systemPromptSection(name, compute) { return { name, compute, cacheBreak: false }}
// 每个 turn 都重新计算,会破坏 prompt cachefunction DANGEROUS_uncachedSystemPromptSection(name, compute, reason) { return { name, compute, cacheBreak: true }}关键区别:
| 特性 | systemPromptSection | DANGEROUS_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()正是因此被移到动态区域
3. 提示词优先级系统
Section titled “3. 提示词优先级系统”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 模式下不追加 ││ 场景:额外指令叠加,不影响基础提示词选择 │└─────────────────────────────────────────────────────────────┘Insight:优先级链的设计哲学
Section titled “Insight:优先级链的设计哲学”这个优先级链体现了几个设计原则:
- 完全替换 vs 追加:Override 是唯一不允许追加的层级,体现了”完全控制或完全默认”的二元思维
- 模式互斥:Coordinator 模式和 Agent 模式互斥(协调器不允许 mainThreadAgentDefinition)
- Proactive 的特殊性:Proactive 模式下 Agent 不替换而是追加——因为自主工作需要基础能力(内存管理、tick 处理、sleep 控制),Agent 只提供领域增强
- Append 的粘性:appendSystemPrompt 除 Override 外始终生效,适合跨模式的通用指令
4. 内外部用户差异化
Section titled “4. 内外部用户差异化”Claude Code 通过 process.env.USER_TYPE === 'ant' 控制内部用户(Anthropic 员工)专属内容。由于 USER_TYPE 是构建时 --define 注入的常量,bundler 可以在外部构建中进行常量折叠和死代码消除。
内部用户专属内容
Section titled “内部用户专属内容”| 差异点 | 内部版(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() 模式
Section titled “isUndercover() 模式”isUndercover() 是 ant-only 的安全机制,用于在公开/开源仓库中隐藏所有内部信息:
激活逻辑:1. CLAUDE_CODE_UNDERCOVER=1 → 强制开启2. 否则自动模式:除非确认在内部仓库列表中,默认开启3. 没有强制关闭选项(安全默认)Undercover 模式下的行为:
- 系统提示词中不包含模型名称和 ID
- 不包含最新模型家族信息
- 不包含 Claude Code 的产品描述
- 不包含 Fast mode 说明
- 提交信息和 PR 描述中不包含任何 Anthropic 内部信息
Insight:内外部双轨的设计意图
Section titled “Insight:内外部双轨的设计意图”- 内部版更严格:反直觉地,面向开发者的内部版约束更多——因为 Anthropic 开发者频繁使用 Claude Code 进行实际工程工作,需要更精确的行为校准
- 数值 > 定性:内部版使用具体数字(<=25 词、<=100 词)而非定性描述(“be concise”),研究表明前者减少约 1.2% output tokens
- 安全默认:Undercover 模式没有强制关闭选项,体现了”宁可误杀不可泄漏”的安全思维
5. Feature Flag 系统
Section titled “5. Feature Flag 系统”Claude Code 使用 GrowthBook A/B 测试平台管理 Feature Flag,通过 feature() 函数(Bun 构建时宏)进行编译时门控,以及 getFeatureValue_CACHED_MAY_BE_STALE() / checkStatsigFeatureGate_CACHED_MAY_BE_STALE() 进行运行时门控。
活跃的 Feature Flag
Section titled “活跃的 Feature Flag”| Flag | 控制内容 | 说明 |
|---|---|---|
PROACTIVE | 自主工作模式 | 启用后 Claude Code 变为自主 Agent,通过 tick 驱动唤醒,主动探索和执行任务 |
COORDINATOR_MODE | 协调器模式 | 使 Claude Code 成为协调器角色,通过 Worker Agent 并行执行任务 |
CACHED_MICROCOMPACT | 缓存微压缩 | 启用 Function Result Clearing(旧工具结果自动清除以释放上下文空间) |
KAIROS / KAIROS_BRIEF | Brief 工具 | 启用 Brief 工具用于简洁化输出 |
VERIFICATION_AGENT | 验证 Agent | 启用对抗式验证——非平凡实现完成后必须通过独立验证 Agent |
FORK_SUBAGENT | Fork 子 Agent | 启用 Fork 模式,子 Agent 继承父上下文和工具池 |
TOKEN_BUDGET | Token 预算 | 启用 token 预算追踪,用户可指定目标消耗量 |
EXPERIMENTAL_SKILL_SEARCH | 技能搜索 | 启用 DiscoverSkills 工具自动发现和推荐技能 |
TRANSCRIPT_CLASSIFIER | 转录分类器 | 启用 Auto Mode 所需的安全分类器 |
编译时 vs 运行时门控
Section titled “编译时 vs 运行时门控”编译时门控(feature()):├── 优势:死代码消除(DCE),不引入运行时开销├── 用法:条件性 require(),避免拉入不需要的模块└── 示例:proactiveModule 仅在 PROACTIVE/KAIROS 启用时加载
运行时门控(GrowthBook):├── 优势:无需重新部署即可调整├── 特点:CACHED_MAY_BE_STALE 后缀表明值可能有延迟└── 示例:tengu_hive_evidence 控制验证 Agent 是否激活Insight:Feature Flag 的精细化控制
Section titled “Insight:Feature Flag 的精细化控制”- 两层门控:编译时 + 运行时的双层设计,既保证构建体积最小(DCE),又支持灰度发布
- 互斥关系:Fork subagent 和 Coordinator mode 互斥——两者都涉及 Agent 编排,同时存在会产生冲突
- ant-only A/B:多个特性先在内部用户中 A/B 测试(如 Verification Agent、数值长度锚点),验证后再推向外部
- DANGEROUS_ 命名约定:
DANGEROUS_uncachedSystemPromptSection的命名是有意识的恫吓设计,防止开发者随意使用会破坏缓存的 uncached section
6. Proactive 模式的特殊路径
Section titled “6. Proactive 模式的特殊路径”当 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 clearing9. Summarize tool results10. Proactive section(tick 驱动、sleep 控制、终端焦点感知等)Proactive 模式的提示词显著更精简——没有标准的”做任务”、“谨慎执行”、“工具使用”等 section,因为自主 Agent 需要更大的行动自由度。
Insight:模式切换是提示词架构的核心挑战
Section titled “Insight:模式切换是提示词架构的核心挑战”Proactive 模式体现了一个根本性的设计张力:标准模式需要”谨慎、确认、最小变更”,自主模式需要”主动、果断、偏向行动”。解决方式不是在同一套提示词中加条件分支,而是走完全不同的组装路径。这避免了”当谨慎规则和主动规则同时存在”时模型的困惑。
7. 子 Agent 的提示词增强
Section titled “7. 子 Agent 的提示词增强”当通过 Agent 工具创建子 Agent 时,enhanceSystemPromptWithEnvDetails() 会在 Agent 自身的系统提示词之后追加:
Agent 原始系统提示词 + Notes(绝对路径、文件引用规范、反 emoji 等) + DiscoverSkills 指引(如果可用) + 环境信息(CWD、平台、模型名称等)这确保了子 Agent 既有领域专属指引,又了解运行环境。
Claude Code 的提示词架构可以用三个核心设计选择概括:
- 缓存边界分离:一条线将 40K+ tokens 分为”所有人共享”和”每人不同”,实现了巨大的推理成本优化
- Section 注册制:每个提示词模块独立计算、独立缓存、独立刷新,实现了高度的可维护性和可组合性
- 优先级链 + 模式互斥:6 层优先级 + Proactive 独立路径,确保不同运行模式获得最适合的提示词组合,而不是一个臃肿的全能提示词