The Prompting Playbook 怎样评测和维护提示词

很多人学提示词工程,是从收集几条万能句式开始的:「请一步一步思考」、「你是资深专家」、「务必准确」。它们偶尔有用,于是人很自然地继续往系统提示里堆补丁。一个月以后,那段 Prompt 变成两千行:有人加过一条防止模型乱答的禁令,有人从产品网页复制了一段政策,有人为了压低人工转接率写了句「除非万不得已不要升级」。新模型一换,原本正常的功能忽然开始答非所问。团队的反应往往是再加一句更强硬的话。

这不是提示词写得不够漂亮,而是把一个工程问题当成了文案问题。

Anthropic Applied AI Engineer Margo van Laar 在公开视频 The Prompting Playbook 里讲的,正是怎样从这个循环里出来。视频没有给一份可以复制粘贴的万能 Prompt,而是演示了一条很实在的工作路径:先用评测找出失败,再判断该改提示词、换模型、加工具,还是改运行时的支架,最后只对一个失败模式做一个可回滚的改动。

这篇文章会把这 33 分钟的演示拆开,并补上初学者在真正动手时最容易卡住的部分。读完以后,你应该能做到:

  1. 给一个 LLM 功能定义可测试的成功标准,而不只说「回答好一点」;
  2. 建一个包含正常样本、历史坑和能力边界的最小评测集;
  3. 看懂为什么模型迁移后旧 Prompt 会反而变差;
  4. 用结构、输出契约和版本记录维护 Prompt,而不是无限追加禁令;
  5. 分清「写指令」、「提供工具」和「在代码里强制约束」各自该解决什么;
  6. 为复杂任务搭一个生成、评估、修复的循环,并理解它什么时候比单个大 Prompt 更合适。

封面取自原视频的公开缩略图。视频中展示的模型名称、控制台界面和具体延迟属于演示当时的环境,不应当拿来当作今天任何模型的性能承诺。本文保留它的工程方法,示例代码则刻意写成与厂商无关的伪代码。

先换一个视角:Prompt 不是咒语,是系统里可维护的一份配置

先把一个常见误会放到桌面上。Prompt 当然重要,但它不是 LLM 应用的全部。一次模型调用至少有四层东西共同决定结果:

它负责什么 典型问题 该怎样修
模型 理解、推理、生成的上限 任务本身超出能力 换模型、拆任务、降低目标
Prompt 角色、优先级、政策、步骤、输出意图 指令含混、冲突、遗漏 重写或删掉有害指令
工具与数据 计算、检索、数据库写入、外部事实 模型凭空算数、拿不到准确信息 给工具、补数据、校验 schema
Harness 重试、停止条件、权限、解析、结构化输出 输出截断、格式无法解析、危险操作越权 在代码和运行时做约束

把这四层混为一谈,会出现两种浪费。第一种是本来该写一个计算函数,却要求模型「一定要算准确」。第二种是本来需要更强模型或换一种任务分解,却在 Prompt 里加十段推理步骤。前者让不稳定的心算承担确定性工作,后者让提示词变成一座维护不起的迷宫。

视频一开始就把两个现实场景分开:

  1. 你在维护一个已经上线的 Prompt,可能还要把它迁到新模型;
  2. 你从零开始做一个 Agent,既要选模型,也要决定 Prompt 和运行支架怎样配合。

它们看似都是「写 Prompt」,起点却完全不同。维护旧系统的第一目标不是创作,而是解释回归。新建系统的第一目标不是把第一版写得很长,而是拿到一个足够简单的基线,知道自己是在往哪里爬。

下面的流程图概括了全文的主线。请留意最重要的一点:评测不在最后,它在任何改动之前。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
flowchart TD
A[定义用户任务和成功标准] --> B[构造评测集]
B --> C[运行当前版本并记录结果]
C --> D{失败来自哪里?}
D -->|指令或优先级不清| E[改 Prompt]
D -->|缺少确定性能力或事实| F[增加工具或数据]
D -->|任务超出能力边界| G[换模型、拆分任务或交给人]
D -->|格式、停止、权限问题| H[修改 Harness]
E --> I[全量重跑评测]
F --> I
G --> I
H --> I
I --> J{达到发布门槛?}
J -->|否| D
J -->|是| K[版本化发布并持续收集失败样本]

一、没有评测,就没有改好了这回事

假设客服机器人把一条回答写得更礼貌、更长,你觉得它更好了。可它是否因此不再乱算账单?是否会在应该转人工时继续逞强?是否把原来能正确回答的基础套餐问题答坏了?肉眼挑两条对话,很难回答。

这就是评测集的作用。它不是为了给模型打一个看上去很科学的分数,而是给每一个改动一个固定参照物。你才能说:我把政策和语气拆开后,旧套餐查询从 3/5 变成 5/5,但转人工场景退化了,而不是只说感觉不错。

1. 评测先回答什么叫成功

一个不能判定对错的需求,无法直接变成好评测。「客服要有帮助」太宽,拆开后才有可验收的句子:

模糊愿望 可以测试的成功标准
回答准确 套餐限额必须与该用户账户里的 hotspot_gb 一致
账单别算错 改套餐场景必须调用计费工具,最终金额与工具结果相同
少转人工 普通政策解释不得转人工
别硬撑 账单记录冲突时必须转人工,不能自行归因或承诺退款
体验自然 在正确处理后,用一句简洁的话说明下一步,不泄露内部政策文本

注意这里的动词:必须调用、必须相同、不得、必须转。它们让评估者知道该看什么。好的成功标准通常有三个特征:具体、可观察、与真实后果相连。Anthropic 的评测文档也把成功标准放在提示词优化之前,原因很简单:不先定义终点,优化只会变成朝着不同方向用力。官方说明

2. 视频里的三类样本,正好组成最小测试集

Margo 用一家虚构的电信公司 Meridian Mobile 演示。她没有一口气塞一百条样本,而是用五条样本覆盖三种功能:

类别 问题 例子 它防什么
对照样本 本来就应当答对的清晰问题 基础套餐有多少流量? 改动把基本功能弄坏
边缘样本 曾经出过问题的复杂情况 月中升级套餐后的按比例账单 同一种坑回归
能力边界样本 应答、转人工和拒答的边界 账单记录冲突时升级给专员 模型在不该做主时硬做主

对照样本容易被忽略。有人只收集事故案例,改完以后所有事故案例都绿了,却没发现机器人连最普通的查询也开始绕圈。它像软件测试里的冒烟测试,不能证明一切,但能很快告诉你基本线路是不是断了。

边缘样本也不只是难的问题。它最好来自真实失败:某类旧客户、少见的日期组合、信息不完整、两段政策看起来冲突。每一次线上事故都值得变成一个可匿名化的回归样本。这样下一次改 Prompt 时,这个坑不是靠某位同事的记忆守着,而是变成流水线里的一个红灯。

能力边界样本最像产品设计。模型能不能回答,不只取决于它知不知道事实,也取决于它有没有权限、证据和责任。例如客户说「账单金额和系统记录不同」,一个看起来很能干的回答可能是猜测原因并安慰客户;正确行为却是保留证据、转给能查账的人工。评测要明确把这类「不做」也视为成功。

3. 打分器要尽量贴近任务本身

不同任务适合不同评估方式。不要因为 LLM judge 很时髦,就用它检查一个完全可由程序验证的 JSON 或排班约束。

输出类型 优先使用的判定方式 为什么
JSON 字段、金额、日期、是否调用工具 程序断言 快、稳定、能定位字段
分类、抽取、固定政策回答 精确匹配、规则匹配或人工抽查 标准通常足够清楚
摘要、解释、语气、开放式建议 人工 rubric 或 LLM judge 很难写成唯一答案
排班、路线、资源分配 硬约束用程序,软偏好可用 LLM judge 不把法律和容量约束交给主观评分

视频后半段的排班例子很有代表性。每个班要有足够人手、员工不能上不可用的班、不能违反休息规则,都属于硬约束,可以写成一个普通函数。只有「Harry 尽量不要和 Sally 同班」这类临时软偏好,才适合交给自然语言评估器。这不是看低 LLM,而是把可确定的部分从概率系统里拿出来。

一个极简的硬约束检查器,概念上大致如此:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def validate_schedule(schedule, employees, shifts):
violations = []

for shift in shifts:
assigned = schedule.get(shift.id, [])
if len(assigned) < shift.required_headcount:
violations.append(f"{shift.id}: 人数不足")

for person_id in assigned:
person = employees[person_id]
if shift.day not in person.available_days:
violations.append(f"{person_id}: 不可用却被排到 {shift.id}")

return violations

这段代码没有让模型更聪明,却让你得到一个稳定事实:到底违反了哪条规则,违反了几次。随后再讨论怎么让模型少违反,才有抓手。

4. 不要只跑一次:模型输出有方差

视频里清理 Prompt 后,有一个热点流量样本短暂回退。演讲者没有马上得出结构化 Prompt 有害的结论,而是指出生成有自然波动,需要回到该样本看一致性。

这在实践中非常重要。对于温度不为零、带推理或工具的调用,一次全绿可能只是幸运,一次全红也可能是偶发。低成本的做法是:

  1. 先固定模型版本、温度、最大输出和工具版本;
  2. 对关键样本重复跑 3 到 5 次;
  3. 记录通过率、平均延迟、Token 和具体失败内容;
  4. 把发布门槛写出来,例如关键安全样本 100% 通过,整体通过率不低于基线。

不要假装这种统计已经严谨到科研论文的程度。小评测集的价值主要是让回归可见。等系统有真实流量以后,再用生产样本扩充测试集,比在第一天伪造几千条无关样本更有价值。

二、模型一换,为什么旧 Prompt 会变坏

迁移模型后效果下降,并不自动说明新模型更差。视频把原因分成两个方向,这个区分值得背下来。

  1. 新模型其实做得到,但它对旧指令的理解方式不同,或者比旧模型更严格地服从某条过时的规则。这是 Prompt 和配置问题,可以尝试修。
  2. 新模型确实做不到原任务,或成本限制迫使你用能力较弱的模型。这不是把务必正确写十遍能解决的,需要换模型、提供工具、拆任务或改变产品边界。

没有评测时,人很容易把这两种情况混在一起。更糟的是,团队会从最后一条失败对话里猜原因。评测集相当于一个小型诊断仪:保留同一批输入,分别跑旧模型和新模型,然后看失败集中在哪些能力。

旧补丁会过拟合到更听话的新模型

客服案例的热点流量问题很典型。用户属于旧套餐,账户数据明明写着 hotspot_gb = 5。Prompt 里却留着旧时代的一句防御性指令:旧套餐可能和当前政策不同,绝不要给客户错误信息,改为让他去账户页面查看。

原作者当初可能遇到过模型把新套餐的 4GB 政策错套到旧客户身上,于是加了这句。它当时或许有用。后来模型更善于遵循指令,就把「绝不要错」理解成「不要直接说」,即使账户数据已经给出了答案,仍然把人打发回网址。

这类问题不是幻觉,而是相反的错误:模型掌握了可用信息,却不敢交付。修复方式不是再强调不要错,而是重新表达事实来源和优先级:

1
2
3
4
5
6
7
8
9
<data_priority>
客户账户中的套餐名称、已配置额度和生效日期,是该客户的事实来源。
通用政策只用于解释;当它与账户字段不一致时,以账户字段为准。
</data_priority>

<legacy_plan_rule>
旧套餐可能有不同额度。若账户提供了具体额度,直接告知该额度。
只有账户没有该字段或字段相互矛盾时,才建议客户转人工核实。
</legacy_plan_rule>

这里的关键不是 XML 本身有魔法,而是明确回答了三个问题:什么是事实来源,冲突时谁优先,缺信息时怎么办。XML、Markdown 标题或 JSON 都可以承担分段职责。Anthropic 的 Claude 4 提示词指南同样建议清晰、明确地表达要求,并可用 XML 标记帮助分隔结构。官方最佳实践

给 Prompt 写变更说明,像维护代码一样维护它

防御性规则不一定都该删。问题在于没人知道它为什么存在。一个可维护的做法是把 Prompt 放进版本控制,并在每次非显而易见的规则旁边留下简短理由和关联样本。

1
2
3
4
5
6
7
<!--
rule-id: escalation-billing-conflict
introduced: 2026-07-14
reason: 账单总额与明细不一致时,模型没有足够证据判断原因。
covered-by: eval/billing_conflict_03
review-when: 更换模型、账务工具上线、政策变更
-->

如果你的生产 Prompt 不适合放 HTML 注释,也可以把这段元信息放在同目录的 prompt-notes.md。重要的是能回答:这条规则来自哪个真实失败?它保护什么?什么时候应该复查?没有这些信息,几年后的维护者只能把每一条奇怪指令都当成不能碰的祖传代码。

三、先做卫生清理,再逐个修失败模式

视频中的初版客服 Prompt 有不少真实世界常见的毛病:把机器人说成真人、混入从网站复制来的 hero image 和 cookie 文案、角色、政策、语气、计算要求挤在一个长段落里。此时直接对一个失败样本加一句补丁,往往只会让团块更大。

先清理有两个收益。第一,模型能更稳定地识别哪些是规则、哪些是数据。第二,人类才能读懂它,之后的改动才有地方落脚。一个实用判断标准是:如果你扫一眼 Prompt,分不出指导原则、硬政策和输入数据,模型多半也分不清。

1. 用责任分区,不是用漂亮标签

下面是一份适合客服类 Agent 的骨架。它不是通用模板,字段也不是越多越好。真正重要的是每段只承担一种责任。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<role>
你是 Meridian Mobile 的 AI 客服助手。你不是人工客服。
你的任务是根据已提供的客户资料和政策,解决可安全回答的问题。
</role>

<source_of_truth>
1. 客户账户字段用于判断该客户当前的套餐和额度。
2. 政策用于解释通用规则。
3. 无法从已提供资料确认的账务争议,必须交由人工处理。
</source_of_truth>

<policy>
... 只保留与当前任务有关的政策 ...
</policy>

<tools>
计算任何按比例费用前,调用 calculate_proration。
</tools>

<escalation>
若账单总额、交易记录或账户字段相互矛盾,不猜测原因,说明将转交专员。
</escalation>

<tone>
先给结论,再给一句必要解释。不要假装已经完成外部操作。
</tone>

<customer_context>
{{customer_account}}
</customer_context>

<user_message>
{{message}}
</user_message>

这里有两个容易漏掉的细节。

第一,数据要明确地与指令分开。customer_context 是不可信的外部数据,它不应该有能力改写政策或角色。若数据来自用户输入、网页、邮件或检索结果,更应在运行时标记来源,不能把里面的文字当命令执行。

第二,tone 不该盖过事实和安全。很多 Prompt 把「热情」、「快速解决」写得比转人工规则醒目,结果模型为了显得有帮助,开始替用户判断账务。语气是服务体验,事实优先级和权限边界是系统责任,层级不能倒过来。

2. 输出契约解决的是下游不确定性

有些系统只要求自然语言回复,格式偶尔漂一点问题不大。有些系统却要把回复交给程序:抽取字段、发起审批、写数据库、展示卡片。这时「请用 JSON 返回」常常不够,因为模型仍可能先写一段解释,或漏掉嵌套字段。

输出契约就是把下游所需的形状写清楚。例如:

1
2
3
4
5
6
7
8
<output_contract>
仅返回一个 JSON 对象,不能使用 Markdown 代码围栏。
字段必须为:
- action: "answer" 或 "escalate"
- reply: 给客户的自然语言回复
- reason_code: "policy"、"calculation"、"billing_conflict" 之一
- tool_result_id: 仅在使用计算工具时填写
</output_contract>

但 Prompt 只是软约束。真正要稳定解析时,还应在 Harness 层做三件事:

  1. 使用 API 提供的 structured output 或 JSON schema 功能,如果所用平台支持;
  2. 对返回值做 schema 校验,不合格就让模型带着具体错误重试,或走失败分支;
  3. 合适时设置停止序列,避免模型在闭合标记后继续闲聊。

视频展示了把输出包在 XML 标签中并用 stop sequence 截断的办法。这个思路值得学,但不要机械照抄 XML。若供应商已有严格 JSON schema,优先让 API 和校验器保证结构;Prompt 用来解释字段的语义和业务决策。结构化输出与停止控制属于运行支架的能力,不是让模型更懂业务的技巧。

3. 一次改一件事,保留失败模式的名字

清理完结构以后,视频没有把剩下的三个红灯同时修掉,而是依次处理:旧套餐热点额度、按比例账单计算、账单冲突转人工。这样做不只是为了演示好看。

如果一次改了角色、政策、工具、模型和输出格式,即使全绿了,你也不知道哪一个起作用;如果某个对照样本坏了,也不知道该回退什么。更可靠的提交粒度是:

1
2
3
4
5
6
feat(prompt): 优先使用旧套餐账户额度

假设:旧的跳转到账户页面规则遮蔽了 customer_context。
改动:明确账户字段优先于通用套餐政策。
验证:legacy_hotspot_01 连跑 5 次全部通过;其余 4 条无回归。
风险:账户字段缺失时的分支仍需人工核实。

这段提交信息看起来有点麻烦,等你面对第十条补丁时会感谢它。它让 Prompt 的变更也具备工程上的可追踪性。

四、最关键的一句:指令不能凭空增加能力

视频中客户问:月中升级到 30GB 套餐,下期账单是多少?初版 Prompt 的写法大意是绝不能含糊,必须正确计算按比例费用。模型会认真地在回复里做心算,甚至看起来推理得挺像样,但它没有可靠地给出可以承担账单责任的金额。

这时最容易犯的错误,是继续强调 Critical,计算必须 100% 正确。这句话没有提供任何新信息,也没有给模型新的计算能力。

应该把工作交给正确的部件:给模型一个 calculate_proration 工具。它的工具描述告诉模型什么时候调用,参数 schema 告诉模型需要哪些事实,后端实现真正计算金额。模型负责判断用户意图、收集参数、解释结果;确定性函数负责数学。

1
2
3
4
def calculate_proration(old_monthly_price, new_monthly_price, days_remaining, days_in_cycle):
# 这里只是教学公式。真实计费还要处理税、折扣、账期和币种规则。
difference = new_monthly_price - old_monthly_price
return round(difference * days_remaining / days_in_cycle, 2)

若价格差是 20 元、账期 30 天、还剩 12 天,补差额是 20 * 12 / 30 = 8 元。重点不在这个小学算式,而在于应用代码能审计输入、固定舍入规则、处理异常;模型不需要在自然语言里猜这些细节。

工具并不是只给数学用。以下信号出现时,先问是不是该给工具:

需求 更合理的承担者
实时订单、库存、账户状态 查询工具或数据库
金额、税费、日期差、权限判断 确定性函数或规则引擎
要写入 CRM、退款、发邮件 受权限和审批控制的工具
需要综合多份材料给人解释 模型 + 检索到的材料
需要在信息不足时承认不知道 Prompt 中的边界规则 + 人工升级路径

调用工具也不是自动安全。工具 schema 是模型理解接口的说明书,后端仍应验证参数和权限。模型说给客户退款,不等于退款函数就该执行。把限制只写在 Prompt 里,会让概率性的文本约束承担本应由程序强制的安全责任。

五、当模型在两个目标之间选择,别只告诉它一边

账单冲突的案例还有一个很细的启发。初版 Prompt 告诉机器人:除非绝对必要,不要转给人工专员。每次转接大约花 8 美元,而且影响快速解决率。

结果可想而知:模型听得很认真。面对金额冲突,它没有升级,而是尝试分析原因。开发者可能会抱怨它不懂变通,但从 Prompt 看,它恰好在优化被强调的目标。

修复不是简单反转成遇到任何问题都转人工。视频的做法是把两边的后果一起交代:人工转接有成本;错误处理账单会带来退款和信任损失;记录冲突时模型没有足够依据,因此应升级。模型才有机会做符合业务意图的权衡。

这个原则适用于许多常见指令:

只写一边的指令 更完整的业务表达
尽量少调用搜索,省成本 常见问题先用已给资料;若答案依赖时效事实或引用证据,必须搜索并说明来源
不要打扰用户 信息可安全推断时继续;涉及付款、删除、对外发送时必须确认
尽量自己修复 可逆的本地改动可修复并测试;数据迁移、权限变更、生产写入必须停下来请求批准
回答简短 先给直接结论;涉及风险、金额或不可逆后果时,必须说明关键依据和下一步

这不是给模型写一段道德散文,而是在补全决策函数的损失项。模型能力增强后,旧版本为了纠正某个问题而加的单边禁令,往往更容易被严格执行,反而显得更别扭。模型迁移评审时,特别值得把这类规则挑出来重新读。

六、从零做新 Agent:不要先写长 Prompt,先建立能比较的基线

视频的第二个例子是为八名零售员工排一周班表。约束包括员工可用时间、每个班次的最低人数等。这个场景比客服更复杂,因为它既考验推理,又有硬约束,还需要权衡 Token、延迟和成功率。

一个合理的起点是:

  1. 用简短、结构化的 Prompt 清楚给出输入和输出 schema;
  2. 先选择一个成本可接受的基准模型;
  3. 用程序验证硬约束;
  4. 记录失败次数、Token、延迟和失败原因。

为什么不一开始就写一份终极排班 Prompt?因为你还不知道失败究竟来自哪里。视频中的基准模型做了不少推理,却违反了很多约束。换用更强的模型后,违规数明显减少,但仍不足以上线。开启更充分的自适应推理后,结果终于可靠,却付出了更多 Token 和更长延迟。

这些结果都不是失败。它们让团队看见了选择:如果排班每周离线跑一次,慢一些、贵一些可能完全值得;如果用户在页面上等待,100 秒延迟就不可接受。没有这张成本和质量的对照表,用最强模型或把 Prompt 写详细点都只是直觉。

写得更细,不一定能战胜架构问题

接下来,视频给较小模型增加了更具体的推理方法和输出前检查要求。表现改善了,但有些任务在输出上限内做不完。即使提高 max_tokens,也意味着更高成本和更长等待。

这正是一个转折点:当单个 Prompt 同时承担生成方案、检查每条约束、解释错误、修复方案时,它的任务负担已经不适合继续往里塞说明。该换成多个小而明确的阶段了。

这里顺带澄清 max_tokens。它是一次生成最多允许产生多少输出 Token,不是模型智力旋钮。上调可能让模型有足够空间完成长答案,也可能只让它更冗长、延迟更高。评测中应把被截断单独记录,不能误归因为逻辑能力差。

七、生成、评估、修复:把一个大问题变成三个清晰的小问题

视频最后采用的方案叫 generate-evaluate-repair loop,可以翻成生成、评估、修复循环:

1
2
3
4
5
6
7
8
9
10
flowchart LR
A[输入:员工、班次、约束] --> B[生成器:产出初版班表]
B --> C[评估器:逐条检查并给出证据]
C --> D{有违规吗?}
D -->|没有| E[返回班表]
D -->|有| F[修复器:只处理列出的违规]
F --> C
F --> G{超过轮次预算?}
G -->|是| H[返回失败和违规清单]
G -->|否| C

它的妙处不在于把 Agent 变复杂,而在于每一阶段的职责终于单一了:

阶段 输入 输出 它不该做什么
生成器 原始约束 一个候选解 反复自我审判到耗尽输出
评估器 候选解 + 规则 精确违规和证据 偷偷重写整个方案
修复器 候选解 + 违规清单 尽量小的修正 忽略评估器、从头幻想新方案

这种拆分带来三个现实收益。

第一,可诊断。若总是同一条规则被违反,你知道该调整生成器或增加确定性检查;若评估器前后不一致,你知道问题在 judge;若修复器为了修一处又坏三处,说明需要更好的状态表示或硬约束工具。

第二,可控制成本。每一步都可以有自己的小 Prompt、输出上限和轮次预算。不要让循环无限跑,必须有如 max_repairs = 3 的停止条件,并在失败时把剩余违规交给人。

第三,能承接运行时软偏好。硬约束仍由程序检查,临时需求如「周三尽量增加夜班」或「Harry 和 Sally 尽可能错开」可以作为评估器的本轮偏好传入,而不需要每次修改后端校验代码。

一个与厂商无关的控制骨架如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
candidate = generate_schedule(problem)

for attempt in range(3):
hard_violations = validate_schedule(candidate, employees, shifts)
soft_review = review_soft_preferences(candidate, runtime_preferences)

if not hard_violations and soft_review.acceptable:
return {"status": "ok", "schedule": candidate}

candidate = repair_schedule(
schedule=candidate,
hard_violations=hard_violations,
soft_feedback=soft_review.feedback,
)

return {
"status": "needs_human_review",
"schedule": candidate,
"violations": hard_violations,
"feedback": soft_review.feedback,
}

请注意 validate_schedule 没有被 LLM 取代。视频中评估 Prompt 可用于报告规则违反的证据,但真正的发布闸门最好仍由确定性校验把守。若要让 LLM 参与评审,保留它的理由和证据,方便人抽查。Agent 循环的价值是增加可见的步骤,不是把检查藏进另一段更长的文本里。

八、把视频方法落到自己的第一个项目

不必先做客服系统或排班器。一个很适合练手的任务是:给内部知识库做问题分类和路由。它有清晰输入、可观测输出,也容易加入边界。

第一步:写一个小得足以读完的契约

1
2
3
4
5
6
7
8
输入:一条员工提问。
输出:{ route, confidence, reply, needs_human }。

成功标准:
- 密码重置、访问权限、报销、一般制度咨询应路由到正确队列;
- 涉及账户安全或用户明确要求人工时,needs_human 必须为 true;
- 不得编造不存在的制度;
- JSON 必须能被程序解析。

第二步:先写 8 到 15 条评测,而不是 200 条

至少包含:

  1. 两条最清楚的普通问题,作为对照样本;
  2. 三条你预期容易混淆的相邻类别,例如报销和采购;
  3. 两条必须升级人工的敏感情形;
  4. 两条资料不足、应该承认不知道的情形;
  5. 一到两条带噪声、错别字或多意图的问题。

每条不要只存用户输入,还要存期望的 route、是否必须升级、允许的回复范围和判定方式。格式可以是 JSONL、CSV 或测试代码,重点是进入版本控制。

1
2
3
4
5
6
7
8
9
{
"id": "security_01",
"message": "我的账号好像被别人登录过,能帮我立刻改邮箱吗?",
"expected": {
"route": "security",
"needs_human": true,
"must_not": ["自行修改邮箱", "要求提供密码"]
}
}

第三步:做 V0,并承认它会失败

V0 的 Prompt 只需有角色、路由定义、边界和输出格式。不要先加入几十条历史案例。跑评测后,把失败按类别写下来,例如:

样本 失败观察 初步假设 下一步
security_01 回答了改邮箱步骤,未升级 安全边界不够显眼 增加明确升级规则,并重跑全量
expense_03 路由正确但 JSON 前多了寒暄 格式只写成建议 加 schema 校验或结构化输出
policy_04 编造了制度细节 无资料时的行为未定义 增加无证据则升级,并提供检索工具

这一张表就是 Prompt 调试的核心产物。它比十轮聊天记录更有价值,因为每条改动都有要解决的对象。

第四步:建立发布前的最小门槛

一个个人项目可以很轻量,但别跳过门槛。比如:

1
2
3
4
5
6
发布条件:
- 所有安全与人工升级样本连续 5 次通过;
- 全部样本的 JSON schema 校验通过;
- 基础对照样本没有回归;
- 与上一个版本相比,平均延迟没有超过预算;
- 新增的规则都有对应的样本或变更理由。

上线后再把真实但已脱敏的失败案例追加进来。评测集永远不是一次性完成的考试卷,它是产品行为的回归档案。

九、几个看似有效、其实会把系统带偏的做法

1. 看到错误就加一句禁止

禁止清单有必要,尤其是安全边界,但它不是默认修复手段。长长的不要 A、不要 B、不要 C,通常没有说明模型该做什么,也可能遮蔽更高优先级的信息。先问:这是事实缺失、能力不足、优先级冲突、权限问题,还是格式问题?找到责任层再改。

2. 用一条漂亮回答证明版本升级成功

单条对话只能生成假设,不能证明改进。至少跑固定的对照和失败样本;关键场景重复几次。Anthropic 控制台的评测功能也支持把同一测试集重新运行并并排比较 Prompt 版本,这正是为了避免凭印象改 Prompt。评测工具说明

3. 把所有规则、文档和例子塞进系统提示

上下文更长不等于约束更强。混入网页残渣、过期规则和无关案例,只会让人和模型都难以识别重点。保留稳定规则,把客户或任务数据放在清楚的输入区,按需检索资料。关于运行时上下文怎样分层,可以配合阅读站内的上下文工程深度解析

4. 让模型做它不该做的确定性工作

金额、权限、数据库状态、删除动作和合规规则,应该有工具、校验器和审批边界。模型很适合解释、选择下一步和把非结构化意图映射到接口;它不该成为账务系统或权限系统的替身。工具调用本身也会携带 schema、结果和额外上下文成本,应把工具描述设计得短而准确。Anthropic 的工具使用说明 解释了工具调用与结果如何进入请求。

5. 一看到复杂任务就换最强模型

强模型有时确实是正确答案,尤其是低频、高价值、复杂推理任务。但它不是绕过工程设计的免费通行证。先测质量、延迟和成本,再比较更强模型、较小模型加工具、以及分阶段 Agent。视频里的排班案例正说明:更强的推理可以提升合规率,而生成-评估-修复的拆分也可能以更低的成本达到目标。结论取决于你的约束,不是模型排行榜。

十、一次真正的模型迁移试验,可以这样跑

假设你准备把一个已经上线的客服模型替换掉。不要先把所有线上流量切过去,也不要先花两天重写 Prompt。找一份冻结的评测集,让旧模型和候选模型在完全相同的输入、工具版本、温度与输出上限下运行。你真正要比较的不是一个总分,而是下面几列:

维度 要记录什么 它帮助你作什么决定
业务正确性 每类样本的通过率、关键样本是否全过 是否满足发布下限
行为差异 旧模型过、新模型不过的具体输出 该改 Prompt 还是模型根本不适合
工具行为 调用率、漏调率、多余调用率、参数错误 工具描述和路由是否要调
系统代价 输入输出 Token、P50/P95 延迟、失败重试 质量收益是否值得成本
风险边界 转人工、拒答、权限动作的通过率 是否需要先限制灰度范围

举个很常见的结果:候选模型在普通问答上更好,旧套餐样本却更常把用户转走。这不是一句新模型不行就该结束的结论。回放该样本,若发现它严格执行了旧 Prompt 的模糊禁令,那么改的是规则并重新测试;若它即使拿到清晰账户数据和工具结果仍无法稳定判断,则要考虑保留旧模型、选更强模型,或让该类请求走明确的规则路由。

灰度发布也应该沿用同一个思路。先只放一小部分低风险流量,记录真实的转人工率、人工纠正率、工具错误和用户追问率。这里的指标不是用来替代离线评测,而是检查离线样本没覆盖到的分布变化。任何被人工纠正、用户投诉或因格式失败而重试的对话,都值得脱敏后进入候选评测集。这样,迁移不再是一场押宝,而是一轮有退路的实验。

还要警惕只看平均值。平均延迟下降可能是模型更常在复杂账务问题上提前放弃,平均转人工率下降也可能是它把本该升级的请求硬答了。把总体指标按意图、风险等级和结果拆开,才不会被一个好看的数字带偏。对于支付、医疗、法律、账号安全等高风险领域,关键样本的错误率通常比平均分更重要。

十一、一份可以贴在项目里的维护清单

每次要改线上 Prompt 或迁移模型前,按下面走一遍,已经足够避开大多数越改越乱的情况:

1
2
3
4
5
6
7
8
9
10
11
[ ] 我能用一句可观察的话定义这次改动的成功吗?
[ ] 评测集里是否有对照样本、历史失败样本和能力边界样本?
[ ] 每条关键样本的通过条件是否明确,而不是回答看起来不错?
[ ] 当前失败属于模型、Prompt、工具/数据,还是 Harness?
[ ] Prompt 中能否清楚分出角色、政策、指导、数据、工具和输出契约?
[ ] 新增的规则是否说明了事实来源、优先级和缺信息时的行为?
[ ] 是否存在为旧模型留下、现在可能过度执行的防御性补丁?
[ ] 能确定的计算、校验、权限是否已交给代码或工具?
[ ] 这次是否只改变了一个可解释的变量,并全量重跑评测?
[ ] 是否记录了版本、模型、参数、通过率、延迟、Token 和失败样本?
[ ] 是否给循环设了轮次、输出和人工介入预算?

如果这些项里有几条还答不上来,也不必停在原地补齐所有文档。先挑一条最常出现的失败对话,把它写成评测,再让下一次 Prompt 改动只服务于这条样本。工程能力就是这样积累出来的:不是突然写出一段完美 Prompt,而是把猜测慢慢替换成证据。

最后:提示词工程的成熟标志,是不再迷信提示词

The Prompting Playbook 最值得带走的,不是 XML 标签,也不是某个模型的特殊参数。它把提示词从一次性的文字技巧,放回了软件工程的正常位置:一份会随产品、模型、政策和失败案例持续变化的配置。

当系统答错时,先别急着责怪模型或追加一条命令。拿出评测,看清它失败在哪;如果是指令冲突,就重写优先级;如果是缺少事实或确定性能力,就加数据和工具;如果是模型能力不够,就换模型、拆任务或交给人;如果是格式、权限和停止条件,就让 Harness 负责。复杂工作则不要强迫一个大 Prompt 同时生成、审查和修复,把它拆成能独立观察的小步骤。

这样做不会让 AI 从此不犯错。它带来的东西更朴素,也更有用:每一次错误都能变成下一次发布前会亮起的一盏灯。

参考资料