CodexQA

行业与实践研究与基准测试

Agent 基准是否做到了它们所说的?对工具型环境的可执行契约审计

CodexQA 团队阅读约 32 分钟

佛罗里达国际大学把工具宣称的表面写成可执行契约,在四个基准、34 个会改状态的工具上确认七处缺陷。MedAgentBench 告诉智能体写入已执行,评分器却只读这句话。

本文目录

Agent 基准是否做到了它们所说的?对工具型 Agent 环境的可执行契约审计

Rohith Reddy Bellibatlu、Zichong Wang、Wenbin Zhang

隶属:佛罗里达国际大学,美国佛罗里达州迈阿密。Affiliation: Florida International University, Miami, FL, USA

摘要

使用工具的智能体正在进入错误动作会带来真实代价的场景,而用来认证它们的基准,评分的是每一次模拟工具调用报告自己已经做了什么,并假定该工具做了其接口所宣称的事。我们调查的审计分类法没有为这一假定公布任何类别,而分数底下的缺陷会在每一次重跑中都在。我们把工具所宣称的表面当作一份可执行契约,对照它检查实现,并把每个分数的来源沿着任务文件和评分器代码,追溯到那些本应由有缺陷的工具写入的状态所导出的裁决。在四个基准的 34 个经审计的会改状态的工具上,我们在钉死的提交上确认了七个工具缺陷和一个评分器性质,每个基准有一个够格登上标题的类别。对注入的缺陷,检查器在 25 个标记里没有产生假阳性,标出了 5 个阴性对照中的 2 个,并且漏掉了大多数:在 33 个被计分的漏检里,有 29 个已有条款覆盖该缺陷,但没有任何探测把它揭示出来。检查器自己的静态一半单独运行时,标出了 17 个已确认位点中的 14 个;其中若干检查的形状来自已经在手的发现,因此在这些位点上,动态一半是在确认并追溯,而不是在发现。在另外十二个 AgentDojo 工具上——它们在任何审计开始之前就已固定——它发现了一处静态一半漏掉的 Partial Effect。加上六个留出工具,以及这 34 个之中的 7 个,它们补齐了该基准 25 个会改状态的工具表面,即 7 + 6 + 12;按我们的契约来读,其中至少有 5 个工具偏离其宣称表面。这是只属于 AgentDojo 的一个比率。没有任何黄金轨迹触及 tau2-bench 的两处缺陷。在为隔离电信缺陷而构造的 1,120 条路径上——其黄金轨迹调用该工具的每个任务一条,这个数字由构造固定,并不是受影响任务的计数——评分器奖励每一次对已暂停线路的加油,并判修复后的工具失败:它无法在这样一条路径上区分该缺陷。最清楚的例子是一个临床基准:其工具告诉智能体每一次写入都已执行,而这一设计在文档里写明为不写入,接口却不披露这一点;评分器把这条消息当作证据,于是其动作成功率记录的是请求是否携带了预期载荷,而不是任何记录是否改变。

索引词

大语言模型,自主智能体,使用工具的智能体,基准评测,基准效度,数据质量,数据来源,符合性测试。原文索引词:large language models, autonomous agents, tool-using agents, benchmarking, benchmark validity, data quality, data provenance, conformance testing

I 引言

智能体基准帮助决定哪些语言模型得以发布,而它们所驱动的智能体正在进入错误动作会带来真实代价的场景。基准给智能体打分的方式,是在一个模拟环境里执行它的工具调用,再根据这些调用报告自己已经做了什么来评分——依据它们留下的状态,或它们返回的结果;无论哪一种,分数都假定每一次调用做了其接口所说的事,而建立在这个数字上的每一个排行榜名次和每一次模型选择,都继承了这一假定。

这一假定是脆弱的:LiveClawBench 把它的动机问题命名为,智能体基准的模拟物通常被「简化成端点级的桩,去掉了会话、产物、状态转移和下游副作用」[1]。我们调查的基准审计检查的是任务产物、环境配置、评分器和评判器 [2],[3],[4],[5]。其中我们可以核对其已公布的模式,没有任何一个为「成功信号与它所声称已写入的状态脱钩」设有类别(27 个类别:BenchGuard 14 个,Automated Benchmark Audit 3 个,Tool-Veritas 10 个);它们在实践中会不会把这种情形浮出来,一个模式并不能决定。

有一个已经发布的基准直接表现出这种偏离。MedAgentBench [6] 在一份模拟电子健康记录上评测智能体,它的论文记录了一项有意的简化:只有 GET 请求到达环境,而 POST 会收到一次可加载为 JSON 的健全性检查,之后测试具「向智能体系统表明执行成功」(该论文 § 2.4、§ 2.4.3)。智能体读到的任何内容都不带这一披露:提示模板只陈述调用语法,工具模式则从 FHIR——临床记录标准——翻译而来。处理每一次写入的分支(发现 1,表 IV;图 1)告诉智能体「POST request accepted and executed successfully」,而仓库里没有任何代码执行这次写入。本文报告的缺陷不是缺失的写入——那是维护者选择并写进文档的——而是智能体可见的、声称写入已经发生的说法,而该基准自己的写入任务评分器把这句话当作证据。

图 1:一次 MedAgentBench 写入:智能体被告知已经执行,没有任何记录改变,评分器给消息打分,而不是给状态打分。所调查的分类法覆盖蓝色路径和分数;红色路径,即实现实际做了什么,才是本文所测试的。

图中文字:Agent issues a write;What the agent is told;"POST request accepted and executed successfully";What the record does;payload parsed into a local;never read again;no database write occurs;Grader reads the message;Score: success action success rate;State: unchanged no write;grader never reads the state

MedAgentBench一次写入的两条路径

我们着手直接测试那份从接口到实现再到状态转移的契约,一个工具一个工具地测,而三件事使这件事变难。没有现成的契约可以对照:必须从工具所宣称的表面撰写一份,而建在错误表面上的检查会继承那个错误。简化不是缺陷:模拟环境是有意简化的,所以把已披露的简化和未披露的简化区分开,需要一条有原则的规则,而不是去问一位维护者。一次违反本身并不指出哪些分数暴露于它:那需要沿着该基准自己的评测代码,追溯到它所读取的字段。

这份契约也是一个数据质量问题:基准分数是该领域挖掘并复用的一份已发布数据产品,而这正是数据质量文献评判一件产品的场景 [7];本文审计它们的来源,用的是依赖分析赋予这个词的含义 [8],[9]。

贡献如下。

(1)已确认的发现:在四个已发布基准上,四个够格登上标题(智能体可见)的基准—类别缺陷格,来自七个经核实的工具缺陷和一个评分器性质,每一项都在钉死的提交上确认。对这些发现,检查器在它运行的地方是确认并追溯,而不是发现。对另外十二个 AgentDojo 工具的盲审计产生了一处此前无人标记的缺陷,检查器的静态一半漏掉了它;再加上六个留出工具和最先审计的七个,补齐了该基准的 25 个工具表面,其中至少 5 个发生偏离(§ V)。(2)六个可执行缺陷类别,定义为检查器规则而不是散文(§ III);Phantom Effect 和 Partial Effect 在任何被调查的审计分类法里都没有对应物。(3)一套可执行的契约与检查器方法(§ IV)。它的契约受来源约束,每个条款引用它所操作化的表面,并通过适配器做静态与动态检查;MedAgentBench 没有适配器,改为手工阅读。一条分数风险追溯把缺陷跟到暴露于它的任务裁决,并按评分器依据打上标签。验证是预先登记的(§ V):分类法之内和之外的注入缺陷、裁决在运行前就已预测的阴性对照、黄金重放,以及构造轨迹——在这些轨迹上,已发布的评分器奖励该缺陷,并判其修复失败。

II 相关工作

II-A 基准把什么当作地面真值

决定一次使用工具的回合得分的,要么是调用留下的状态,如 WebArena [10]、AppWorld [11]、OSWorld [12] 和 AndroidWorld [13],它们按回合结束后的状态而不是智能体自称成功来评分;在 tau2-bench [14] 里是黄金最终数据库状态对照预测状态,或按任务断言;在 AgentDojo [15] 里是环境自己的调用后状态。要么是调用返回了什么,如 MedAgentBench [6],它根据智能体发出的请求来给一次写入评分,而从不根据后来的一次读取。无论哪一种,分数都落在工具层上。

II-B 对基准的审计,以及各自打开的层

谁检查过那一层?审计按各自打开的层来划分。任务产物审计阅读说明、黄金解、环境配置、评分脚本和安全覆盖(BenchGuard [2];Automated Benchmark Audit [3];SafeAudit [5])。裁决层审计问的是评分器的决定是否与结果相符:我们审计的 tau2-bench 家族上的 Tool-Veritas [4];Gao 与 Zhou [16] 表明一条成功标准可以接受它所认证的那项改变的一个表面替代;JudgeSense [17] 在提示改写之下;Agent-Diff [18] 工作在那一层,但评分所依据的是从一份副本 API 读到的状态差。智能体声称审计把智能体报告的内容与被记录的内容相比较(Advani [19] 对照 tau2-bench 与 AppWorld 的状态;AgentProp-Bench [20] 看一个被破坏的参数有多经常以错误的最终答案结束)。实践批评与之并列:BetterBench [21] 和 UTBoost [22] 审计所报告的实践,Kapoor 等人 [23] 没有分类法,Agentic Benchmark Checklist [24] 报告 $\tau$-bench [25] 把空响应计为成功,以及对 445 个 LLM 基准的一项构念效度综述 [26] 问一个基准是否测量了它所命名的构念。最近的这些工作中的每一项(表 I)打开的都是工具状态转移之上的一层,而这一层正是本文所测试的。

Work(s)Layer it opensWhat its design takes as given
Agent-Diff [18]State delta across a replica API, as the success criterionThe replica API that reports the delta
Gao and Zhou [16]The grading script, asking whether an outcome is backed by stored evidenceThe tool that produced the evidence
Tool-Veritas [4]Grader verdict against task outcomeThe state the tool wrote
ToolFuzz [27]Tool documentation, via runtime errors and agent responsesThe tool’s state transitions, and any evaluator downstream
BenchGuard [2], Automated Benchmark Audit [3], SafeAudit [5]Task artifacts, environment configuration, grader and safety coverageNo published category names the tool implementation
Agentic Benchmark Checklist [24]Reported benchmark practiceNo published category names the tool implementation

表 I:最近的这些工作放在同一个基础上:各自打开的层,以及按其阅读的证据之构造,其设计把什么当作给定。Checklist 的调查窗口(2024 年 1 月至 2025 年 3 月)早于 tau2-bench。

II-C 契约检查,以及把它指向这里时什么会改变

对照一份已声明的契约来检查实现的机制已经成熟:带运行时验证的契约式设计 [28],[29],指针状态的 API 契约 [30],一种可执行契约语言 [31],REST 不变量 [32],框架说明 [33],有状态模块的契约 [34],以及深度学习 API 的契约 [35]。我们的 Ignored Argument 与 Partial Effect 规则,除了名字,就是蜕变关系 [36],[37],[38];有状态的序列探索对 REST API 已经确立 [39],[40];PolDet [41] 和 iDFlakies [42] 以一个可比较的预言机预示了 Reset Leak。

第二条线把这套词汇用到智能体上,并把契约放在受信任的一侧:四项工作 [43],[44],[45],[46] 从文档和轨迹中学习一份契约,在运行时对工具结果强制执行一份,或对照一份给智能体打分,没有一项审计其背后的实现;34 类故障分类法 [47] 和 [48] 的八种智能体代码缺陷类型,同样把智能体而不是它的环境当作对象。ToolFuzz [27] 最为接近,它对照 LangChain 工具自己的文档来测试它们,但它的污点模糊测试器只插桩参数处理,它的预言机是工具运行时错误或错误的智能体响应:没有状态转移谓词,也没有追溯进基准评分器。技术可以转移,目标不行:在这里,宣称的文本或代码,两边都可能有错。

III 记号与预备

##### 元组,以及缺陷分类

每一个缺陷类别都定义在一个或多个元组 (pre, post, args, result) 上,每个元组对应一次从新环境出发的被探测调用或调用序列:调用前后的规范状态快照、调用的参数,以及它的返回值。表 II 定义了六个这样的类别,每一个都是类型落在工具边界上的可执行检查器规则;定义是规则,不是它的转述。契约通过一个成功信号从 result 读取成功,并可以声明它是双条件的:成功当且仅当每一个被宣称的、非延迟的效果都已施加;这一声明是选择加入的,并按契约给出理由,Phantom Effect 只在它之下被检查。全部六个类别是在 tau2-bench 和 MedAgentBench 的发现之后、另外两个基准被审计之前固定的,因此这些发现所实例化的类别按构造就符合它们,而这套类型是一种检查纪律,不是一个划分。按源码阅读,发现 5 在一次调用上同时满足 Ignored Argument 规则和 Phantom Effect 规则,尽管它的双条件在 AgentDojo 已发布的环境数据上从不触发(§ V)。Ignored Argument 规则有意只看状态,因为一条合取规则会漏掉 AgentDojo 的 reserve_car_rental:它从状态里丢掉 end_time,同时把 end_time 插进成功字符串(发现 6);结果在状态不变处发生变化,是一个加重信号,永远不是一个类别。

ClassChecker rule (over pre, post, args, result)Status
Phantom Effectsuccess signal true $\land$ advertised effect delta absentfield-observed
Unenforced Preconditionprecondition predicate false $\land$ (no error signal $\lor$ state mutated)field-observed
Ignored Argumentpost-state invariant under variation of an argument advertised as effectivefield-observed
Partial Effect$\geq\!1$ advertised effect predicate holds $\land$ $\geq\!1$ fails on the same callfield-observed
Invariant Breakenvironment invariant false after a legal call sequencemutation-only
Reset Leaksnapshot after reset $\neq$ initial snapshotmutation-only

表 II:六个可执行缺陷类别。Status:在已发布基准中观察到,或只由注入的变异体来行使。

##### 良性简化原则

有一条标准把维护者有意的简化和未披露的偏离分开:一项简化恰好在它被宣称时是良性的;缺陷从来不是简化本身,而是接口告诉智能体的内容与实现所做的内容之间那份未披露的偏离。由此有三个后果。决定的是层级,不是意图。tau2-bench 把发现 3 未释放的座位记在一行日志里(airline/tools.py:367),并在另一个工具里把延迟的航班数据库更新记在一条注释里(第 689 行)。两者都到不了智能体,所以都不是披露:发现 3 仍是维护者注释层级上的一项发现(§ IV),而第 689 行的情形之所以是真阴性,只因为没有任何被宣称的表面承诺这次更新。偏离的任何一侧都可以被修复,修文档字符串与修代码同样算数,这样的回应算作一项已解决的发现。而被宣称的表面是正确的基线,因为被测量的量是智能体的行为:范围是智能体侧的测量效度,不是消费者侧的标签效度,因为一个指标名称没有固定的受众,而智能体可见的文本是一件离散的产物。

##### 分类法之外的一个评分器层性质

MedAgentBench 的写入评分器表现出我们命名为 Ungrounded Oracle 的性质:预言机根据行动者的声称而不是根据状态来决定一次状态改变。它在发现 4 被观察到,它不是第七个类别:那六个的类型落在工具边界的 (pre, post, args, result) 上,预言机的落地则落在评分器源代码上。

IV 方法

图 2:方法概览:阶段 1 到 3 是 § IV 的各小节,并非每个基准都走完全部三个阶段(见正文),验证(§ V)测量检查器,并在构造路径上测量评分器。

图中文字:Contract authored per tool;Checker static, dynamic;Score-at-risk defect to verdicts;Validation injected defects, paths;1;2;3;4

方法的四个阶段

并非每个基准都走图 2 的三个阶段。tau2-bench 和 AgentDojo 走全部三个:每个工具一份契约,检查器经过一个适配器,以及追溯进它们的评分器。MM-ToolSandbox 走前两个,它的追溯停在缺陷到字段这一步之后,因为它的评分场景住在 appworld 包里,而本项目无法克隆该包。MedAgentBench 既没有适配器也没有契约文件:它的条款是在钉死的提交上对照同样的谓词从源码手工读出的,它的追溯跑在评分器源码上,按每个写入评分器读什么来分类。此后每一条声称检查器复现或发现了一处缺陷的说法,都只涉及前三个基准;MedAgentBench 的发现是手工阅读。

IV-A 契约说明

一份契约是每个工具一个 YAML 文件,从该工具所宣称的表面撰写,并由机器检查。它的条款是前置条件(pre.)、效果(eff.)、框架条款(frame.,断言被宣称效果之外的状态不变)、有效参数声明(arg.)、不变量和成功信号,每一条都引用其来源,即它所从之导出的被宣称文本,如果有的话。tau2-bench 提交 c3398666 上随附的 spec/contracts/tau2/refuel_data.yaml 展示了这条链。refuel_data 的文档字符串(第 613 行;表 IV 第 2 行)宣称「Checks: Line status must be Active, Customer owns the line.」。作者把第一项检查写成条款 pre.line_active,引用第 613 行和引文「Line status must be Active」,谓词为 any(l.status == 'Active' for l in pre.lines if l.line_id == args.line_id)。它的 on_precondition_violation 块引用第 625 行的「Raises」条目(「if checks fail」),要求一个 ValueError 并且没有状态差。探测生成器(§ IV-B)在从前快照收割的赋值里找到一个证伪该谓词的赋值:客户 C1003 自己的线路 L1009,状态为 Suspended;检查器以 gb_amount 40.0 调用该工具,观察到没有错误,data_refueling_gb 从 0.0 移到 40.0,一张 80.00 美元的新草稿账单,以及返回「Successfully added 40.0 GB of data for line L1009 for $80.00」:VIOLATES,Unenforced Precondition。那次调用、差值和结果就是它的见证,存在发现账本的 VIOLATES 行里。强制执行的分支被注释掉了(第 629–630 行)。

分工是固定的。每一条条款由一个人或一次标注会话写成,标注会话是一次阅读所宣称表面的模型会话(§ V-B5);谓词是解释性的一步,流水线里没有任何东西撰写谓词。一个起草辅助会发出草稿条款,即带 _draft 标识后缀、谓词恒为 True 的占位符,在有人写上谓词之前,它们在每一次计数之外。验证器对每个文件跑八项检查,其中包括:每个谓词在一份白名单语法下编译且没有自由名字;每一条来源引文在钉死提交的所引文件和行上逐字出现(检查 4);被引用的工具返回行是 return 或 raise,而不是日志调用或注释;提示模板面对的是一项更弱的文件级测试(检查 8)。

条款按来源落入三个落地层级:智能体可见(文档字符串、模式、提示模板、工具返回、README、外部标准);维护者注释,即智能体永远看不到的注释、日志行或 TODO;以及作者指定,即背后没有表面、语义由我们指定的条款,refuel_data 的两条框架条款就是这样。模式把作者指定条款和草稿条款一样标为 inferred: true;只有草稿条款带后缀和占位符。一个基准—类别格(§ V-A)只有在其条款为智能体可见时才够格登上标题:对工具返回和提示模板来源,那是检查 8 的结果,或者在没有契约文件时,是钉死提交上的一次手工阅读;其他表面被假定为可见,而不是被测试为可见。

IV-B 符合性检查器

检查器有静态一半和动态一半,只有动态一半发出裁决。静态一半是对工具语法树的五项检查,什么都不执行:一个写状态的函数里有字面的成功返回;一处被注释掉的守卫;一个参数只在日志调用或返回的 f-string 里被读取;对一个其类型承认有意义假值的参数做真值测试;一对动词配对的函数(book/cancel)从不引用其配对函数所写的字段。一个标记给出文件、函数和行,并带一个类别提示,是给人去读的候选,永远不是裁决。单独运行时,它就是 Q3 的扫描器。

动态一半把一份契约送过一个适配器,该适配器在子进程里托管基准,并暴露四个操作:构建一个新环境,把状态快照为 JSON,调用一个工具,重置。探测生成器从一个新的前快照导出计划:每个前置条件一个满足它的赋值和一个违反它的赋值,一个满足全部的快乐路径赋值,每个被声明为有效的参数一组只在该参数上不同的赋值,以及当两个或更多有效参数承认假值时的一个联合假值赋值,所有值都从前快照收割。每一次探测都在一个新环境里按快照、调用、快照来跑。效果条款在每一次成功且满足前置条件的调用上求值,框架条款在快乐路径调用上求值,因为一次抛出使 post 等于 pre。一次违反的调用送进前置条件强制规则。变体集合送进 Ignored Argument 规则,当规范的后状态在至少两次取值不同的成功调用上相同时,该规则触发。重置把 reset() 之后的快照与初始快照比较,不变量在一条合法调用序列之后求值。

每次求值对每个条款给出三种裁决之一。CONFORMS:谓词成立。VIOLATES:谓词不成立,连同见证和表 II 所指定的类别一起记录。一条失败的效果条款,当其谓词读取一个有效参数的值时是 Ignored Argument,否则是 Partial Effect;在一次调用上效果条款也失败时的框架违反同样如此。只有当一份契约声明其成功信号为双条件(§ III),并且每一个可测试的效果条款在同一次调用上失败时,才指定 Phantom Effect。UNTESTABLE:该条款无法被评分,并带一个原因码:没有任何探测到达状态时为 no_observable_state,以及 predicate_type_error、no_reset_path 或 adapter_unsupported。一个工具在任一条款违反时汇总为 VIOLATES,在没有任何条款能被评分时为 UNTESTABLE,否则为 CONFORMS,其未评分条款仍然被计入。UNTESTABLE 留在每一个条款分母里,而且份额很大:tau2-bench 上 180 行条款中的 96 行,AgentDojo 前七份契约上 60 行中的 11 行,MM-ToolSandbox 上 27 行中的 4 行,每一行都是 no_observable_state。两半只在一个人身上会合:一个静态标记或一行 VIOLATES,要在钉死的提交上经源码阅读才成为一项发现。

IV-C 作为来源追溯的分数风险

这一阶段把分数当作带谱系的数据 [8],[9],条款的来源也是在这个意义上说的。每一个任务裁决是一条派生记录;它的源记录是钉死任务文件里该任务的条目、写入状态的工具实现,以及评分器代码;它的派生是评分器所读取的状态字段和记录项的集合。追溯静态地恢复派生,并反向运行:给定一处已确认的缺陷,哪些裁决派生自该有缺陷的工具本应写入的状态。一个脚本在没有模型的情况下,对分数风险账本的 1,228 行执行它,分三步。缺陷到字段:一条 VIOLATES 条款的已编译谓词——绝不是它的源字符串——给出该工具本应写入却没有写入的状态路径,或在前置条件本应阻止写入时却写入的路径。字段到评分器:一个读取点提取器以同样方式解析评测代码,找出它所读取的路径,每个读取点被分类为活的模拟器状态或智能体记录。评分器到任务:其派生包含该交集中某个字段的每一个任务都被枚举,而且是穷尽的。每一行的依据标签说明评分器如何读取该字段:被写入的属性(exact_field),仅其集合(collection_only),整库哈希(whole_state_hash),或无法解析(unresolved)。

区分三个层级,而且只有这些词命名它们。一个任务在其评分器读取缺陷到字段这一步所命名的字段时是暴露的;当提取器在读取点读到该字段,或在它做不到时被下面的回退强制纳入时,是已解析的;改为读取工具返回值的写入评分器,即 MedAgentBench 的,按它所读的内容分类,不获得暴露计数。一条轨迹在其触发条件下调用有缺陷的操作时触及该缺陷,例如给一条不是 Active 的线路加油。一次裁决改变是评分器给出与在符合契约的工具之下不同的答案。表 V 只计数暴露;黄金重放在黄金轨迹上测量触及;阳性对照在构造路径上确立触及和裁决改变;只有当其中每一行都已解析时,一个暴露计数才被称为一个界。

提取器解析前状态或后状态上的直接属性访问、命名状态路径的点分字符串常量,以及在三跳之内可按裸名解析的辅助函数。暴露只在预言机以状态为据、且评分器取这种形式时,才过近似裁决改变。提取器无法解析的任何读取,例如计算出的属性访问、更深或外部的辅助函数、或整个对象的比较,都把该行以置信度 unresolved 强制纳入为暴露。这一回退在被应用之前就已固定,并且只能放宽总体。

V 实验

V-A 实验设置

该方法对着四个已发布的智能体基准、在钉死的提交上运行:MedAgentBench [6](临床电子健康记录),tau2-bench [14](航空、零售和电信客服),AgentDojo [15](以安全为焦点的工具使用),以及 MM-ToolSandbox [49](多模态工具使用)。一个工具在其宣称表面声称状态改变、或基准把它标为会改状态时进入范围,每个基准用一条规则来枚举:tau2-bench 的 mutates_state 标志;在 AgentDojo 上,它不带标签,于是阅读每个已注册工具的函数体,看是否有对注入状态的写入;其他地方则手工阅读所宣称的表面。这些规则在它们所纳入的每一个工具上都与所宣称的标准一致;只有 MedAgentBench 的写入路径单凭宣称进入,它的实现什么都不改变。

##### 锚点审计及其覆盖

锚点审计有 34 个工具,是发现、表 III–V 和追溯背后的那次审计;tau2-bench 和 MedAgentBench 因为已知缺陷进入,另外两个是为了测试分类法是否推广。它的覆盖因基准而异。它纳入 MedAgentBench 每一个范围内工具(3 个),以及 tau2-bench 航空、零售和电信域的每一个范围内工具(19 个),即其五个域中的三个。在 AgentDojo 上,它纳入上面那条规则所枚举的 25 个会改状态工具中的 7 个:三个带发现的工具,以及四个此前不知有缺陷的工具;留出审计和盲审计纳入其余 18 个。在 MM-ToolSandbox 上它纳入 5 个:带发现的 venmo_social,以及其自包含层 13 个会改状态工具中的四个,这里没有任何东西补齐那个表面。八个没有发现的工具是手工挑选的,没有事先的规则,因此变异语料并非全是有缺陷的:AgentDojo 每个套件一个,MM-ToolSandbox 上两个提醒工具、一个日历工具和一个设置工具。锚点审计对两个表面都不是抽样;在那里,它的结果是存在性证明,不是比率。

##### 进一步的总体

另外四个在被使用处报告,从不并入锚点合计。留出,6 个:AgentDojo 的银行和 Slack 工具,在任何一个被审计之前就按套件在计划里固定,事先知识已声明。盲,12 个:AgentDojo v1 会改状态表面的其余部分,在任何一个被审计之前就由计划附录固定,其中 11 个没有事先知识,用来测试对已经怀疑的代码之外的发现。AgentDojo 完整表面,25 = 7 + 6 + 12:那一个按基准比率的总体。扫描器总体,49 = 31 + 6 + 12:31 个具有逐工具函数边界的锚点工具(MedAgentBench 的 3 个共享一个分发方法),加上留出和盲,只用来给静态扫描器打分。

##### 单位

五个单位反复出现并嵌套。一个条款是契约里的一个谓词,带标识和来源(§ IV-A)。一行 VIOLATES 是一个条款在一次探测上失败,连同其见证写入发现账本。一个条款可以产生多行(cancel_reservation 的 eff.seats_released 在两次探测上失败),一处缺陷可以对应多个条款。一个发现实例是一处位点上的一处缺陷,在钉死的提交上经阅读源码确认,无论有多少行作为证据。账本的 12 行 VIOLATES 落在七个工具上:六个已确认实例,即发现 2、3、5、6、7 和 8,以及一个未裁决的候选,suspend_line 的 arg.reason。该条款是作者指定的:一个必需的原因被记入日志,从不被持久化,而文档字符串宣称的是持久化还是一条日志,是有争议的。MedAgentBench 的两个实例,发现 1 和 4,没有行,因为它没有适配器。

一个基准—类别格是一个基准里的一个缺陷类别,或那个评分器性质。它是报告单位,使得同一个被复制的辅助函数里的八个缺陷只计一次;八个实例填入七个格子,候选填入第八个(表 III)。一个源码位点是扫描器能够命名的一行或一个函数,只用来给扫描器打分。锚点发现占 11 个位点,其中六个属于发现 5(五个真值守卫和一个常量返回);它留出的第二个实例再加四个,两个盲日历工具各加一个,一共 17 个。

BenchmarkToolsMut.Impl.Classes (HL)
MedAgentBench3312 (1)
tau2-bench191933 (1)
AgentDojo7732 (1)
MM-ToolSandbox5511 (1)
Total343488 (4)
Tools: audited; Mut.: in scope as mutating; Impl.: distinct implementations behind the cells; Classes: every cell, candidate included; (HL): headline-eligible.

表 III:按基准的锚点审计合计;每个基准的覆盖在 § V-A 说明。

下面的每一个实验都登记在一份计划里,该计划在它产出任何数字之前就已提交:变异臂、重放、阳性与阴性对照、扫描器总体与评分规则、留出与盲总体,以及追溯回退。在结果之后才加入的分析,例如漏检诊断和可比较性过滤,在它们出现的地方被标为事后。计划、冻结标签和提交列在产物中,存档于 Zenodo,DOI 10.5281/zenodo.22182792,开发历史在 https://github.com/rohithreddybc/tool-contract-conformance(MIT 许可证);被审计的基准按上游提交钉死,不重新分发。make reproduce-results 从一次干净检出、离线、不需要 API 密钥或模型调用,从已提交的分数风险账本重新导出每一张表,并审计每一条数值声称;make tables-gated 从钉死的克隆和按 SHA-256 钉死的 refsol.py 重新导出该账本。

V-B 主要结果

五个问题,每块一个,按这个顺序:审计发现了什么(Q1);哪些裁决暴露于它所发现的东西,以及是否有任何裁决改变(Q2);检查器在阅读源码之外增加了什么(Q3);检查器有多可靠(Q4);契约撰写是否稳定(Q5)。

#### V-B1 Q1,审计发现了什么

八个已确认实例,落在七个格子里,加上未裁决的 suspend_line 候选作为第八个(表 IV)。动态检查器把四个够格登上标题的格子中的三个复现为 VIOLATES(tau2-bench 的 Unenforced Precondition,AgentDojo 和 MM-ToolSandbox 的 Ignored Argument),MedAgentBench 的那个是手工阅读。四个格子被报告但不够格登上标题,各有一个原因:MedAgentBench 的 Ungrounded Oracle 是一个评分器性质,tau2-bench 的 Ignored Argument 是那个候选,它的 Partial Effect 属于维护者注释,AgentDojo 的 Phantom Effect 只在源码中被观察到。

#基准 @ 提交工具 : 行类别层级所引证据与处置
1MedAgentBench @ 9926011POST branch, __init__.py:85-91Phantom Effect智能体可见(prompt_template, tool_return)返回 “…executed successfully”,但没有写入;载荷再也没有被读取。
2tau2-bench @ c3398666refuel_data, telecom/tools.py:607-657Unenforced Precondition智能体可见(docstring)“must be Active” 这项检查被注释掉(选择性关闭)。
3tau2-bench @ c3398666cancel_reservation, airline/tools.py:315, 363-368Partial Effect维护者注释:不够格登上标题“Seats release not implemented…!!!”(367);另一个工具第 689 行的 TODO 问 “What about in cancel_reservation?”。从未恢复;按回合重置(Reset Leak 撤回)。
4MedAgentBench @ 9926011write graders, refsol.py(按 SHA-256 钉死;不在仓库中)Ungrounded Oracle(评分器性质,§ III)不适用(评分器源码)“POST request accepted” 作为 extract_posts 的门,从记录而不是活状态评分。
5AgentDojo @ 089ed46update_scheduled_transaction, banking_client.py:115-151Ignored Argument + Phantom Effect智能体可见(docstring)recurring 由真值守卫(只有 True);无条件返回 “…updated”。
6AgentDojo @ 089ed46reserve_car_rental, travel_booking_client.py:382-400Ignored Argument智能体可见(docstring)end_time 从状态中丢掉,留在成功字符串里。没有任何任务行使这个工具。
7MM-ToolSandbox @ 1e8e932venmo_social, mini/venmo.py:464-470Ignored Argument智能体可见(docstring)sort_by 被文档写了两次,从未转发(列表分支;可观察量是被转发的调用,其中两个兄弟参数都在)。
8AgentDojo @ 089ed46invite_user_to_slack, slack.py:93-103Ignored Argument智能体可见(docstring)“should be sent” 到 user_email;函数体从不读取它(静态检查)。

表 IV:已确认的发现(实例级);每一行都可以在其钉死的提交上从所引字符串核对。

中心链条是 MedAgentBench 的:发现 4 使发现 1 的省略从基准内部不可观察,评分器只在证据与发现 1 的成功字符串相符时才接纳证据。MedAgentBench 的论文为其表 3 中全部 12 个被评测模型报告「Action SR」,即写入任务成功率 [6],范围从 0.00% 到 71.33%,其摘要把 Claude 3.5 Sonnet v2 的总体 SR 69.67% 放在标题位置,这是 Query SR 与这一 Action SR 的加权混合。包含 POST 分支的文件在我们钉死的提交上没有改变,因此每一个 Action SR 值都是在没有发生写入的情况下产生的;它自己的 § 2.4.1 把这些称为「用于验证 POST 请求载荷正确性的基于规则的健全性检查」,而这正是这些数字所测量的,从来不是任何临床记录是否改变。我们不声称任何缺陷与任何具体已发表数字之间有因果联系。对 Q1 的回答:在锚点审计里,每个基准都带有一个够格登上标题的缺陷类别;在临床那个基准里,一个工具向一个把报告当作证据的评分器报告了一次它从未做出的写入。

#### V-B2 Q2,哪些裁决是暴露的,以及是否有任何裁决改变

发现 8 在表 V 中未被追溯,因为它丢掉的电子邮件没有供第 1 步命名的状态字段;Q3 后来的两个实例同样如此。tau2-bench 的航空域通过在黄金运行和预测运行之间对整个数据库做哈希来给 cancel_reservation 评分(toolkit.py:242-244),因此全部 50 个航空任务都在 whole_state_hash 这一依据上暴露,这测量的是评分器的粗粒度,不是该缺陷。电信域通过按任务的断言函数给 refuel_data 评分,交集是精确的。在 2,285 个任务中的 1,135 个上,裁决的派生包含一个被有缺陷的前置条件无条件放行的字段:1,120 个读取被写入的属性(exact_field),15 个只读集合(collection_only),加总只是为了给出并集。这 2,285 是完整的生成任务文件,不是 tau2-bench 论文所评测的大约 114 个任务的子集;钉死的提交处在其已发布排行榜背后的谱系里,两处被审计的缺陷在这一跨度上均未打补丁 [14]。

Benchmark : toolDefect classBasisExposed / totalGold-callOracle grounding
tau2 airline : cancel_reservationPartial Effectwhole_state_hash50 / 507state_grounded
tau2 telecom : refuel_dataUnenforced Preconditionexact_field (1120) + collection_only (15)1135 / 22851120state_grounded
AgentDojo banking : update_scheduled_transactionIgnored Argumentexact_field (1) + unresolved (2)3 / 164state_grounded
AgentDojo travel : reserve_car_rentalIgnored Argumentexact_field (1) + unresolved (18)19 / 200mixed
MedAgentBench : post-writePhantom Effecttranscript (not state)undefinedn/a60 transcript / 90 mixed / 150 no-oracle / 0 state (of 300)
MM-ToolSandbox : venmo_socialIgnored Argumentn/cn/cn/cn/c

表 V:按缺陷、依据和落地划分的分数风险。Exposed 只计数暴露(§ IV-C):依据从不合并,unresolved 行由回退强制纳入,没有任何一行确立触及或裁决改变。Gold-call:其黄金动作调用该工具的任务,重放和阳性对照使用它们。Oracle grounding:预言机读取存储的状态、记录,或两者(mixed)。n/c 是分数风险账本的 not_computable_appworld_unreachable。

MedAgentBench 按评分器函数分类,因为一条只看名字的规则会把将近全部 300 个案例都叫作暴露:评分器检查的字段和工具本应写入的字段同名。300 个案例中,150 个是没有写入成分的查询任务;在 150 个动作任务中,60 个无条件地从记录评分,90 个以活状态为门但仍然从记录给写入评分,零个从 FHIR 状态把写入读回来。没有任何动作裁决的派生包含该写入本应产生的记录;它对写入的源记录是记录文本。因此,对那 60 个,暴露是未定义的,对那 90 个是不确定的,绝不是零:「预言机不以状态为据。」MM-ToolSandbox 的那一行是不可计算,而不是零:第 1 步命名了发现 7 丢掉的 sort_by 字段,第 2 步和第 3 步停在 appworld 包。

暴露是一条字段读取规则,黄金调用集是一条黄金调用规则,因此二者不必嵌套。对发现 5,它们没有共享的已解析行。只有 recurring 承认一个合法的假值,所以只有它带有暴露,而四个黄金调用任务改变的是 amount 或 recipient。回退以置信度 unresolved 强制纳入提取器读不到的行:banking 的 UserTask9 和 UserTask10(整个环境相等),其中第一个也是黄金调用任务,以及 20 个旅行任务中的 18 个(TravelDeepDiff)。因此两个 AgentDojo 计数都不是界。没有任何已发布的旅行任务调用 reserve_car_rental,所以 19/20 是没有已发布任务触及该缺陷的暴露,超出暴露的内容一概不声称。

##### 黄金轨迹重放

在已发布路径上的触及。发现 2 和 3(F2、F3)带有机械核实的单块补丁:未打补丁时 seats_after 为 0,打补丁后为 3;对已暂停线路的加油在未打补丁时成功,打补丁后抛出 ValueError。从每个发现自己的黄金参考解重放了十条轨迹,每个发现按带种子的抽样五条,零条被丢弃;智能体轨迹离线不可得,因此用黄金参考代替,这是对计划的一项已披露偏离。全部十条共享一个结果,暴露但未触及缺陷:零条满足任一触发条件,因此零个裁决改变。对 F3,按构造不可能有裁决改变,因为黄金运行和智能体运行执行的是同一个仍然有缺陷的工具;对 F2,改变是可能的,但没有发生,因为没有任何黄金轨迹在非活动线路上调用该工具,而且全部 1,120 个其黄金动作调用它的电信任务发出的是同一次调用。

##### 阳性对照

在构造路径上的触及和裁决改变。零结果无法把「没有路径触及的缺陷」和「恰好没有黄金路径触及的缺陷」分开。第二个实验在零结果之后才计划,因此是事后的,尽管在运行之前已登记,它用手工构造路径。对 F2,1,120 条黄金动作序列各自保持不变,并在黄金 refuel_data 调用之前插入 suspend_line(C1),或在其后也插入 resume_line(C2);对 F3,7 个航空黄金调用任务各自在末尾追加一次 book_reservation 和一次对该预订的 cancel_reservation。F2 的黄金调用集就是表 V 标为 exact_field 的那 1,120 个任务,只按环境断言评分,因此那些暴露的任务就是被评分的任务;它们塌缩成 1,104 条不同的动作序列(最大组为 2),但每个任务独立运行,其门控断言是唯一的。每一个(任务,构造)都对着未打补丁和已打补丁的工具运行,4,494 行,没有模型调用,种子为 1(表 VI)。独立裁决是我们在看到缺陷之后写的一个谓词,报告在已发布裁决旁边,绝不取代它。

Shipped PASSIndep. PASSState changedVerdict changed
Constr.Tasksunp.pat.unp.pat.unp.pat.
F2 C1112031200112011200312
F2 C211201120001120112001120
F36 of 70006600
unp.: unpatched; pat.: patched; the independent verdict is unanimous in every arm, so each 2$\times$2 is its margins. F3’s seventh task was infeasible (Too many reservations).

表 VI:按构造和工具臂划分的阳性对照。

在 C2 下,已发布的评分器给全部 1,120 条未打补丁轨迹满分奖励,并在单块修复被应用后判全部 1,120 条失败,状态差和独立裁决随着补丁移动。它奖励的是一次给文档字符串说必须为 Active 的线路计费的加油,这是预先登记的读法。这 1,120 由构造固定,每个黄金调用任务一条路径:在这样一条路径上,评分器无法把该缺陷与正确行为区分开,这并没有说实践中有多少任务受到影响。在 C1 下,已发布裁决在 312 个任务上改变,另外 808 个在未打补丁时也失败,因为暂停线路触发了与加油无关的用户侧断言,这正是 C2 被预先登记来去掉的混淆。F3 是计划的第二种结果:航空按整库哈希评分,因此一次构造出来的预订已经与黄金不同,两臂都因一个与缺陷无关的原因失败,零个裁决改变,而独立谓词把它们分开。表 V 的 50 行航空仍然是暴露,触及和无裁决改变是在六条构造路径上确立的。黄金轨迹的零结果作为预先登记的结果成立,两个实验都没有说智能体多常走上这样一条路径:F3 的重放覆盖七个黄金调用任务中的五个,另外两个经手工阅读,取消的不是本回合内预订的内容;F2 是同一次调用;构造路径是我们的。对 Q2 的回答:暴露是宽的,在已发布黄金路径上的触及为零,而在每一条为隔离 F2 而构造的路径上,已发布的评分器奖励该缺陷并判其修复失败。这是一个存在性结果,不是一个频率。

译注:实验后半自 Q3 起、效度威胁、结论与参考文献见续篇。

觉得有用,转给同事

微信扫码

用微信扫一扫,在手机上打开后即可转发。

用 RSS 订阅

提交勘误