
一、一个常见误会
1.1 人设思维的问题
一说起 system prompt,很多人首先想到的是一段熟悉的话术:你是谁、你擅长什么、最好再有一点稳定人格。对聊天系统这种理解够用,对要读文件、调工具、动 shell、跨轮执行的代理系统则明显不够。
人设 解决的是"它像什么",控制平面 解决的是"它能做什么、什么时候做、做错了怎么办、谁来兜底"。两者不在同一层。
1.2 Claude Code 的答案
Claude Code 的实现说明了这一点:它的 system prompt 是一组分层拼装的行为区块,更接近一套运行时协议,而不是一篇人物小传。
二、分层结构:Prompt 从一开始就不是一块整布
2.1 多 Section 拼装
在 getSystemPrompt() 里,Claude Code 返回的是一个由多个 section 组成的数组,而不是一段完整字符串。这个细节很重要------一旦 prompt 变成多个块,系统就正式承认它内部包含一组职责不同的约束。
2.2 三类核心内容
这些 section 至少包含三类东西:
第一,身份和总任务说明。 系统说明自己是一个交互式代理,要用可用工具帮助用户完成软件工程任务,同时嵌入了一些安全约束,比如不要乱猜 URL。
第二,系统级规则。 系统明确规定:
-
用户能看见的是哪些文本
-
工具调用可能触发权限审批
-
用户拒绝后不能机械重试
-
tool result 和 user message 里可能混入 system-reminder
-
上下文会被自动压缩
这些内容有一个显著特征:它们并不关心模型"像不像一个聪明助手",而是关心它是否是一个守规矩的执行体。这就是控制平面的语气,它的核心任务是定义边界。
第三,工程性指令。 不要随意增加需求,不要越权优化,不要为了让结果显得完整而隐瞒验证失败,不要在没有必要时制造抽象。这些内容看起来像写作风格要求,其实它们和工程约束绑得很紧。一个会自动"顺手优化一切"的模型,从产品角度看也许很热情,从工程角度看则相当危险。
所以,从源码结构上就能看出来:Claude Code 的 prompt 要解决的是如何让模型在复杂运行时里遵守边界。
三、优先级:Prompt 真正的价值不在文字本身
3.1 明确的优先级链
如果 prompt 只是写在那里,还不够说明问题。真正决定它是否属于控制平面的,是系统是否给它定义了严格优先级。
buildEffectiveSystemPrompt()把 prompt 的来源明确排成一条链:
override system prompt(覆盖系统提示)
coordinator system prompt(协调系统提示)
agent system prompt(代理系统提示)
custom system prompt(自定义系统提示)
default system prompt(默认系统提示)
最后还会统一拼接 appendSystemPrompt。
3.2 特例与不变式
proactive mode 的处理更直白:如果 agent prompt 和 proactive mode 同时存在,agent prompt 不再替换默认 prompt,而是附加在其后。通用制度可以叠加岗位说明书,但不能被岗位说明书直接冲掉。
核心骨架如下:
python
sources = [override, coordinator, agent, custom, default]
base = first_present(sources) // 高优先级源会整段替换默认
if proactive_mode and agent:
base = default + agent // 特例:叠加而非替换
return base + appendSystemPrompt // append 永远在最后一层
三条不变式:
1. 基线必须唯一 —— 存在且只有一个 base 2. 顺序硬编码 —— 不靠"后写为准" 3. append 只能附加 —— 不替换任何内容
这三条一旦被破坏,prompt 就会退化成一块谁后写谁说了算的涂鸦板。
四、记忆系统:Prompt 不只是约束当前行为
4.1 连接长期记忆
如果说前面这些内容已经像一套运行时说明书,那么看到 Claude Code 如何处理 memory 和 CLAUDE.md 后,就会更清楚地意识到:这里的 prompt 已经是整个上下文治理入口,而不只是"写给模型看的一段话"。
系统会把 project instructions、local instructions、team memory、auto memory 等不同来源的内容整理成统一格式,再拼接进 prompt 相关上下文中,连每种内容的来源说明都写得很细。
4.2 用 Prompt 规定记忆如何形成
更关键的是,系统连"如何保存记忆"这件事都变成了 prompt 的一部分。它会明确告诉模型:
-
memory 是文件化持久系统
-
MEMORY.md是索引,不是正文 -
要如何写 frontmatter
-
哪些信息不该保存
-
plan 和 task 不该被误用成 memory
这件事非常关键。它把 prompt 的职责从"约束当前行为"扩展到了**"约束未来知识的沉淀方式"**。这已经超出了通常意义上的提示词,更接近一份写给运行时参与者的知识治理协议。
换句话说,Claude Code 不只是用 prompt 规定"这一轮怎么说话",还用 prompt 规定"长期记忆如何形成"。一个系统只要走到这一步,它的 prompt 就不可能再只是语气问题,而必然进入制度问题。
五、缓存与成本:控制平面还要算账
5.1 Prompt 也是计算成本
多数人理解 prompt 时,很少会想到性能。常见想法是 prompt 只是喂给模型的文本,写好即可。Claude Code 的实现更务实:prompt 同时也是计算成本。它越复杂、变化越频繁,缓存命中就越差,系统运行就越贵、越慢。
5.2 可缓存与不可缓存
系统把 prompt section 区分成两类:
-
可缓存的
systemPromptSection -
会打破缓存的
DANGEROUS_uncachedSystemPromptSection
而 resolveSystemPromptSections() 会优先从缓存里拿已经计算过的内容,只在必要时重算。系统还会在 /clear 或 /compact 之后清空这些状态。
这件事看起来像优化,实际上同样属于控制平面。一个真正可运行的 prompt 系统,不可能只考虑表达能力,而不考虑它对吞吐、延迟和缓存的影响。系统甚至把静态部分和动态部分用 boundary 显式分开------这说明它在设计时已经承认:有些内容在会话中相对稳定,有些内容会逐轮变化,二者不能混在一起消耗缓存。
一个工程系统只要开始关心"哪部分 prompt 会导致缓存失效",它就已经不再把 prompt 当作文案创作。文案追求完整表达,控制平面追求可治理、可复用、可预测的行为成本。
六、用户覆盖:可以改内容,但不能跳过结构
6.1 支持自定义
Claude Code 并没有把用户锁死在默认 prompt 上。CLI 明确支持覆盖和追加:--system-prompt、--system-prompt-file、--append-system-prompt、--append-system-prompt-file 等选项。用户当然可以带着自己的规约来。
6.2 秩序优先
但这里有个关键点:系统虽然允许覆盖和追加,却仍然坚持用统一的 buildEffectiveSystemPrompt() 做最终装配。这说明它允许自定义,但不放弃秩序。用户可以改内容,系统仍然保留结构。
没有结构的可定制,最后往往会退化成另一种随意。今天加一段,明天减一段,后天某个 agent 又替换掉基线约束,系统行为就会越来越像临时口头通知。Claude Code 的选择是让用户修改,但修改必须发生在既定优先级和分层机制里。
七、为什么说 Prompt 更像宪法,而不是台词
7.1 台词 vs 宪法
如果把前面各节放在一起看,可以得到一个相当明确的结论:Claude Code 的 prompt 更像宪法。
所谓台词,是给角色在场上说的;所谓宪法,是规定权力边界、责任关系和例外情况如何处理。Claude Code 的 prompt 更接近后者。
7.2 五个结构条件
它满足了几个结构条件:
| 维度 | 说明 |
|---|---|
| 分层 | 不是一块写到底 |
| 优先级 | 不是谁后写谁说了算 |
| 完整控制平面 | 与 memory、CLAUDE.md、agent instructions、MCP instructions 一起组成 |
| 缓存机制 | 有缓存和动态 section 机制,不是随手拼一段文本 |
| 与 Runtime 耦合 | 不是游离于系统之外的装饰物 |
这也是为什么"写一个好 prompt"单独拿出来时价值有限。更重要的问题是:prompt 在系统里处于什么位置,它和哪些模块配合,它是否参与权限、状态、上下文和长期记忆的治理。如果不回答这些问题,所谓好 prompt 往往只是在某个顺利场景里暂时成立。
八、总结
8.1 核心原则
这一章可以归纳成一句话:
Prompt 的价值,在于它是否被纳入一套清楚的控制结构。
8.2 五个源码位置指向同一结论
| 源码位置 | 结论 |
|---|---|
constants/prompts.ts |
prompt 写成分段控制结构,不是统一宣言 |
utils/systemPrompt.ts |
明确规定了 prompt 来源的优先级 |
utils/claudemd.ts |
项目级和长期记忆内容纳入上下文装配 |
memdir/memdir.ts |
用 prompt 规定了长期记忆的保存规则 |
constants/systemPromptSections.ts |
prompt 变成可缓存、可失效、可按段重算的运行时对象 |
8.3 最终结论
所以,一个成熟代理系统里的 prompt,不该被理解成"让模型入戏的开场白"。它更像一套运行中的制度文本 。制度文本当然也可以写得清楚,但最重要的部分始终是约束力。