Claude Code 源码解剖

Claude Code 的提示词控制面

从行为引导措辞、模型发布注解、ant-only 门控、Undercover 模式和 GrowthBook 分流,拆解提示词如何变成可维护、可灰度、可回滚的行为控制面。

第 7 章 16 分钟

Claude Code 的提示词控制面

第 6 章讲的是系统提示词如何被分段、缓存和合成。这一章看另一层:这些提示词内容如何控制模型行为,如何随模型世代变化,如何只对内部用户开放,如何在公开仓库里隐藏内部信息,如何通过 Feature Flag 做灰度。

这里的重点不是“提示词写得好不好”,而是:提示词如何进入工程控制面

核心直觉

提示词负责改变模型的行为分布,但不是硬安全边界。Claude Code 把提示词、构建期门控、运行时上下文、Feature Flag、权限系统放在一起,才形成可维护的 Agent 行为控制面。

先看源码入口

源码定位点关键符号负责什么
restored-src/src/constants/prompts.ts行为引导段落极简主义、失败恢复、可逆性、验证完成等行为规则
restored-src/src/tools/BashTool/prompt.tsBash 工具提示词Git 安全协议、工具偏好、危险命令边界
restored-src/src/constants/prompts.ts:117-118@[MODEL LAUNCH]FRONTIER_MODEL_NAME新模型发布时的源码内检查清单
restored-src/src/constants/prompts.ts:204-241Capybara v8 缓解段落过度注释、彻底性、主动性、虚假声明等模型特定调优
restored-src/src/constants/prompts.ts:617-619process.env.USER_TYPE === 'ant' DCE 注释内部提示词在外部构建中被死代码消除
restored-src/src/utils/undercover.ts:28-37isUndercover()公开仓库压制内部模型信息
restored-src/src/utils/model/antModels.tstengu_ant_model_overrideresolveAntModel()内部模型覆盖和别名解析
GrowthBook 配置tengu_* flags提示词策略、模型配置和实验分流

这一章的读法:不要把 prompt 当文本读,要看它旁边的门控、注释、环境变量和实验 flag。

总流程图

flowchart TB A["模型/用户/仓库上下文"] --> B["getSystemPrompt()<br/>系统提示词段落"] C["BashTool/prompt.ts<br/>工具局部提示词"] --> B D["@[MODEL LAUNCH]<br/>模型发布检查清单"] --> B E["USER_TYPE === 'ant'<br/>内部提示词 DCE 门控"] --> B F["isUndercover()<br/>公开仓库压制内部信息"] --> B G["GrowthBook tengu_*<br/>A/B 测试和模型覆盖"] --> B B --> H["模型行为分布<br/>少过度工程 / 先验证 / 谨慎 Git / 准确报告"] H --> I["工具执行和权限系统<br/>硬边界兜底"] I --> J["遥测 / 实验结果 / 下一轮调优"]

提示词控制面有两个输出:

  • 软输出:让模型更可能按期望方式思考和行动。
  • 硬输出:通过代码门控和权限系统,保证某些边界不能只靠模型自觉。

行为引导:源码里不是口号,而是针对模型偏差的补偿

原文把 Claude Code 的行为引导提炼成多种模式。这里挑几类最能说明源码密度的。

极简主义:反过度工程

原文引用的 prompts.ts 指令大意是:

Don't create helpers, utilities, or abstractions for one-time operations.
Don't design for hypothetical future requirements.
Three similar lines of code is better than a premature abstraction.

这段提示词证明它不是泛泛说“保持简单”,而是给模型一个可操作判断:

句子控制的模型倾向
不要为一次性操作创建 helper防止模型过早抽象
不要为假设的未来需求设计防止 gold-plating
三行相似代码优于过早抽象用数值锚点覆盖模型默认 DRY 倾向

这类规则适合放 prompt,因为“过度抽象”很难写成通用代码检查,但模型能在生成时被这种偏好影响。

失败恢复:不要盲目重试,也不要过早放弃

原文里的失败处理指令:

If an approach fails, diagnose why before switching tactics.
Don't retry the identical action blindly, but don't abandon a viable approach after a single failure either.
Escalate to the user with ask_user_question only when you're genuinely stuck after investigation.

这段代码式文本证明一个三阶段恢复协议:

失败
-> 读错误、检查假设
-> 尝试有针对性的修复
-> 真的卡住后再问用户

它同时压住两个坏习惯:无限重试和一失败就甩给用户。

可逆性意识:用风险维度引导模型

原文引用的核心句:

Carefully consider the reversibility and blast radius of actions.
Generally you can freely take local, reversible actions like editing files or running tests.
But for actions that are hard to reverse, affect shared systems beyond your local environment, or could otherwise be risky or destructive, check with the user before proceeding.

这里最重要的不是“危险动作要问”,而是引入两个维度:

维度问的问题
reversibility这个动作容易撤回吗
blast radius这个动作影响本地还是共享系统

这让模型在没见过的操作上也能类比判断,而不是只死背危险命令列表。

版本控制安全协议:工具提示词里也有硬语气

BashTool/prompt.ts 里的 Git 协议更具体:

Git Safety Protocol:
- NEVER update the git config
- NEVER run destructive git commands (push --force, reset --hard, checkout ., restore ., clean -f, branch -D) unless the user explicitly requests these actions.
- NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it
- NEVER run force push to main/master, warn the user if they request it
- CRITICAL: Always create NEW commits rather than amending, unless the user explicitly requests a git amend.

这段提示词证明三种写法:

写法作用
NEVER 大写提高规则权重,表达硬禁区
unless the user explicitly requests明确豁免条件,不让模型乱拒绝
CRITICAL + 因果解释--amend 这种微妙风险给出原因,方便模型泛化

容易误解

Git 安全协议写在 prompt 里,不等于 Git 安全只靠 prompt。真正执行时还要由 Bash 权限、安全分类、用户确认等代码路径兜底。

工具偏好引导:把模型从 Bash 拉回专用工具

模型训练数据里有大量 catgrepsedfind。如果不引导,模型会倾向用 Bash 做一切。BashTool/prompt.ts 通过前置说明重定向:

IMPORTANT: Avoid using this tool to run find, grep, cat, head, tail, sed,
awk, or echo commands, unless explicitly instructed or after you have
verified that a dedicated tool cannot accomplish your task.

 - File search: Use Glob (NOT find or ls)
 - Content search: Use Grep (NOT grep or rg)
 - Read files: Use Read (NOT cat/head/tail)
 - Edit files: Use Edit (NOT sed/awk)
 - Write files: Use Write (NOT echo >/cat <<EOF)

这段证明工具提示词是“工具选择路由器”。它不是解释 Bash 怎么用,而是在模型准备选择 Bash 时,先提醒它是否应该选择更专用的工具。

行为链路是:

模型想用 Bash
-> 读到 BashTool prompt 开头的工具偏好
-> 发现任务是 read/search/edit
-> 改用 Read/Grep/Glob/Edit
-> 执行层获得更结构化、更可控的工具调用

模型发布注解:@[MODEL LAUNCH] 是源码里的迁移清单

Claude Code 源码里有特殊注释:

// @[MODEL LAUNCH]: Update the latest frontier model.
const FRONTIER_MODEL_NAME = 'Claude Opus 4.6';

这不是普通注释,而是分布式检查清单。新模型发布时,工程师搜索 @[MODEL LAUNCH] 就能找到需要重新评估的点。

原文列出的 prompts.ts 更新点包括:

位置要更新或评估什么
FRONTIER_MODEL_NAME新模型市场名称
模型 ID 对象各层级模型 ID
过度注释缓解新模型是否还需要 comment restraint
彻底性反制是否需要继续提醒完成前验证
主动性反制是否需要继续提醒模型指出误解和相邻 bug
虚假声明缓解新模型 false claims rate 是否下降
getKnowledgeCutoff()新模型知识截止日期

这说明提示词控制面是随模型版本演进的。新模型不是简单替换 ID,还要重新评估行为补偿。

读源码抓手

@[MODEL LAUNCH] 比搜某个模型名更可靠。它告诉你“模型升级时哪些地方必须重新评估”,而不是只告诉你当前写了哪个模型。

模型特定缓解:Capybara v8 的四类补丁

原文提到 Capybara v8 有几个行为问题,源码用 ant-only 提示词先内部缓解。

问题缓解目标源码特征
过度注释默认不写注释,只在 WHY 不明显时写Default to writing no comments
彻底性不足完成前跑测试、执行脚本、检查输出Before reporting a task complete, verify it actually works
主动性不足发现用户误解或相邻 bug 时要指出You&#39;re a collaborator, not just an executor
虚假声明测试失败就说失败,没验证就说没验证Report outcomes faithfully

这里的工程重点是生命周期:

flowchart LR A["发现模型偏差<br/>如 FC rate 上升"] --> B["添加提示词缓解"] B --> C["USER_TYPE === 'ant'<br/>内部构建验证"] C --> D["GrowthBook / A-B<br/>外部灰度"] D --> E["@[MODEL LAUNCH]<br/>下个模型发布时重评估"] E --> F["保留 / 软化 / 删除"]

模型特定提示词不应该永久散落在源码里,所以它旁边需要 @[MODEL LAUNCH] 这类迁移锚点。

USER_TYPE === &#39;ant&#39;:内部提示词在外部构建里物理消失

原文引用了 prompts.ts 的编译器契约注释:

DCE: `process.env.USER_TYPE === 'ant'` is build-time --define.
It MUST be inlined at each callsite (not hoisted to a const) so the
bundler can constant-fold it to `false` in external builds and
eliminate the branch.

这段注释证明 USER_TYPE === &#39;ant&#39; 不是普通运行时判断。外部构建时,打包器把 process.env.USER_TYPE 常量折叠为非 ant,然后删除整个分支。

行为链路:

源码里直接写 process.env.USER_TYPE === 'ant'
-> bundler --define 内联 USER_TYPE
-> 外部构建中条件为 false
-> ant-only 字符串和内部代号被 DCE 删除

为什么不能提取成变量?因为 hoist 成 const isAnt = process.env.USER_TYPE === &#39;ant&#39; 后,某些打包器可能无法在每个调用点做常量折叠,内部提示词就可能残留。

核心直觉

ant-only 提示词不是“外部用户看不到而已”,而是外部构建产物里不应该存在。这是防泄露边界,不只是功能门控。

公开仓库隐身:压制内部模型信息

内部用户在公开仓库贡献代码时,不能让提示词、commit、PR 文案泄露内部模型名或代号。isUndercover() 负责判断:

export function isUndercover(): boolean {
  if (process.env.USER_TYPE === 'ant') {
    if (isEnvTruthy(process.env.CLAUDE_CODE_UNDERCOVER)) return true;
    return getRepoClassCached() !== 'internal';
  }
  return false;
}

这段代码证明:

规则行为
只有 ant 用户才考虑 Undercover外部用户本来没有内部信息
CLAUDE_CODE_UNDERCOVER=1 强制开启内部仓库也可手动隐身
仓库不是 internal 就开启不确定时按公开仓库处理
没有强制关闭防止误判导致内部代号泄露

Undercover 会压制多处内容:

压制位置行为
computeEnvInfo模型名称/ID 清空
computeSimpleEnvInfo环境信息里移除模型描述
模型家族列表不出现 Opus/Sonnet/Haiku 内部 ID
Claude Code 平台信息可被外部看到的描述被压制
Fast Mode 说明不暴露内部模型路由
getAntModelOverrideSection()返回 null
attribution 文案commit/PR 归因文本清空

容易误解

Undercover 不是“不要在回答里说模型名”的提示词。它是在系统提示词构建阶段直接不注入这些信息,让模型根本看不到。

灰度实验:提示词策略也要可回滚

Claude Code 的 tengu_* Feature Flag 不只控制功能,也控制提示词和模型策略。例如:

控制点例子作用
模型覆盖tengu_ant_model_override内部模型列表、默认模型、提示词后缀
自动权限tengu_auto_mode_config权限分类策略
Prompt cachetengu_prompt_cache_1h_config缓存 TTL 策略
Ultraplantengu_ultraplan_prompt_identifier远程规划提示词变体
事件采样tengu_event_sampling_config遥测采样

提示词策略进入 GrowthBook 后,发布方式变成:

写一版新行为提示词
-> 内部 ant-only 验证
-> GrowthBook 分流外部用户
-> 记录曝光和行为结果
-> 放量 / 回滚 / 修改措辞

这让 prompt 变成可实验、可回滚的行为策略,而不是发版后全量生效的静态文本。

状态和数据结构

结构字段或标记控制什么
prompts.ts 行为段落极简、验证、可逆性、失败恢复模型默认行为倾向
BashTool/prompt.tsGit Safety Protocol、工具偏好映射Bash 使用边界和专用工具选择
@[MODEL LAUNCH]源码注释标记新模型发布检查清单
USER_TYPE === &#39;ant&#39;构建期内联条件内部提示词和模型配置是否进入产物
isUndercover()repo class + env是否压制内部模型信息
tengu_ant_model_overrideGrowthBook config内部模型覆盖、提示词后缀
tengu_* flagsGrowthBook 远程配置行为策略灰度、A/B、kill switch

设计取舍

取舍点源码体现工程判断
行为引导放 prompt极简主义、失败恢复、验证完成模糊行为偏好难以写成硬校验,适合软约束
危险动作不只靠 promptGit 协议 + 权限系统prompt 塑形,代码兜底
模型偏差有生命周期@[MODEL LAUNCH]新模型发布时统一重评估缓解,而不是永久累积
内部验证先行USER_TYPE === &#39;ant&#39;新策略先在内部构建验证,再灰度外部
DCE 防泄露条件必须内联内部代号和提示词不能残留在外部 bundle
不确定就 UndercovergetRepoClassCached() !== &#39;internal&#39;对泄露风险 fail-closed
提示词策略可远程分流GrowthBook tengu_*prompt 变成可实验、可回滚的控制策略

读源码抓手

  1. 先读 constants/prompts.ts 里的行为指令,不要只看中文概括,关注反面案例和数值锚点。
  2. 再读 tools/BashTool/prompt.ts,看 Git Safety Protocol 和 Bash 到专用工具的重定向。
  3. @[MODEL LAUNCH],列出模型发布时需要重评估的所有提示词和模型配置。
  4. process.env.USER_TYPE === &#39;ant&#39;,确认哪些提示词只在内部构建存在。
  5. utils/undercover.ts,看公开仓库信息压制的触发条件。
  6. antModels.ts,理解 tengu_ant_model_override 如何控制内部模型列表和提示词后缀。
  7. 最后把 GrowthBook flags 和遥测事件放在一起看:某条提示词策略如何灰度、曝光、回滚。

小结

- 提示词控制面负责塑形模型行为,但不替代权限和执行层硬边界。 - Claude Code 的行为提示词有具体模式:极简、失败诊断、可逆性、工具偏好和准确报告。 - @[MODEL LAUNCH] 把模型升级的提示词重评估写进源码,而不是靠外部记忆。 - USER_TYPE === &#39;ant&#39; 和 Undercover 说明提示词里也有构建期和仓库级安全边界。 - GrowthBook 让提示词策略可以灰度、A/B、回滚,成为真正的工程控制面。