工程化 Agent 的评测,和评测一个普通模型完全是两码事。模型评测看的是输入输出,跑一批测试集、算个准确率就完事了;但 Agent 是一个带工具调用、带多轮决策、带状态管理的动态系统,它的失败模式可能是"工具选错了""循环卡死了""中间步骤对了但最终答案格式不对"——这些用传统的单轮评测根本抓不住。我最近在做一个叫羲和 XiheAgent 的工程化 Agent 项目,需要一套能真正反映它在复杂任务上表现的评测方案,最后选定了 GAIA 这个基准来跑全流程。这篇文章就把整个评测的设计思路、踩过的坑、以及实测数据完整拆一遍,适合正在做 Agent 开发、需要给自家 Agent 建立评测体系的同学参考。
1. 为什么 GAIA 是工程化 Agent 评测的合适起点
1.1 GAIA 到底在测什么
GAIA(General AI Assistants benchmark)的核心设计理念和传统 NLP 基准有本质区别。它不是在测"模型知不知道某个事实",而是在测"一个带工具的智能体能不能完成一件真实世界里的复合任务"。每道题都是一个需要多步推理、工具调用、信息整合才能得到最终答案的任务,答案格式被严格约束(通常是短字符串或数字),这样评测才能自动化判分。
GAIA 的题目分三个难度层级。Level 1 通常只需要一到两步操作,比如查一个公开数据再做个简单计算;Level 2 需要多步工具调用和跨源信息整合,中间还得处理一些干扰信息;Level 3 则是长链条任务,可能涉及文件解析、代码执行、多轮搜索验证的组合。这个分层对工程化 Agent 特别有价值,因为它能暴露出 Agent 在不同复杂度下的能力衰减曲线——很多 Agent 在 Level 1 上表现不错,一到 Level 3 就崩,原因往往不是推理能力不够,而是工具编排和状态管理出了问题。
我选择 GAIA 作为主评测基准,还有一个很实际的原因:它的答案可验证。GAIA 的题目设计者刻意让最终答案是一个确定性的短字符串,这就避免了用另一个模型来打分带来的不确定性。对于工程化场景来说,评测结果的可复现性比什么都重要,你总不希望每次跑评测分数都在飘。
1.2 工程化 Agent 和 Demo Agent 的评测差异
这里得说清楚一个前提:羲和 XiheAgent 是工程化 Agent,不是那种跑个 Demo 就完事的玩具。工程化意味着它要处理并发请求、要有稳定的工具调用重试机制、要有可观测的执行链路、要能在部分工具失败时优雅降级。这些特性在评测里必须被覆盖到,否则你测出来的分数再高,上线后照样出问题。
Demo Agent 的评测通常只看最终答案对不对,但工程化 Agent 的评测得看更多维度。比如同一个任务,Agent 用了 3 步完成和用了 15 步完成,虽然答案都对,但工程上的意义完全不同——步数多意味着 token 消耗大、延迟高、出错概率累积。再比如工具调用失败后的重试策略,Demo 里可能直接抛异常,工程化 Agent 必须能重试或者换路径。所以我在设计评测方案时,除了 GAIA 的准确率,还额外采集了执行步数、工具调用次数、单任务耗时、失败重试次数这些工程指标。
1.3 评测目标的确立
在动手之前我把评测目标明确成了三条。第一,测出羲和 XiheAgent 在 GAIA 三个难度层级上的准确率基线,作为后续迭代的参照。第二,定位能力短板——是推理不行、工具编排不行、还是特定类型工具(比如文件解析、代码执行)支持不到位。第三,验证工程特性,包括并发下的稳定性、失败恢复能力、以及执行链路的可观测性。
这三条目标决定了评测不能只是"跑一遍算个分",而是一套完整的流程:环境准备、任务分发、执行监控、结果判分、指标聚合、问题归因。下面我按这个流程逐步展开。
2. 评测环境搭建:那些文档里不会写的细节
2.1 运行环境与依赖锁定
GAIA 的题目里有一部分需要文件处理能力,比如解析 Excel、读取 PDF、处理图片里的信息。这意味着评测环境必须预装对应的处理库,而且版本要锁死。我踩过的第一个坑就是 pandas 版本不一致导致某个 Excel 解析结果不同——新版 pandas 对某些日期格式的推断规则变了,直接让一道题的答案从正确变成错误。所以环境依赖必须用 lock 文件固定,我最终是把整个评测环境打成了容器镜像,每次评测都从同一个镜像启动。
具体来说,基础镜像选 Python 3.11,因为部分 Agent 框架对 3.12 的兼容性还不稳定。核心依赖包括 pandas、openpyxl(Excel 处理)、PyPDF2 和 pdfplumber(PDF 处理)、Pillow(图片处理)、以及 requests 用于网络工具。这里有个细节:pdfplumber 比 PyPDF2 在表格提取上强很多,GAIA 里有几道题需要从 PDF 表格里取数,用 PyPDF2 会直接提取失败,所以两个都装上,让 Agent 自己选。
2.2 工具集的准备与沙盒隔离
羲和 XiheAgent 在评测时挂载的工具集包括:网页搜索、网页抓取、Python 代码执行、文件读写、以及一个通用的 HTTP 请求工具。这里最关键的是代码执行工具的沙盒隔离。GAIA 的题目里 Agent 会自己写代码来处理数据,如果代码执行没有隔离,一个死循环就能把整个评测进程拖垮。
我的做法是用独立的子进程加超时控制来跑代码,每个代码执行任务给 30 秒硬超时,超时直接 kill 并返回错误信息给 Agent,让它自己决定重试还是换方案。这个超时值不是拍脑袋定的——我统计了 GAIA 里需要代码执行的题目,正常完成的代码执行时间中位数在 3 秒左右,P95 在 12 秒,所以 30 秒足够覆盖正常情况,又能及时掐掉异常。
提示:沙盒隔离不只是超时,还要限制文件系统访问范围。我见过 Agent 写的代码把评测中间结果文件覆盖了,导致后续题目读取到脏数据。建议给每个任务分配独立的工作目录。
2.3 网络工具的稳定性处理
网页搜索和抓取是 GAIA 评测里最不稳定的环节。外部网站的响应时间、反爬策略、页面结构变化都会影响结果。我的处理方式是给网络工具加了三层保护:请求超时设为 15 秒、失败自动重试 2 次(间隔递增)、重试仍失败则返回明确的错误状态让 Agent 感知。
这里有个经验:不要让网络工具在失败时返回空字符串,那样 Agent 会以为"搜到了但没内容",从而做出错误决策。必须返回结构化的错误信息,比如{"status": "error", "reason": "timeout", "retryable": true},Agent 才能正确判断下一步。这个细节看起来小,但实测下来对 Level 2 以上题目的成功率影响很大。
3. 任务分发与执行监控的设计
3.1 评测任务的批量调度
GAIA 验证集有 165 道题,如果串行跑,按每题平均 40 秒算要将近两个小时,迭代一次太慢。所以我做了并发调度,但并发度不能无脑拉高。羲和 XiheAgent 本身要调外部工具,并发太高会触发搜索接口的限流,反而拖慢整体。
我实测下来并发度设在 4 到 6 之间比较稳。再高的话,网络工具的失败率会明显上升,重试带来的额外耗时抵消了并发收益。调度器用的是简单的任务队列加固定大小的工作池,每个任务独立记录开始时间、结束时间、状态。任务之间完全隔离,一个任务失败不影响其他任务。
3.2 执行链路的可观测性
这是工程化 Agent 评测和普通评测最大的区别。我需要看到 Agent 每一步在干什么:它调用了哪个工具、传了什么参数、拿到了什么结果、下一步决策是什么。羲和 XiheAgent 内部有执行轨迹记录,评测时我把这些轨迹全部落盘,每个任务一个 JSON 文件。
轨迹记录里我特别关注几个字段:step_index(第几步)、action_type(是推理还是工具调用)、tool_name、tool_input、tool_output、latency_ms。有了这些,出问题的时候我能精确复现 Agent 的决策路径。比如有一道题 Agent 反复搜索同一个关键词五次,看轨迹才发现是第一次搜索结果被截断了,Agent 没意识到已经拿到部分信息,又去重搜。
3.3 中间状态的持久化
长链条任务跑到一半失败是常事,如果每次都从头跑,浪费太大。我给评测加了检查点机制:每个任务每完成一步就把当前状态(包括已收集的信息、已执行的工具调用历史)持久化。任务失败重跑时可以从最后一个检查点恢复。
这个机制在调试阶段帮了大忙。有一道 Level 3 的题,Agent 前 8 步都正确,第 9 步代码执行超时失败。有了检查点,我直接从那一步恢复调试,不用重跑前面 8 步。不过要注意,检查点恢复只适用于幂等的工具调用,对于有副作用的操作(比如写文件)要谨慎,我的做法是恢复时把工作目录也一起快照。
4. 判分逻辑:准确率之外的工程指标
4.1 答案匹配的严格与宽松
GAIA 官方给的判分是精确匹配,但实际跑下来会发现有些答案"意思对了但格式差一点"。比如题目要的是数字42,Agent 返回42.0或者42 元。如果严格精确匹配,这些都会被判错,但工程上这明显是判分逻辑太死板。
我的处理是分两层:主指标用官方精确匹配,保证和公开榜单可比;辅助指标用一个归一化匹配,把数字统一成数值比较、字符串去空格转小写、去掉常见单位后缀。两个指标都记录,分析问题时看归一化指标能更真实反映 Agent 的能力,对外汇报时用精确匹配指标。
| 匹配方式 | 处理规则 | 用途 |
|---|---|---|
| 精确匹配 | 完全字符串相等 | 对外可比的主指标 |
| 归一化匹配 | 数值归一、去空格、去单位 | 内部分析能力短板 |
| 包含匹配 | 标准答案被包含在输出中 | 排查"答案对但啰嗦"的情况 |
4.2 工程指标的采集口径
准确率之外,我采集了这几类工程指标。执行步数,反映 Agent 的决策效率;工具调用总次数,反映对外部依赖的强度;单任务端到端耗时,反映用户体验;工具调用失败率和重试率,反映系统稳定性;token 消耗,反映成本。
这些指标的采集口径要统一。比如耗时,我定义的是从任务开始到最终答案产出的墙钟时间,包含所有工具调用等待。工具调用失败率的分母是所有工具调用次数,分子是返回错误状态的调用次数。口径不统一的话,不同批次评测的数据没法对比。
4.3 失败归因的分类体系
光知道哪道题错了没用,得知道为什么错。我建了一套失败归因分类,每道错题人工或半自动打标签。分类包括:推理错误(逻辑链断了)、工具选择错误(该用搜索却用了代码)、工具参数错误(搜索关键词不对)、信息整合错误(拿到了正确信息但组合错了)、格式错误(答案对但格式不符)、超时、以及外部工具不可用。
这套分类跑下来,我发现羲和 XiheAgent 的主要失分点在"信息整合错误"和"工具参数错误"上,推理错误反而占比不高。这个结论直接指导了后续的优化方向——重点不是提升模型推理能力,而是优化工具调用的参数构造和信息汇总逻辑。
5. 实测数据与能力短板定位
5.1 分层准确率表现
跑完整套 GAIA 验证集后,羲和 XiheAgent 的精确匹配准确率在 Level 1 上是 78.3%,Level 2 是 51.2%,Level 3 是 22.7%。这个衰减曲线很典型,也符合预期。Level 1 的题目大多一两步就能解决,Agent 的工具调用基本不会出错;Level 2 开始需要多步整合,失败主要出在中间步骤的信息丢失;Level 3 的长链条任务对状态管理要求极高,任何一步的偏差都会累积放大。
归一化匹配下,三个层级的准确率分别是 81.5%、56.8%、27.3%,提升幅度在 Level 2 和 Level 3 上更明显,说明有一部分失败确实是格式问题而非能力问题。
5.2 步数与成功率的关联分析
我把每个任务的执行步数和是否成功做了交叉分析,发现一个很明显的规律:成功任务的步数集中在 3 到 8 步,而失败任务里有一大批步数超过 12 步。这说明当 Agent 陷入"反复尝试"的状态时,基本就离失败不远了。
进一步看轨迹,这些长步数失败任务有个共同模式:Agent 在某一步拿到了不完整的信息,然后基于这个不完整信息继续推理,越走越偏,最后要么超时要么给出错误答案。这提示我需要在 Agent 里加一个"信息充分性检查"机制,在关键决策点让 Agent 评估当前信息是否足够,不够就明确去补,而不是硬着头皮往下走。
5.3 工具维度的失败分布
按工具类型统计失败率,结果很有意思。网页搜索相关的失败占了总失败的 43%,代码执行占 21%,文件处理占 18%,其余是推理和整合问题。网页搜索失败率高,一部分是外部不可控因素(网站响应慢、页面结构变化),另一部分是 Agent 构造搜索关键词的能力不足——它经常用整句去搜,而不是提取关键实体。
针对这个,我做了个优化:在搜索工具外面包一层关键词提取,让 Agent 先输出结构化查询(实体加限定词),再转成搜索请求。这个改动让搜索相关的失败率降了大概三分之一。
6. 评测流程的可复现性保障
6.1 随机性来源的控制
Agent 评测里随机性来源比模型评测多得多。模型推理有温度参数带来的随机性,工具调用有网络波动带来的随机性,代码执行有环境差异带来的随机性。要保证评测可复现,这些都得控制。
温度我设成 0,虽然不能完全消除随机性,但能大幅降低。网络工具我加了响应缓存,同一批次评测里相同的请求直接返回缓存结果,这样至少同一批次内是可复现的。代码执行环境用固定镜像,依赖版本锁死。做完这些,同一批次重跑两次的结果差异能控制在 2% 以内。
6.2 评测批次的管理
每次改了 Agent 的代码或者工具配置,都要重新跑评测。我给每次评测分配一个批次 ID,记录当时的 Agent 版本、工具配置版本、环境镜像版本。这样任何时候都能追溯某个分数是在什么条件下跑出来的。
批次之间对比时要注意,只有环境一致的数据才能直接比。我有一次对比两个批次发现分数涨了 5 个点,后来发现是其中一个批次换了搜索工具的实现,根本不是 Agent 本身变好了。所以批次元数据一定要记全。
6.3 回归测试集的维护
全量 GAIA 跑一次成本不低,日常迭代不可能每次都跑全量。我从中挑了一部分题目组成了回归测试集,覆盖三个难度层级和各类工具,大概 40 道题。每次代码改动先跑回归集,通过了再跑全量。回归集里的题目选择有讲究,要覆盖之前出过问题的场景,相当于把踩过的坑都固化成了测试用例。
7. 从评测结果反推 Agent 优化方向
7.1 信息整合环节的强化
前面提到"信息整合错误"是主要失分点,具体表现是 Agent 在多步搜索后,手里有好几段信息,但组合的时候漏掉了关键片段或者做了错误的关联。我的优化思路是在 Agent 的决策循环里加一个显式的"信息汇总"步骤,每收集到新信息就更新一份结构化的任务状态,而不是让信息散落在对话历史里。
这个改动本质上是把隐式的上下文记忆变成显式的状态管理。实测下来,Level 2 的准确率提升了大概 6 个百分点,效果比单纯换更强的模型还明显。
7.2 工具调用参数的规范化
工具参数错误主要集中在搜索关键词和代码输入上。对于搜索,我加了前面说的关键词提取层。对于代码执行,我让 Agent 在写代码前先声明"这段代码要解决什么子问题、输入是什么、预期输出是什么",相当于强制它想清楚再写。这个约束减少了代码执行报错的概率,也方便失败时定位。
7.3 长任务的步数控制
针对长步数失败的问题,我加了一个软性的步数预算机制。每个任务根据难度层级给一个建议步数上限,Agent 接近上限时会收到提示,让它评估当前进展、决定是继续还是换策略。这不是硬性截断,而是给 Agent 一个"该收敛了"的信号。实测下来,超长步数的失败任务明显减少。
8. 一些实操中的体会
评测工程化 Agent 这件事,最大的感受是"评测本身也是一个工程系统"。你不能指望跑个脚本就得到可信的结论,环境、调度、监控、判分、归因每一环都得认真设计。GAIA 是个好基准,但它只是起点,真正有价值的是你在跑评测过程中建立起来的那套可观测、可复现、可归因的流程。
另外一个体会是,评测指标要服务于优化决策。如果一堆指标看完你不知道下一步该改什么,那这些指标就是无效的。我现在看评测报告,第一眼看的不是总分,而是失败归因的分布,因为那直接告诉我力气该往哪使。羲和 XiheAgent 从最初 Level 2 只有三成多准确率,到现在五成出头,靠的不是某个单点突破,而是评测驱动的一轮轮针对性优化。
最后分享一个具体技巧:把每次评测的失败案例存下来,定期回顾。有些失败是偶发的,有些是系统性的,回顾多了你就能分辨出来。我现在的做法是每周抽半小时翻一遍本周新增的失败案例,经常能发现一些指标上看不出来但实际很要命的问题,比如某个工具在特定输入下的静默失败。这种问题不主动翻案例是发现不了的。