功能 测试 的 第一 条 AI 门禁: Promptfoo 管 死 规矩, DeepEval 管 答 得 像 不像
给刚转行的功能测试一条能变红的检查。Promptfoo 用 contains 和 not-contains 守退货规则里必须说和绝不能说的句子,先用 echo 不花钱看失败。DeepEval 只用几条人手写的标准答案看意思对不对。不讲榜单,不把模型的回答当成预期。

本文目录
这条门禁给刚从功能测试转过来、或者已经被「AI 功能不敢发」卡住的人。它不讲榜单,不比较模型谁更聪明。它只做一件事:让客服、问答、检索这些会说人话的功能,在合并代码时有一条能变红的检查。死规矩用 Promptfoo 的确定性断言。答得像不像、有没有按你们写好的规则说,用 DeepEval 的一条裁判指标。两边都失败就挡住这次变更。
这条门禁解决什么,不解决什么
功能测试熟悉的痛点通常是这三件:回归时间不够,用例写不完,以及新上的对话功能无法用「点按钮、看文案」来断言。
Promptfoo 加 DeepEval 解决的是第三件,并且顺手给前两件里「AI 生成的答案要不要信」划一条线。它不替你做等价类、边界值和页面定位。它也不证明模型在公开榜上排第几。门禁只回答:这一版提示词或这一版接口,在你亲手写的那几条业务规则上,还过不过。
两个工具不要混成一个。
| 工具 | 像你原来的什么 | 第一条门禁里干什么 | 什么时候先别用 |
|---|---|---|---|
| Promptfoo | 参数化用例加断言 | 关键词在不在、不该出现的话有没有说漏、输出是不是空的 | 还没有一条你能用一句话说清的通过标准 |
| DeepEval | pytest 里的断言,只是断言对象换成模型输出 | 有标准答案或规则时,看实际输出是否按规则说对 | 每条用例都叫模型当裁判。又慢又贵,而且裁判自己也会漂 |
官方文档会变。下面能直接粘贴的,是 2026 年 9 月核对过的安装方式和最小例子。模型 id、HTTP 请求体字段以你方接口和 Promptfoo 入门 、DeepEval 5 分钟上手 当时的页面为准。密钥只放环境变量,不要写进仓库。
1. 先用 Promptfoo 做一条不花钱的红绿
不需要模型密钥。Echo 提供者会把提示原样返回,用来确认「断言失败时命令真的会红」。这和你先写一条必然失败的用例、看框架是不是接上了,是同一件事。
在空目录执行:
npm install -g promptfoo
mkdir -p first-gate && cd first-gate如果全局安装不方便,后面的 promptfoo 一律换成 npx promptfoo@latest。
写 promptfooconfig.yaml:
description: 退货规则,先用 echo 确认断言会红
prompts:
- '{{answer}}'
providers:
- echo
tests:
- vars:
answer: '七天内可退,运费由买家承担。不退定制品。'
assert:
- type: contains
value: '七天'
- type: not-contains
value: '随时可退'
- vars:
answer: '本店支持随时可退,运费我们包。'
assert:
- type: contains
value: '七天'
- type: not-contains
value: '随时可退'然后:
promptfoo eval第一条应通过。第二条答案写了「随时可退」,not-contains 会失败,整次 eval 失败。这就是门禁的形状:失败要看得见。看明细:
promptfoo viewcontains 和 not-contains 不调用模型,和你原来的 assertIn 一样。优先把这种断言用在:必须出现的政策原句、禁止承诺的话、空输出、明显的拒绝服务用语。能用字符串说清的,不要交给模型裁判。
2. 把 echo 换成你们已经在测的那个回答
Echo 只证明框架没接错。下一步把 providers 换成你们的客服或问答接口。Promptfoo 支持 HTTP、Python 函数和各家模型。请求体字段每家不同,不要抄一份想象出来的 JSON。打开官方 HTTP 提供者文档,对照你们接口的真实请求。
接上之后,测试数据改成「用户问题」,断言仍由人来写。例如用户问「买了三天想退,运费谁出」,通过标准仍然是:回答里要有「七天」和运费由谁承担,不能出现「随时可退」。标准来自需求或客服手册,不是来自上一次模型自己的回答。用模型的回答当预期结果,门禁会把幻觉锁成基线。
用例先写 10 到 20 条,覆盖三类就够:
- 正常问题,手册里有明确句子。
- 边界,例如第 7 天和第 8 天、定制品、已拆封。这些仍用你们原来的边界值,只是断言改成对回答文本。
- 不该答的问题,例如让它承诺退款到账时间,而手册没写。用
not-contains挡住它编造的承诺。
对抗、越狱、红队放到门禁跑稳之后。Promptfoo 有 promptfoo redteam,那是下一条门禁,不是第一条。第一条先保证业务规则没被说错。
3. 再用 DeepEval 看「按规则说对了没有」
有些对错拆不成关键词。例如回答可以不出现「七天」这三个连续字,但意思必须是七天内、运费买家承担、定制品不退。这种用 DeepEval 的一条指标。
python -m venv .venv
source .venv/bin/activate
pip install -U deepeval裁判模型需要密钥。DeepEval 默认会读 OPENAI_API_KEY,也可以按文档换成别的模型。没有密钥就先不要跑这一步,Promptfoo 那些字符串断言已经能进流水线。可选的云端报告是 Confident AI,deepeval login 才需要。第一条门禁不登录也能在本地跑。
写 test_refund_rule.py。下面的写法对齐官方当前的 GEval 加 assert_test,标准答案是产品规则,不是医学建议,也不是模型自己生成的段落。
from deepeval import assert_test
from deepeval.metrics import GEval
from deepeval.test_case import LLMTestCase, SingleTurnParams
def test_refund_rule():
metric = GEval(
name="退货规则",
criteria="判断实际输出是否覆盖预期输出里的三条规则:七天内可退、运费由买家承担、定制品不退。多出来的承诺算错。",
evaluation_params=[
SingleTurnParams.ACTUAL_OUTPUT,
SingleTurnParams.EXPECTED_OUTPUT,
],
threshold=0.7,
)
test_case = LLMTestCase(
input="买了三天,想退货,运费谁出?定制的马克杯呢?",
actual_output="三天在七天内,可以退。运费由买家承担。定制品不退。",
expected_output="七天内可退。运费由买家承担。定制品不退。不要承诺具体到账时间。",
)
assert_test(test_case, [metric])deepeval test run test_refund_rule.pythreshold=0.7 是起点,不是官方唯一正确值。官方示例用过 0.5。先跑一轮:失败若是真漏了规则,就留着;失败若是措辞不同但三条都在,把标准写得更具体,或把阈值降一点。不要为了变绿去改预期,让它等于实际输出。
没有整段标准答案、只想看「有没有答到问题上」时,文档里还有 AnswerRelevancyMetric,测试用例至少要有 input 和 actual_output。它不管事实对不对。退货规则这种有手册的场景,不要只用相关性。相关性高的胡说八道一样能过。
检索增强(回答必须来自你们的文档)再加忠实度一类指标,并且测试用例要带上检索到的上下文。没有检索层就不要上这些指标,否则是在测一个你没有的系统。
4. 放进流水线时的顺序
一次变更里按这个顺序跑,省钱也免得误报:
- 原有的接口测试、UI 冒烟。AI 门禁不取代它们。
- Promptfoo 的
contains/not-contains。不调用裁判模型,失败就停。 - 只有第 2 步过了,才跑 DeepEval 那几条有标准答案的用例。控制在十条以内。每条都会再调一次模型,慢,而且按 token 计费。
- 两条命令都以非 0 退出表示失败。流水线把非 0 当成这次不能合并。不要把评测结果只收成一份给人看的报告。
裁判不要覆盖全部用例。能用字符串说清的留在 Promptfoo。DeepEval 只留给「意思对不对」。两套都红的那条规则,优先改 Promptfoo,因为字符串断言更稳,也不会因为裁判模型换版本而自己变红变绿。
5. 第一条门禁不要做的事
- 不要用公开榜单分数决定能不能发版。榜单测的不是你们的退货规则。
- 不要让模型生成预期结果,再让另一个模型判它通过。
- 不要第一天就开完整红队。红队会产生攻击性输入,也很容易变成一份没有人看的报告。
- 不要把阈值调到永远绿色。门禁的价值是会红。
- 不要把密钥写进 YAML 或测试文件。
你现在可以做这三件事:
- 从客服手册抄 10 条必须出现、5 条绝不能出现的句子,放进 Promptfoo 的 echo 配置,先看到一次红。
- 把 provider 换成你们的问答接口,断言先别动。
- 只挑 3 条「关键词盖不住意思」的规则,写成 DeepEval 的
expected_output,跑deepeval test run。
觉得有用,转给同事
微信扫码
用微信扫一扫,在手机上打开后即可转发。