用自己的工具评估Agent能力
指导如何在本地系统上评估开源模型的Agent性能,帮助企业做出模型选择决策。
指导如何在本地系统上评估开源模型的Agent性能,帮助企业做出模型选择决策。
这是一篇由人撰写的、聚焦 AI 智能体的博文。
AI 智能体越来越多地代替我们与软件交互:描述一个任务,智能体选择库、编写调用、运行它们并调试自己的错误。当库设计不合理时,它会欣然绕过它,从头重写逻辑。这为库开发引入了一个新概念:代码不仅要正确、快速,还要设计得让智能体能够有效地驱动它。笨重的 API 或过期文档让我们开发人员烦恼,但现在也会让智能体走更长的、代价更高的路径。
大多数基准测试只关注最终答案。我们想要整个过程:不仅是智能体是否正确,还有它需要多少工作量来完成,以及这如何在模型、库版本和任务中变化。我们正是这样衡量的,使用 transformers 作为案例研究。
在这里,我们将介绍一个针对工具的基准测试,重点关注如何找到答案,并提供一个这样的工具的简单实现,完全在由 pi coding agent 驱动的开源模型上运行,所有模型 × 版本 × 任务的完整扫描都在 Hugging Face Jobs 中展开,这样每次运行都能看到相同的硬件。
但是,你如何为智能体优化软件?
我们坚信以下两个软件原则:
如果没有测试,那就不可用
如果没有文档,那就不存在
这在智能体优化工具领域仍然成立,而且难得的是,这两者直接相关联。
你希望你的工具对智能体存在:它需要易于发现。API 需要清晰,文档需要全面。它们需要以智能体能够快速访问有用文件和示例的方式来组织。如果你希望你的工具对智能体有效,那么你应该针对智能体使用来测试它。
我们将在整个博文中使用 transformers 作为示例:智能体使用它来解决 ML 任务(文本分类、图像字幕、音频转录),而不是对其贡献代码;尽管这个工具被设计为可以与任何可以从命令行操作的工具一起使用。
我们对 transformers 的直觉是,通过几个改变可以大幅简化使用:一个 CLI、一个 Skill 和自包含的、特定任务的示例。这是最近应用于 hf CLI 的相同方案,经过重新设计以优化智能体,其中智能体使用的令牌少了 1.3–1.8 倍(最多 6 倍)。我们想知道这种成果是否具有普遍性,以及它是否也对 transformers 有用。
直觉是一个强大的工具,但在我们为这样一个广泛使用的代码库(如 transformers)添加数千行代码的 PR 之前,我们需要更多的证据。我们开始衡量成功是什么样子。
两个智能体都可以为情感分类任务产生正确的标签,但其中一个:
编写一个 40 行的 Python 脚本,导入 transformers,调试一个形状错误,重新运行两次,最后打印答案;
输入 transformers classify --model ... --text "..." 并且一次调用就完成了。
两者都达到了 POSITIVE(0.9999),以下是智能体在这个确切任务上实际采取的两条路径:
# Task: classify the sentiment of "I absolutely loved the movie, it was fantastic!"
- # one agent: pipe a script into python and parse the output
- python - <<'PY'
- from transformers import AutoTokenizer, AutoModelForSequenceClassification
- import torch
- import torch.nn.functional as F
-
- model = AutoModelForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased-finetuned-sst-2-english")
- tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased-finetuned-sst-2-english")
- inputs = tokenizer("I absolutely loved the movie, it was fantastic!", return_tensors="pt")
- with torch.no_grad():
- logits = model(**inputs).logits
- probs = F.softmax(logits, dim=1)
- idx = torch.argmax(probs, dim=1).item()
- print(model.config.id2label[idx], probs[0][idx].item())
- PY
+ # the other agent: one command
+ transformers classify \
+ --model distilbert/distilbert-base-uncased-finetuned-sst-2-english \
+ --text "I absolutely loved the movie, it was fantastic!"
两种方法都达到了相同的结果。但它们在成本、延迟、令牌使用和失败方面的特征非常不同。
如果你的评估只检查最终字符串,你就看不到这些,也看不到你对库所做的更改(CLI 改进、更好的错误消息、一个 Skill)是否真的帮助了智能体。
我们使用这个工具的目标是评估智能体执行给定任务需要做多少工作,以及对库的更改是否改进了性能。
关于我们如何在这里评估智能体的几句话。
我们在三个变体(或"层级")下运行每个任务;智能体可以接触 transformers 的三种不同方式:
bare pip install transformers, and nothing else
clone the full transformers source, checked out in the working directory
skill a packaged Skill: the CLI's docs + task examples, loaded in context
这些不是嵌套的:skill 不包含 clone(它提供精选的文档,而不是源树),两者都不严格包含另一个,每个都给智能体不同类型的帮助。正如我们将看到的,模型有时在 clone 上的表现可能比 skill 更好。
目前我们只关注可以提供精确匹配的确定性任务,因为它们为实验提供了很好的基础。模型即裁判和其他方案是其他任务的明显下一步。
每次运行都是自己的 Hugging Face Job:每个(模型 × 版本 × 任务)一个,所以整个扫描在相同的硬件上并行运行,这保持了大规模比较的公平性。
结果和追踪记录存储在 Hugging Face Bucket 中:快速、无需版本控制,并且可以处理非常高的写入并发。
不是所有驱动智能体的模型都相等,它们之间的差异改变了你在运行它们时应该关注的内容。
一方面,你有最大、最有能力的开源模型。对于相当普遍的任务,这些最终应该能得到正确的答案。对于它们来说,任务完成度接近 100% 并停止告诉你关于你的工具的很多信息;更相关的基准是智能体花费的努力:花了多少轮、令牌和秒数,以及它们是否走了一条干净的路径或使用了已弃用的 API。
本地模型在大小上变化很大,它们的能力也是如此。诸如"匹配 %"之类的指标比它们更大的对应物更相关,因为你可以看到模型大小/能力如何影响你特定工具上的结果。
这个工具不仅为库维护者提供了关于如何改进仓库以支持智能体交互的指导,还帮助评估不同的智能体和模型在用户关心的任务上的表现。
这个工具从几个方面对每次运行进行评分,这样你就可以问对于每一类模型什么是真正重要的:
match %:最终答案是否包含预期的结果(逐任务、不区分大小写的子字符串/正则表达式/精确匹配,都在报告中显式说明);
median time and median tokens(新的与缓存的与生成的);
runs with error %:包括一个护栏,标记那些没有产生任何内容的运行(0 个输出令牌、没有工具调用、没有答案),以防止无声失败伪装成"0";
marker adoption:工具定义的行为标记;见下面对这是什么的解释。
所有这些都落到一个你可以直接查看的报告中:
实时报告:概览、覆盖范围和结果,全部在客户端。
并且因为它捕获了每次运行的原生智能体追踪记录,数字只是开始:你可以逐命令读取智能体做了什么。这些追踪记录可以通过 Hub 的 agent-traces 查看器共享:
在 Hub 的 agent-traces 查看器中呈现的一次运行:answer-question 任务上的 MiniMax-M2.7。在 Hub 上打开此追踪记录 ↗
在结果之前,快速回顾一下设置。每次运行会改变四件事:驱动智能体的模型、它运行的 transformers 版本、任务和层级(bare / clone / skill)。如前所述,我们为两个不同的模型类别查看不同的指标。
由于大型开源模型通常会得到正确的结果,你真正衡量的是实现这一点所花费的努力。它需要十轮还是一轮?它是否遵循了你已弃用的 API 路径,因为它相信过时的文档?它是否遇到了你没有预见的错误?
最自然的实验方式是固定一个强模型,然后改变工具的修订版本:也就是我们测试的 transformers 各个连续 Git 版本,从 v5.8.0 和 v5.9.0 等已发布标签,到引入 CLI 和 Skill 的特定提交。我们希望观察它给 AI 智能体带来的负担究竟是增加了还是减少了。我们在 transformers 上使用这套测试框架,检查添加专用 CLI 和 Skill 是否真的减轻了 AI 智能体的工作负担。
对于测试中使用的三个大模型,所有任务的平均耗时表明,Skill 提交减少了完成任务所需的时间:
各层级、各修订版本的耗时中位数:Skill 提交(绿点)最快。
另一方面,在克隆仓库的实验中,我们可以看到,引入 CLI 和示例的提交显著增加了 token 消耗,稍后我们就会看到这一点。
各层级、各修订版本新增 token 数中位数:CLI 进入仓库后,clone 变体的 token 数骤增。
阅读 clone 变体的轨迹就能解释原因。这个提交不仅添加了一条命令,还将 CLI 的实现以及一组 cli/agentic/*.py 使用示例直接放进了仓库。
在 clone 变体中,AI 智能体面前是一个完整的 transformers 检出目录,大约三分之一的运行会在调用新接口之前,先阅读这些新内容(/cli/ 目录树和示例脚本)来学习接口。这使输入 token 中位数从约 4k 上升到约 6.4k。
因此,这两张图展示的是同一项权衡的两个方面:这个提交让大模型节省了时间(它们会使用 CLI,而不是调试 Python),但代价是消耗更多 token(它们阅读了教会自己使用 CLI 的代码)。这是合并 PR 前值得了解的一项权衡。
不过,有一点尚未被基准测试覆盖,而它对 CLI 有利:阅读 CLI 的成本会随着连续运行而被摊销。我们的设置是为一次性实验构建的。每次运行都是一个全新的 AI 智能体,需要从头重新发现 CLI,因此每次都要支付发现成本。在实际使用中,AI 智能体只需学习一次接口,随后便能在同一个会话中连续解决一个又一个任务,将这项成本摊到许多请求上。我们在这里测得的 token 增幅更接近最坏情况,而不是用户日常会看到的情况。
开放模型让我们能够精细控制这里最重要的变量:规模、配置、量化方式、提供商、训练方式,以及任何会因模型而异的因素。它们也是良好工具界面最重要的应用场景:如果让一个小模型在空白环境中“使用 transformers 完成 X”,它可能会猜测一个早在若干版本前就已发生变化的 API,可能执行不必要的工具调用,也可能得到错误答案。
因此,这里的实验与上面相反:固定修订版本,然后遍历不同模型。这有助于看清哪些模型真正完成了任务,不仅能比较 token 数和耗时,还能具体了解哪些模型无法可靠地处理工具调用。我们的直觉是,模型越小,工具使用和任务本身都会越困难;为了验证这一点,我们用测试框架测试了一系列不同规模的模型:
各层级、各模型的匹配率:Skill 层级提升了较大模型的表现,却降低了较小模型的表现。
这似乎也与摄入的 token 数量相关:
各层级、各模型新增 token 数中位数。
关于公平比较,需要说明一点:当覆盖范围不均衡时,直接对所有任务求平均会产生误导(一个只完成了耗时较短任务的模型看起来会很快)。报告提供了“仅限共同任务”开关(可跨模型和/或修订版本使用),以便进行同类比较;同时还提供了覆盖率热力图,让你准确看到哪些“任务 × 修订版本 × 模型”组合实际运行过。
这里汇集了两件事:如何越过“AI 智能体是否成功”这一层,进一步观察它做了什么、如何完成;以及我们从测试框架中得到的第一批结果。
匹配率、token 数和耗时可以告诉你一次运行的成本,但无法充分说明底层究竟发生了什么。
因此,我们引入了“标记”这一概念。标记是一种具名模式,由 profile(一个面向特定工具的小型插件,用来告诉测试框架如何构建和驱动某个库)针对每次运行进行匹配。
它是对你所关注行为的一行标签,通过 AI 智能体执行的 shell 命令、编写的代码、读取的文件或最终答案来进行检查。一次运行可能触发多个标记,也可能一个都不触发;报告会按模型和修订版本展示每个标记的触发频率。
对于 transformers,我们声明了若干标记,但这里只关注其中最相关的两个:
cli:AI 智能体调用了 transformers 命令行工具(例如 transformers classify …),而不是编写 Python。
pipeline:它选择了高级 pipeline(...) Python API。
我们通过观察这些标记来判断某项变更是否真的改变了 AI 智能体的行为。有趣的是,模型越大,就越倾向于利用新上下文,而不是依赖自身记忆;因此,它们也越倾向于使用新引入的 CLI。
各层级、各模型的 CLI 采用率:只有 Skill 层级会使用它,而且模型越大,使用率越高。
采用 CLI 是一种新行为:CLI 是在单个提交中加入的,不存在于任何模型的训练数据中,而且文档也很少。效果很明显:真正会使用 CLI 的是附带 CLI 文档的 Skill 变体,其采用率达到 55.3%。
在不同模型规模间比较该提交可以发现,CLI + Skill 对较大模型有帮助:在 Skill 层级,Kimi 和其他大型 AI 智能体会使用 CLI,并以更少的轮次完成任务。(在 clone 层级,它们会先花费更多输入 token 阅读新的 CLI 代码,正如我们上面所看到的,因此收益体现在时间和轮次上,而不是原始 token 数上。)
Kimi-K2.6、GLM-5.1 和 MiniMax-M2.7 在不同修订版本上的表现
但在某些小模型设置中,它似乎会损害性能。一种合理的解释是,小模型依赖记忆中的 API 模式,会复现它们在训练数据中见过的 pipeline(...) 代码片段。对它们而言,新概念意味着更大的出错面。你可以直接在测试框架中观察到这一点:匹配率更低、重试次数更多,而 cli 标记几乎不触发。这一点在 Qwen3-4B 模型上尤其明显:Skill 几乎没有改变其匹配率,却显著影响了成本分布。
其中几乎所有影响都来自 clone 层级。此时检出目录中包含 CLI 实现和 cli/agentic/*.py 示例,而 4B AI 智能体会批量读取它们:新增 token 数中位数从约 2.4k 跃升至约 23k,耗时和输出量也随之暴涨,却没有带来任何准确率收益。
Qwen3-4B 在不同修订版本上的表现。CLI + Skill 提交让成本分布大幅扩散;在 clone 层级,AI 智能体会批量读取新加入的 CLI 源码(新增 token 数约为原来的 10 倍),匹配率却毫无提升。(重复 token 数保持不变:此设置没有使用提示词缓存。)
不过,有时 Skill 会直接破坏正确性。从运行轨迹中可以看到其具体原因,例如对于 Qwen3-14B:添加 Skill 后,其总体匹配率从 67%(bare)下降到 43%;在最简单的任务上,这种崩溃尤其明显:classify-sentiment 在 clone 变体上的匹配率为 100%,加入 Skill 后却降至 0%。
Qwen3-14B 在 classify-sentiment 任务上按层级划分的表现:clone(蓝色)在所有修订版本上都保持 100%,但 Skill 变体(绿色)在 CLI + Skill 修订版本上暴跌至 0%。
查看运行轨迹后可以发现,模型误以为 CLI 是一个可以直接调用的工具(类似 agentic-harness 中的 web-search 工具)。Skill 并不是可执行工具:它只是加载到 AI 智能体上下文中的文档,而 transformers CLI 只能通过 shell 运行(经由 bash);因此,这种做法行不通。
Qwen3-14B 读取 Skill 后,在 56 次 Skill 运行中有 39 次,要么发出 transformers(command="classify", ...) 工具调用(这个工具从未注册),要么因为在已有的 read、bash、edit、write 工具中找不到类似工具,就认定自己无法运行模型并放弃。无论是哪种情况,它都没有退回使用那个在 clone 检出目录上取得 100% 得分的单行 pipeline(...),而是直接宣告任务不可能完成。
Qwen3-14B 在 classify-sentiment 上的表现(Skill 变体):它推断 read、bash、edit、write 无法运行模型,于是放弃。
这正是我们构建这套测试框架想要捕获的问题:同一项变更加快了大模型,却最终破坏了小模型。一开始这让我们觉得有些反直觉,而且如果没有测试,我们很可能会直接按原样发布。对维护者而言,结论是:面向 AI 智能体的 API 应该在不同规模的模型上进行评估,因为新的操作入口可以减少强模型的工作量,却也可能给较小模型增加歧义。这也暗示了一种修复方式:与其手写一个 Skill 并在事后检查,不如预先针对较弱模型生成并验证 Skill。
这正是 Upskill 所做的事情:只有当强模型的解决方案能够显著帮助较小模型时,它才会将该解决方案转换为 Skill。
该评测框架只需一个 CLI:agent-eval。安装后运行一套评测,通过 HF Jobs 将其扩展到多个模型 × 多个修订版本,并将报告发布为 Hugging Face Space。
仅限在可信的本地环境中使用。该评测框架会在绕过权限检查的情况下运行编码智能体,并执行你所指定的任意修订版本中的代码;追踪记录可能包含提示词、输出内容和本地路径。在将其用于并非由你编写的代码或分享结果之前,请先阅读 SECURITY.md。
完整且持续更新的设置与使用说明位于 README 中。
检查最终答案可以告诉你智能体是否能够使用你的库,但无法说明其成本:经历了多少轮交互、消耗了多少 token、出现了哪些错误,以及采取了怎样的路径才得到答案。该评测框架会针对你选择的修订版本和模型衡量这些指标。
在 transformers 上,它发现了一个我们原本可能仅凭信念就发布的问题:CLI + Skill 能提升最大的开放模型,却会损害最小模型的表现。在合并之前了解这一点非常有价值!
它基于 profile,并且以可适配性为设计目标:将其指向你自己的库,定义若干任务及其预期答案,即可获得相同的报告。代码和任务都在仓库中,追踪记录则托管在 Hub 上。如果你将它用于自己的项目,请告诉我们!
该评测框架完全构建在 Mario Zechner 的编码智能体 CLI——pi——之上:它驱动每一次开放模型运行,并且只需一个 HF_TOKEN 即可提供模型服务。正是这一点,让开放模型的大规模扫描评测真正变得可行。
感谢我们评测过的这些模型背后的模型构建者和推理服务提供商。总体而言,这些模型的表现都远远超过了基础基线所显示的水平。
更多博客文章
欢迎 Thinking Machines 的 Inkling
开源社区正在支持用于智能体强化学习的 OpenEnv
· 注册或登录后发表评论