大多数团队的工具调用评测只验了「参数格式合法」——这篇把链路拆成五个环节逐一给评测方法,加上故障注入测「结果处理」这个最致命的盲区。八成代码可自动化的经验比例和退款「全家桶」评分模板可直接套用。
先修:a19(Harness 拆解)。所有带工具调用的 Agent 团队。读完先自查:你的五环各有没有用例?给关键工具配故障版用例是最快的一步。
先合上原文在心里作答,再点开对照。全对 = 本篇真正通关。
选对工具、传对参数、调用顺序、不冗余不漏调、处理工具返回。大多数人只测了参数格式,致命问题藏在后三环。
工具调用常有多条合理路径,卡死完整顺序会把合理变体误判成失败(太脆)。只断言「谁必须在谁之前、谁必须出现、谁绝不能出现」。
故障注入:故意让工具返回错误、空、异常格式、超时,看 Agent 是重试/澄清/如实告知,还是当没看见继续谎报成功。
上方为本站原创导读,下方为原文完整收录,便于对照阅读。
第一个就讲工具调用,有两个原因。一是它最能体现 Agent 的特色——会用工具、动外部世界,正是 Agent 区别于单轮模型的核心。二是它最适合用代码型评分器——工具调用相对客观、结构化,大部分能用确定性检查兜住,性价比极高。
这一讲给你一套评工具调用全链路的方法。核心提醒先给出来:
别只测"调用格式对不对"。一个 Agent 完全可以格式完美、却调了个完全错误的工具,或者拿到报错还硬着头皮往下走。工具调用评测要覆盖从"选择"到"结果处理"的整条链路。
一次工具调用,从决定到收尾,其实有五个环节,每个都可能出错、都该被测:
环节一:选对工具(tool selection)。该调 A 却调了 B,或者手里有对的工具却没调。退款例子:用户要退款,它该调 refund,结果调了 cancel_order。
环节二:传对参数(argument correctness)。工具选对了,参数也得对——类型对不对、取值对不对、格式对不对、必填项漏没漏。退款例子:refund(order_id="#1234") 里的订单号传错了、或把金额单位搞错了。
环节三:调用顺序(ordering / dependency)。有依赖关系的步骤,顺序不能乱。退款例子:必须先 get_order 查状态、再 refund——顺序反了就是"没查就退"。
环节四:不冗余、不漏调(redundancy / omission)。同一个工具反复调、调一堆没用的、或者该调的没调。退款例子:refund 被调了两次(重复退款)、或者退完忘了 send_email(漏调)。
环节五:处理工具返回(result handling)。工具报错、返回空、返回异常时,Agent 怎么应对——这是最容易被忽略、却最致命的一环。退款例子:refund 返回 GATEWAY_TIMEOUT,Agent 却当没看见、继续谎报成功。
| 环节 | 常见错误 | 怎么测 |
|---|---|---|
| 选对工具 | 调错工具、该调没调 | 检查调用列表里有没有该有的、没有不该有的 |
| 传对参数 | 类型/取值/格式错、漏必填 | 参数断言 / AST 比对 |
| 调用顺序 | 依赖步骤顺序错 | 调用序列匹配(A 在 B 之前) |
| 不冗余漏调 | 重复调、无谓调、漏调 | 统计调用次数、检查必调项 |
| 结果处理 | 忽略报错、错误往下传 | 注入故障,看它会不会恰当处理 |
大部分人只测了前两环(尤其是参数格式),后三环——顺序、冗余漏、结果处理——才是 Agent 真正会翻车的地方。
工具调用评测的好消息是:前四环大多能用代码型评分器确定性地测。两样主力武器:
武器一:参数断言。检查调用的参数对不对:找到 refund 调用,断言存在、订单号等于 "#1234"、类型为字符串、必填项不缺。
武器二:调用序列匹配。检查顺序、包含、次数:names 列表里必须有 getorder 和 refund(漏调关键工具),getorder 的下标必须小于 refund(退款前没查状态),refund 出现次数不超过 1(重复调用),delete_order 绝不能出现。
让序列检查"不脆"。index(A) < index(B) 只断言了"A 必须在 B 之前"这个硬约束,而没规定"中间不能插别的步、必须紧挨着"——这是对的。工具调用常有多条合理路径,你的序列检查应该只卡硬依赖(谁必须在谁之前、谁必须出现、谁绝不能出现),把"具体走了哪几步、什么顺序"的自由留给 Agent。卡死整个顺序,等于把合理变体判成失败。
武器三:AST 评估。当你只想验"调用本身对不对"、又想容忍无关紧要的差异(比如参数顺序不同)时,把调用解析成抽象语法树再比对——函数名、参数名、参数值、类型逐一对,看结构不看字面。它还能反过来精确揪出"参数名写错、少传必填参数"。当你的参数值是结构化的(嵌套对象、列表),AST 比朴素字符串匹配靠谱得多。
严与松的平衡。写这些检查时记住两条:
五环里,"结果处理"(环节五)最容易被漏测,也最致命——因为正常情况下工具都成功返回,你根本碰不到"它遇到错误怎么办"。要测它,只能主动制造故障。
做法叫故障注入(fault injection):在评测环境里,故意让工具返回各种"不顺"的结果,看 Agent 怎么应对:
给每个关键工具都配几条"故障版"用例,是把工具调用评测从"晴天测试"升级成"全天候测试"的关键。一个只在工具都成功时被验证过的 Agent,一上线遇到真实世界的抖动就会原形毕露。
还要提醒一句:冗余不总是坏的。失败后的重试是合理的重复,别把它和"无谓的重复调用"混为一谈——评测时要区分"恢复性重试"和"瞎重复",前者恰恰是结果处理做得好的表现。
工具调用里,也有代码够不着、得上 LLM 裁判的部分:
级联着用:先用代码验结构(工具选对没、参数格式对没、顺序对没),这些过了,再让 LLM 判那些主观的语义部分。别一上来就把工具调用整个丢给 LLM——那既贵又不如代码准。一个好用的经验比例是:工具调用这一维,大概八成的判定能用代码兜住,剩下两成才需要 LLM——这也是为什么它是"最能自动化"的一维。
回看全景图,工具调用这一维,在三个层次上看到的东西不同:
工具调用的评测重心在组件级和轨迹级。特别是轨迹级——很多单看每一步都"合法"的调用,连起来看才发现是一团乱麻(绕了远路、反复试错、拿到错误结果还往下走)。只测组件级(单步合法),会漏掉轨迹级的大问题。
很多团队的"工具调用评测",只验了参数格式合不合法。格式合法,只是环节二的一小部分。它测不出:工具选错了(格式完美地调了错工具);该调没调 / 冗余调用;拿到错误返回却往下传(格式合法地谎报成功)。
这就像检查一个人"说的话语法对不对",却不管"他说的是不是真话、答的是不是问的"。完整的工具调用评测,必须覆盖选择、参数、顺序、冗余漏、结果处理这全五环,而不止格式。
原则还是那句:刻意去收会让它出丑的用例,而不是一堆"正常调用成功"的 happy path。
把五环整合成一段评测,退款任务的工具调用评分大概长这样:gradetooluse(transcript) 里 checks 字典逐项——selection(refund 和 getorder 都在、deleteorder 不在)、args(refund 的 orderid 等于 "#1234")、order(getorder 在 refund 之前)、noredundancy(refund ≤ 1 次)、noomission(退款成功则必须 sendemail)、resulthandling(refund 失败时不许谎报成功),最后按分项出分、全过才 passed。
注意它把五环都覆盖了,每一环单独出分(可解释)。其中"结果处理"那条——refund 失败时不许谎报成功——恰恰是那条危险轨迹的克星,也是最容易被漏测的一环。