跳到主要内容

真正能阻断 PR 合并的提示词回归测试

· 阅读需 12 分钟
Tian Pan
Software Engineer

问任何一个 AI 工程团队是否测试了他们的提示词,他们都会说"是的"。再问一句:一个有问题的提示词能否让 PR 失败并阻断合并?房间里会安静很多。对大多数团队而言,诚实的答案是否定的 —— 他们偶尔会跑一些评估笔记本,也许有一份记录已知提示词问题的共享 Notion 文档,以及一种模糊的感觉:事情比以前更糟了。那不是测试,那是在碰运气。

这个差距的存在,是因为提示词测试在感觉上与单元测试有本质区别。代码要么行为正确,要么不正确。提示词的输出处于一个连续谱上,输出是非确定性的,而且运行足够多的样本以建立信心会花费真金白银。这些都是真实的约束,但没有一个是无法克服的。那些建立了真正阻断合并的提示词 CI 的团队,并不是在每次构建上花费五十美元 —— 他们在三分钟以内、花费不到一美元的情况下完成运行,这得益于几个让这个问题变得可处理的设计决策。

为什么"我们测试提示词"这个说法站不住脚

典型的提示词测试工作流是这样的:工程师修改了一个系统提示词,在 playground 里随便看了几个输出,把一些例子粘贴到聊天线程中来比较新旧版本,然后就发布了。有时会有一个共享的评估电子表格。有时有人写了一个 Jupyter notebook,运行了二十个例子并输出一个分数。但几乎从未有人将那个分数接入 CI,以一种可以阻止合并的方式。

这种现状的存在有三个原因。

非确定性被当作借口。 LLM 不会两次产生相同的输出(除非你强制它这样做),所以团队假设你无法编写断言。这是错误的。你可以为你的部分用例编写确定性断言,并为其余部分编写带阈值的概率性断言。这种方法与单元测试不同,但结论 —— 这个 PR 让事情变得更糟了,不要合并 —— 是一样的。

评估成本被视为固定的。 如果你天真地以生产 temperature 对每次提交运行整个评估套件,是的,你会花太多钱。但你不必这样做。可行的提示词 CI 版本涉及一个精心挑选的小型测试用例集(30–100 个例子),而不是你的完整生产流量样本。当你停止将"CI 门控"与"全面的离线评估"混为一谈时,大部分成本问题就消失了。

没有人负责失败信号。 在传统代码库中,一个失败的单元测试会阻断合并并通知 PR 作者。而对于提示词评估,结果会出现在某个仪表板中,需要有人记得去查看。如果失败信号没有集成到 PR 审查流程中,它就会在截止日期的压力下被忽略。CI 集成不是可选的 —— 它是整个关键所在。

轻量级提示词测试框架的结构

目标是一个在五分钟内运行完成、每次运行成本在两美元以下、并能产生 CI 系统可以像处理任何其他测试退出代码一样消费的通过/失败信号的套件。以下是构建方法。

黄金测试用例文件

黄金测试用例(golden fixture)是一个版本化的输入/输出对,代表你的提示词必须正确处理的情况。把它想象成前端开发中的快照测试 —— 它捕获已知的良好行为,并在某些内容改变时发出警告。

一个支持工单分类提示词的测试用例文件可能如下所示:

- id: billing-cancellation-intent
input: "I want to cancel my subscription and get a refund for this month"
expected_intent: billing_cancellation
expected_sentiment: negative
must_contain: ["refund", "cancel"]
must_not_contain: ["upgrade", "recommend"]

- id: technical-bug-report
input: "The export button does nothing when I click it in Firefox"
expected_intent: technical_bug
expected_sentiment: frustrated
must_contain: ["issue", "team"]

优秀的黄金测试用例有几个共同属性。它们由人工精心整理,而不是自动生成 —— 只有当你确信预期输出实际上是正确的时,测试用例才有价值。它们包含边缘案例和历史上有问题的输入,而不仅仅是你的提示词一直以来处理得很好的简单情况。它们与提示词本身一起被提交到版本控制中,因此提示词变更和测试用例变更在同一次提交中同行。

你今天编写的测试用例将编码你对正确行为看起来是什么样子的理解。这值得投入时间。

在 Temperature 零下的确定性断言

对于硬断言 —— 有特定正确答案的情况 —— 以 temperature=0 运行你的模型。这使模型具有确定性:给定相同的输入和相同的模型版本,它每次都会产生相同的输出。现在你可以编写能够可靠地通过或失败的断言了。

这是大多数团队所遗漏的部分。他们以生产 temperature(通常是 0.7 或更高)运行他们的 CI 评估,然后想知道为什么结果会有噪音。分割你的测试用例集:确定性情况使用 temperature=0 和硬断言;模糊或创造性的情况使用带有软评分的单独评估路径。

确定性子集不需要很大。三十到五十个覆盖你最关键行为的情况 —— 如果这些行为退化会对真实用户造成伤害的情况 —— 足以给你一个有意义的门控。

LLM 作为语义断言的评审

并非所有内容都可以表达为字符串匹配或分类标签。对于"正确性"是语义性的输出 —— 捕获关键点的摘要、准确但不是逐字的解释 —— 你可以使用第二个模型调用来评估第一个。

这个模式很简单:你将模型输出加上评分标准发送给评审模型,并要求它按比例评分或发出带推理的通过/失败判定。这里的评审提示词非常重要。模糊的标准会产生不一致的分数。具体的、分解的标准会产生你可以依赖的分数。

评估产品描述输出的标准可能如下所示:"如果描述提到了至少两个具体的产品特性,不包含任何事实性错误的声明,并且以第二人称书写,则评分为 1。否则评分为 0。"这是评审模型可以持续评估的内容。

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates