Claude Code 的提示词控制面
第 6 章讲的是系统提示词如何被分段、缓存和合成。这一章看另一层:这些提示词内容如何控制模型行为,如何随模型世代变化,如何只对内部用户开放,如何在公开仓库里隐藏内部信息,如何通过 Feature Flag 做灰度。
这里的重点不是“提示词写得好不好”,而是:提示词如何进入工程控制面。
核心直觉
提示词负责改变模型的行为分布,但不是硬安全边界。Claude Code 把提示词、构建期门控、运行时上下文、Feature Flag、权限系统放在一起,才形成可维护的 Agent 行为控制面。
先看源码入口
| 源码定位点 | 关键符号 | 负责什么 |
|---|---|---|
restored-src/src/constants/prompts.ts | 行为引导段落 | 极简主义、失败恢复、可逆性、验证完成等行为规则 |
restored-src/src/tools/BashTool/prompt.ts | Bash 工具提示词 | Git 安全协议、工具偏好、危险命令边界 |
restored-src/src/constants/prompts.ts:117-118 | @[MODEL LAUNCH]、FRONTIER_MODEL_NAME | 新模型发布时的源码内检查清单 |
restored-src/src/constants/prompts.ts:204-241 | Capybara v8 缓解段落 | 过度注释、彻底性、主动性、虚假声明等模型特定调优 |
restored-src/src/constants/prompts.ts:617-619 | process.env.USER_TYPE === 'ant' DCE 注释 | 内部提示词在外部构建中被死代码消除 |
restored-src/src/utils/undercover.ts:28-37 | isUndercover() | 公开仓库压制内部模型信息 |
restored-src/src/utils/model/antModels.ts | tengu_ant_model_override、resolveAntModel() | 内部模型覆盖和别名解析 |
| GrowthBook 配置 | tengu_* flags | 提示词策略、模型配置和实验分流 |
这一章的读法:不要把 prompt 当文本读,要看它旁边的门控、注释、环境变量和实验 flag。
总流程图
提示词控制面有两个输出:
- 软输出:让模型更可能按期望方式思考和行动。
- 硬输出:通过代码门控和权限系统,保证某些边界不能只靠模型自觉。
行为引导:源码里不是口号,而是针对模型偏差的补偿
原文把 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 拉回专用工具
模型训练数据里有大量 cat、grep、sed、find。如果不引导,模型会倾向用 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're a collaborator, not just an executor |
| 虚假声明 | 测试失败就说失败,没验证就说没验证 | Report outcomes faithfully |
这里的工程重点是生命周期:
模型特定提示词不应该永久散落在源码里,所以它旁边需要 @[MODEL LAUNCH] 这类迁移锚点。
USER_TYPE === 'ant':内部提示词在外部构建里物理消失
原文引用了 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 === 'ant' 不是普通运行时判断。外部构建时,打包器把 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 === 'ant' 后,某些打包器可能无法在每个调用点做常量折叠,内部提示词就可能残留。
核心直觉
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 cache | tengu_prompt_cache_1h_config | 缓存 TTL 策略 |
| Ultraplan | tengu_ultraplan_prompt_identifier | 远程规划提示词变体 |
| 事件采样 | tengu_event_sampling_config | 遥测采样 |
提示词策略进入 GrowthBook 后,发布方式变成:
写一版新行为提示词
-> 内部 ant-only 验证
-> GrowthBook 分流外部用户
-> 记录曝光和行为结果
-> 放量 / 回滚 / 修改措辞
这让 prompt 变成可实验、可回滚的行为策略,而不是发版后全量生效的静态文本。
状态和数据结构
| 结构 | 字段或标记 | 控制什么 |
|---|---|---|
prompts.ts 行为段落 | 极简、验证、可逆性、失败恢复 | 模型默认行为倾向 |
BashTool/prompt.ts | Git Safety Protocol、工具偏好映射 | Bash 使用边界和专用工具选择 |
@[MODEL LAUNCH] | 源码注释标记 | 新模型发布检查清单 |
USER_TYPE === 'ant' | 构建期内联条件 | 内部提示词和模型配置是否进入产物 |
isUndercover() | repo class + env | 是否压制内部模型信息 |
tengu_ant_model_override | GrowthBook config | 内部模型覆盖、提示词后缀 |
tengu_* flags | GrowthBook 远程配置 | 行为策略灰度、A/B、kill switch |
设计取舍
| 取舍点 | 源码体现 | 工程判断 |
|---|---|---|
| 行为引导放 prompt | 极简主义、失败恢复、验证完成 | 模糊行为偏好难以写成硬校验,适合软约束 |
| 危险动作不只靠 prompt | Git 协议 + 权限系统 | prompt 塑形,代码兜底 |
| 模型偏差有生命周期 | @[MODEL LAUNCH] | 新模型发布时统一重评估缓解,而不是永久累积 |
| 内部验证先行 | USER_TYPE === 'ant' | 新策略先在内部构建验证,再灰度外部 |
| DCE 防泄露 | 条件必须内联 | 内部代号和提示词不能残留在外部 bundle |
| 不确定就 Undercover | getRepoClassCached() !== 'internal' | 对泄露风险 fail-closed |
| 提示词策略可远程分流 | GrowthBook tengu_* | prompt 变成可实验、可回滚的控制策略 |
读源码抓手
- 先读
constants/prompts.ts里的行为指令,不要只看中文概括,关注反面案例和数值锚点。 - 再读
tools/BashTool/prompt.ts,看 Git Safety Protocol 和 Bash 到专用工具的重定向。 - 搜
@[MODEL LAUNCH],列出模型发布时需要重评估的所有提示词和模型配置。 - 搜
process.env.USER_TYPE === 'ant',确认哪些提示词只在内部构建存在。 - 读
utils/undercover.ts,看公开仓库信息压制的触发条件。 - 读
antModels.ts,理解tengu_ant_model_override如何控制内部模型列表和提示词后缀。 - 最后把 GrowthBook flags 和遥测事件放在一起看:某条提示词策略如何灰度、曝光、回滚。
小结
- 提示词控制面负责塑形模型行为,但不替代权限和执行层硬边界。 - Claude Code 的行为提示词有具体模式:极简、失败诊断、可逆性、工具偏好和准确报告。 - @[MODEL LAUNCH] 把模型升级的提示词重评估写进源码,而不是靠外部记忆。 - USER_TYPE === 'ant' 和 Undercover 说明提示词里也有构建期和仓库级安全边界。 - GrowthBook 让提示词策略可以灰度、A/B、回滚,成为真正的工程控制面。