Claude Code 的提示词工程
不要把 Claude Code 的 prompt 理解成“一大段总提示词”
很多人第一次研究 Claude Code,都会先找那段“终极 system prompt”。
但源码里真正存在的,不是一条 prompt,而是一整套分层装配的提示词系统。
Claude Code 至少同时存在这几类 prompt:
- 会话级 system prompt
- 运行时动态追加的 prompt section
- 工具级 prompt
- 专项子系统 prompt
- 多 Agent / teammate 模式下的附加 prompt
也就是说,Claude Code 的 prompt 工程不是“写一段厉害的话”,而是“把不同职责的提示词放到不同层,再按运行时状态拼起来”。
一张图看懂 Claude Code 的提示词体系
第一层:主会话的 System Prompt
Claude Code 最核心的 prompt 入口在 constants/prompts.ts。
源码里最醒目的一段是:
function getSimpleIntroSection(outputStyleConfig: OutputStyleConfig | null): string {
return `
You are an interactive agent that helps users ${
outputStyleConfig !== null
? 'according to your "Output Style" below, which describes how you should respond to user queries.'
: 'with software engineering tasks.'
} Use the instructions below and the tools available to you to assist the user.
IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming.`
}
这段话定义了 Claude Code 的基础身份:
它不是纯聊天机器人,而是一个带工具、带任务目标、面向软件工程的交互式 Agent。
中文翻译
你是一个交互式智能体,负责帮助用户完成软件工程任务。请结合下面的指令和可用工具来协助用户。
重要:除非你能确定某个 URL 确实是在帮助用户完成编程任务,否则绝不能为用户凭空生成或猜测 URL。
这段 prompt 的作用
- 先确定“身份”
- 再确定“任务域”是软件工程
- 再强调“工具可用”
- 最后给出安全边界
这类 prompt 属于 Claude Code 的总纲提示词。
第二层:System Prompt 不是固定字符串,而是动态分段拼装
Claude Code 并没有把所有系统提示词写死成一个超长模板。
它会把许多 section 动态拼起来:
const dynamicSections = [
systemPromptSection('session_guidance', () =>
getSessionSpecificGuidanceSection(enabledTools, skillToolCommands),
),
systemPromptSection('memory', () => loadMemoryPrompt()),
systemPromptSection('env_info_simple', () =>
computeSimpleEnvInfo(model, additionalWorkingDirectories),
),
systemPromptSection('language', () =>
getLanguageSection(settings.language),
),
systemPromptSection('output_style', () =>
getOutputStyleSection(outputStyleConfig),
),
DANGEROUS_uncachedSystemPromptSection(
'mcp_instructions',
() => isMcpInstructionsDeltaEnabled() ? null : getMcpInstructionsSection(mcpClients),
'MCP servers connect/disconnect between turns',
),
]
这说明 Claude Code 的 system prompt 至少由这些部分组成:
- 会话指导
- Memory 记忆
- 环境信息
- 语言偏好
- 输出风格
- MCP 指令
动态装配流程图
中文解释
这意味着 Claude Code 在做的不是:
把一段固定 system prompt 塞给模型
而是在做:
根据当前会话状态,拼装出当前这一轮最合适的 system prompt
这也是它比很多“复制一段提示词”的 AI 工具更工程化的原因。
第三层:用户可以替换或追加 System Prompt
在 main.tsx 里,CLI 直接暴露了 prompt 定制入口:
addOption(new Option('--system-prompt <prompt>', 'System prompt to use for the session').argParser(String))
addOption(new Option('--append-system-prompt <prompt>', 'Append a system prompt to the default system prompt').argParser(String))
而在 utils/queryContext.ts 里,系统又进一步把这两种语义分开处理:
// customSystemPrompt replaces the default system prompt entirely.
// appendSystemPrompt appends extra text after the default system prompt.
中文翻译
customSystemPrompt会完全替换默认系统提示词。
appendSystemPrompt会在默认系统提示词后面追加额外内容。
为什么这点很重要
很多产品只有“覆盖 prompt”这一种模式,但 Claude Code 区分了两类需求:
- replace:我要完全换掉默认系统行为
- append:我要保留默认能力,只在末尾增加约束
这是一种很典型的工程设计。
因为绝大多数真实需求并不是“推翻默认 prompt”,而是“在默认 prompt 上叠加额外规则”。
第四层:Teammate 模式还会自动追加额外 prompt
在多 Agent 协作模式下,Claude Code 还会给 teammate 附加专属说明。
main.tsx 里有这样一段:
if (isAgentSwarmsEnabled() && storedTeammateOpts?.agentId && storedTeammateOpts?.agentName && storedTeammateOpts?.teamName) {
const addendum = getTeammatePromptAddendum().TEAMMATE_SYSTEM_PROMPT_ADDENDUM;
appendSystemPrompt = appendSystemPrompt ? `${appendSystemPrompt}\n\n${addendum}` : addendum;
}
而真实追加内容定义在 utils/swarm/teammatePromptAddendum.ts:
export const TEAMMATE_SYSTEM_PROMPT_ADDENDUM = `
# Agent Teammate Communication
IMPORTANT: You are running as an agent in a team. To communicate with anyone on your team:
- Use the SendMessage tool with \`to: "<name>"\` to send messages to specific teammates
- Use the SendMessage tool with \`to: "*"\` sparingly for team-wide broadcasts
Just writing a response in text is not visible to others on your team - you MUST use the SendMessage tool.
`
中文翻译
你正在以团队成员 Agent 的身份运行。
如果你要和团队中的其他成员沟通:
- 使用
SendMessage工具,并把to指向具体成员名字- 只有在必要时才使用
to: "*"进行全员广播仅仅输出普通文本,团队里的其他成员是看不到的。
你必须使用SendMessage工具。
这段 prompt 的本质
这不是“知识型提示词”,而是角色切换提示词。
它的目标不是让模型更懂代码,而是让模型理解:
- 自己当前处于什么身份
- 自己的可见性边界是什么
- 自己和其他 Agent 的沟通方式是什么
第五层:工具本身也带 prompt
Claude Code 的很多工具不是只有 schema,没有语言说明。
它们本身就带 prompt,用来指导模型“什么时候用、怎么用、不要怎么用”。
这也是 Claude Code 很重要的一层提示词工程。
1. Read 工具的 prompt
return `Reads a file from the local filesystem. You can access any file directly by using this tool.
Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid.
Usage:
- The file_path parameter must be an absolute path, not a relative path
- By default, it reads up to 2000 lines starting from the beginning of the file
- This tool can only read files, not directories. To read a directory, use an ls command via the Bash tool.
- You will regularly be asked to read screenshots. If the user provides a path to a screenshot, ALWAYS use this tool to view the file at the path.`
中文翻译
这个工具用于读取本地文件系统中的文件。你可以直接使用它访问任意文件。
如果用户给了一个文件路径,可以默认认为这个路径是有效的。使用规则:
file_path参数必须是绝对路径,不能是相对路径- 默认最多从文件开头读取 2000 行
- 这个工具只能读文件,不能读目录;如果要读目录,请通过 Bash 工具执行
ls- 用户经常会要求你读取截图;只要用户给了截图路径,就必须使用这个工具来查看
这类工具 prompt 的价值
它并不是在告诉模型“Read 工具存在”。
它是在告诉模型:
- 参数该怎么填
- 哪些输入是非法的
- 什么时候该用别的工具
- 多模态文件应该怎么读
这会直接影响模型的工具选择质量。
2. Bash 工具的 prompt
tools/BashTool/prompt.ts 非常长,因为它承担了大量 Shell 行为约束。
其中一段很关键:
Do NOT use the Bash tool to run commands when a relevant dedicated tool is provided.
To read files use Read instead of cat, head, tail, or sed
To edit files use Edit instead of sed or awk
To create files use Write instead of cat with heredoc or echo redirection
Reserve using the Bash tool exclusively for system commands and terminal operations that require shell execution.
中文翻译
当存在更合适的专用工具时,不要使用 Bash 工具。
- 读取文件时,使用
Read,不要用cat、head、tail或sed- 编辑文件时,使用
Edit,不要用sed或awk- 创建文件时,使用
Write,不要用 heredoc 的cat或echo重定向- Bash 工具应当保留给真正需要 Shell 执行的系统命令和终端操作
这段 prompt 的本质
它并不是在教模型 Shell,而是在做工具路由约束。
Claude Code 希望模型优先走结构化工具,而不是一上来就 cat、sed、echo 一把梭。
因为结构化工具更容易:
- 被审计
- 被权限系统管理
- 被前端可视化
- 被后续模型理解
3. ExitPlanMode 工具的 prompt
tools/ExitPlanModeTool/prompt.ts:
export const EXIT_PLAN_MODE_V2_TOOL_PROMPT = `Use this tool when you are in plan mode and have finished writing your plan to the plan file and are ready for user approval.
IMPORTANT: Only use this tool when the task requires planning the implementation steps of a task that requires writing code.
If you have unresolved questions about requirements or approach, use AskUserQuestion first.
Do NOT use AskUserQuestion to ask "Is this plan okay?" or "Should I proceed?" - that's exactly what THIS tool does.`
中文翻译
当你处于 Plan Mode,并且已经把计划写入 plan 文件、准备好让用户审批时,使用这个工具。
重要:只有当任务确实需要规划一个“要写代码的实现步骤”时,才能使用这个工具。
如果你对需求或方案仍有未解决的问题,先使用
AskUserQuestion。不要用
AskUserQuestion去问“这个计划可以吗?”或“我可以继续吗?”
这正是ExitPlanMode这个工具本身要完成的事情。
为什么这段 prompt 很有代表性
它体现了 Claude Code 的一个核心思路:
prompt 不只是教模型“做什么”,还要教模型“不同工具之间的职责边界”
也就是说,prompt 在这里承担了状态机约束的作用。
工具 prompt 的关系图
第六层:专项子系统也会单独维护自己的 prompt
Claude Code 里还有很多不直接面向用户主会话的 prompt。
这些 prompt 只服务某个子系统,但同样很重要。
1. /init 命令的 prompt
commands/init.ts 里有一大段 NEW_INIT_PROMPT,这是 /init 命令背后的完整工作说明。
开头就很典型:
const NEW_INIT_PROMPT = `Set up a minimal CLAUDE.md (and optionally skills and hooks) for this repo.
CLAUDE.md is loaded into every Claude Code session, so it must be concise — only include what Claude would get wrong without it.
## Phase 1: Ask what to set up
Use AskUserQuestion to find out what the user wants:
...`
中文翻译
为当前仓库建立一个最小但有效的
CLAUDE.md,必要时也可以建立 skills 和 hooks。
因为CLAUDE.md会被加载到每一次 Claude Code 会话里,所以它必须保持简洁,只保留 Claude 在默认情况下容易做错、但又必须知道的信息。第一阶段:先询问用户要设置什么。
使用AskUserQuestion弄清楚用户的真实需求。
这说明了什么
/init 并不是“写个模板文件”这么简单。
Anthropic 实际上是把一个完整的“仓库初始化顾问工作流”写进了 prompt。
2. 记忆筛选 prompt
memdir/findRelevantMemories.ts:
const SELECT_MEMORIES_SYSTEM_PROMPT = `You are selecting memories that will be useful to Claude Code as it processes a user's query.
Return a list of filenames for the memories that will clearly be useful to Claude Code as it processes the user's query (up to 5).
Only include memories that you are certain will be helpful based on their name and description.
If you are unsure if a memory will be useful, then do not include it. Be selective and discerning.`
中文翻译
你现在要从记忆库中挑选那些对 Claude Code 处理当前用户请求真正有帮助的记忆。
请返回一组文件名,最多 5 个。
只有当你能确定某个记忆根据其名称和描述确实有帮助时,才把它选出来。
如果你不确定它有没有用,就不要选。要保持克制和判断力。
这类 prompt 的特点
它不是为了生成用户可见回答,而是为了做检索裁剪。
它的目标是减少噪音,把真正相关的记忆塞回主会话。
3. Tool Use Summary prompt
services/toolUseSummary/toolUseSummaryGenerator.ts:
const TOOL_USE_SUMMARY_SYSTEM_PROMPT = `Write a short summary label describing what these tool calls accomplished.
It appears as a single-line row in a mobile app and truncates around 30 characters, so think git-commit-subject, not sentence.
Keep the verb in past tense and the most distinctive noun.
Drop articles, connectors, and long location context first.`
中文翻译
请写一个很短的摘要标签,用来描述这一批工具调用完成了什么。 它会显示在移动端应用的一行列表里,大约 30 个字符就会被截断,所以要像 Git commit 标题,而不是完整句子。
请使用过去式动词,并保留最有辨识度的名词。
优先删掉冠词、连接词和过长的位置上下文。
这段 prompt 的意义
这说明 Claude Code 已经把 prompt 用到了非常产品化的层面:
- 不是只驱动“主回答”
- 还驱动 UI 上的摘要文案
- 而且 prompt 里直接写了显示场景和长度约束
4. Prompt Suggestion prompt
services/PromptSuggestion/promptSuggestion.ts:
const SUGGESTION_PROMPT = `[SUGGESTION MODE: Suggest what the user might naturally type next into Claude Code.]
Your job is to predict what THEY would type - not what you think they should do.
THE TEST: Would they think "I was just about to type that"?
NEVER SUGGEST:
- Evaluative ("looks good", "thanks")
- Questions ("what about...?")
- Claude-voice ("Let me...", "I'll...", "Here's...")
- New ideas they didn't ask about
Reply with ONLY the suggestion, no quotes or explanation.`
中文翻译
你现在处于“提示建议模式”:请预测用户接下来最自然会输入什么。
你的任务是预测“他们自己会打什么”,而不是“你觉得他们应该做什么”。
判断标准是:用户看到这个建议时,会不会觉得“对,我刚刚正想这么输”。
绝对不要建议:
- 评价类文本,比如“看起来不错”“谢谢”
- 提问句
- Claude 自己的说话口吻,比如“让我来……”“我会……”
- 用户根本没有提过的新想法
只输出建议本身,不要带引号,也不要带解释。
为什么这段 prompt 很值得研究
它是典型的产品交互 prompt。
它不是面向“完成任务”,而是面向“预测用户下一句输入”,这已经非常接近产品里的推荐系统逻辑。
5. Agent 默认 prompt
Claude Code 给子 Agent 也准备了专门的默认 prompt。
constants/prompts.ts:
export const DEFAULT_AGENT_PROMPT = `You are an agent for Claude Code, Anthropic's official CLI for Claude.
Given the user's message, you should use the tools available to complete the task.
Complete the task fully—don't gold-plate, but don't leave it half-done.
When you complete the task, respond with a concise report covering what was done and any key findings.`
中文翻译
你是 Claude Code 的一个 Agent。
给定用户消息后,你应该使用可用工具完成任务。
任务要完成彻底,不要过度设计,但也不要做到一半就停。
完成后,请给出一份简洁报告,说明做了什么,以及最关键的发现。
它和主会话 prompt 的区别
主会话 prompt 更强调:
- 与用户沟通
- 安全边界
- 会话规则
而 Agent prompt 更强调:
- 接任务
- 用工具
- 完成闭环
- 向上汇报
这说明 Claude Code 在不同运行角色上,使用了不同 prompt 模板。
第七层:输出风格本身也是 prompt
Claude Code 连“输出风格”都是 prompt 化的。
constants/outputStyles.ts 里有一段 EXPLANATORY_FEATURE_PROMPT:
const EXPLANATORY_FEATURE_PROMPT = `
## Insights
In order to encourage learning, before and after writing code, always provide brief educational explanations about implementation choices ...
These insights should be included in the conversation, not in the codebase.`
中文翻译
为了鼓励学习,在写代码前后,都要简短解释实现方案的选择。
这些解释应该出现在对话里,而不是写进代码库。
这意味着什么
Claude Code 不只是用 prompt 控制“做什么”,还用 prompt 控制:
- 解释风格
- 教学深度
- 与用户的沟通方式
这本质上就是把“产品模式”实现成了 prompt。
Claude Code 的 prompt 结构总表
| 类型 | 源码位置 | 作用 | 典型内容 |
|---|---|---|---|
| 主会话 System Prompt | constants/prompts.ts | 定义身份、行为、安全边界 | 工具使用、任务风格、风险控制 |
| 动态 Section | constants/prompts.ts / queryContext.ts | 按会话动态拼装 | memory、env、language、output style、MCP |
| 用户覆盖与追加 | main.tsx / queryContext.ts | 支持 replace / append | systemPrompt、appendSystemPrompt |
| 角色附加 Prompt | teammatePromptAddendum.ts | 进入特定角色时修正行为 | teammate 通信规则 |
| 工具 Prompt | BashTool / FileReadTool / ExitPlanModeTool | 约束工具调用行为 | 参数规范、使用时机、职责边界 |
| 专项子系统 Prompt | init.ts / findRelevantMemories.ts / promptSuggestion.ts | 驱动某个子工作流 | 初始化、记忆筛选、下一句建议 |
| Agent Prompt | constants/prompts.ts | 给子 Agent 设定职责 | 完成任务并回报结果 |
| 输出风格 Prompt | outputStyles.ts | 改变表达方式 | Explanatory、Learning |
真正值得学的不是某一句 prompt,而是这种分层方法
如果你只盯着 Claude Code 某一段英文 prompt,很容易得出一个错误结论:
它厉害,是因为 prompt 写得长
但从源码看,更准确的结论应该是:
它厉害,是因为 prompt 被拆成了不同层,分别负责身份、工具、模式、子系统和交互风格,然后在运行时装配。
这套方法的好处很明显:
- 更容易维护
- 更容易做模式切换
- 更容易做 A/B 实验
- 更容易让不同工具拥有不同约束
- 更容易把 prompt 与产品逻辑绑定
小结
Claude Code 的提示词工程可以概括成一句话:
它不是一条总 prompt,而是一套由主会话 prompt、动态 section、工具 prompt、子系统 prompt、角色附加 prompt 共同组成的运行时提示词系统。
如果你想自己做一个类似 Claude Code 的产品,最值得借鉴的不是“抄 prompt”,而是这三个思路:
- 把 prompt 按职责拆层
- 让不同工具拥有自己的 prompt
- 让不同模式和子系统拥有独立 prompt,而不是全都塞进总提示词里