深色模式
系统提示词与角色设计
摘要:本文面向构建长期运行、需稳定行为的 AI 应用的工程师。覆盖系统提示词(system prompt)的核心职责、角色设定三要素、用 XML 标签/分隔符隔离不同区块、长上下文下「文档在前、问题在后」的摆放原则、预填充(prefill)引导格式,以及把 prompt 当代码管理的工程化方法。适用模型:Claude 4 系列(上下文 200K)、GPT-4o(128K);功能与数值标注
[版本相关]。
核心概念:系统提示词是什么
系统提示词是每次请求都携带的「固定指令层」,定义模型身份、行为边界、输出格式。它与用户消息分离,是应用可控性的主入口。Anthropic 官方针对 Claude 4 提出四条基础原则:明确具体(Be Explicit)、提供上下文(Add Context)、谨慎示例(Vigilant with Examples)、积极指导(Tell What TO Do)——即「告诉模型做什么」比「不要做什么」更有效。
角色设定三要素
- 身份:你是谁(如「资深 SRE」「法律顾问」)。
- 背景:在什么场景下工作(如「排查生产 K8s 告警」)。
- 任务:要完成什么目标(如「给出根因与可执行命令」)。 角色不是装饰,而是激活模型对应知识的开关。但注意:角色本身不能替代安全边界,见 提示注入攻防。
架构与原理:prompt 是「固定 + 变量」的模板
把 prompt 拆成固定部分(角色、输出格式、规则)与变量部分(用户输入、检索结果),用占位符(如 )做成可复用模板。这正是把 prompt 当「代码」而非随手文本管理的核心。
生产实践
长上下文摆放顺序(Anthropic 官方建议)
当上下文很长(Claude 支持到 200K tokens),把大段文档放在问题之前,而不是之后;用 <documents> 等标签包裹;对多文档编号 <document index="1">。模型对开头与结尾信息召回更可靠(Lost-in-the-Middle,见 上下文窗口),关键查询放最后。
1. 用 XML 标签清晰分隔(Anthropic 强烈推荐)
text
你是一个文本分类专家。
<context>
{{retrieved_docs}}
</context>
<task>
请按以下步骤操作:
1. 找出句子的关键概念
2. 匹配最相关的 3 个标题
3. 选出最佳答案
</task>
<output_format>
只输出标题名称,不要解释。
</output_format>
<sentence_to_classify>
{{sentence}}
</sentence_to_classify>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2. 积极指导而非禁止
text
# 反例(消极)
不要使用 markdown,不要用列表,不要解释。
# 正例(积极)
用一段流畅中文回答;如需列举,使用编号句子;直接给结论,不展开解释。1
2
3
4
5
2
3
4
5
3. 预填充(Prefilling)引导格式
在 assistant 消息开头预填片段,强制模型延续该格式。需要 JSON 时预填 {:
python
# Anthropic 预填充示例 [未实测,示意]
msg = client.messages.create(
model="claude-3-5-sonnet-20240620",
max_tokens=1024,
messages=[
{"role": "user", "content": "把下面工单结构化为 JSON:{{ticket}}"},
{"role": "assistant", "content": "{"}, # 预填,引导模型补全合法 JSON
],
)1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
4. 提供上下文的理由(让规则可迁移)
Anthropic 强调:解释「为什么」比只给规则更好。例如把「绝不用省略号」改为「因为输出会被语音朗读,所以不要用省略号」。理由帮助模型在新场景泛化。
操作步骤:把 prompt 当代码管理
1. 模板化 + Git 版本化
python
# system_prompt.py —— 纳入 Git,变更走 PR 与 eval
SYSTEM = """你是资深 SRE,负责线上告警初判。
背景:告警来自 Prometheus,需快速定位。
规则:
1. 先给最可能的 3 个根因
2. 每个根因配一条可执行命令
3. 仅输出 JSON:{{"root_causes":[...],"commands":[...]}}
原因:下游系统直接解析 JSON 触发自愈。
"""1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
2. 用 eval 集回归(见 principles.md 原则 6)
bash
# 伪命令:回归系统提示变更 [未实测,按你的框架替换]
pytest tests/system_prompt_eval.py --model claude-3-5-sonnet-202406201
2
2
验证
- 单元层:单一复杂用例确认角色/格式生效。
- 对抗层:尝试让模型越界(泄露规则、忽略格式),确认边界稳固。
- 集合层:eval 集统计格式合规率与越界率。
回滚与清理
系统提示是全局行为开关
改系统提示会一次性改变所有用户请求的表现。变更前保留旧版与 eval 基线,通过配置中心或模型路由秒级回滚。不要把系统提示硬编码在多个仓库。
故障排查
| 现象 | 原因 | 处理 |
|---|---|---|
| 模型忽略格式 | 指令被长文档淹没 | 用 XML 标签隔离 + 格式置后 |
| 角色「入戏」不足 | 角色描述太泛 | 补身份/背景/任务三要素 |
| 长文档中段信息丢失 | Lost-in-the-Middle | 文档前置、查询置尾、改 RAG |
| 输出混入解释 | 用了消极禁止 | 改为积极指导 |
| 频繁越界/泄露规则 | 边界未硬化 | 显式边界 + 输入隔离(见注入篇) |
安全与合规
- 系统提示可能含业务规则甚至密钥占位,属敏感资产:纳入访问管控,避免被用户提取(OWASP LLM07 系统提示泄露)。
- 角色不能替代权限控制:即使 system 说「不能调用危险工具」,Agent 仍可能因注入而尝试——权限须在运行时(工具层)收紧。
- 多租户场景:系统提示中的变量部分须做好租户隔离,防止跨租户内容串味。
成本与性能
- 系统提示通常是固定前缀,每次请求都重复发送。长系统提示(含大量规则/示例)可用 上下文压缩与缓存 摊薄成本——例如 Anthropic Prompt Caching 对 5 分钟 TTL 的缓存读取仅收基础输入价的 10%。
- 示例越多、规则越细,输入 token 越多,但换来更稳定的行为,通常划算。
- 模型选型:Claude 4 对长、结构化 system prompt 表现强;简单场景可用小模型降成本
[版本相关,价格以官网为准]。