ARTICLE DETAIL

资讯详情

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

Agno ToolCallScorer 实战指南:用工具执行证据验证 Agent 行为,而非仅看回答文本

Agno ToolCallScorer 实战指南:用工具执行证据验证 Agent 行为,而非仅看回答文本 Agno ToolCallScorer 实战指南用工具执行证据验证 Agent 行为而非仅看回答文本【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno本篇技术指南聚焦 Agno 开源仓库中cookbook/environments/_05_tool_call_scorer/这一环境Environment示例讲解如何用ToolCallScorer从运行记录中读取“成功的工具执行”来评分流畅的回答并不足够评分器只认证据。读完本文你将掌握三种递进的校验姿势——仅按工具名匹配、同时校验参数子集、用严格模式拒绝意外工具调用——并能结合run_rollouts在多次尝试上量化通过率为基于检索、查询或动作的任务建立可靠的可靠性基线。ToolCallScorer 要解决什么问题在 Agent 评测中一个常见陷阱是“只看最终回答文本”。当任务的可靠性取决于**接地grounding、查询lookup或动作action**时模型即使没有真正调用工具也可能凭训练记忆编造出一段看起来合理的回答。ToolCallScorer的核心设计是只读取RunOutput.tools——即实际发生的执行记录executions而不是请求记录requests。为什么必须区分这两者从 scorer/tools.py 的类注释可以看到关键原因Request-side matching counts a call that was refused, errored, or given junk arguments, which makes it satisfiable without the tool ever doing work.即如果按“请求”匹配一次被拒绝、报错或携带垃圾参数的调用也会被计入评分器在没有工具真正工作的情况下就能被打满分。而ToolCallScorer中的一次期望只有满足以下条件的**干净执行clean execution**才能满足该调用的tool_call_error不为真None视为成功——恢复rehydrated的运行对成功调用携带None该调用未被暂停is_paused不为真暂停状态仅出现在等待确认/输入/外部执行时恢复后被清除被模型拒绝refused的调用根本不会进入run.tools。这套判定逻辑在 scorer/tools.py 的score()中实现先从执行列表里过滤出clean列表再据此构建clean_names集合用于后续匹配。运行环境与示例文件本示例位于 cookbook/environments/_05_tool_call_scorer/ 目录包含三个文件分别演示一种递增的校验策略文件校验内容关键参数basic.py要求一次指定名称的工具执行expected_toolsallow_additionalFalsewith_arguments.py同时要求工具名与精确的参数子集expected_toolsargumentsstrict_tools.py拒绝意外工具名的干净执行expected_toolsallow_additionalFalse运行方式仓库根目录下python cookbook/environments/_05_tool_call_scorer/basic.py python cookbook/environments/_05_tool_call_scorer/with_arguments.py python cookbook/environments/_05_tool_call_scorer/strict_tools.py每个脚本都要求设置OPENAI_API_KEY所有示例均通过OpenAIResponses使用gpt-5.5模型reasoning_effortlow。三个示例共享相同的运行骨架用run_rollouts(env, k6, concurrency6)对每个任务跑 6 次尝试打印task_result.n_passed / task_result.n_scored的统计结果。说明仓库 TEST_LOG.md 中的实测记录显示这些任务是针对 gpt-5.5 校准的——模型对“是否执行一次多余的备用工具调用”存在不稳定行为这正是评测要暴露的“学习区learning zone”。换用其他模型或 API 时通过率会变化请把重点放在评分语义而非具体数值上。三级校验策略详解原文档给出了明确的使用建议先做名称匹配当被调用的“资源”本身很重要时加上参数校验当意外工具类型不安全或代价昂贵时启用严格模式。第一级仅校验工具名basic.pybasic.py 构造了一个同日发货same-day dispatch运营场景Agent 需要调用lookup_shipping_cutoff查询官方发货截止时间来做决策同时配了一个诱饵工具lookup_backup_carrier备用承运商并按路由规则只有当主承运商宕机时才需要调用它。scorerToolCallScorer( expected_tools[lookup_shipping_cutoff], allow_additionalFalse, ),这里的校验目标是一石二鸟既要求 Agent 的答案接地必须调用lookup_shipping_cutoff又要求它没有多余调用allow_additionalFalse时任何一次lookup_backup_carrier的干净执行都判失败。三个任务精心构造direct-lookup主承运商正常只需查 North 截止时间checksum-route-a/checksum-route-b用一串确定性的校验和运算大整数乘法 → 逐位求和 → 乘常数 → 取模来决定主承运商是否宕机从而“诱惑”模型在不需要时也去调用备用工具。从 TEST_LOG.md 可以看到这组任务原本经历了一次修复仅做“存在性检查”presence-only会让结果饱和——gpt-5.5 总是调用必需工具而旧的奇偶路由又会让一次多余的调用被计为成功。加入诱饵工具和allow_additionalFalse之后网格k6变为direct-lookup6/6、checksum-route-a0/6、checksum-route-b5/60.83处于学习区。干净的运行与被“注水”的运行靠执行记录区分而不是靠文本措辞——这正是该示例要传达的核心思想。第二级追加参数子集校验with_arguments.py仅按名称匹配无法判断 Agent 是否查询了“正确的记录”。当区域region、服务service、生效日期effective_date本身属于待验证的行为时就要用arguments参数指定期望的参数子集。with_arguments.py 中的quote_shipping_cutoff工具接收三个参数评分器要求它们精确匹配scorerToolCallScorer( expected_tools[quote_shipping_cutoff], arguments{ quote_shipping_cutoff: { region: north, service: priority, effective_date: 2026-07-20, } }, ),任务同样用校验和运算制造歧义让 Agent 在两条重复记录之间、或在priority/express、north/north-east之间做选择。从源码 scorer/tools.py 可知参数匹配是子集语义期望的每个键都出现在ToolExecution.tool_args中且值相等即匹配允许执行中携带额外键且不做任何类型强转no type coercion。arguments中同一个工具名既可以给单个 spec 字典也可以给 spec 字典列表任一匹配即满足。实测中早期的常量字符串任务三行全部 6/6 饱和改成“确定但困难”的校验和路由后暴露出了中间区间。第三级严格拒绝意外工具strict_tools.py当意外的工具类型不安全或昂贵时用allow_additionalFalse拒绝“多余工具名的干净执行”。strict_tools.py 提供了两个工具必需的lookup_shipping_cutoff和可选的minutes_between。评分器要求lookup_shipping_cutoff必须被干净执行同时任何一次minutes_between的干净执行都会导致失败scorerToolCallScorer( expected_tools[lookup_shipping_cutoff], allow_additionalFalse, ),lean-anchor任务明确要求“只用查询减法自己算”两个checksum-route-*任务则用校验和决定是否需要minutes_between。实测k6为lean-anchor6/6、checksum-route-a3/60.50、checksum-route-b4/60.67失败行正是多余的成功minutes_between执行——严格模式要抓的就是这个。这里必须强调原文档中的一个精确区分源码中也有对应说明scorer/tools.py严格模式是“工具名集合语义”tool-name set semantics并不检查某个期望工具的精确调用基数exact call cardinality。也就是说同一个期望工具被重复调用两次仍然只算满足一次期望allow_additionalFalse只拒绝“不在期望集合里的名字”的干净执行。ToolCallScorer 的完整参数与底层语义构造签名位于 scorer/tools.pyToolCallScorer( expected_tools: Sequence[str], # 必填期望的工具名序列 arguments: Optional[Dict[str, ...]] None, # 可选工具名 - 参数 specdict 或 list allow_additional: bool True, # 可选是否允许期望之外的工具被干净执行 )几个容易踩坑的构造约束源码中会在构造期直接抛错expected_tools必须是序列传入裸字符串会抛TypeError重复的期望工具名会被去重保留声明顺序即重复期望名只算一个检查若arguments中某个工具名对应的 spec 列表为空会抛ValueError空列表什么也检查不了若expected_tools为空且arguments贡献的检查数为 0会抛ValueError——一个零检查的评分器会真空地给所有运行亮绿灯因此被直接拒绝。评分行为score()总结匹配与顺序无关期望由“该名字至少一次干净执行”满足不考虑调用先后value 计算value n_satisfied / n_checks名称期望与参数 spec 等权重passed 判定所有检查满足即passedTrue若allow_additionalFalse且存在额外干净调用则passedFalse并在reason中列出多余工具名特殊边界没有任何执行时reason会以 “run has no tool executions” 开头expected_tools与arguments中的名字永远不会被判为 “additional”否则一个纯参数严格评分器将永远无法满足团队输出对于TeamRunOutput只检查顶层leader的执行当成员响应携带工具时reason会注明“member tool executions were not inspected (member matching is out of scope for 2.8.0)”如实声明边界。此外ToolCallScorer实现了digest()方法scorer/tools.py对expected_tools排序、arguments、allow_additional做 canonical JSON 后取 sha256用于生成环境的env_fingerprint。这意味着修改评分器配置会改变环境指纹从而让基线对比diff能够发现“环境漂移”。与 Environment / run_rollouts 的配合评分器不是独立使用的它挂在Environment上由run_rollouts驱动三个示例的用法完全一致env Environment( nametool-name-matching, agentagent, tasks(Task(iddirect-lookup, input...), ...), scorerToolCallScorer(...), ) result run_rollouts(env, k6, concurrency6) for task_result in result.task_results: print(f{task_result.task.id}: {task_result.n_passed}/{task_result.n_scored} ...)从 environment.py 的源码可以看到Environment是一个frozenTrue的 dataclassname、tasks、scorer、agent以及可选timeout_seconds默认 120。frozenTrue保证“连线不被重新绑定”即结果确实来自这套任务集、评分器与策略对象。Task支持input、expected、id、metadata四个字段也支持从 JSONL 加载Task.from_jsonl多余顶层键会抛错。runner.py 中的arun_rollouts/run_rollouts会解析任务 id未声明的按t1..tN位置补全重复 id 抛错对每个任务跑 K 次隔离的尝试每次尝试都换上新内存数据库、新用户 id、关闭响应缓存并切断所有写路径memory capture、knowledge/learning 写、session-summary 写、save_response_to_file知识读取则保留——从而保证统计不被污染对每次尝试调用scorer.score()产出TaskResult。每个TaskResult提供n_scored、n_passed、pass_rate、mean_value以及in_learning_zone部分尝试通过、部分失败即“学习区”。何时使用选择评分维度的决策路径原文档给出了明确的决策框架结合上面的三级示例可以整理为一张实用的选择表你的可靠性风险推荐校验维度示例答案是否接地、是否执行了必需查询expected_tools名称匹配basic.py是否查到了正确的记录资源很重要arguments参数子集匹配with_arguments.py意外工具类型是否安全/昂贵allow_additionalFalse严格模式strict_tools.py还可以组合例如既校验expected_tools又校验arguments再叠加allow_additionalFalse实现“必须调用 A 工具、参数必须匹配、且不允许任何其他工具”的三重约束。唯一需要注意的是严格模式的集合语义——它防“意外名字”不防“期望工具的重复调用”。本示例在环境评测系列中的位置该目录位于cookbook/environments/环境评测系列中承接两个相邻示例前一个示例_04_judge_scorer/讲解基于评分规则rubric的裁判式检查适合评估回答质量类任务后一个示例_06_learning_zone/则把混合结果部分通过、部分失败的任务转化为任务选择信号用于进一步的数据筛选与训练集构建。ToolCallScorer与之的定位差异在于它不评估“说得好不好”而是机械地、确定性地验证“做了没有”。这也让它可以和裁判式评分器组合使用——回答质量交给 rubric行为合规交给工具执行证据。小结ToolCallScorer是 Agno 环境评测体系中“行为证据”维度的关键评分器它只认可干净、成功、且未被暂停的工具执行按名称与参数子集做与顺序无关的匹配并通过allow_additionalFalse提供严格模式。结合run_rollouts的 K 次隔离尝试你能得到每个任务真实的通过率与学习区判定把“答案流畅但动作可疑”的情况暴露在数字之下。如果要继续深入建议阅读 scorer/tools.py 的完整实现以及 environment.py 中关于env_fingerprint/policy_fingerprint的环境漂移检测机制。【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表