如何为 Deep Agents 构建评估体系


快速阅读

最好的 AI 代理评估应该直接衡量我们在生产环境中关心的代理行为。盲目添加成百上千个测试往往会带来“代理正在变好”的错觉。Deep Agents 是一个开源的模型无关代理框架。团队认为:更多评估 ≠ 更好代理,应当构建能反映实际生产中期望行为的针对性评估。文章详细介绍了他们的三步法:

  1. 数据管理:通过日常内部测试(Dogfooding)、适配外部基准(如 Terminal Bench 2.0 或 BFCL),以及手写针对性测试来收集数据。
  2. 指标定义:首先确保“正确性”(如是否执行了并行工具调用),通过标准后,再转向“效率”(通过测量解决率和设定“理想执行轨迹”以减少不必要的操作步骤)。
  3. 评估运行:使用 pytest 和 GitHub Actions 在 CI 环境中自动运行,通过标签对评估进行分类,并通过 LangSmith 进行调用链路跟踪。

评估塑造代理行为

我们一直在整理评估内容,以衡量和改进 Deep Agents。Deep Agents 是一个开源的、与具体模型无关的代理工具框架(Harness),它驱动了诸如 Fleet 和 Open SWE 这样的产品。评估(Evals)定义并塑造了代理的行为,这就是为什么我们需要经过深思熟虑来设计它们。

每一个评估都是一个推动代理系统行为改变的“向量”。例如,如果一个针对“高效文件读取”的评估失败了,你可能会去调整系统提示词(System Prompt)或 read_file 的工具描述,引导它的行为直到测试通过。你保留的每一个评估,都会随着时间的推移给整个系统施加行为上的压力。

因此,在添加评估时保持深思熟虑至关重要。人们很容易陷入一种诱惑:盲目地添加数百(甚至数千)个测试用例。这会导致一种错觉——你在某个评估套件上获得了高分,以为“代理变强了”,但这可能根本无法准确反映你在生产环境中真正关心的行为表现。

更多评估 ≠ 更好代理。相反,我们应该构建那些能反映生产环境中期望行为的“目标评估”。

在构建 Deep Agents 时,我们会将在生产环境中真正重要的行为编入目录,例如“跨越文件系统的多个文件检索内容”或“准确无误地组合 5 个以上的工具链式调用”。比起仅仅使用汇总后的基准测试得分,我们在整理评估时采用了以下方法:

  1. 决定我们希望代理遵循哪些具体的行为。然后去研究并整理那些能够以“可验证的方式”衡量这些行为的目标评估。
  2. 为每个评估添加一份文档字符串(Docstring),解释它是如何衡量某项代理能力的,确保每个评估都具备“自我说明”的能力。我们还会给每个评估打上标签(例如 tool_use),以便进行分组运行。
  3. 审查输出日志(Traces),以理解失败的模式,并相应地更新评估覆盖范围。

由于我们将每一条评估运行记录都追踪到一个共享的 LangSmith 项目中,团队中的任何人都可以随时介入分析问题、进行修复,并重新评估某个给定测试的价值。这创造了一种关于“添加和维护优秀评估”的共担责任文化。在各种评估中运行大量模型也会非常昂贵,因此针对性的评估能在省钱的同时切实改善你的代理。

在这篇博客中,我们将涵盖:

  • 我们如何管理数据
  • 我们如何定义指标
  • 我们如何运行评估

我们如何管理数据

我们收集评估数据的方式主要有以下几种:

  1. 从我们**“自产自销(Dogfooding)”**内部使用代理的反馈中收集。
  2. 从外部的基准测试(比如 Terminal Bench 2.0 或 BFCL)中提取选定的评估,并常常针对特定的代理进行调整。
  3. 为我们认为重要的一些行为,手工编写专属的评估和单元测试。

我们每天都在使用自己的代理系统。每一个错误都成了我们编写评估、并更新代理定义与上下文工程实践的绝佳机会。

注意:我们将 SDK 的单元测试和集成测试(如系统提示词透传、中断配置、子代理路由等)与模型能力评估明确分开。任何模型都能通过那些系统性测试,所以将它们包含在打分体系中不会增加任何有效信号。你绝对应该编写单元和集成测试,但本篇博客将专门聚焦于“模型能力评估”。

“吃狗粮”(Dogfooding)与阅读调用追踪是极好的数据源

追踪日志(Traces)使得发现错误成为可能,它们为我们理解代理行为提供了数据。因为追踪日志往往非常庞大,我们使用内置的代理(如 Polly 或 Insights)来大规模分析它们。你也可以用其他代理(如 Claude Code 或 Deep Agents CLI)加上拉取追踪的方式(如 LangSmith CLI)做到这一点。我们的目标是了解每一种失败模式,提出修复方案,重新运行代理,并持续跟踪进度和回归测试情况。

例如,现在有很大一部分错误修复 PR 是由 Open SWE(我们的开源后台编码代理)推动的。使用它的团队会接触许多具有不同上下文、规范和目标的各种代码库,这自然会导致错误发生。Open SWE 的每一次交互都被追踪记录,因此它们很容易转化为评估用例,确保相同的错误不会再次发生。

其他评估则是从现有的基准测试(如针对函数调用的 BFCL)中提取并进行调整的。对于编码任务,我们集成了 Harbor,以在沙盒环境中运行选自 Terminal Bench 2.0 等数据集的任务。还有许多评估是从零开始编写的,它们作为重点测试来观察隔离行为(例如仅仅测试 read_file 工具)。

根据“测试内容”对评估进行分组

建立一个关于评估的分类体系,有助于我们在中间视角(既不是单一的总体分数,也不是单独的某次运行)了解代理的表现。

提示:通过它们“测试了什么”来创建这个分类体系,而不是看它们“来自哪里”。例如,来自 FRAMES 和 BFCL 的任务可以被统一标记为“外部基准”,但这无法体现它们实际上分别衡量了“检索”和“工具调用”能力。

如今,所有的评估都是代理在某项任务上的端到端运行。我们有意鼓励评估结构的多样性。有些任务通过一个输入提示就能在一步内完成,而另一些则需要与其他模拟用户的模型进行多达 10 轮以上的对话。

我们如何定义指标

在为我们的代理选择模型时,我们首先看重**“正确性”**。如果一个模型不能可靠地完成我们关心的任务,其他一切都毫无意义。我们在自己的评估集上运行多个模型,并随着时间推移不断完善代理框架,以解决我们发现的问题。

衡量正确性取决于正在测试的具体内容。大多数内部评估使用自定义断言,例如“代理是否并行化了工具调用?”。像 BFCL 这样的外部基准则使用与数据集中的“真理答案”进行精确匹配。对于那些涉及语义正确性的评估(例如判断代理是否在记忆中持久化了正确的内容),我们使用“LLM-as-a-judge(用大语言模型作为裁判)”。

一旦有几个模型越过了“正确性”的门槛,我们就会转向**“效率”**。两个能够解决相同任务的模型,在实际应用中的表现可能会大相径庭。由于模型体量的原因,其中一个可能会花费额外的轮次、进行不必要的工具调用,或者在任务处理上进展缓慢。在生产环境中,这些差异直接表现为更高的延迟、更高的成本,以及更糟糕的整体用户体验。

综合来看,我们在每次评估运行时衡量的指标包括:

  • 解决率(Solve rate):衡量代理解决任务的速度,通常用预期的步骤数来进行标准化。就像延迟比率(latency ratio)一样,它捕捉的是解决任务的端到端时间,包括模型往返、供应商延迟、错误的尝试以及工具执行时间。对于那些我们可以定义完美执行轨迹的简单任务,解决率往往比延迟比率更容易操作。

这为我们通过目标明确的评估集来选择模型提供了一种简单的方法:

  1. 优先检查正确性:在你真正关心的任务上,哪些模型足够准确?
  2. 其次比较效率:在那些足够优秀的模型中,哪一个能在正确性、延迟和成本之间取得最佳的折中平衡?

评估相关的实用指标示例

为了使模型比较更具操作性,我们会仔细研究模型是如何成功或失败的。这需要一个具体的参照点,来界定“准确性”之外的所谓“良好”执行应该是怎样的。

我们使用的一个基础概念是**“理想执行轨迹(Ideal trajectory)”**。这是一条产生正确结果且没有任何“不必要”动作的步骤序列。

对于那些简单的、范围明确的任务,变量定义得足够严密,最佳路径通常显而易见。对于更开放式的任务,我们通过表现最好的模型来近似绘制一条轨迹,然后随着模型和框架的改进不断重新审视这个基准。这样,观察代理行为便能帮助我们不断完善对“理想执行轨迹”的先验认知。

考虑这样一个简单的请求:

“我居住的地方现在的时间和天气是怎样的?”

一个代理的理想执行轨迹可能是这样的:

  1. 进行了最少且必要的工具调用(如:解析用户 -> 解析位置 -> 获取时间和天气)。
  2. 在可能的地方并行化了独立的工具调用。
  3. 没有不必要的中间对话轮次直接给出了最终答案。 (理想轨迹结果:4 个步骤,4 次工具调用,耗时约 8 秒)

现在,将它与另一条虽然在技术上仍然正确,但效率较低的轨迹进行对比: (效率低下的轨迹结果:6 个步骤,5 次工具调用,耗时约 14 秒)

虽然两条轨迹最终都是正确的,但这包含了一次不必要的工具调用,且没有进行并行的工具调用。这无疑增加了延迟和成本,同时也为失败创造了更多可能。

(上面的例子仅作说明:如果直接使用 REPL 代码解释器可能解决得更快,但工具调用版本让这理念更容易解释。)

这样的框架让我们能够在各项评估中同时考察正确性与效率。我们维护并更新这些指标,将运行过程提取为可量化的数字,以用于比较实验。

我们如何运行评估

我们使用带有 pytest 的 GitHub Actions 在持续集成(CI)中运行评估,因此每一次更改都会在一个干净的、可重复的环境中进行。每次评估都会创建一个携带特定模型的 Deep Agent 实例,交给它一项任务,然后计算正确性与效率指标。

我们还可以利用标签(tags)来运行部分评估的子集,这不仅能节省成本,还能对特定功能进行重点实验。例如,如果要构建一个需要大量本地文件处理与信息综合的代理,我们可能会将重点放在打上了 file_operations 和 tool_use 标签的评估子集上。

export LANGSMITH_API_KEY="lsv2_..."

uv run pytest tests/evals --eval-category file_operations --eval-category tool_use --model baseten:nvidia/zai-org/GLM-5

我们的评估架构和具体实现已在 Deep Agents 的代码库中开源。

下一步计划

我们正在不断扩展我们的评估套件,并围绕开源 LLM 开展更多工作!我们很快就会分享以下激动人心的内容:

  • 开源模型在各个评估类别中与闭源前沿模型的测量对比。
  • 将评估作为一种机制,实时自动改进正在执行任务的代理。
  • 公开分享我们是如何随着时间推移,针对每个代理来维护、精简和扩展评估库的。

Deep Agents 是完全开源的。欢迎尝试并让我们知道您的想法!我们非常乐意帮助各个团队构建优秀的 AI 代理和评估体系。

🔗 原文链接:How we build evals for Deep Agents