我翻了Claude Code的全部源码,提示词根本不是你想的那样
基于 Claude Code 2026-03-31 源码逆向拆解。一份值得学习的 Prompt 工程方法论。
你以为 Anthropic 写提示词的方式,是一个天才坐下来,憋出一段绝妙的 system prompt?
翻完源码我才发现——他们根本不是在”写提示词”,而是在造一个操作系统。
Claude Code 的 system prompt 是 十几个函数按条件拼装出来的。有静态层、动态层、缓存分界线、feature flag 注入、内外用户分流、工具级微型 prompt、甚至有专门为「防止缓存失效」设计的代码架构。
下面这篇,我把最值得学的部分压缩成 10 个核心技巧。每个技巧都附源码原文,然后给出可迁移的中文模板。
一、不要写一坨 prompt,要「分层拼装」
打开 src/constants/prompts.ts,你会看到 getSystemPrompt() 函数不是返回一个字符串,是一个数组,每个元素是一个独立模块:
静态层(可跨用户全局缓存)├── Intro(身份定义 + 安全红线)├── System(基础行为规范)├── Doing Tasks(编码行为准则)├── Executing Actions(操作风险分级)├── Using Your Tools(工具使用偏好)├── Tone and Style(语气格式)└── Output Efficiency(输出控制)────── DYNAMIC_BOUNDARY(缓存分界线)──────动态层(每用户 / 每会话不同)├── Session-specific Guidance├── Memory(CLAUDE.md / MEMORY.md)├── Environment Info(CWD、OS、模型名)├── Language / Output Style├── MCP Server Instructions└── Feature-gated Sections(Token Budget 等)
源码里甚至有这样一行:
// WARNING: Do not remove or reorder this marker// without updating cache logicexportconstSYSTEM_PROMPT_DYNAMIC_BOUNDARY ='__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'
分界线上面的所有内容用 scope: 'global' 做全局缓存。下面的才是每个用户不同的部分。
这意味着: 当你有一百万用户同时用 Claude Code,Anthropic 只需要为每个用户缓存分界线以下那一小截动态内容,上面几千 token 的规则全部命中缓存、零重复计算。
你该怎么学: 不要再写一个 3000 行的超级 system prompt。至少拆成:基础规则 → 场景规则 → 角色规则 → 工具规则 → 输出规则 → 运行时上下文。每层独立维护,按需拼装。
二、身份定义只需要一句话,剩下的全是约束
看看 Claude Code 怎么定义自己的身份——getSimpleIntroSection() 只有一句:
You are an interactive agent that helps userswith software engineering tasks.
就这么朴素。没有”你是世界上最厉害的 AI”,没有”你拥有深厚的专业知识”。
但紧跟着的不是鼓励,而是两条硬约束:
IMPORTANT: Assist with authorized security testing...Refuse requests for destructive techniques, DoS attacks...IMPORTANT: You must NEVER generate or guess URLsunless you are confident the URLs are for programming.
整个 prompt 的调性就此定下: 身份只是入口,约束才是主体。
翻完全文,你会发现 Claude Code 的 prompt 中,限制类指令的数量大约是鼓励类指令的 3 倍。它不断在削减模型的「错误自由度」:
-
• 不要对没读过的代码提建议 -
• 不要创建非必要的文件 -
• 不要做超出用户要求的”改进” -
• 不要写假设性的抽象 -
• 不要凭空说测试通过 -
• 没验证就明确说没验证
这背后的核心逻辑是: 一个成熟 Agent 的 prompt,主要工作不是激发模型的能力——模型本来就能做很多事——而是压制它的典型失败模式(幻觉、过度工程化、报喜不报忧、自作主张)。
可迁移模板:
约束:1. 未读取相关文件前,不要提出修改建议。2. 未验证执行结果前,不要声称"已完成"或"通过"。3. 不要为了"更优雅"而引入额外抽象,除非需求明确要求。4. 不要补做用户未要求的重构、清理、兼容层、注释。5. 若出现失败,先定位原因,再决定是否切换策略。6. 对不可逆、影响共享状态的动作,先说明并征得确认。
这类约束,价值远大于”你是世界级 AI 工程师”。
三、「不要做 X」永远要配「要做 Y」
这是源码里最一致的写法模式。纯粹的禁止会让模型迷茫(它不知道该做什么),所以 Claude Code 的每条 Don’t 后面都有一个 Do:
源码原文(getSimpleDoingTasksSection()):
Don't add error handling, fallbacks, or validationfor scenarios that can't happen. Trust internal codeand framework guarantees. Only validate at system boundaries.Don't create helpers, utilities, or abstractions forone-time operations. Three similar lines of code isbetter than a premature abstraction.
注意——每条禁止都写了为什么(Trust internal code / Three similar lines is better)。这不是装饰,这是让模型在边界情况能自己判断的关键。
再看风险操作部分(getActionsSection()),它没有说”要小心”,而是直接列清单:
Examples of risky actions that warrant user confirmation:- Destructive: deleting files/branches, dropping tables, rm -rf, overwriting uncommitted changes- Hard-to-reverse: force-pushing, git reset --hard, amending published commits- Visible to others: pushing code, commenting on PRs, sending messages to external services
技巧提炼:
-
• 用 Examples of...列具体场景,比抽象的”要谨慎”有效十倍 -
• 用 For instance给微观示例,消除理解歧义 -
• 每个 Don’t 配一个 Do 或 instead,否则模型会在两个极端之间摆荡
四、工具描述不是 API 文档,而是「调用策略」
这可能是源码里最被低估的 prompt 技巧。
大多数团队写 tool description 就写个参数说明和返回值。但 Claude Code 的每个 Tool prompt 都是一份微型 prompt 工程作品,至少包含四层:
层一:功能(What)
Performs exact string replacements in files.
层二:硬约束(Must / Never)
- You MUST use your Read tool at least once before editing.- ALWAYS prefer editing existing files.- NEVER write new files unless required.
层三:失败条件(This will FAIL if…)
- The edit will FAIL if old_string is not unique in the file.
注意这个措辞。不是”请确保 old_string 唯一”,而是”如果不唯一就会失败”。写出失败条件比写出成功条件更有效,因为模型会主动规避已知的失败路径。
层四:决策边界(When to Use / When NOT to Use)
TodoWriteTool 是最极致的示范——它的 prompt 超过 200 行,用了完整的 When/When NOT + 正面示例 + 反面示例 + reasoning 解释:
## When to Use This Tool1. Complex multi-step tasks requiring 3+ distinct steps2. User provides multiple tasks3. After receiving new instructions — immediately capture## When NOT to Use This Tool1. Single, straightforward task2. Task can be completed in less than 3 trivial steps3. Task is purely conversational
每种情况都配了 <example> + <reasoning> 块:
<example>User: "Rename getCwd to getCurrentWorkingDirectory"Assistant: *Uses grep to find all 15 instances across 8 files**Creates todo list with specific items for each file*<reasoning>1. First searched to understand the scope2. Found multiple occurrences → determined this was complex3. Todo list ensures every instance is tracked</reasoning></example>
<reasoning> 的价值: 它不只是展示行为,而是教模型决策逻辑。模型能从 reasoning 里学到”为什么这种情况要用/不用这个工具”,比单纯给 example 强得多。
五、子 Agent 提示词——源码里最精华的 500 行
AgentTool/prompt.ts 是整个代码库中最长、最精心打磨的 prompt。它教 Claude 如何给子 Agent 写 prompt——这是 prompt 写 prompt 的元级技巧。
核心规则一:像给新同事布置任务
Brief the agent like a smart colleague who justwalked into the room — it hasn't seen this conversation,doesn't know what you've tried, doesn't understandwhy this task matters.- Explain what you're trying to accomplish and why.- Describe what you've already learned or ruled out.- Give enough context that the agent can make judgment calls rather than just following a narrow instruction.
核心规则二:永远不要委托理解
这是源码里最有洞察力的一条:
Never delegate understanding. Don't write "based on yourfindings, fix the bug" or "based on the research,implement it." Those phrases push synthesis onto the agentinstead of doing it yourself. Write prompts that proveyou understood: include file paths, line numbers, whatspecifically to change.
翻译一下:如果你写出了”根据你的调研结果来实现”这种话,说明你在偷懒——你应该自己先消化调研结果,再给子 Agent 明确的执行指令。
核心规则三:查询 vs 调查要区分
Lookups: hand over the exact command.Investigations: hand over the question — prescribed stepsbecome dead weight when the premise is wrong.
查找类任务(“帮我查这个文件在哪”)→ 直接给命令。 调查类任务(“帮我搞清楚为什么报错”)→ 给问题,不要预设步骤,因为前提可能就是错的。
核心规则四:用 <commentary> 解释”没发生的事”
AgentTool 的示例里引入了一个精妙的标签:
<commentary>Turn ends here. The coordinator knows nothing about thefindings yet. What follows is a SEPARATE turn — thenotification arrives from outside. It is not somethingthe coordinator writes.</commentary>
这个标签教的不是”要做什么”,而是”在这个时间点你不知道什么”。 用来防止模型在子 Agent 还没返回时就编造结果。
六、输出控制:从”简洁点”到可量化
源码里有两个版本的输出控制策略,一个给外部用户,一个给 Anthropic 内部:
外部版(定性):
Keep your text output brief and direct. Lead with theanswer or action, not the reasoning. Skip filler words,preamble, and unnecessary transitions.
内部版(定量 + 数字锚点):
Length limits: keep text between tool calls to ≤25 words.Keep final responses to ≤100 words unless the taskrequires more detail.
源码注释写道:
// Numeric length anchors — research shows ~1.2% output// token reduction vs qualitative "be concise".// Ant-only to measure quality impact first.
1.2% 看起来不多? 乘以 Anthropic 的调用量,那是天文数字的成本差异。
内部版还有一段教科书级的写作指南(getOutputEfficiencySection()):
Write user-facing text in flowing prose while eschewingfragments, excessive em dashes, symbols and notation.Avoid semantic backtracking: structure each sentence soa person can read it linearly, building up meaningwithout having to re-parse what came before.Use inverted pyramid when appropriate (leading with theaction). If something about your reasoning must be inuser-facing text, save it for the end.
技巧提炼:
-
• 要精确控制长度 → 给数字(≤25 词 / under 200 words) -
• 要控制风格 → 给具体的写作规范(倒金字塔、避免语义回溯) -
• 不要笼统地说”写好点”或”简洁些”
七、诚实报告——双向约束
Claude Code 的 prompt 里反复强调结果真实性,但精妙的是它写了双向约束:
方向一:不许夸大
Report outcomes faithfully: if tests fail, say so withthe relevant output; if you did not run a verificationstep, say that rather than implying it succeeded.Never claim "all tests pass" when output shows failures.
方向二:不许贬低
Equally, when a check did pass or a task is complete,state it plainly — do not hedge confirmed results withunnecessary disclaimers, downgrade finished work to"partial," or re-verify things you already checked.The goal is an accurate report, not a defensive one.
为什么需要双向? 因为模型有两种失败模式——一种是报喜不报忧(“基本完成了”),另一种是过度防御(“可能还有问题,建议再检查一下”)。只压制一个方向会把模型推向另一个极端。
可迁移模板:
结果报告规则:1. 只报告已验证事实,不把推测写成结果。2. 未执行的步骤标注"未执行",不暗示已完成。3. 失败保留失败事实和关键输出,不弱化为"基本完成"。4. 已确认成功的结果直接陈述,不无意义地过度保守。
八、Prompt Cache 优化——大多数人不知道的成本杀手
这是整个源码里最独特的部分。Anthropic 在 prompt 层面做缓存优化的深度,远超我的预期。
8.1 Agent 列表导致的缓存雪崩
源码注释里有这样一段:
// The dynamic agent list was ~10.2% of fleet cache_creation// tokens: MCP async connect, /reload-plugins, or// permission-mode changes mutate the list → description// changes → full tool-schema cache bust.
翻译:Agent 列表原来放在 Tool description 里。每次 MCP 服务器连接状态变化,Tool description 就变了,导致整个 tools block 的缓存失效——这一项就烧掉了全平台 10.2% 的缓存创建开销。
解决方案:把 Agent 列表从 Tool description 移到 attachment message(用户消息附件),这样 Tool schema 保持不变,缓存不会被穿透。
8.2 用命名约束来防止缓存破坏
exportfunctionDANGEROUS_uncachedSystemPromptSection(name: string,compute: ComputeFn,_reason: string// 强制解释为什么需要破坏缓存) {return { name, compute, cacheBreak: true }}
函数名叫 DANGEROUS_uncached,而且强制传入 _reason 参数。这不是代码洁癖——这是用代码架构约束团队行为:你想破坏缓存?可以,但你得解释为什么,而且函数名会在 code review 时立刻引起注意。
你在构建 Agent 系统时该怎么做:
-
• 把 system prompt 分成”几乎不变的”和”经常变的”两部分 -
• 会变化的信息通过 user message 注入,不要塞进 system prompt -
• 特别注意 Tool description——它的任何变化都会导致整个 tools block 缓存失效
九、自主性 vs 风险——「低风险默认自主,高风险默认确认」
很多团队的 Agent prompt 只有两个极端:要么每步都问用户(像客服机器人),要么全自主(乱改乱发乱删)。
Claude Code 的做法是精确分级。在同一份 prompt 里,既有很强的自主指令:
Read files, search code, explore the project, run tests,check types, run linters — all without asking.Make code changes. Commit when you reach a good stopping point.If you're unsure between two reasonable approaches, pick oneand go. You can always course-correct.
也有很明确的风险边界:
Destructive operations, hard-to-reverse operations, andactions visible to others require confirmation.Do not use destructive actions as a shortcut to makeobstacles go away.
而且它还处理了一个微妙的问题——授权范围不可外推:
A user approving an action (like a git push) once does NOTmean that they approve it in all contexts. Unless actionsare authorized in advance in durable instructions likeCLAUDE.md files, always confirm first. Authorization standsfor the scope specified, not beyond.
可迁移模板:
自主执行原则:- 信息收集、检索、分析、草稿生成 → 默认自主执行- 共享状态修改、对外发送、生产数据写入、删除、覆盖 → 默认先确认- 若用户已给出授权,仅在授权范围内自主,不得外推
十、最值得学的是「四件套联动」
翻完全部源码,我最大的感受是:
Claude Code 几乎没有那种”单靠一段神 prompt 横扫一切”的设计。它依赖的是四件事协同工作:
1. Prompt → 定义行为边界、策略、模式、格式
2. Tool → 把关键动作外显化、参数化、可审计
3. State → todo、plan mode、progress、phase 显式管理
4. Memory → 长期连续性 + 压缩恢复能力
Plan Mode 超越了“复杂任务前先思考”的指令层面——它是一个完整的模式切换系统,有专门的 EnterPlanModeTool、明确的进出条件、独立的工具白名单和输出 schema。
Todo 跳出了“请一步步思考”的 CoT 框架——它是一个显式状态机,pending / in_progress / completed 三态流转,严格单任务,阻塞不可伪装完成。
Memory 突破了“请总结一下对话”的摘要模式——它是一个专门的 memory extraction subagent,执行严格编辑规则:只更新已有 section、不改 header、不加 filler、Key Results 完整、Current State 最新。
Claude 源码的核心启示:与其让提示词更聪明,不如给模型一套可控的工作制度。
附:可直接复用的高密度 Prompt 模板
综合以上所有技巧,压缩成一个你可以直接拿去改的模板:
你是一个面向复杂任务执行的智能代理。# 基本原则- 优先完成用户真实目标,而不是表面措辞。- 在证据不足时,不把推测写成事实。- 在未验证执行结果前,不声称完成。- 不做用户未要求的重构、抽象、兼容层。- 不对未读取的对象提出修改建议。- 遇到失败先定位原因,再决定是否切换策略。- 低风险动作默认自主;不可逆动作默认先确认。# 任务执行- 单步任务直接完成。- 多步任务先建显式任务列表,维护当前进行中步骤。- 同一时刻只保持一个步骤 in_progress。- 完成后立即更新状态,不把部分完成描述为全部完成。- 发现新的后续步骤,补充到任务列表。# 提问策略- 能通过上下文、检索、工具或推断解决的,不先问用户。- 只在缺失信息会显著影响结果、存在多个高影响方案、 或动作需要授权时才提问。- 提问必须具体、最小化、面向决策。# 工具使用- 工具不只是能力,也是工作流的一部分。- 调用前确认是当前最优下一步。- 工具失败后读失败信息,判断原因再采取下一步。- 对关键结果及时提炼,避免上下文压缩后丢失。# 结果报告- 简洁、准确、可验证。- 明确区分:已确认 / 待确认 / 未执行 / 失败。- 已确认成功直接陈述,不过度防御。- 最终报告包含:做了什么、结果、是否验证、遗留问题。# 输出控制- 先给结论,再给过程。- 工具调用间的文本 ≤ 25 词。- 最终回复 ≤ 100 词,除非任务需要更多细节。
总结:8 条设计哲学
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
最后: 很多人研究 prompt 技巧,学到的是 “be concise” “think step by step” 这种措辞。Claude 源码真正厉害的地方不在句子层,在编排层。它教你的不是怎么写一句更聪明的话,而是怎么把模型塞进一个可控的工作制度里。
这才是工程级 prompt 和玩具级 prompt 的本质区别。
夜雨聆风