ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI Agent 工具调用准确性评测:选择错误与参数错误分开测

AI Agent 工具调用准确性评测:选择错误与参数错误分开测 AI Agent 工具调用准确性评测选择错误与参数错误分开测原文OpenRouter Blog - 《How to Test Tool-Calling Accuracy in AI Agents》https://openrouter.ai/blog/tutorials/how-to-test-tool-calling-accuracy-in-ai-agents/Agent 上线以后最常听到的一句反馈是它有时候不调工具。这句话没法直接拿来优化因为不调背后其实是两类完全不同的失败。OpenRouter 在 2026 年 9 月 30 日发了一篇教程把这个含糊的问题拆成了两个可测的维度并给了一套能直接跑的评测脚手架。这篇按它的思路整理成一份可落地的测试方案。一、先分清两类失败Agent 用工具时只有两个地方会出错选错工具或者选对了工具但参数传错。工具选择错误该调 refund_order 却调了 lookup_order参数错误工具选对了但 order_id 传成了另一单。这两类失败的修法完全不同。前者要改工具描述和工具数量后者要改参数 schema 和示例。混在一个准确率里算等于把两个 bug 平均成一个数字。原文提到DeepEval 把工具正确性和参数正确性做成两个独立指标Phoenix 也单独提供工具选择评估器思路是一致的。工具选择这一侧还有个很容易漏的用例不需要调工具的请求同样要测。如果只检查回复里有没有工具调用一个多调了无关工具的模型照样能通过。所以用例集里必须包含模型已经有足够信息、应该直接回答的样本以及需要两步才能完成的样本——比如处理 ord_7281 的退款正常路径是先查单再发起退款。参数这一侧要分两步看结构对不对以及值对不对。结构层面要拦住的是非法 JSON、缺必填字段、类型写错、枚举值越界、多传了工具不认识的参数。值层面则是另一回事原文举的例子很典型一个只带 order_id 的调用值写成 ord_7282 完全符合 schema因为 order_id 本来就是字符串但用户问的是 ord_7281——结构合法不等于值正确。二、三种评测方法按能不能机械判断来选方法检查什么适合什么场景无参考答案的 LLM 评委在具体语境下这个工具选择或参数值是否合理无法机械判断、多种选择都成立的决策JSON Schema 校验JSON 结构、必填字段、类型、枚举、未声明字段返回调用的结构合法性轨迹比对调了哪些工具、必要时是否按顺序有已知标准路径的工作流LLM 评委要喂三样东西用户的请求、可用的工具列表、模型的实际输出然后问选这个工具合不合适包括是否本就不该调工具。它适合搜索类场景比如一个研究 Agent 同时有 web_search 和 search_internal_docs哪个更合适取决于用户到底想问什么。用它的时候要固定两样东西判断标准和评委模型否则跨模型比较就没意义。原文还补了一条原则能靠等值比较、schema 校验或业务规则判定的就别再花一次模型调用。Schema 校验的关键技巧是复用同一份 schema。发给模型的那份工具定义直接拿来校验它返回的参数不用另写一套。工具定义里要显式写 additionalProperties: false否则多传字段不会被拦下来。轨迹比对针对多步流程。像查单、校验退款资格、发起退款这种有强制顺序的链路只看单次调用没用得看整体序列。原文提到 LangSmith 的轨迹评估器支持严格、无序、子集、超集四种匹配方式另一套基准的做法更宽松它把参考动作列表重放一遍得到目标数据库终态只要某个序列能推出等价终态就算通过。这个判据很实用如果两个工具谁先谁后都行就别因为参考轨迹用了另一种顺序而判失败。三类检查也可以叠加在同一个用例里比工具名、用 JSON Schema 校参数结构、再比已知参数值。三、一份可以直接跑的评测脚本原文给了一套跨模型评测的最小脚手架先装两个包pipinstallopenai jsonschema主流程完整保留如下importjson,osfromjsonschemaimportDraft7Validator,ValidationErrorfromopenaiimportOpenAI clientOpenAI(base_urlhttps://openrouter.ai/api/v1,api_keyos.environ[OPENROUTER_API_KEY])tools[{type:function,function:{name:lookup_order,description:Look up an order by its ID.,parameters:{type:object,properties:{order_id:{type:string}},required:[order_id],additionalProperties:False,},},}]# 直接复用发给模型的 schema不再另写一套tool_schemas{t[function][name]:t[function][parameters]fortintools}test_cases[{name:known order,messages:[{role:user,content:Check the status of order ord_7281.}],expected_calls:[{name:lookup_order,arguments:{order_id:ord_7281}}],},{name:no tool needed,messages:[{role:user,content:What does an order status of shipped mean?}],expected_calls:[],},]defgrade_case(model,case):responseclient.chat.completions.create(modelmodel,messagescase[messages],toolstools,tool_choiceauto,extra_body{reasoning:{effort:low},provider:{require_parameters:True},},)callsresponse.choices[0].message.tool_callsor[]expectedcase[expected_calls]# 1) 工具选择整数组比对而不是只看第一个tool_selection[c.function.nameforcincalls][e[name]foreinexpected]# 2) 结构用同一份 schema 校验参数schema_ok,parsed[],[]forcallincalls:schematool_schemas.get(call.function.name)ifschemaisNone:schema_ok.append(False)continuetry:argsjson.loads(call.function.arguments)Draft7Validator(schema).validate(args)except(json.JSONDecodeError,ValidationError):schema_ok.append(False)continueschema_ok.append(True)parsed.append({name:call.function.name,arguments:args})schema_validall(schema_ok)ifcallselseNone# 3) 取值结构合法之后再比对具体参数值values_okNoneifexpected:values_okschema_validisTrueandparsedexpected passedtool_selectionifnotexpectedelse(tool_selectionandschema_validisTrueandvalues_okisTrue)return{tool_selection:tool_selection,schema_valid:schema_valid,argument_values:values_ok,passed:passed}几个参数值得单独说清楚tool_choice 设为 auto这是配了工具之后的默认行为保持默认才能测出真实的自主选择能力extra_body 里的 reasoning.effort 统一设成 low避免候选模型默认推理档位不同带来的干扰provider.require_parameters 设为 true保证请求只路由到支持全部参数的供应商否则被测的就不是你写的那份参数了刻意不设 temperature因为部分模型不在 supported_parameters 里声明它同理不设 max_tokens截断会切掉工具调用返回的 JSON制造出假的 JSON 解析失败。原文还提醒每个用例都要跑多次用例集里要补上难例缺参数、工具描述高度相似、一次要调多个工具、以及根本不该调工具的请求。这套脚手架评估的是单轮工具调用多步流程要在完整 trace 上收集调用再评分。四、跨模型比较时别把变量也一起换了脚本最后会打印每个模型通过多少条用例但只有在用例、评分逻辑、模型设置、路由配置四样都保持一致时这个数字才有可比性。原文在常见错误里列了四条都是踩出来的只测干净请求真实用户会缺信息、会问两个相似工具该用哪个、会问一句根本不需要工具的话这些都必须进用例集只看第一个工具调用一次回复可能带多个工具调用要整数组比对否则漏判把合法调用当成正确调用schema 只管结构值对不对——哪个客户、哪一单、什么日期、多少钱——它管不了在不同模型之间改评测工具、提示词、评委、设置、路由改任何一样比较就作废。还有一条路由细节容易被忽略在带工具的请求上平台默认会启用按工具调用错误率重排供应商的机制。想测真实生产链路就保持默认想测某一个具体端点就用 order 字段钉住供应商并关掉回退。另外即使平台侧已经有工具调用错误率的统计把结构失败分成非法 JSON、未知工具名、schema 不匹配三类本地 harness 里的 schema 校验仍然要留着因为两者测的层级不同。五、和同系列另外两篇的配合OpenRouter 同期还发了另外两篇教程讲的正好是这套脚手架的前后两步。一篇是从生产流量构建 golden 评测集建议先抽 20 到 50 条真实请求人工复核再扩到 100 到 1000 条完整回归集流程是抽样、去重聚类、补预期输出、首轮评估修正评分标准、提交 Git 接入 CI核心观点是用真实流量而不是合成数据才能保住请求的分布和失败模式。另一篇讲提示词、模型、工具定义或检索设置变更之后重跑锁定的用例集对照书面行为契约做回归。三篇串起来就是一条完整链路用真实流量建集把工具调用拆成两个维度评每次变更后回归重跑。回到最开始那句它有时候不调工具现在可以拆成三个能出数字的问题工具选择错了多少、参数结构错了几条、参数值错了几条。数字分开之后该改描述、该改 schema 还是该改模型一眼就能看出来。
返回列表