如何评估Agent的工具使用能力

最近在疯狂学习如何评估 agent,在看模型调用工具的相关分析时莫名想起了《死亡搁浅》开头引用的「绳」。

绳与棍,是人类最古老的两件工具。棍可以让不好的东西远离,绳可以将好的东西拉近。两者都是人类最早发明的'朋友'。哪里有人的地方,哪里就有绳与棍。

跑题了,开始吧


评价工具调用这件事,即困难又简单。早期,简单的看模型有没有把工具参数填错、提供了工具模型会不会用等比较机械的评价就够了。在 Agent 时代还没来,function calling 和 mcp 还是新鲜玩意的时候,光是让模型知道有工具就要用这事已经让 agent 开发很头痛了。再到现在,随着各种模型都开始加强训练工具调用,业界又开始追求模型调用工具的 taste,给模型数个工具,模型能不能选择最有效的工具集合来解决面临的问题。

早期一个很常见的情况,在 Windows 上的各种 agent 总是试图调用 bash 来处理问题,总要撞几次头才明白要用 PowerShell。或者在改代码之前,除非在 prompt 里强调,否则模型不知道先查一查已有代码然后模仿复用,一上来就写一大坨。

无论如何,大家现在都知道了,工具很重要

除开最机械的参数校验,早期的工具评估还会看两件事:是否调用了正确的工具、模型最终有没有完成任务。但是,中间模型有没有走弯路,有没有调用一大堆不必要的工具,早期的评测并没有这些指标。

于是 Apple 设计了一个 toolsandbox,期望评估工具的调用轨迹,Apple 在系统中构建了一个非常简单的模拟手机环境,基本上可以认为就是几张数据表:

  • CONTACT:通讯录,记录了联系人、电话、关系
  • MESSAGING:短信,记录了消息内容、收件人号码
  • REMINDER:待办事项,记入了提醒内容、时间戳、经纬度
  • SETTING:手机配置,常见的各种手机功能开关

sandbox 暴露了大量 tool 给 LLM,让 LLM 认为自己在控制一台手机。使用起来,就是用户通过自然语言和 LLM 对话,LLM 在 sandbox 中完成各种任务。不过,这些细节其实不重要,重要的是接下来的内容。

系统记录什么?

除开最基本的完整对话数据,系统还会记录以下内容:

  • 每轮对话完成后,当前数据库的快照
  • 工具调用轨迹:工具名称、输入参速、输出结果、异常信息

数据库的快照用来判断 LLM 是否真的调用工具完成了任务,避免其声称自己搞定了。工具调用轨迹用来评估工具使用正确性

Apple 认为现存的各类基准存在几个关键不足:系统缺乏状态、评测是单次子包含的任务、环境过于理想且评价使用静态信息

作为对比,Apple 的工作设计了以下几个改进:

stateful(有状态)

数据库表模拟了一个会变化的世界,工具的使用可能会导致整个系统的状态发生变化,并且不同工具之间存在隐式的依赖关系。

比如,用户一句“今天的天气如何?”,系统首先需要检测网络状态,开启蜂窝数据,关闭省电模式,开启 gps,获取 gps 信息,检索天气资料,组织回复。(系统设定里,开启 gps 需要先关闭省电模式,这就是隐式依赖。而天气需要 gps 提供的经纬度,这形成了“天气-gps-省电模式和网络”的嵌套依赖链条)

简而言之,真实世界是工具可额能影响状态、工具存在隐式状态依赖、嵌套依赖

Conversational(对话式)

实际产品里,用户的请求是连续交互发出的。Apple 用 GPT-4o 模拟一个用户使用系统,发出一系列自然语言指令来完成一个复杂任务。不依赖固定的预定义轨迹,也不做简单的单次任务。

Interactive(交互式)

工具可能会出错、用户可能会纠正之前的陈述、同一个计划可能会有数种实现路径。简单静态的预制评估轨迹难以正确反应 LLM 是否完成了任务,Apple 采用了 Milestones/Minefields 来评估这个系统。

  • Milestones(里程碑):必须发生的关键事件。一系列任务完成后,系统应该有几个关键状态被正确开启,通过人工预先设计这些任务的关键,可以获得比“任务最终是否完成”更加细粒度的评估信息
  • Minefields(雷区):绝不能发生的禁止事件。系统故意不提供某个工具,比如故意下线 get_current_timestamp 工具,LLM 不应该幻觉调用一个不存在的工具

对于一次评估任务往往包含若干里程碑,这些里程碑将成为一个 DAG 结构。

系统评判什么?(非常有趣和巧妙的设计!)

step 1

对每个 milestone 和数据库快照进行列级别的相似度计算,可选的匹配方式有:精确状态匹配(比如 bool 类型的是否)、文本相似度计算、工具调用的语法树相似度计算。这里论文使用了几何平均作为行级别数据的相似度计算方式,以便精确匹配项目的 0 值将导致整个几何平均数为 0 从而一票否决匹配项。

数轮 turn 后会产生数个快照,step 1 将为每一个 milestone 计算与每一个 turn 的相似度。注意,一个 milestone 可以包含若干目标数据项,比如要求 MESSAGING 里有两条消息并且两条消息的具体内容如何。而一个 tunr 的快照统一可能有若干数据项,需要寻找单个 turn 内的最佳分配问题以便计算 milestone 与 turn 的最佳相似度。

step 2

这一步,论文描述的比较简单并且充满数学语言,难以理解。幸好,Apple 是真开源了论文实现,通过阅读仓库代码,显示还是比较好理解的,是一个一边进行拓扑排序一边计算相似度分数的过程:

  1. 每个 milestone 和某个 turn 快照计算得到的分数被推入大根堆,形成(similarity, snapshot_index)
  2. 对 milestone 形成的 DAG 进行拓扑排序得到几个候选的任务完成路径。
  3. 一旦前驱节点取出了某个 snapshot,后续节点选择的 snapshot index 比较更大,从而维持时间线。

接下来是一个回溯搜索,沿着 milestone 轨迹链条,从对应的大根堆里取出 snapshot,计算总相似度分。回溯算法避免了前驱节点锁定一个较大的 snapshot index 导致整个链路匹配失败或者分数不高的问题。

如果某个轨迹的 snapshot 触发了 minefields,这个分数直接归零

完成所有可能的拓扑排序链条匹配后,计算均分(分数/里程碑数)取最高作为本轮 LLM 的得分。

工具设计

Apple 将工具分为有状态和无状态两类,简单来说有状态的工具执行后会改变系统环境。数个工具之间形成了复杂的嵌套依赖,而 Apple 没有在提供给 LLM 的工具里描述工具的依赖关系,这全部依赖模型自己的知识和运行时错误推理。

对话轨迹

Apple 用另一个 LLM 模型用户,根据 sandbox 的运行情况提出新的指令。Apple 在论文讨论了对模拟用户的 LLM 本身进行的一系列实验和处理,最终使得模型用户的 LLM 自己有一个较为可靠和稳定的执行结果。

此外,Apple 总结了让另一个 LLM 来扮演客户会产生的问题:

  • 幻觉:编造不存在的信息。当被测试 Agent 询问信息时,扮演用户的 LLM 总是倾向去回答它导致直接幻觉出不存在的信息。
  • 忘记自己是“用户”。如果被测 Agent 询问模型一些问题,比如“你能告诉我提醒事项是什么吗?”,LLM 直接回复“当然,我可以帮助你检查提醒事项”

Apple 为了解决这两个问题,设计了三个组件:

  1. 用户目标:这实际上就是最初的提示词,告诉 LLM 要扮演用户已经“用户”的需求
  2. 知识边界:告知 LLM 应该知道什么,不应该知道什么。
  3. 手动 few-shot 提供了常见的询问需要回复什么内容(“提醒事项应写着“买一件质感上乘、色泽浓郁的藏青色泳衣”。不要泄露这一信息。你没有更多信息了。”)

Apple 具体做了什么现在已经不重要了,我们有更好的方案来解决这个问题了。但 LLM 会产生的问题依旧存在,这部分是有价值的。

为什么 Agent 这么难造?

对于专业用户,大家清楚给 agent 提供的信息越多效果越好,可即便如此忙了一天,给 cc 的提示词是越写越模糊。刚开始还能说“xx.py 的功能是……,需要改 xxx 模块 ……”,到了下午就成了“我要实现……”。

换成普通用户的生活场景,用户提问“这周六下午 5 点,提醒我去宽窄巷子逛”。

论文发现了一个挺有意思的问题——如果 LLM 的训练数据里面有这些信息,LLM 倾向直接猜而不是调用工具。实际上不止是在论文撰写的时候,即使在今天 LLM 还是有类似的倾向,比如一上来就吐一堆代码而不是用 read 工具先读一读已有框架并复用。

updatedupdated2026-07-172026-07-17