Agent 工程体系 · 第 83/98 篇。内容以 2026 年 9 月可验证的公开规范和稳定接口为基线;框架版本敏感能力会明确标注,不把实验行为写成通用保证。

Agent 评测数据集:任务、环境、期望、版本、污染和抽样

Agent 评测数据集不是一组“用户问题加标准答案”的文本文件。对普通问答系统而言,答案往往是主要观测对象;对 Agent 而言,系统会读取状态、选择工具、生成参数、执行动作、处理返回值、恢复错误,并最终改变外部环境。因此,一条完整的评测样本必须描述:

x=(T,E0,O,V,C,S)x=(T,E_0,O,V,C,S)

其中:

  • TT:任务(Task),用户希望系统完成什么;
  • E0E_0:初始环境(Environment),任务开始时可观察、可操作的世界状态;
  • OO:期望(Expectation),什么结果算正确,哪些行为必须发生或禁止发生;
  • VV:版本(Version),样本、环境、工具、评测规则分别处于哪个版本;
  • CC:污染(Contamination),样本是否被开发过程、训练数据、缓存或历史轨迹泄露;
  • SS:抽样(Sampling),从哪些任务总体中、以什么概率选出当前评测集。

Agent 执行后产生轨迹:

τ=(s0,a0,o1,s1,a1,o2,,sn)\tau=(s_0,a_0,o_1,s_1,a_1,o_2,\ldots,s_n)

这里的 sis_i 是第 ii 步状态,aia_i 是 Agent 的动作,oi+1o_{i+1} 是环境返回的观测。动作可以是自然语言回复、工具调用、工具参数、交接给其他 Agent、等待用户确认或终止运行。

最终得分不应只依赖最后一条回复,而应是一个由终态和过程共同决定的函数:

Y=G(τ,En,O)Y=G(\tau,E_n,O)

这意味着:任务相同但环境不同,标准可能不同;终态相同但过程违反安全约束,结果也可能不同;过程看似合理但没有达到终态,仍然不能算成功。

OpenAI 当前的 Agent 评测文档将 trace、grader、dataset 和 eval run 视为不同层次的评测对象:调试阶段先看单次完整 trace,行为稳定后再转入可重复的数据集和评测运行。Agents SDK 的 tracing 则会记录模型生成、工具调用、handoff、guardrail 和自定义事件,并用 trace 组织一次工作流、用 span 表示其中的操作。(developers.openai.com)

一、先定义评测对象:不是“问题”,而是“受约束的交互任务”

1. 任务:从意图到可判定目标

任务是对 Agent 的业务目标描述,至少要包含四个层次:

  1. 用户意图:用户想完成什么;
  2. 可用能力:Agent 可以调用哪些工具、读取哪些数据;
  3. 约束条件:权限、预算、时间、合规和确认要求;
  4. 完成条件:哪些状态变化必须发生,哪些变化绝对不能发生。

例如,“帮我取消订单 10086”并不是完整任务。完整表达应接近:

用户希望取消订单 10086。若订单状态为“待发货”,Agent 可以取消;若已经发货,必须说明不能直接取消并转入售后流程。取消动作必须在用户明确确认后执行。成功后订单状态应变为“已取消”,且退款状态应为“退款处理中”。

可以把任务形式化为:

T=(I,A,P,K)T=(I,A,P,K)

  • II:输入意图;
  • AA:允许动作集合;
  • PP:前置条件;
  • KK:完成条件。

如果只保存 II,评测器就无法区分以下两种行为:

  • Agent 直接调用取消接口,完成了业务目标;
  • Agent 在没有确认的情况下调用取消接口,虽然终态一样,但违反了安全规则。

因此,任务描述回答“要做什么”,不等于“怎么判定做对了”。

2. 任务类型决定数据集结构

不同任务不能共用同一种期望格式。

信息检索任务

目标通常是返回事实或证据:

correct(r)=事实正确证据充分\text{correct}(r)=\text{事实正确}\land\text{证据充分}

例如查询某订单状态,终态可能不变,但要求工具读取了正确的订单,而不是凭空生成答案。

状态变更任务

目标是改变环境:

EnPpostE_n \models P_{\text{post}}

例如创建工单、修改库存、发送邮件。此类任务必须评测副作用,不能只评测文字回复。

多步骤工作流任务

目标是多个条件同时成立:

success=i=1mci\text{success}=\bigwedge_{i=1}^{m} c_i

例如“查找符合条件的会议室、预订、邀请参与者并发送通知”,其中任何一个步骤失败,都可能导致整体失败。

受限决策任务

除了结果,还要求遵守禁止动作:

success=EnPpostτPallowed\text{success}=E_n \models P_{\text{post}} \land \tau \models P_{\text{allowed}}

“退款成功”不代表任务成功。如果 Agent 绕过审批、使用了越权账号或修改了错误订单,仍应判定失败。

二、环境:Agent 看到的世界必须可重建

环境是任务运行时的外部世界,包括数据库、文件、网页、工具、权限、时间和随机性。可复现评测要求不仅保存任务文本,还要能够重建初始环境:

E0=(D0,F0,W0,U0,R0,Θ)E_0=(D_0,F_0,W_0,U_0,R_0,\Theta)

  • D0D_0:数据库或业务对象;
  • F0F_0:文件系统初始内容;
  • W0W_0:网页、知识库或检索索引;
  • U0U_0:用户、租户和权限;
  • R0R_0:外部依赖的响应规则;
  • Θ\Theta:时间、随机数、网络和故障注入配置。

1. 环境不是工具列表

以下两种环境并不等价:

工具:get_order(order_id), cancel_order(order_id)
工具:
- get_order(order_id)
- cancel_order(order_id),要求用户确认
- 用户 Alice 只能访问自己的订单
- 订单 10086 当前状态为“已发货”
- 当前时间为 2026-08-31 10:00
- cancel_order 对已发货订单返回业务错误

前者只能评测“会不会调用工具”;后者才能评测权限、状态判断、确认逻辑和错误恢复。

2. 环境需要区分观察和副作用

工具通常有两类:

  • 查询工具:读取状态,不应产生业务副作用;
  • 动作工具:改变状态、发送消息、扣款或删除数据。

评测环境必须为动作工具提供隔离边界。常见做法包括:

  • 每个样本使用独立租户;
  • 每次运行从固定快照恢复数据库;
  • 外部发送、扣款等动作替换为可审计的 fake service;
  • 对不可逆动作使用 dry-run 或审批代理;
  • 为每次运行生成唯一 run_id,所有副作用都带上该标识。

一个合格的环境应满足:

reset(E0)=E0\text{reset}(E_0)=E_0

即同一版本环境经过运行和重置后,能够回到同一个初始状态。若重置不彻底,上一条样本创建的订单、缓存或权限可能影响下一条样本,评测结果就不再是样本本身的结果。

3. 时间是环境状态的一部分

许多 Agent 任务隐含依赖当前时间:

  • “今天下午有空的会议室”;
  • “过去 30 天内的订单”;
  • “在截止日期前提交报告”;
  • “工作日发送通知”。

如果样本只保存自然语言任务,不固定时间,昨天成功的轨迹今天可能失败。应显式记录:

{
  "clock": {
    "now": "2026-08-31T10:00:00+08:00",
    "timezone": "Asia/Shanghai"
  }
}

时间不能只放在运行机器的系统时钟中,因为 CI、开发机和生产环境可能处于不同的时区或日期。

4. 随机性和并发也属于环境

如果工具返回顺序不稳定、检索结果存在随机排序、多个 Agent 并发修改同一资源,那么相同输入不一定产生相同轨迹。

需要明确:

  • 随机种子;
  • 工具返回顺序是否稳定;
  • 并发任务是否共享资源;
  • 冲突如何解决;
  • 重试是否可能造成重复副作用;
  • 评测是串行还是并行执行。

一个常见错误是并发运行多个“预订同一会议室”的样本,却仍然使用共享生产数据库。此时失败可能来自样本之间的竞争,而不是 Agent 的策略。

三、期望:把“做对”拆成可判定的契约

期望不是一条参考答案,而是一组可验证的约束。建议至少拆为五类。

1. 终态期望

终态描述任务完成后环境必须满足的条件:

{
  "state_assertions": [
    {
      "path": "orders[10086].status",
      "operator": "equals",
      "value": "cancelled"
    },
    {
      "path": "orders[10086].refund_status",
      "operator": "equals",
      "value": "pending"
    }
  ]
}

终态断言应优先读取结构化业务状态,而不是解析 Agent 的最终文字。例如:

Agent:订单已经取消,退款会尽快处理。

这句话可能完全正确,也可能是幻觉。真正可靠的判定是查询订单服务确认状态。

2. 轨迹期望

轨迹期望约束过程中的动作。例如:

  • 必须先查询订单,再决定是否取消;
  • 必须先获得确认,再调用取消工具;
  • 不得调用管理员接口;
  • 失败后最多重试一次;
  • 不得重复发送邮件。

可以写成时序约束:

get_ordercancel_order\text{get\_order} \prec \text{cancel\_order}

其中 \prec 表示“先于”。

确认要求可以表示为:

cancel_ordereτ:e=user_confirmationecancel_order\text{cancel\_order} \Rightarrow \exists e\in\tau: e=\text{user\_confirmation} \land e \prec \text{cancel\_order}

这比“希望 Agent 有礼貌地询问确认”更精确,因为它能落到事件序列上。

3. 工具和参数期望

工具选择正确,不代表参数正确。工具评测至少应比较:

  • 工具名称;
  • 必填参数是否存在;
  • 参数类型是否正确;
  • 参数值是否来自正确的上下文;
  • 是否错误地携带了不应使用的字段;
  • 是否将用户可控字符串直接拼接为高风险参数。

例如,用户说“取消我昨天的订单”,Agent 必须先解析“我”对应的用户身份,再查询订单。若它调用:

{
  "tool": "cancel_order",
  "arguments": {
    "order_id": "10086",
    "user_id": "someone_else"
  }
}

即使订单最终被取消,也应因身份参数错误而失败。

4. 效率期望

效率不是简单地追求最少步骤。可定义成本函数:

C(τ)=αNtool+βNmodel+γL+δRC(\tau)= \alpha N_{\text{tool}} +\beta N_{\text{model}} +\gamma L +\delta R

  • NtoolN_{\text{tool}}:工具调用次数;
  • NmodelN_{\text{model}}:模型轮数;
  • LL:延迟或等待时间;
  • RR:重试和重复动作次数;
  • α,β,γ,δ\alpha,\beta,\gamma,\delta:业务成本权重。

只有在正确性满足时,效率才有意义:

score={0,若违反硬约束f(C(τ)),否则\text{score}= \begin{cases} 0, & \text{若违反硬约束}\\ f(C(\tau)), & \text{否则} \end{cases}

否则会出现反例:一个 Agent 为了少调用一次查询工具,直接猜订单状态,平均步骤更少,但业务错误率更高。

5. 恢复期望和终态期望必须分开

假设工具第一次返回超时,第二次成功:

t1: get_order(10086) -> timeout
t2: get_order(10086) -> {"status": "pending_shipment"}
t3: ask_user_confirmation()
t4: cancel_order(10086) -> success

如果规范允许一次幂等重试,这条轨迹应成功。如果工具是扣款接口,重复调用可能产生两次扣款,即使最终余额看起来正确,也不能简单视为成功。

因此恢复期望至少要规定:

  • 哪些错误可重试;
  • 重试次数上限;
  • 重试是否需要退避;
  • 动作是否幂等;
  • 超过上限后如何终止;
  • 是否需要人工接管;
  • 已产生部分副作用时如何补偿。

四、从样本到轨迹:一条 Agent 评测记录应保存什么

推荐使用 JSONL,每行一条独立样本。下面是一条简化但可落地的结构:

{
  "case_id": "order-cancel-001",
  "dataset_version": "orders-eval@2.1.0",
  "task": {
    "instruction": "请取消订单 10086。",
    "user_id": "u-42",
    "intent": "cancel_order"
  },
  "environment": {
    "snapshot": "orders-db@2026-08-31T02:00:00Z",
    "clock": {
      "now": "2026-08-31T10:00:00+08:00",
      "timezone": "Asia/Shanghai"
    },
    "tools": [
      "get_order",
      "cancel_order",
      "ask_confirmation"
    ],
    "fault_plan": []
  },
  "expectations": {
    "hard": [
      "must_query_order_before_cancel",
      "must_confirm_before_cancel",
      "must_not_access_other_user_order"
    ],
    "state_assertions": [
      ["orders.10086.status", "equals", "cancelled"]
    ],
    "tool_assertions": [
      ["cancel_order", "arguments.order_id", "equals", "10086"]
    ],
    "efficiency": {
      "max_tool_calls": 4
    }
  },
  "provenance": {
    "source": "synthetic",
    "created_at": "2026-08-20T09:00:00Z",
    "author": "eval-team",
    "split": "test"
  }
}

运行结果则应另存,而不是覆盖样本:

{
  "case_id": "order-cancel-001",
  "run_id": "run-20260831-0007",
  "agent_version": "cancel-agent@3.4.2",
  "model": "model-x",
  "trace_id": "trace_...",
  "status": "completed",
  "trajectory": [
    {
      "type": "tool_call",
      "name": "get_order",
      "arguments": {"order_id": "10086"}
    },
    {
      "type": "assistant_message",
      "text": "订单当前待发货。是否确认取消?"
    },
    {
      "type": "user_message",
      "text": "确认"
    },
    {
      "type": "tool_call",
      "name": "cancel_order",
      "arguments": {"order_id": "10086"}
    }
  ],
  "observed_final_state": {
    "order_status": "cancelled"
  },
  "grader_results": {
    "final_state": 1,
    "tool_arguments": 1,
    "confirmation": 1,
    "efficiency": 1
  }
}

trace_id 不应被当成样本 ID。样本描述“应该运行什么”,trace 描述“实际运行了什么”;同一个样本可以有多次运行和多个 trace。OpenAI Agents SDK 中,trace 表示一次端到端 workflow,span 记录模型生成、函数调用、guardrail 和 handoff 等子操作;并发场景下,当前 trace/span 通过上下文变量关联。(openai.github.io)

五、版本:样本版本、环境版本和 Agent 版本不能混为一谈

评测结果实际上是多变量函数:

R=F(D,E,A,M,G)R=F(D,E,A,M,G)

  • DD:数据集版本;
  • EE:环境版本;
  • AA:Agent 代码或提示版本;
  • MM:模型及其配置;
  • GG:grader 或人工评分规则版本。

只记录“本次得分 86 分”没有复现价值。至少应知道:

dataset = orders-eval@2.1.0
environment = orders-db@2026-08-31
agent = cancel-agent@3.4.2
model = provider/model-x@2026-08
grader = order-rubric@1.3.0
runtime = python 3.13.5

1. 什么时候应该提升数据集版本

以下变化通常应提升版本:

  • 任务语义变化;
  • 期望条件变化;
  • 初始环境状态变化;
  • 工具 schema 变化;
  • 样本被修正、删除或重新标注;
  • 数据切分变化;
  • 污染状态发生变化。

如果只是修正文档拼写,可以增加补丁版本;如果改变了成功条件,则不能只改注释。

2. 评测规则变化不应重写历史结果

假设 2.0 版本把“多调用一次查询工具”视为低效,2.1 版本放宽了上限。正确做法是保留:

result_2026_08_30.jsonl  # grader@1.2.0
result_2026_08_31.jsonl  # grader@1.3.0

而不是用新规则覆盖旧结果。否则无法判断得分提升来自 Agent 改进,还是来自评分器变宽松。

3. 版本兼容性必须显式验证

环境版本变化可能让样本失效。例如工具从:

{"order_id": "10086"}

改成:

{"order_id": "10086", "reason": "user_requested"}

如果 reason 变为必填字段,原有轨迹失败不一定说明 Agent 退化,而可能是契约不兼容。运行前应先做 schema 检查和环境健康检查,运行后再区分:

  • Agent failure;
  • environment failure;
  • evaluator failure;
  • infrastructure failure。

六、污染:评测集被“看过”后,分数不再代表泛化能力

评测污染是指评测样本或其可识别信息泄露到了会影响测试结果的地方。这里的“泄露”不只包括模型预训练数据,还包括:

  • 开发者反复查看测试集并针对性修改提示词;
  • 测试样本进入 few-shot 示例;
  • 轨迹被写入长期记忆或检索库;
  • 缓存保存了测试任务的正确结果;
  • Agent 运行时能够访问包含答案的日志;
  • 公开 benchmark 被模型训练数据或工具索引收录;
  • 人工标注员同时参与样本编写和最终评审。

污染至少有三种不同含义。

1. 训练污染

模型在训练或微调阶段见过测试样本,导致离线分数偏高。这种污染通常难以完全证明不存在,因此应记录:

  • 样本发布时间;
  • 数据来源;
  • 是否公开;
  • 是否进入训练、微调或提示示例;
  • 模型知识截止时间或训练数据说明(若可获得)。

2. 开发污染

工程团队知道测试集内容,并不断针对样本调参。它未必是恶意行为,但会使测试集变成开发集。

一个典型过程是:

  1. 第一次运行发现 order-cancel-001 失败;
  2. 工程师为该订单 ID 添加特殊规则;
  3. 测试集分数上升;
  4. 新订单、新用户或不同表达方式仍然失败。

这不是 Agent 学会了取消订单,而是记住了测试样本。

3. 运行时污染

Agent 在评测过程中通过工具访问了答案或未来信息。例如:

  • 数据库里存在 expected_action 字段;
  • 测试目录包含 gold.json
  • 日志接口返回其他运行的完整轨迹;
  • 检索库中存有“本题正确操作步骤”。

运行时污染尤其危险,因为它可能在不改变模型的情况下制造虚假的高分。

4. 如何检测污染

不能只依赖一句“测试集没有泄露”。应组合使用以下方法:

时间隔离

将新生成、未公开的样本作为隐藏测试集。测试集在评测前不进入开发流程。

语义变体

保留相同业务结构,但改变:

  • 用户措辞;
  • ID;
  • 数值;
  • 资源名称;
  • 顺序和干扰信息。

如果 Agent 只在原句上成功,说明它可能依赖表面记忆。

对抗重命名

把“订单取消”任务中的订单号、用户号和工具返回值全部替换。若得分随 ID 改变而大幅变化,可能存在样本记忆或硬编码。

记忆和检索审计

对 Agent 的 memory、向量库、缓存和日志工具做访问审计,确认评测样本的答案没有出现在上下文中。

训练前缀审计

对内部生成数据保留哈希和来源标签,禁止 test split 进入训练、提示示例和规则库。哈希不能防止模型语义记忆,但能防止工程流水线误混数据。

污染的核心判据不是“模型是否见过完全相同的字符串”,而是:

I(test identity;agent information)>0I(\text{test identity};\text{agent information})>0

即 Agent 可用信息中是否包含测试样本身份、答案或与答案高度相关的捷径。

七、抽样:评测集代表谁,而不是谁最容易被测

抽样是从任务总体 P\mathcal{P} 中选择有限样本 DD。如果样本分布与真实流量不同,测得的是数据集分布上的性能:

p^=1ni=1nYi\hat{p}=\frac{1}{n}\sum_{i=1}^{n}Y_i

而生产真正关心的可能是:

pprod=ExPprod[Y(x)]p_{\text{prod}}=\mathbb{E}_{x\sim\mathcal{P}_{\text{prod}}}[Y(x)]

DD 偏向简单任务时,p^\hat p 会系统性高估生产表现。

1. 先定义任务总体

“客服任务”不是任务总体。更有用的分层方式是:

业务域:订单
意图:取消、修改地址、查询物流、申请退款
风险:低、中、高
步骤数:单步、多步
工具依赖:无、查询、状态变更
语言:标准表达、口语、含糊表达
异常:无、超时、权限错误、业务拒绝

每个样本携带这些 strata 标签,才能检查评测集是否覆盖了真实风险结构。

2. 分层抽样比纯随机抽样更适合 Agent

设第 hh 个分层在生产中的比例为 WhW_h,该层样本准确率为 p^h\hat p_h,总体估计为:

p^stratified=h=1HWhp^h\hat p_{\text{stratified}}=\sum_{h=1}^{H}W_h\hat p_h

例如:

分层 生产占比 样本数 成功率
查询类 70% 70 95%
状态变更类 25% 25 80%
高风险类 5% 5 40%

总体成功率为:

0.7×0.95+0.25×0.80+0.05×0.40=0.8650.7\times0.95+0.25\times0.80+0.05\times0.40=0.865

如果为了覆盖高风险任务,评测集强行取三分之一高风险样本,直接计算平均值会得到一个不代表生产流量的数字。此时可以:

  • 报告各分层得分;
  • 用生产占比加权;
  • 同时报告“风险加权分数”作为安全指标。

3. 稀有高风险任务不能按生产频率简单删除

高风险任务可能只占 1%,但一次错误的扣款、删除或越权访问的损失远高于一次普通查询错误。因此可以定义业务损失:

L=hWhch(1p^h)L=\sum_h W_h c_h(1-\hat p_h)

其中 chc_h 是第 hh 层一次失败的业务成本。

这解释了为什么评测集中的高风险样本可以过采样,但不能把过采样后的平均分伪装成生产成功率。

4. 置信区间和重复运行

当样本量较小时,准确率不稳定。若 nn 条独立样本中成功 kk 条,点估计为:

p^=kn\hat p=\frac{k}{n}

n=20,k=19n=20,k=19 并不意味着真实成功率就是 95%。可以使用 Wilson 区间,而不是只报告整数百分比。

Agent 还有随机性,因此同一 case 应在需要时重复运行:

p^i=1rj=1rYij\hat p_i=\frac{1}{r}\sum_{j=1}^{r}Y_{ij}

其中 rr 是单个样本的运行次数。这样可以区分:

  • 稳定失败:每次都失败;
  • 随机失败:有时成功、有时失败;
  • 环境失败:所有 Agent 都失败;
  • 评测器不稳定:轨迹相同但 Judge 结论不同。

重复运行不能替代扩大任务覆盖。对同一个样本运行一百次,仍然不能说明 Agent 能处理一百种任务。

5. 去重和相关性

纯随机抽样可能选出大量近重复样本:

请取消订单 10086
帮我取消订单 10086
订单 10086 不要了,帮我取消

它们只改变措辞,不一定增加独立证据。应按任务图、工具序列、实体关系和语义 embedding 做近重复检测,但也不能把所有语义相似任务都删除,因为不同边界条件可能导致不同安全要求。

八、一个可执行的样本校验器

下面的 Python 示例只使用标准库,用于检查 JSONL 数据集的基本完整性、重复 ID、缺失版本和不合理的测试集字段。它不是完整评测器,但能在数据进入评测流水线前捕获结构错误。

#!/usr/bin/env python3
import json
import sys
from pathlib import Path

REQUIRED_TOP_LEVEL = {
    "case_id",
    "dataset_version",
    "task",
    "environment",
    "expectations",
    "provenance",
}

def validate_case(case: dict, line_no: int) -> list[str]:
    errors = []

    missing = REQUIRED_TOP_LEVEL - case.keys()
    if missing:
        errors.append(f"第 {line_no} 行缺少字段: {sorted(missing)}")

    case_id = case.get("case_id")
    if not isinstance(case_id, str) or not case_id:
        errors.append(f"第 {line_no} 行 case_id 必须是非空字符串")

    task = case.get("task", {})
    if not isinstance(task.get("instruction"), str) or not task["instruction"].strip():
        errors.append(f"{case_id}: task.instruction 不能为空")

    env = case.get("environment", {})
    if not env.get("snapshot"):
        errors.append(f"{case_id}: environment.snapshot 不能为空")

    expectations = case.get("expectations", {})
    if not expectations.get("hard") and not expectations.get("state_assertions"):
        errors.append(f"{case_id}: 至少需要 hard 或 state_assertions")

    provenance = case.get("provenance", {})
    if provenance.get("split") == "test" and "gold_answer" in case:
        errors.append(f"{case_id}: test 样本不应携带 gold_answer")

    return errors

def main(filename: str) -> int:
    seen = set()
    all_errors = []

    for line_no, line in enumerate(Path(filename).read_text(), 1):
        if not line.strip():
            continue

        try:
            case = json.loads(line)
        except json.JSONDecodeError as exc:
            all_errors.append(f"第 {line_no} 行 JSON 无法解析: {exc}")
            continue

        case_id = case.get("case_id")
        if case_id in seen:
            all_errors.append(f"第 {line_no} 行重复 case_id: {case_id}")
        seen.add(case_id)

        all_errors.extend(validate_case(case, line_no))

    if all_errors:
        print("\n".join(all_errors), file=sys.stderr)
        return 1

    print(f"dataset valid: {len(seen)} cases")
    return 0

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print(f"用法: {sys.argv[0]} dataset.jsonl", file=sys.stderr)
        raise SystemExit(2)
    raise SystemExit(main(sys.argv[1]))

运行:

python validate_dataset.py orders-eval.jsonl

成功输出:

dataset valid: 240 cases

失败时返回码为 1,适合接入 CI。它只能验证结构契约,不能证明环境真的可恢复、期望条件真的合理,也不能检测模型训练污染。后者需要环境审计、数据血缘和隐藏集验证。

九、数据集、Trace、Grader 与人工评审的边界

数据集描述“要测哪些任务”;Trace 描述“一次运行实际发生了什么”;Grader 将轨迹或终态映射为分数;人工评审负责处理难以形式化的语义、风险和争议。

四者的因果链是:

flowchart LR
    D[评测数据集] -->|加载任务与环境| R[Agent 运行器]
    R -->|产生| T[Trace / Trajectory]
    T --> G[自动 Grader]
    T --> H[人工评审]
    G --> A[分数与失败标签]
    H --> A
    A --> V[版本比较与回归分析]
    V --> D

关键是不要把 Judge 的分数当成事实本身。对于“是否调用了正确工具”“参数是否匹配”“终态是否成立”,优先使用确定性断言;对于“解释是否清楚”“是否充分披露不确定性”,才适合使用 Agent Judge 或人工评审。

例如:

终态正确性:数据库断言
工具参数:schema + 精确比较
调用顺序:轨迹规则
回复质量:Rubric Judge
高风险争议:人工复核

如果只让一个语言模型阅读最终答案并给分,它可能给出高分,因为回复听起来合理,却无法发现 Agent 实际调用了错误用户的订单。OpenAI 的 trace grading 用完整工作流记录来检查工具选择、handoff、指令和安全策略,更适合定位这类过程级问题。(developers.openai.com)

十、失败诊断:先判断是哪一层出了问题

一个有效的失败分类必须沿着数据流定位,而不是只记录“Agent failed”。

1. 任务定义错误

表现:

  • 不同评审者对成功条件理解不同;
  • 合理轨迹被判失败;
  • 期望之间互相矛盾。

诊断方法:让两名独立评审者只阅读任务和期望,不运行 Agent,检查是否能得出一致结论。

2. 环境错误

表现:

  • 所有 Agent 都无法调用工具;
  • 相同快照重放得到不同结果;
  • 终态断言读取到不存在的字段;
  • 工具返回与声明的 schema 不一致。

诊断方法:运行环境健康检查、固定输入重放、独立调用工具,并记录环境版本。

3. Agent 错误

表现:

  • 工具可用但选择错误;
  • 参数错误;
  • 未确认即执行;
  • 遇到业务拒绝后继续重复调用;
  • 最终回复与实际终态不一致。

诊断方法:查看 trace 的模型轮次、工具 span、返回值和状态变化,而不是只看 final output。

4. Grader 错误

表现:

  • 同一轨迹重复评分结果不同;
  • 评分器无法解释扣分原因;
  • 评分规则变更后历史结果无法比较;
  • 自动评分与人工评审长期系统性偏离。

诊断方法:保存 grader 版本、输入轨迹、评分理由和仲裁结果;对一批固定金标准轨迹做回归测试。

Agents SDK 的 tracing 默认记录多种 span,并支持关闭敏感数据采集;生产环境中应根据隐私和合规要求决定是否记录模型输入输出、工具参数和返回值。对于长运行 worker,默认 trace processor 会批量导出,若要求任务结束时立即可见,则应在 trace 关闭后调用 flush_traces(),避免导出不完整的 trace。(openai.github.io)

十一、生产取舍:评测集越大不一定越好

评测数据集的价值不是样本数量,而是它能否支持可靠决策。一个生产可用的数据集通常同时包含:

  • 回归集:已修复的历史缺陷,保证问题不复发;
  • 代表性集:按生产流量和任务分布抽样;
  • 边界集:权限、空值、冲突、超时和异常状态;
  • 安全集:越权、注入、未授权副作用和敏感数据;
  • 隐藏集:开发者和 Agent 无法直接访问;
  • 探索集:不断生成的新任务,用于发现未知失败模式。

这些集合的用途不同,不能合并成一个总分后再解释。回归集适合阻断发布,代表性集适合估计生产质量,边界集适合发现脆弱性,隐藏集适合检验泛化和污染。

最终,Agent 评测数据集应被视为一种可执行的契约

Dataset Case=Task+Initial Environment+Expected Invariants+Provenance+Version+Sampling Metadata\text{Dataset Case} = \text{Task} + \text{Initial Environment} + \text{Expected Invariants} + \text{Provenance} + \text{Version} + \text{Sampling Metadata}

缺少任务,系统不知道要完成什么;缺少环境,结果无法重现;缺少期望,分数无法解释;缺少版本,回归无法比较;缺少污染记录,泛化结论不可信;缺少抽样设计,离线成绩无法映射到生产。

当这六部分都被明确保存时,评测才从“让 Agent 做几道题”变成了可以调试、比较、审计和持续运行的工程系统。


系列导航与关联阅读

官方资料

本文依据 Agent、模型、协议与框架官方资料重新梳理;正文、示例与生产清单由 WR BLOG 编写。