在这里插入图片描述

目录

  1. 系统提示词的解剖
  2. 从零写一份生产级系统提示词
  3. 版本管理与回归测试
  4. token预算与压缩
  5. 系统提示词与RAG的配合
  6. 多智能体场景的元指令分工
  7. 泄露风险与防泄露
  8. 反模式与检查清单

摘要

系统提示词是元指令最大的工程载体,写得好坏直接决定应用的输出协议、边界与成本。本文把它的写作拆成角色、边界、协议、风格四块结构,给出一份生产级实例与版本管理、回归测试的代码化方案。后半篇覆盖 token 预算、RAG 分工、多智能体元指令、泄露防御四个进阶场景。

1. 系统提示词的解剖

第 1 篇确立了元指令的判据:以模型行为为作用对象。系统提示词是元指令最集中的落点,也是工程上最常被写坏的一份文本。把它拆成结构,坏点才看得见。

1.1 四大块结构

一份合格的系统提示词由四个功能块组成,各自回答一个固定问题:

图:系统提示词的四大功能块

系统提示词

角色定义

能力边界

输出协议

风格规则

决定口吻与视角

决定做与不做

决定输出形态

决定语言与禁忌

图下解读:四块缺任何一块,对应的行为就交给模型默认习惯。默认习惯与业务预期不一致时,线上表现就是随机漂移。

四块的职责与写坏的症状一一对应:

功能块回答的问题典型规模写坏的症状
角色定义你是谁两到三句口吻漂移,专业度不稳
能力边界做什么不做什么三到五条越界答题,拒绝缺失
输出协议输出长什么样一段格式约定解析失败,下游报错
风格规则用什么语言腔调不超过三条中英混杂,风格跳变

规模一栏是经验区间。角色写半页纸、风格写十几条的版本都见过,实际效果不如精简版,原因在下一节。

1.2 每块写多细:可判定性判据

粒度的判据只有一条:能不能判定违规。能力边界里的"只处理工单分诊"可判定,越界回答一眼可查;风格规则里的"既要亲切又要专业"不可判定,模型只能各拍各的。

两种写法的差距看角色块就够:

弱写法:你是一个乐于助人的助手。
强写法:你有五年运维背景的工单分诊员,面向内部运维同事,
        可以直接使用术语,不需要解释基础概念。

弱写法没有错,但它把"乐于助人"的解释权完全交给模型。强写法把受众、知识背景、术语尺度全部钉死,同样的四个问题在两份提示词下会得到两档稳定性的回答。

边界讨论:规则总量要有上限。第 1 篇的宪法式规则集实验给出的经验值是二十条以内,超过后服从率明显下滑。写不下时,正确动作是拆任务族模板,不是往一份里硬塞。

可判定性判据的落地方法:写完每条规则后在旁边标注"怎么验"。能写出验证动作的留,写不出的改写成能验的,改不动的删掉。这个动作三十秒一条,一整份提示词十分钟过完,产出的验证清单直接就是第 3 章回归用例集的种子。

判据还能反过来用:模型表现不稳的地方,先查对应的规则是不是不可判定。线上口吻忽正式忽随意,多半是风格块写了"亲切且专业"这类双重要求,模型在两个解释间随机摆。把双重要求拆成两条可判定的单句,摆动立刻消失。

1.3 从 Demo 到生产的三道坎

同一份系统提示词,demo 与生产之间隔着三道坎:

坎demo 表现生产要求
输出协议肉眼看着像 JSON字段级可解析可校验
边界行为常见问题答得好越界与拒答路径全覆盖
成本提示词多长无所谓token 预算与缓存策略

三道坎对应后文三章的工程动作:协议坎靠回归测试与结构化输出,边界坎靠用例与仲裁,成本坎靠预算表与压缩。demo 的通过标准是演示成功,生产的通过标准是失败可控。

写提示词之前先想清楚目标形态,能省掉一半返工。给老板演示的版本和扛线上流量的版本,从第一行就该不一样。

三道坎还有个时间维度容易被忽略:demo 阶段没踩过的坑,生产头一周会集中踩一遍。预留一周的灰度缓冲,把三道坎在真实流量下各过一遍,比上线后救火便宜一个数量级。灰度期间的通过标准提前写死:解析失败率、越界回答率、token 成本三项,任何一项超线就暂停放量。

结构清楚了,下一章动手写一份完整的。

2. 从零写一份生产级系统提示词

2.1 完整实例:工单分诊助手

选一个真实业务场景:运维平台要把用户工单转给正确的处理组。下面这份系统提示词四块齐全,可以直接投产:

// 来源:自实现 / triage_system_prompt.txt(生产骨架)
你是「快修云」工单分诊助手。

## 角色定义
你有五年运维背景,负责把用户工单转给正确的处理组。

## 能力边界
只处理工单分诊。用户询问价格、法律、医疗话题时,回复超出
范围并引导创建普通咨询工单。
无法确定处理组时归入待人工分诊,不允许猜测。

## 输出协议
每次输出一个 JSON 对象,字段如下:
category:处理组,取值 network、database、account 或 pending
confidence:0 到 1 之间的置信度
reason:不超过 30 字的分诊理由
禁止输出 JSON 以外的任何文字。

## 风格规则
使用简体中文。reason 面向运维同事,允许使用术语。

源码说明:四块各就各位之外,还有两个容易忽略的设计。能力边界里写了兜底动作"归入待人工分诊",不确定时有路可走,模型才不会硬猜。输出协议用字段级描述而不是给整段示例,省 token 且无歧义。

2.2 迭代:写完才是开始

系统提示词没有一次写对的,迭代靠固定循环:

图:系统提示词的迭代循环

是

否

写初版

固定用例回测

达标吗

小流量灰度

定位失败用例

修改对应功能块

线上监控反馈

图下解读:循环的入口是固定用例集,出口是灰度。没有固定用例集的迭代等于裸奔,每次改动的影响范围无从知晓。

迭代期内最常见的四类修改动因,各自对应不同的功能块:

修改动因典型表现应改的块
解析失败率上升下游报 JSON 错误输出协议
越界回答答了不该答的问题能力边界
口吻投诉太随意或太生硬角色定义
成本超标单次请求 token 超预算全部,做压缩

2.3 写作顺序与同级评审

四大块的写作顺序影响质量。推荐顺序是能力边界最先写,因为它定义做不做;输出协议次之,它对接下游;角色定义第三,它决定口吻;风格规则最后,多数场景它是可选项。

这个顺序的反直觉之处在角色后置。多数人从"你是一个…"起笔,写完角色才开始想边界,结果边界被角色的热情稀释。先把不做的写清楚,角色的活动范围自然收敛,两块不会打架。

评审用同构检查:四大块各自一栏,逐行问三个问题,这条可判定吗、与其他块冲突吗、哪个用例能击穿它。同级评审一小时能过完一份中型提示词,发现的冲突比线上运行一周更多。

评审还有个前置条件容易漏:评审人手里的用例集要与写手一致。写手心里的边界用例与评审人的不同,同一份提示词会得出相反的评价。开评前先对齐用例集十分钟,比评审中争吵一小时有效。评审的产出不只是修改意见,还有更新后的用例集,两份资产同步演进。

动因定位到块,修改就不至于牵一发动全身。这份迭代能力要成立,前提是提示词有版本和测试,这正是下一章的主题。

评审的产出还要有个固定格式:一张标记表,每条规则一行,三列分别是规则编号、判定结果(通过、存疑、不通过)、备注。存疑的规则标记具体的用例编号,下次评审时优先复查。这张表本身进版本库,与提示词文件一起提交,让每次评审的结论都可追溯。

3. 版本管理与回归测试

3.1 提示词注册表

提示词改动没有版本管理,回滚就靠翻聊天记录。一个够用的注册表三十行不到:

# 来源:自实现 / prompt_registry.py(提示词注册表)
import time
from pathlib import Path

class PromptRegistry:
    def __init__(self, base_dir: str = "prompts"):
        self.base = Path(base_dir)

    def save(self, name: str, text: str) -> str:
        # 版本号用时间戳,天然递增且不可复用
        version = time.strftime("%Y%m%d%H%M%S")
        path = self.base / name / f"{version}.txt"
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(text, encoding="utf-8")
        return version

    def load(self, name: str, version: str = "latest") -> str:
        d = self.base / name
        if version == "latest":
            version = sorted(p.stem for p in d.glob("*.txt"))[-1]
        return (d / f"{version}.txt").read_text(encoding="utf-8")

if __name__ == "__main__":
    reg = PromptRegistry()
    v = reg.save("triage", "你是快修云工单分诊助手")
    print(v, len(reg.load("triage")))

源码说明:save 永远新增文件不覆盖,任何历史版本都可回取;load 默认取最新,测试时显式传版本号做对照。注册表落盘后,git 只需管目录,回滚变成指定版本号的字符串。

图:带版本管理的发布回路

是

否

修改提示词

存入注册表带版本号

固定用例集回归

通过吗

发布新版本号

回滚上一版本

图下解读:回路的关键是发布与代码同构:版本号、回归、灰度、回滚四件套一件不少。提示词从"一段字符串"升级成"一个可运维的制品"。

3.2 回归测试:固定用例集

固定用例集是迭代的锚点。用例数量十到三十条,覆盖正常、边界、越界三类,断言只检查输出协议与关键判定:

# 来源:自实现 / test_triage_prompt.py(回归测试骨架)
import json
from prompt_registry import PromptRegistry

CASES = [
    {"in": "数据库连不上了,报错连接超时",
     "want": {"category": "database"}},
    {"in": "帮我算算企业版一年多少钱",
     "want": {"category": None}},      # 越界,应拒答引导
    {"in": "密码忘了怎么找回",
     "want": {"category": "account"}},
]

def run_cases(system_text: str, chat) -> int:
    # chat 为接真实或模拟模型的回调函数
    passed = 0
    for c in CASES:
        resp = chat(system_text, c["in"])
        try:
            out = json.loads(resp)
        except json.JSONDecodeError:
            continue                    # 协议失败直接判不过
        if out.get("category") == c["want"]["category"]:
            passed += 1
    return passed

if __name__ == "__main__":
    reg = PromptRegistry()
    cur = reg.load("triage")
    print("通过用例数", run_cases(cur, chat))

源码说明:断言分两级,JSON 可解析是协议级,category 判对是语义级。两级分开统计后,失败原因一眼可辨:协议挂了查输出协议块,语义挂了查能力边界块。

回归要对照跑:新版本与当前线上版本各跑一遍,通过数只增不减才能发布。偶发失败用固定随机种子与低温采样压平,把模型随机性从测试变量里剔除。

4. token预算与压缩

4.1 窗口是预算表

上下文窗口是稀缺资源,每一块都该有配额。以下是一份 8K 窗口的示例分配,数字本身可调,配额思想不可省:

用途预算占比说明
系统提示词800一成四大块齐全的常量
少样本示例1200一成半两到三个精简示例
检索上下文3500近半RAG 检索结果
对话历史1500不足两成滑动窗口截断
输出预留1000一成多按业务最长输出定

预算不齐的常见后果是输出被截断:输入把窗口吃光,模型写到一半戛然而止。输出预留是雷打不动的一格,谁也不能挪用。

粗估工具让预算可执行:

# 来源:自实现 / token_est.py(中文 token 粗估)
def est_tokens(text: str) -> int:
    # 中文一字按一点五个 token,其他文本四字符一个 token
    cn = sum(1 for ch in text if "\u4e00" <= ch <= "\u9fff")
    other = len(text) - cn
    return int(cn * 1.5 + other / 4)

if __name__ == "__main__":
    s = "你是快修云工单分诊助手,输出 JSON 格式的分诊结果。"
    print(est_tokens(s))  # 约 30 token

源码说明:粗估误差在两成以内,做预算表足够。精确计数要用目标模型自己的 tokenizer,上线前以精确数为准校一次表。

图:超限时各块的让位顺序

是

否

是

否

上下文窗口超限

先截对话历史

还超吗

再减检索条数

通过

还超吗

最后瘦身示例

图下解读:让位顺序反映信息的新鲜度排序:历史最旧先砍,检索次之,示例最后。系统提示词与输出预留不在让位序列里,前者是行为契约,后者是交付空间。

4.2 压缩手段与底线

预算内的压缩按收益排序:删连接词与重复限定、合并同类规则、示例瘦身。一段三百 token 的系统提示词,压到两百 token 通常不损行为,因为删掉的多是礼貌性填充。

底线只有一条:输出协议不可压。字段定义、取值范围、禁止事项一个字都不能省,协议块的每个词都在为解析成功率付费。压协议省下的 token,会以十倍的代价还在线上解析失败里。

边界讨论:压缩有收益递减。系统提示词压到一百 token 以下时,四大块开始互相侵占,行为稳定性先于成本崩掉。合理区间是一百五到八百 token,低于下限通常说明职责拆得太散,高于上限该拆任务族模板。

预算表也不是一次写就的文档。每月复算一次:系统提示词的长度随规则增删在变,检索片段的平均长度随文档库在变,两个漂移源都足够悄悄吃掉输出预留。复算只要跑一遍 est_tokens 加一段统计,十分钟的成本,换的是不发生线上截断事故。

系统提示词管行为,检索管事实,两件事的边界下一章划清。

压缩还有个心理陷阱值得点名:压缩过程本身有成就感,每删掉一段都觉得赚了 token,但没人回头验证删掉的规则是否真的无效。正确的动作是每次压缩后跑一遍回归用例集,通过数不降才算压缩成功。不跑回归的压缩等于闭眼删代码,偶尔会删到承重墙。

5. 系统提示词与RAG的配合

5.1 分工边界

RAG(检索增强生成)负责把外部知识实时拼进上下文。它与系统提示词的分工原则一句话:行为进提示词,事实进检索库。

图:一次 RAG 请求的组装时序

模型 组装器 检索器 用户 模型 组装器 检索器 用户 提问 发起相似度检索 返回相关文档片段 系统提示词加片段拼装 发送完整请求 按输出协议作答

图下解读:组装器是分层思想的落点。系统提示词是常量骨架,检索片段是动态血肉,两者在组装器相遇,各管各的失效模式:行为漂移查提示词版本,答案过期查检索库更新。

四条判据决定一段内容放哪边:

判据放系统提示词放检索库
变化频率稳定不变随时更新
体量几百 token 内无上限
内容性质行为约定事实数据
失效后果行为漂移答案过期

5.2 最常见的错位

典型错位是把领域知识写进系统提示词:产品价格表、故障案例库、API 文档,几百行贴进去。三个恶果随即而来:每次请求都为不相关的知识付 token;价格一改就要发版提示词;模型引用的还是旧价。

反向错位同样存在:把行为规则做成检索文档。规则只在被检索命中时生效,没命中就失忆,分诊助手的输出协议时有时无,多半是这种病。

排查方法用四条判据逐项过:变化频率高于每周的,挪检索库;体量超一千 token 的,挪检索库;内容是行为约定的,挪系统提示词。挪完跑一遍回归用例集,行为无回退即切换完成。

错位的修复有个顺序陷阱:把知识从提示词挪到检索库时,系统提示词要同步加一条"基于检索内容回答,检索不到就承认不知道"。没有这条规则,模型会继续按旧习惯硬答,知识已挪走但行为没跟上,幻觉率反而先涨再降。

错位的自查还有个五分钟版本:数一数系统提示词里有多少行是"事实陈述"(可以归真假的句子)而不是"行为约定"(规定做什么的句子)。事实陈述超过三成,基本可以判定有错位。逐行标注一遍,标为"事实"的行就是需要挪走的候选清单。过渡期至少跑两周回归,确认新行为稳定后才算完成。

5.3 知识边界的灰区处理

检索不到答案时,模型的反应由系统提示词决定。三种预置模式:

模式系统提示词动作适用场景
严格拒答无证据即回答不知道合规、医疗、法务
置信声明给答案并标注证据不足内部辅助决策
兜底转人工引导转人工通道高价值客服

灰区行为必须显式声明,因为模型的默认习惯是硬答。声明之外还要写判定标准:什么算无证据。检索结果与问题相关度低于阈值、只命中部分关键词,都写成可执行的规则,让灰区有边界。

灰区是幻觉的高发地带,也是系统提示词与 RAG 配合的最前线。这里的规则每写清楚一条,线上的幻觉投诉就少一类,投入产出比高于在提示词里堆十句"不要编造"。

灰区的规则也有量化方法:对三种模式各配一组测试用例,一组有证据、一组部分命中、一组完全无关,看模型在每组的反应是否与预置模式一致。不一致的用例说明判定标准写得太抽象,模型理解出了偏差,需要在系统提示词里给出更具体的边界描述。这个测试十五分钟跑一轮,灰区规则的迭代靠它驱动。

单智能体的分工到此闭环。当系统里出现多个智能体,元指令的分层要再升一级,这是下一章的话题。

6. 多智能体场景的元指令分工

6.1 三角色与三份元指令

多智能体系统里最容易犯的错,是给每个智能体抄同一份万能系统提示词。正确做法是按角色分管辖权,规划者、执行者、审查者各持一份互不重叠的元指令。

图:三角色的元指令分工

拆成子任务

产出结果

不合格打回

合格

用户任务

规划者

执行者

审查者

汇总交付

元指令定拆分原则

元指令定工具边界

元指令定验收标准

图下解读:三份元指令各管一段,规划者定怎么拆,执行者定怎么调工具,审查者定怎么验收。任何一份越界管辖,打回循环就会空转:审查者忍不住亲自改稿,执行者开始自作主张定目标。

调用侧的代码模式,用同一个客户端分发不同系统提示词:

# 来源:自实现 / agent_call.py(OpenAI 兼容客户端调用 vLLM)
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",  # vLLM 起的兼容端点
    api_key="EMPTY",                      # 本地服务无需鉴权
)

def call_agent(system: str, user: str) -> str:
    resp = client.chat.completions.create(
        model="Qwen2.5-7B-Instruct",      # vLLM 启动时加载的模型名
        messages=[
            {"role": "system", "content": system},
            {"role": "user", "content": user},
        ],
        temperature=0.2,                  # 协议型输出用低温
        max_tokens=512,
    )
    return resp.choices[0].message.content

if __name__ == "__main__":
    print(call_agent(PLANNER_SYSTEM, "用户反馈登录后白屏"))

源码说明:三份系统提示词来自第 3 章的注册表,按角色名加载。调用参数也随角色分化:执行者要稳定走低温,规划者可以在脑暴场景放宽温度,参数与元指令同属行为配置,应该一起版本化。

6.2 管辖权划分表

角色元指令管辖禁止染指
规划者任务拆分与执行顺序具体工具调用细节
执行者工具调用规范与重试任务全局目标
审查者验收标准与驳回理由重新执行任务

管辖权表的价值在故障定位:多智能体输出异常时,先判断是哪一角色的越权行为,再定位到对应那份系统提示词的功能块修。没有这张表,排查会在三份提示词之间来回打转。

管辖权表还有个建设期的用法:写三份系统提示词之前,先把这张表画出来贴在旁边,逐条检查自己的每条规则是否越界。表比代码先行的原因很实际:三份提示词都写完再对照,越界的地方已经互相纠缠,拆起来事倍功半。先画表再写词,每份从第一行就在正确的管辖范围内。

角色的数量也可以按这张表扩展。四角色以上的系统,每加一个角色就在表里加一行,同时检查新角色的管辖是否与已有角色重叠。超过五个角色后,管辖权矩阵的复杂度会超过人能维护的上限,此时应考虑分组分层而不是继续加平级角色。

7. 泄露风险与防泄露

7.1 Sydney 事件复盘

2023 年 2 月,必应聊天机器人被用户用话术套出了内部系统提示词,代号 Sydney 与完整规则清单直接展示在对话里。手法并不复杂:诱导模型忽略先前指令、进入调试模式、把系统段当素材复述。

图:系统提示词的泄露路径

用户构造诱导话术

注入指令进入对话

模型把系统提示词当素材

复述规则全文

泄露完成

攻击者据此定制攻击

图下解读:路径的起点无法封死,用户输入里混进指令是言论自由的副产品。能设防的位置在第二到第三步之间:让系统段被复述的成本足够高、收益足够低。

事件后的行业共识很清醒:系统提示词不是保密边界,任何写进去的内容都要当作"可能被公开"来对待。

7.2 防泄露四手段

手段做法挡住什么
不放秘密密钥口令永不进提示词直接泄密
输出过滤检测规则原文回显并拦截复述式泄露
结构分离规则拆条编号,泄露可定位批量泄露
监控告警异常复述请求触发告警定向套取

四手段里第一条是底线也是全部前提。密钥放在提示词里,等于把家门钥匙贴在门上,后面三手段只是延缓被发现的时间。

边界讨论:防泄露无法根除,只能抬高门槛。模型对系统段的服从是概率行为,足够长的对抗话术总能找到缝隙。系统化的攻防是第 9 篇的主题,本篇只需要记住结论:秘密进环境变量,规则当公开文本写。

四手段的实施优先级按成本排:第一条零成本纯纪律,第一天就能做到;第二与第四条各需一段代码,一周内能落地;第三条需要重构提示词结构,适合配合下一次大版本。四条不必同时上线,但第一条不能等,它依赖的是意识而不是工程。

7.3 泄露发生后的响应预案

泄露不是如果而是何时的问题,预案要在事前写好:

动作时限负责角色
确认泄露范围与版本一小时内值班工程师
评估泄露内容敏感级两小时内安全负责人
修补并重新发布提示词当天提示词负责人
复盘并回填对抗用例一周内三方共审

预案的第一原则是内容分级。泄露的只是行为规则,影响是定向攻击成本下降;泄露了密钥或内部数据,走的是完全不同的安全事件流程。分级决定响应节奏,混级响应要么过度要么不足。

第二原则是修补后必须回填。同一话术能套出这一版,就能套出下一版相似写法,把攻击样本加入对抗用例集,同类攻击才会真正失效。

预案每年至少演练一次。未演练过的预案在真实事件里执行延误远超预期,常见卡点是没有预设谁有权临时下线提示词。演练把这些卡点提前暴露,成本半天。

8. 反模式与检查清单

8.1 五大反模式

全文收敛成五条反面清单,出现的任何一条都指向明确的修正动作:

反模式症状修正动作
万能提示词一份提示词服务所有任务按任务族拆模板
规则打架同层规则互相矛盾对照功能块逐条排
秘密进提示词提示词里有口令密钥挪环境变量
知识塞提示词几百行事实数据常驻挪检索库
无版本裸奔改提示词不留记录上注册表

反模式之间的升级关系值得单独说:万能提示词是根因,其余四条是它的下游症状。一份提示词服务所有任务,规则自然越堆越多(规则打架),知识自然往里塞(知识塞提示词),改动牵一发动全身没人敢留版本(无版本裸奔)。从第一条开刀,后面四条自动减轻;反过来一条条修,治标不治本。

8.2 上线检查流程

图:系统提示词上线检查流

否

是

否

是

否

是

系统提示词定稿

四大块齐全吗

补块再检

回归用例全过吗

定位功能块修改

token 在预算内吗

按让位顺序压缩

发布并记录版本

图下解读:三道关卡对应前三章的能力:结构检查、行为检查、成本检查。任何一道不过就退回对应环节,全部通过才进发布,版本号随之落库。

发布记录里同时登记本次用的清单版本。哪一版提示词配哪一版检查项,事后审计才有据可查,清单自身的演进也成了可追溯的资产。

总结

系统提示词的工程化是一条完整流水线:四大块结构决定内容边界,可判定性决定粒度,注册表与回归用例决定迭代安全,预算表决定成本底线。行为进提示词、事实进检索库、秘密进环境变量,三句口诀划清了系统提示词与相邻组件的界。多智能体场景按管辖权拆元指令,泄露防御从"不写秘密"起步。把提示词当代码管理,是本篇唯一需要记住的立场。

外部引用

Logo

更多推荐