Skip to content

02.4 角色与系统提示词

System 与 User 的真实权重差异,以及人格锚定为什么会漂移。

读完你能做什么:写出不会在 30 轮对话后失效的角色设定,并知道该把哪条指令放在哪一层。


一、指令的四个层级

在任何一次推理中,你的指令可能存在于四个不同的位置,它们的权重和生命周期完全不同:

text
┌─────────────────────────────────────────────────────┐
│ L1  系统提示词 (System Prompt)                        │  ← 最稳定,全程有效
│     · Claude Code: --system-prompt / --append-*      │
│     · API: system 参数                                │
├─────────────────────────────────────────────────────┤
│ L2  项目级持久指令                                     │  ← 每次会话加载
│     · [Custom Instructions] (自定义指令)               │
│     · CLAUDE.md / .claude/rules/                     │
├─────────────────────────────────────────────────────┤
│ L3  会话内的早期消息                                    │  ← 会被稀释
│     · 你在第 1 轮定的规则                              │
├─────────────────────────────────────────────────────┤
│ L4  最近的一条消息                                     │  ← 权重最高,但只对本轮
│     · 你刚刚输入的内容                                 │
└─────────────────────────────────────────────────────┘

1.1 权重与生命周期矩阵

层级单次影响力持续时间适合放什么
L1 系统提示词全程身份、安全边界、绝不可违反的规则
L2 项目指令中高每次会话项目事实、团队规范、常驻约束
L3 早期消息中 → 低(随轮次衰减)直到被压缩本次任务的背景
L4 最近消息最高本轮具体任务、格式要求、关键强调

核心洞察:L4 的单轮影响力最高,L1 的持久性最强。把「必须永远遵守」的放 L1/L2,把「这一轮最重要」的放 L4。


二、角色设定(Role Prompting)

2.1 有效的角色 vs 无效的角色

text
❌ 你是一个乐于助人的 AI 助手
   → 零信息量。这是默认状态。

❌ 你是世界上最好的程序员
   → 空洞的赞美不改变输出分布

⚠️ 你是一名 Python 专家
   → 有一点作用,但太宽泛

✅ 你是一名有 10 年经验的 Python 后端工程师,长期在资源受限的小团队工作。
   你的风格是:优先选择标准库而非引入新依赖;宁可写笨一点但一眼能看懂的代码,
   也不写聪明的单行表达式;对性能问题先测量再优化。
   → 每一句都在收窄输出分布

判据:角色描述中的每一句话,都应该能改变模型在某个具体决策点上的选择。「10 年经验」→ 更保守;「资源受限小团队」→ 倾向简单方案;「先测量再优化」→ 不会一上来就给你一堆微优化。

2.2 角色的三个组成部分

text
<role>
{身份}:你是一名 XX 领域的 YY 角色,有 N 年 ZZ 方面的经验。
{倾向}:你的判断偏好是 AAA 而非 BBB。
{风格}:你的输出习惯是 CCC。
</role>

实例:

text
<role>
身份:你是一名安全审计工程师,主要经验在 Web 应用渗透测试与代码审计。
倾向:你假设所有外部输入都是恶意的;你更关心"能不能被利用"而非"是否符合规范";
      对于理论上存在但实际不可达的漏洞,你会明确标注为「低优先级」而不是渲染成危机。
风格:每条发现给出「攻击路径」而非仅仅「代码有问题」。没有发现时直接说没有,
      不列举可能性来充数。
</role>

三、人格漂移:为什么 30 轮后它不听话了

3.1 现象

会话开头你说「回答要简洁,不超过 3 句」,前 10 轮它遵守得很好,第 30 轮开始又变啰嗦了。

3.2 机制

三个叠加的因素:

  1. 相对位置衰减 —— 你的规则在第 1 轮,现在是第 30 轮。中间隔了几万 token。规则在整个上下文中所占的"注意力份额"被大量新内容摊薄。
  2. 自身输出的反向示范 —— 如果中间有几轮它的回答偏长而你没纠正,这些长回答本身成了上下文中的"示例",模型会认为长回答是被接受的。这是最强的一个因素。
  3. 压缩损耗 —— 会话触发 /compact 后,早期的规则可能被摘要成一句「用户要求简洁」,丧失了具体性。

3.3 三种修复手段

手段 A:把规则提升到 L1/L2

bash
# Claude Code:追加到系统提示词
claude --append-system-prompt "所有回答控制在 5 句话以内。禁止写开场白和结尾总结。"

或写进 CLAUDE.md

markdown
## 输出规范
- 回答控制在 5 句话以内
- 禁止开场白("好的,我来帮你...")和结尾总结("总的来说...")
- 代码优先于散文

系统提示词和 CLAUDE.md 不会随轮次衰减,且 CLAUDE.md 在 /compact 后会被重新注入。

手段 B:定期重申(L4 强化)

text
> 提醒:接下来所有回答仍然遵守 5 句话以内的限制。

成本低但需要你手动做。 适合临时性的规则。

手段 C:清理被污染的上下文

[Edit] (编辑) 回到偏离开始的那一轮,或者直接 /clear 重开。见 01.2 界面全解

完整机制分析见 04.2 注意力机制自白


四、Claude Code 的系统提示词控制

Claude Code 提供四个 flag,粒度很细:

Flag行为用途
--system-prompt替换整个默认提示词完全改变身份(非编码 Agent)
--system-prompt-file用文件内容替换同上,但提示词较长
--append-system-prompt追加到默认提示词末尾加规则,保留编码能力
--append-system-prompt-file追加文件内容同上

4.1 什么时候用 append,什么时候用 replace

bash
# ✅ append:它仍然是编码助手,只是多了规则
claude --append-system-prompt "所有 TypeScript 代码必须开启 strict 模式。禁止使用 any。"

# ⚠️ replace:它不再是编码助手了
claude --system-prompt "你是一个日志分析器。读取输入的日志,输出 JSON 格式的异常统计。不要解释。"

重要--system-prompt 会丢弃 Claude Code 的全部默认提示词,包括工具使用指导和安全指令。用它意味着你要为工具调用行为的正确性负责。

4.2 组合规则

  • --system-prompt--system-prompt-file 互斥
  • append 类 flag 可以和 replace 类组合使用

五、Output Styles(输出风格)

对于需要在不同人格间反复切换的场景,比每次传 flag 更好的方案是 output styles。

text
> /output-style

它把人格配置持久化成可切换、可共享的配置,适合:

  • 同一个项目里,"写代码"和"写文档"需要不同风格
  • 团队共享统一的输出规范

六、System vs User:一个常见误解

误解:「把规则放系统提示词里,模型就一定会遵守。」

真相:系统提示词的权重更高、更稳定,但它仍然是概率性的影响,不是硬性开关

在 Claude Code 的官方文档里有一句很关键的说明:CLAUDE.md 的内容是作为系统提示词之后的用户消息递送的,不是系统提示词本身 —— 它会被读取并尽力遵守,但不保证严格合规。

6.1 什么时候必须用硬性机制

如果某条规则必须执行,不能依赖概率,就不该用提示词,应该用 hook:

需求错误方案正确方案
禁止执行 rm -rfCLAUDE.md 写「不要用 rm -rf」PreToolUse hook 拦截
每次编辑后必须格式化提示词要求PostToolUse hook 自动跑 formatter
禁止读取 .env提示词要求permissions.deny 规则
提交前必须跑测试提示词要求PreToolUse hook 匹配 Bash(git commit *)

这是本手册反复强调的一条界线:提示词管"倾向",hook 和权限管"边界"。 详见 06.5 Hooks 生命周期钩子


七、可复制的系统提示词模板

7.1 严谨型(技术工作)

text
<identity>
你是一名资深工程师,为一个 4 人的后端团队工作。
</identity>

<epistemics>
- 区分「我知道」「我推测」「我不知道」,并明确标注
- 引用代码时给出文件路径和行号
- 不确定 API 行为时,先查文档或跑一次验证,不要凭印象回答
- 用户说你错了时,先验证再认错,不要立刻附和
</epistemics>

<style>
- 直接给答案,不写开场白
- 能用代码或表格说清的不写段落
- 有取舍时明确列出取舍,不要只推荐一个方案却不说代价
</style>

<hard_rules>
- 金额计算一律用定点数类型,禁止浮点
- 不主动执行破坏性操作(删除、drop、force push),必须先请示
</hard_rules>

7.2 教学型(学习场景)

text
<identity>
你是一名技术导师,面向有编程基础但对本领域陌生的学习者。
</identity>

<method>
- 先给出一个可运行的最小例子,再解释原理
- 每引入一个新概念,立刻给一个"如果不用它会怎样"的对照
- 主动指出学习者可能形成的错误直觉
</method>

<style>
- 不使用"很简单""显而易见"这类词
- 每次解释后给一个 30 秒能验证的小实验
</style>

延伸阅读

基于 VitePress 构建 · 内容采用原作者授权