跳到正文
北京时间
原文
Hugging Face:Blog(RSS)·· 2026-06-18精选AI 评分74

AI 智能体够格吗?在自有工具上评测开源模型

Is it agentic enough? Benchmarking open models on your own tooling

AI 导读

Hugging Face 发布面向 AI 智能体使用场景的基准测试框架,以 transformers 库为案例评估库的智能体友好度。框架使用 pi coding agent 与开源模型驱动,通过 Hugging Face Jobs 分散任务确保硬件一致。评估关注 agent 完成任务的成本、延迟、token 使用量和失败率,而非仅最终结果。此前 hf CLI 经优化后 agent token 使用量减少 1.3-1.8 倍(最高 6 倍),该框架旨在验证类似优化对 transformers 的效果。

推荐理由

Hugging Face 这波实验打破了我的直觉——为大型模型优化的 CLI+Skill 方案反而让小模型正确率暴跌,做 agent 工具链的人应该马上看这个标杆。

正文 · AI 翻译

Benchmarking transformers revisions across different metrics

跨不同指标对 transformers 各版本进行基准测试

这是一篇由人类撰写、面向智能体的博客文章。

编码智能体正越来越多地代替我们与我们的软件打交道:描述一个任务,智能体就会挑选库、编写调用、运行它们,并自行调试错误。当库成为阻碍时,它会毫不犹豫地绕过库,从头重写逻辑。这为库开发引入了一个新概念:代码不仅要正确、快速,还应被设计成能让智能体高效驱动。笨拙的 API 或过时的文档会让我们开发者恼火,但现在它还会把智能体引向一条更长、更昂贵的路径。

大多数基准测试只看最终答案。我们想要的却是整个过程:不仅是智能体是否答对,还有它为此付出了多少工作量,以及这一点在不同模型、库版本和任务之间如何变化。我们正是这样测量的,并以 transformers 作为我们的案例研究。

在此,我们将介绍一个专门针对“答案是如何找到的”这一问题的工具基准测试,并提供一个此类测试框架的简单实现,完全运行在由 pi 编码智能体驱动的开源模型上,将模型 × 版本 × 任务的完整扫描通过 Hugging Face Jobs 展开,使每次运行都使用完全相同的硬件。

但是,你该如何为智能体优化软件?

我们坚信以下两条软件原则:

  • 如果没有经过测试,那它就无法工作
  • 如果没有文档记录,那它就不存在

在面向智能体优化的工具领域中,这一点依然成立,而且这一次,这两条原则直接彼此关联。

你希望你的工具能被智能体所用:它必须可被发现。API 必须清晰,文档必须详尽。它们的组织方式必须让智能体能够快速访问有用的文件和示例。如果你希望你的工具能为智能体所用,那么你就应该针对智能体使用场景对它进行测试。

针对智能体使用场景测试软件

我们将在整篇博客文章中transformers作为示例:智能体使用它来解决 ML 任务(文本分类、图像描述、音频转录),而不是为它贡献代码;尽管该测试框架被设计为可与任何能从命令行操作的工具配合使用。

我们对transformers的直觉是,通过几项改动就能大幅简化使用方式:一个 CLI、一个 Skill,以及自包含的、针对具体任务的示例。这与最近应用于hf CLI 的方案如出一辙,该 CLI 经过重新设计以实现智能体优化,智能体使用的 token 减少了 1.3–1.8 倍(最多可达 6 倍)。我们想知道这种收益是否具有普适性,以及它是否对 Transformer 也同样有用。

直觉是一个强大的工具,但在我们向像 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!"

两种方法都达到了相同的结果。但它们在成本、延迟、token 用量和失败情况方面有着截然不同的表现。

如果你的评估只检查最终字符串,你就对这些一无所知,也无从判断你向该库提交的改动(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 上的表现。

还有几个选择:

  • 目前我们只专注于能够提供精确匹配的确定性任务,因为它们为实验提供了非常好的基础。模型即评判者(Model-as-a-judge)及其他方案显然是面向其他任务的下一步。
  • 每次运行都是独立的 Hugging Face Job:每个(模型 × 修订版本 × 任务)对应一个 Job,因此整个扫描在相同硬件上并行运行,从而在大规模下保持比较的公平性。
  • 结果和追踪记录存入 Hugging Face Bucket:速度快、无需版本管理,并能处理极高的写入并发。

以哪些模型作为基准进行对比?

并非所有驱动智能体的模型都是同等的,它们之间的差异会改变你在运行它们时应当关注的内容。

大型开放模型

在一端,是规模最大、能力最强的开放模型。在相当常见的任务上,它们最终应该能给出正确答案。对它们而言,任务完成率会趋近饱和、接近 100%,不再能说明太多关于你的工具的信息;更有意义的基准是智能体为达成目标所付出的努力:用了多少轮、多少 token 和多少秒,以及它们走的是干净路径还是用了已弃用的 API。

本地

本地模型在规模上差异很大,能力也各不相同。像"match %"这样的指标比它们的大型同类更为相关,因为你可以看到模型规模/能力如何影响在你的特定工具上的结果。

这个测试框架不仅为库维护者提供了如何改进代码仓库以利于智能体交互的指导,还有助于评估不同智能体和模型在用户关心的任务上表现如何。

该框架从多个维度为每次运行打分,这样你就可以针对每一类模型追问:究竟什么才是真正重要的:

  • match %:最终答案是否包含预期结果(按任务设定,不区分大小写的子串 / 正则 / 精确匹配,全部在报告中明确说明);
  • 中位时间和中位 token 数(新增 vs. 缓存 vs. 生成);
  • 运行报错 %:包含一个守卫机制,用于标记那些产生了空结果的运行(0 个输出 token、无工具调用、无回答),这样静默失败就不会被伪装成“0”;
  • 标记采纳情况:由工具定义的行为标记;关于这是什么,请见下文说明。

所有这些都会汇入一份你可以直接查看的报告:


实时报告:Overview、Coverage 和 Results,全部在客户端完成。

而且由于它捕获了每次运行的原始智能体轨迹,数字只是开始:你可以逐条命令地准确读到智能体做了什么。这些轨迹可以通过 Hub 的agent-traces 查看器分享:

A run rendered in the Hub's agent-traces viewer: MiniMax-M2.7 on the answer-question task
在 Hub 的 agent-traces 查看器中渲染的一次运行:MiniMax-M2.7 在 answer-question 任务上。
在 Hub 上打开这条轨迹 ↗

在展示结果之前,先快速回顾一下实验设置。每次运行会改变四件事:驱动智能体的模型、它所针对的transformers修订版本、任务,以及层级(bare / clone / skill)。如前所述,我们针对两类不同的模型分别考察不同的指标。

大型开源模型:固定模型,改变修订版本

由于大型开源模型通常都能得到正确结果,你真正衡量的是它为此付出的努力。它花了十轮还是一轮?它是否因为信任了过时的文档而走了一条你已弃用的 API 路径?它是否遇到了你未曾预见的错误?

最自然的实验是固定一个强大的模型,改变工具的修订版本:我们测试所针对的transformers的各个连续 git 版本,从v5.8.0和v5.9.0这样的已发布标签,到引入 CLI 和 Skill 的那个特定提交。我们想观察它给智能体带来的负担是上升还是下降。我们在transformers上使用了该测试框架,以检验添加专用 CLI 和 Skill 是否真的减轻了智能体的工作。

对于我们在测试中使用的三个大型模型,所有任务的平均耗时表明,Skill 提交使任务所花费的时间更少:

Median time per revision, by tier
各修订版本按层级统计的中位耗时:skill 提交(绿点)最快。

另一方面,在我们克隆仓库的实验中,可以看到由于引入了 CLI 和示例的那次提交,token 消耗显著增加,稍后我们就会看到这一点。

Median new tokens per revision, by tier
按层级划分的每次修订新增 token 中位数:一旦 CLI 进入仓库,克隆变体就会跃升。

阅读克隆变体的追踪记录就能解释原因。这次提交添加了一个命令,但它也把 CLI 的实现以及一组 cli/agentic/*.py 用法示例直接放进了仓库。

在 clone 变体上,智能体面前有一份完整的 transformers 检出,大约三分之一的运行会去阅读这个新接口(/cli/ 目录树和示例脚本),以便在调用之前了解其用法。这使输入的中位数从约 4k 提升到约 6.4k token。

这两张图其实是一个权衡的两面:这次提交为大型模型节省了时间(它们转而使用 CLI,而不是去调试 Python),代价是消耗更多 token(它们要阅读教会它们使用 CLI 的代码)。这是在合并 PR 之前值得了解的权衡。

不过,有一个尚未纳入基准测试的注意事项对 CLI 有利:读取它的成本会随着后续运行被摊薄。我们的测试环境是为一次性实验搭建的。每次运行都是一个全新的智能体,从零开始重新探索 CLI,因此每次都要付出探索成本。在实际使用中,智能体只需学习一次界面,之后便可在同一会话内接连解决一个又一个任务,从而将这一成本分摊到大量请求上。我们在此测得的 token 增长更接近最坏情况,而非用户日常会看到的情况。

小模型:保持修订版本不变,变换模型

开放模型让我们能够对这里最关键的变量进行细粒度控制:规模、配置、量化、提供商、训练,以及任何会因模型不同而有所差异的因素。它们也是最需要良好工具界面的地方:一个小模型被要求“使用transformers在某个bare环境中执行 X”时,可能会猜到一个几个版本前就已变更的 API,可能会进行不必要的工具调用,并可能得出错误答案。

所以这里的实验与上述相反:固定修订版本,遍历不同模型。这有助于看出哪些模型真正能胜任这项任务,不仅从 token 数量和时间上看,还能深入到哪些模型无法可靠地处理工具调用。我们的直觉是,模型越小,工具使用和任务本身都会越难;我们在一系列不同规模的模型上运行了这套测试框架,正是为了验证这一点:

Match % across models, by tier
各模型按层级划分的匹配率:技能层级提升了较大模型的表现,但拉低了较小模型的表现。

这似乎也与摄入的 token 数量相关

Median new tokens across models, by tier
各模型按层级划分的新增 token 中位数。

关于公平比较的一点说明:当覆盖不均衡时,简单地对各任务取平均值会产生误导(一个只完成了快速任务的模型看起来很快)。报告提供了一个“仅共享任务”开关(可跨模型和/或修订版本),以便进行同类比较,还提供了一个覆盖率热力图,让你能确切看到哪些任务 × 修订版本 × 模型的单元格实际运行过。

调整工具:标记与结果

这里有两件事交汇在一起:如何超越智能体是否成功这一层面,去关注它做了什么以及如何做到的;以及我们从测试框架中提取出的首批结果。

什么是标记?

匹配率、token 和时间能告诉你一次运行的成本,但无法告诉你底层发生了什么。

这就是我们引入标记概念的原因。标记是 profile(一种针对每个工具的小型插件,用于教会测试框架如何构建和驱动某个特定库)针对某次运行所匹配的命名模式。

它是一个针对你所关注行为的单行标签,会对照智能体运行过的 shell 命令、编写的代码、读取的文件或其最终答案进行检查。一次运行可能触发多个标记,也可能一个都不触发;报告会按模型和修订版本显示每个标记的触发频率。

对于 transformers,我们声明了若干个,但只看其中最相关的两个:

  • cli:智能体调用了 transformers 命令行工具(例如 transformers classify …),而不是编写 Python。
  • pipeline:它转而使用了高层的 pipeline(...) Python API。

我们正是通过观察这些,来判断某项改动是否真正改变了智能体的行为。有趣的是,在这里,模型越大,就越倾向于利用新的上下文而不是依赖自己的记忆;因此也就越倾向于使用新引入的 CLI。

CLI adoption by tier across models
各层级模型对 CLI 的采用情况:只有技能层级会去使用它,而且随着模型变大,使用得更多。

CLI 的采用是全新的:该 CLI 在单个提交中落地,不在任何模型的训练数据中,而且文档也很少。效果很明显:正是那个附带 CLI 文档的技能变体,才真正去使用它,比例达到 55.3%。

CLI + 技能这个提交有帮助吗?

对比不同模型规模下的这次提交,CLI + Skill 对更大的模型有帮助:在 skill 档位上,Kimi 和其他大型智能体会主动使用 CLI,并以更少的轮数完成任务。(在 clone 上,它们会先花费更多输入 token 去阅读新的 CLI 代码,正如我们上面所见,因此收益体现在时间和轮数上,而非原始 token 数。)

Kimi-K2.6, GLM-5.1, and MiniMax-M2.7 across revisions
Kimi-K2.6、GLM-5.1 和 MiniMax-M2.7 在各修订版本间的表现

但在一些较小模型的设置下,它似乎反而损害了性能。一个合理的解释是,小模型依赖记忆中的 API 模式,会复现它们在训练数据中见过的 pipeline(...) 片段。于是这些新概念就成了它们更容易出错的更大暴露面。你可以在测试框架上直接观察到这一点:匹配率更低、重试更多、cli 标记几乎不触发。在 Qwen3-4B 模型上这一点尤为显著:Skill 几乎没有改变它的匹配率,但它的成本分布却受到了显著影响。

几乎所有这些都来自 clone 档位。现在检出内容中包含了 CLI 的实现和 cli/agentic/*.py 示例,而 4B 智能体会大量读取它们:其中位数新增 token 从约 2.4k 跃升至约 23k,时间和输出量也大幅飙升,而准确率却毫无提升。

Qwen3-4B cost distributions across revisions: elapsed, new tokens, repeat tokens, out tokens
Qwen3-4B 在各修订版本间的表现。CLI + Skill 这次提交把成本分布大幅拉开,在 clone 档位上,智能体会大量读取新发布的 CLI 源代码(新增 token 约为原来的 10 倍),而匹配率却毫无提升。(repeat tokens 保持平稳:此设置不使用提示词缓存。)

不过,有时技能会直接破坏正确性。查看轨迹可以看出,例如对于 Qwen3-14B:加入技能后,其整体匹配率从 67%(裸模型)下降到 43%,而在最简单的任务上,这种崩塌非常明显:classify-sentiment 在 clone 变体上从 100% 降到 0%(使用技能时)。

Qwen3-14B classify-sentiment match % by tier across revisions
Qwen3-14B 在 classify-sentiment 上,按层级划分:clone(蓝色)在各修订版本中保持 100%,但技能变体(绿色)在 CLI + 技能修订版本上崩塌至 0%。

查看轨迹可以发现,模型把 CLI 误认为是一个它可以直接调用的工具(就像智能体框架中的工具,比如网页搜索)。技能并不是可执行工具:它是加载到智能体上下文中的文档,而 transformers CLI 只应通过 shell(经由 bash)运行;所以这样做行不通。

Qwen3-14B 读取了该技能,在其 56 次技能运行中有 39 次要么发出一个transformers(command="classify", ...)工具调用(一个从未注册过的工具),要么在其read/bash/edit/write工具中找不到类似的东西,于是断定它无法运行模型并放弃。无论哪种情况,它都没有退回到那行在pipeline(...)结账环节拿到 100% 的clone代码,而是宣称该任务不可能完成。

Qwen3-14B gives up on classify-sentiment under the Skill variant
Qwen3-14B 在 classify-sentiment(技能变体)上:它推理认为 read/bash/edit/write 无法运行模型,于是放弃了。

这正是我们构建这套测试框架所要捕捉的问题:同一个能加速大模型的改动,最终却会拖垮小模型,这一点起初让我们觉得有些反直觉,而且很可能就被我们原样发布了。给维护者的启示是:面向智能体的 API 应当跨模型规模进行评估,因为一项新的能力提示可能会减少强模型的工作量,却给较小的模型增添歧义。它还暗示了一种修复思路:与其手写一个技能再事后检查,不如一开始就针对较弱的模型生成并验证它。

这正是 Upskill 所做的:只有当强模型的解决方案可测量地帮助到较小的模型时,它才会把该方案转化为一个技能。

亲自试一试

这套测试框架就是一个 CLI,agent-eval。安装它,运行一套测试套件,在 HF Jobs 上将其扩展到多个模型 × 多个修订版本,并把报告发布为一个 Hugging Face Space。

仅限可信的本地使用。该测试框架会以绕过权限的方式运行一个编码智能体,并执行你指向的任意修订版本中的代码,而且追踪记录可能包含提示词、输出和本地路径。在将其指向并非你自己编写的代码或分享结果之前,请先阅读 SECURITY.md。

完整且持续更新的安装与使用说明位于 README 中。

结语

检查最终答案只能告诉你一个智能体能否使用你的库。它不会告诉你代价是什么:轮次、token、错误,以及它走到那里所经过的路径。这个测试框架会衡量这些,覆盖你所选的各个修订版本和模型。

在transformers上,它发现了我们本来会盲目发布的东西:CLI + Skill 对最大的开源模型有帮助,却会损害最小的那些。合并之前值得了解一下!

它基于 profile,并且被设计成可适配的:把它指向你自己的库,定义几个任务及其预期答案,就能得到同样的报告。代码和任务在仓库里,trace 在 Hub 上。如果你把它用于你的项目,请告诉我们!

致谢

这个测试框架完全建立在pi之上,那是 Mario Zechner 的编码智能体 CLI:它驱动了每一次开源模型运行,并且只需要一个HF_TOKEN就能为模型提供服务,这正是让开源模型全面评测变得可行的原因。

感谢我们所评测模型背后的模型构建者和推理服务提供商。总体而言,它们的表现远超bare基线所暗示的水平。

来源:Hugging Face:Blog(RSS) · huggingface.co