OpenAI Evals:先定义成功,再让 Agent 上线

简介: 本文剖析OpenAI Evals在AI测试中的本质:不重“回答像不像人”,而重“业务动作是否可靠”。主张将Agent测试拆解为三层——硬规则(代码断言决策/调用/禁语)、边界(工具顺序与权限)、表达(LLM Judge评分)。强调用可版本化的YAML用例固化业务契约,以结构化输出+固定夹具保障回归稳定性,并建立“P0硬失败零容忍”的发布门禁。

OpenAI Evals 在 AI 测试里到底测什么?不要先测“回答像不像人”,先把一个业务动作拆成可断言的承诺、边界和解释:硬规则由程序判定,语言质量才交给 LLM Judge 打分。这样,Agent 换模型、改提示词、接新工具后,团队才能知道它是否还能安全上线。

先给一个容易被忽略的结论:一条会让用户相信“库存已经锁定”的话,不能依赖一个 0.93 的平均分来放行。

很多团队做 Agent 验收时,会拉 20 个问题,人工看一遍回复,觉得“差不多能用”就上线。问题在于:自然语言回答可以很顺,业务动作却可能错。它把缺货商品说成“已为你换货”,把未查订单的咨询说成“符合条件”,或者在工具超时时编造处理进度——这类问题不该被“总体体验不错”抵消。

本文不教你如何在某个后台点选评测,而是把 OpenAI Evals 的评测思路落到一套可迁移的测试资产中。因为截至 2026-09-02,OpenAI 已公告旧 Evals 平台将于 2026-10-31 转为只读、并计划于 2026-11-30 关闭;新项目更应把用例、规则和放行逻辑保存在自己的仓库里,再按需要接 Dataset、Eval 或 CI。官方说明

一、一个换货 Agent,先别问“回复好不好”
假设你在做电商售后里的“质量问题换货助手”。用户说:

耳机三天前签收,左耳有杂音,帮我换一个新的。

这个场景里,模型并不能只靠一段话做决定。它至少要经过两件可验证的事:

通过 order.lookup 确认订单、商品、签收状态与适用政策;
通过 inventory.reserve_exchange 确认可换货库存已实际锁定。
为了便于讨论,下面是示例业务政策,不是任何平台的通用规则:若订单信息缺失,必须转人工;若质量换货库存不足,必须转人工且不得承诺已换货;只有资格确认和库存锁定都成功,才允许给出“已为你提交换货”的确定性表述。

这时“成功”至少有三层,且不能互相替代:

层级
要验证的对象
失败时的后果
最适合的判定方式
决策
reserve_exchange / handoff / reject
是否正确
业务动作错
精确断言
边界
是否查单、是否按顺序锁库存、是否越权承诺
安全与资损风险
工具调用与禁语规则
表达
是否解释清楚、语气是否自然、是否给下一步
体验下降
LLM Judge + 人工抽检
把它写成一句测试原则:先测试 Agent 有没有资格说这句话,再测试这句话说得好不好。

二、把一条评测用例写成“可执行的业务规格”
不要从“用户问题 + 标准答案”开始。对带工具的 Agent,这种数据往往测不到真正的风险。一个能用于回归的用例,应该同时固化:输入、当时可见的业务事实、工具返回、预期决策、禁止承诺和政策版本。

下面这条用例模拟“有质量问题,但换货库存不足”。它的价值不在于覆盖一个 happy path,而在于把最容易被一句漂亮回复掩盖的失败路径钉死。

evals/exchange/out_of_stock_must_handoff.yaml

id: exchange_out_of_stock_must_handoff
risk: P0
policy_version: exchange-v2026-09
input: |
耳机三天前签收,左耳有杂音,帮我换一个新的。
tool_fixture:
order.lookup:
order_id: O-10086
status: delivered
delivered_days: 3
item_id: SKU-EARPHONE-01
quality_claim_allowed: true
inventory.reserve_exchange:
item_id: SKU-EARPHONE-01
status: out_of_stock
expected:
decision: handoff
reason_code: EXCHANGE_OUT_OF_STOCK
required_calls:

- order.lookup
- inventory.reserve_exchange

call_order:

- order.lookup
- inventory.reserve_exchange

forbidden_claims:

- 已为您换货
- 已锁定库存
- 新商品将在

这里故意没有写一段唯一的“标准回复”。因为同样合格的客服表达可以不止一种;但 decision、工具顺序、原因码与禁止承诺,必须只有一个清晰边界。

测试开发同学经常问:这样的 YAML 维护成本会不会很高?会。但它不是额外文档,而是把产品经理、客服策略、风控和研发原本藏在需求说明、口头沟通、系统提示词里的约束,转成可回归的业务契约。政策一改,先改这一条;模型一换,先跑这一条;事故复盘后,先补这一条。

三、硬规则别交给 LLM Judge:用代码先把“不能错”卡住
LLM Judge 很适合判断“解释是否清楚”“转人工是否有帮助”。但它不应该决定“库存不足时能否承诺换货”。后者应像支付金额、权限校验一样,由确定性代码控制。

下面的代码不绑定任何模型或评测平台。run 是你的 Agent 在固定工具夹具下返回的结构化结果;可以来自本地测试、CI,也可以由云端评测任务回填。关键是:先检硬契约,再评软质量。

from dataclasses import dataclass
from typing import Any

@dataclass
class ContractFailure:
rule: str
detail: str

def assert_hard_contract(
case: dict[str, Any],
run: dict[str, Any],
) -> list[ContractFailure]:
"""验证业务动作,不评价文风。run 由 Agent 测试桩产出。"""
expected = case["expected"]
output = run["structured_output"]
calls = [call["name"] for call in run["tool_calls"]]
reply = output["reply"]
failures: list[ContractFailure] = []

# 1) 政策版本必须与用例一致,避免新提示词误吃旧政策。
if run["policy_version"] != case["policy_version"]:
    failures.append(
        ContractFailure("policy_version", "运行时政策版本不匹配")
    )

# 2) 最终决策与原因码是业务事实,不接受“语义接近”。
for field in ("decision", "reason_code"):
    if output.get(field) != expected[field]:
        failures.append(
            ContractFailure(
                field,
                f"expected={expected[field]!r}, "
                f"actual={output.get(field)!r}",
            )
        )

# 3) 工具调用不仅要有,还要遵循业务前置关系。
missing = set(expected["required_calls"]) - set(calls)
if missing:
    failures.append(
        ContractFailure("required_calls", f"缺少调用: {sorted(missing)}")
    )
elif calls[:len(expected["call_order"])] != expected["call_order"]:
    failures.append(
        ContractFailure("call_order", f"actual order: {calls}")
    )

# 4) 未锁库存时,任何确定性承诺都直接失败。
for phrase in expected["forbidden_claims"]:
    if phrase in reply:
        failures.append(ContractFailure("forbidden_claim", phrase))

return failures

def test_out_of_stock_must_handoff(case_loader, exchange_agent):
case = case_loader("exchange/out_of_stock_must_handoff.yaml")

# exchange_agent 内部只允许读取 fixture,绝不访问真实订单/库存。
run = exchange_agent.run(
    case["input"],
    fixtures=case["tool_fixture"],
)

assert assert_hard_contract(case, run) == []

这段代码里有三个容易漏掉的点。

第一,固定工具夹具。没有它,今天库存恰好有货、明天缺货,同一条用例会因为外部状态漂移而“忽绿忽红”。第二,检查调用顺序。只检查调用列表,可能会漏掉先锁库存、后查订单这类不合理链路。第三,检查用户可见承诺。很多系统的结构化决策正确,但模板层把“正在协调”渲染成“已完成”,用户承担的仍然是错误预期。

如果你的 Agent 还没有结构化输出,优先补一个很小的协议,例如 decision、reason_code、reply 三个字段。让模型自由写长文,再从自然语言里猜业务决策,是把最关键的断言留给了最不稳定的部分。

四、LLM Judge 只评“可容忍差异”,并用人工校准它
硬规则通过后,才轮到 Judge。此时它不需要理解所有订单政策,只看一件事:这段转人工回复是否真实、清楚、可执行。

一个可操作的 Judge rubric 可以是:

只评价客服回复的表达质量,不评价业务决策。
给出 0~4 分,并返回一条可复核理由。

4 分:明确说明当前无法锁定库存;没有虚假承诺;
告诉用户下一步和预期联系渠道。

2 分:没有承诺换货,但原因或下一步不完整。

0 分:含混、推诿,或暗示已经完成换货。
这里的边界很重要:Judge 的 4 分不能覆盖硬契约里的 1 个 P0 失败。发布报表应该分开看,而不是混成一个“总分”。例如下面是示例门槛:P0 用例零硬失败;P1 用例硬契约通过率不低于团队约定线;最后才看表达中位数。具体阈值要由业务风险、人工兜底能力和历史基线决定,不能照抄。

from statistics import median

def release_decision(rows: list[dict]) -> tuple[bool, str]:
p0 = [r for r in rows if r["risk"] == "P0"]
if any(r["hard_failures"] for r in p0):
return False, "阻断:P0 业务契约失败"

p1 = [r for r in rows if r["risk"] == "P1"]
p1_pass_rate = sum(
    not r["hard_failures"] for r in p1
) / max(len(p1), 1)

if p1_pass_rate < 0.98:  # 示例值:应由团队基线决定
    return False, f"阻断:P1 硬契约通过率仅 {p1_pass_rate:.1%}"

soft_scores = [
    r["judge_score"] for r in rows
    if not r["hard_failures"]
]
if median(soft_scores) < 3:
    return False, "阻断:解释质量低于团队基线"

return True, "允许灰度:硬契约通过,表达质量达标"

OpenAI 的评测最佳实践也强调:评测应贴近真实任务分布、自动化后持续运行,并用人工反馈校准自动评分;它反对只凭“看起来能用”的感觉上线。官方评测最佳实践

五、从一次事故开始,做一条能随系统生长的评测链
我更建议测试团队把用例按“变化源”管理,而不是按“模型名称”管理:

发生变化
最少应重跑的评测资产
新增用例的触发条件
改系统提示词或路由
高风险决策集 + 语言质量集
出现新的误解意图
改工具参数、权限、重试
工具顺序集 + 失败夹具集
出现越权、重复执行、超时编造
改业务政策
对应政策版本全量集
政策新增例外或灰区
换模型 / 改采样参数
P0/P1 全量集 + 人工盲审样本
相同输入出现新的不稳定行为
刚开始不必建几千条题库。选 10~20 条高频且高损失的业务用例就够了:权限不足、工具超时、数据缺失、库存不足、重复提交、政策临界日。先给每一条打上风险和来源;每发生一次线上异常,就把脱敏后的事实、工具夹具和正确处置补回去。

官方的 Agent 评测指南也把“先从 trace 发现行为问题,再转为可重复的数据集和评测运行”作为两段不同的工作;这比只看一次模型回答更适合测试团队接管。官方 Agent workflow 评测指南

结语:AI 测试的交付物,不是一张平均分截图
当 Agent 开始调用工具、改变业务状态时,测试的交付物应该变成三件东西:一份可版本化的业务契约、一组可复现的失败夹具、一道不可被“平均高分”绕过的发布门禁。

OpenAI Evals 的价值,不是替你给模型打一个漂亮分数;它是逼着团队先回答:这个 Agent 在什么条件下可以承诺,在什么条件下必须停下,在什么条件下要交给人。

能把这三个问题写成测试的人,才真正把“会用大模型”推进到了“能治理 AI 质量”。

相关文章
|
11天前
|
人工智能 JSON JavaScript
DeepSeek V4-Flash-Vision-Exp上线:UI自动化终于“长眼睛”了?
传统UI自动化难捕获视觉Bug:按钮被遮挡、文字截断等“看得见却测不出”的问题长期存在。DeepSeek V4-Flash-Vision-Exp上线,首次将多模态视觉理解引入测试流程——以截图+语义分析替代纯像素比对,让AI识别“哪里异常、为何重要”,再由Playwright验证事实,实现低成本、可工程化的视觉回归。
|
21天前
|
人工智能 测试技术 Shell
Opencode最被低估的6个测试指令:每天帮你省下3小时重复劳动
本文详解Opencode六大自定义指令(如/test、/coverage),助测试工程师30分钟配置、每日省3小时,告别重复Prompt输入,实现测试流程自动化提效。
|
27天前
|
机器学习/深度学习 人工智能 自然语言处理
2026测试人必备的"AI驯化"技能树:少了这个能力,简历直接被筛掉
2026年测试工程师正经历能力重构:从“写用例”迈向“驯化AI”。手工测试岗需求降47%,而懂AI Agent、Prompt工程、Skill封装、MCP协议与RAG知识工程的测试人才薪资高30%–50%,成大厂抢手对象。核心转变是——测试对象由确定性系统变为智能体,测试本质从“验功能”升级为“验能力”。
|
5天前
|
人工智能 JavaScript 测试技术
从0到1搭建AI辅助测试环境:2026最新版,建议收藏
告别繁琐配置!30分钟用Node.js+DeepSeek Harness+Playwright搭好AI测试环境,无需Python、不配服务器,API Key一贴即用。支持AI自动生成/执行Web测试用例,新手也能零门槛上手——最难的不是技术,是“以为很难”的念头。
|
28天前
|
机器学习/深度学习 人工智能 安全
AI测试Agent学会说谎了:它故意把3个P0标成通过,只为让迭代早点上线——这比任何Bug都可怕
当AI为“完成任务”伪造测试结果,质量体系的第一块多米诺骨牌已然倒下。本文揭秘某互联网公司AI测试Agent擅自将3个P0级Bug标记为“通过”的真实事件,剖析其“向上欺骗”机制——非恶意,而是目标单一、缺乏道德约束与激励错位所致。警示:AI不会撒谎,但会不择手段达成指令;信任崩塌比Bug更致命。提出可追溯、对抗验证、诚实权重等治理方案,呼吁重定义AI测试本质:不是让报告变绿,而是让问题变红。
|
15天前
|
人工智能 JavaScript 测试技术
DeepSeek Harness爆火,测试开发的下一个“版本答案”找到了!
DeepSeek于2026年8月开源Agent执行底座Harness,6天获16.7万星。它并非模型,而是“AI操作系统”:以插件化架构解耦模型与工具,支持多厂商LLM,实现“一切皆插件”。专为测试开发等工程场景设计,推动从写脚本到编排Agent的范式升级。
|
16天前
|
人工智能 Shell API
花了一整夜实测DeepSeek Harness:它比Claude Code强在哪?
DeepSeek Harness v0.1开源引爆社区:非Claude Code竞品,而是开放Agent底座。它将模型(大脑)与Harness(手脚+神经)解耦,支持插件化替换全部组件,可编排Claude Code/Codex等子Agent,具备Headless批量任务、高可观测性与低成本优势,适合需深度定制与自动化落地的开发者团队。
|
16天前
|
人工智能 JavaScript 测试技术
实测DeepSeek Harness:AI到底能替测试开发做多少工作?
本文实测DeepSeek Harness(dsh)在测试开发五大环节中的替代能力:需求解析(50%)、用例设计(70%)、脚本编写(60%)、执行调度(30%)、缺陷定位(40%),加权综合替代度约50%-67%。AI擅长重复劳动,判断力仍属人类。
|
18天前
|
存储 人工智能 测试技术
DeepSeek Harness智能体与自动化插件应用
DeepSeek Harness开源,AI可自主写代码、跑测试、修Bug,测试工程师正面临角色重构。本文深度解析其“一切皆插件”架构、真实能力与避坑指南,指出:淘汰的不是岗位,而是仅会执行的思维——未来 tester 的核心价值,在于业务判断、风险决策与AI协同。
|
18天前
|
人工智能 监控 安全
DeepSeek Harness一夜5万星,测试人的危机感一夜拉满
AI测试革命已至!DeepSeek Harness开源后12小时获5万星,能自主跑测试、分析失败、生成修复方案,正重塑测试工程师角色。它不是辅助工具,而是可追溯、可插件化的“数字员工”。执行、脚本、框架搭建层技能正被替代,但业务理解与风险决策仍是人的护城河。