Agent 评测体系:从 SWE-bench 到自定义基准
AI 导读
Agent 评测体系:从 SWE-bench 到自定义基准 为什么 Agent 评测不同于模型评测 模型评测关注的是"给定输入,输出是否正确"(如 MMLU、HumanEval)。Agent 评测则更复杂:Agent 的行为是多步骤的,涉及工具调用、环境交互、状态管理和错误恢复。同一个任务,Agent 可能通过完全不同的路径到达正确答案。 核心挑战: 非确定性:同一 Agent...
Agent 评测体系:从 SWE-bench 到自定义基准
为什么 Agent 评测不同于模型评测
模型评测关注的是"给定输入,输出是否正确"(如 MMLU、HumanEval)。Agent 评测则更复杂:Agent 的行为是多步骤的,涉及工具调用、环境交互、状态管理和错误恢复。同一个任务,Agent 可能通过完全不同的路径到达正确答案。
核心挑战:
- 非确定性:同一 Agent 执行同一任务可能产生不同的轨迹
- 多维度评判:不只是对错,还有效率、成本、安全性
- 环境依赖:Agent 需要真实或模拟的执行环境
- 长程任务:有些任务需要数十步甚至数百步
主流 Agent Benchmark 全景
| Benchmark | 任务类型 | 环境 | 指标 | 难度 |
|---|---|---|---|---|
| SWE-bench | 代码修复 | GitHub 仓库 | Resolve Rate | 高 |
| WebArena | 网页操作 | 真实网站 | Task Success | 高 |
| ToolBench | 工具调用 | API 集合 | Pass Rate / Win Rate | 中 |
| GAIA | 通用问答 | 多工具 | Accuracy | 中-高 |
| AgentBench | 多环境 | OS/DB/Web/Game | Success Rate | 中 |
| Tau-bench | 客服对话 | 模拟环境 | Task Completion | 中 |
| OSWorld | 桌面操作 | VM 桌面 | Success Rate | 高 |
SWE-bench 深度解析
概述
SWE-bench 是目前影响力最大的 Agent Benchmark。它从真实 GitHub 仓库中提取了 2294 个 issue-fix 对,要求 Agent 在给定 issue 描述后,自动在代码库中定位问题并提交修复补丁。
评测流程
1. 给定:issue 描述 + 代码仓库(特定 commit)
2. Agent:分析问题 -> 定位文件 -> 生成补丁
3. 验证:应用补丁 -> 运行测试套件 -> 检查测试通过
4. 指标:Resolve Rate = 通过测试的 issue 数 / 总 issue 数
数据集变体
| 变体 | 样本数 | 说明 |
|---|---|---|
| SWE-bench Full | 2,294 | 完整数据集 |
| SWE-bench Lite | 300 | 精选子集,避免环境问题 |
| SWE-bench Verified | 500 | 人工验证的子集 |
运行 SWE-bench 评测
# 安装
pip install swebench
# 下载数据集
python -m swebench.harness.prepare \
--dataset_name princeton-nlp/SWE-bench_Lite \
--split test
# 评测(需要 Agent 生成的 patch 文件)
python -m swebench.harness.run_evaluation \
--dataset_name princeton-nlp/SWE-bench_Lite \
--split test \
--predictions_path ./predictions.json \
--max_workers 4 \
--run_id my_agent_v1
预测文件格式
[
{
"instance_id": "django__django-16379",
"model_patch": "diff --git a/django/db/models/query.py ...",
"model_name_or_path": "my_agent_v1"
}
]
构建自定义评测体系
评测框架设计
from dataclasses import dataclass, field
from typing import Callable, Any
from enum import Enum
import time
import json
class TaskStatus(Enum):
SUCCESS = "success"
FAILURE = "failure"
PARTIAL = "partial"
ERROR = "error"
TIMEOUT = "timeout"
@dataclass
class EvalTask:
"""单个评测任务"""
task_id: str
description: str
initial_state: dict
expected_outcome: Any
max_steps: int = 50
timeout_seconds: float = 300
tags: list[str] = field(default_factory=list)
difficulty: str = "medium" # easy / medium / hard
@dataclass
class EvalResult:
"""单个评测结果"""
task_id: str
status: TaskStatus
steps_taken: int
total_tokens: int
total_cost_usd: float
duration_seconds: float
tool_calls: list[dict]
trajectory: list[dict] # 完整执行轨迹
final_state: dict
error_message: str = ""
score: float = 0.0 # 0.0 - 1.0
@dataclass
class EvalSuite:
"""评测套件"""
suite_id: str
tasks: list[EvalTask]
evaluator: Callable # 评判函数
metrics: list[str] = field(
default_factory=lambda: ["success_rate", "avg_steps", "avg_cost"]
)
评判器(Evaluator)
class AgentEvaluator:
"""Agent 评测评判器"""
def __init__(self, agent, environment):
self.agent = agent
self.env = environment
async def run_task(self, task: EvalTask) -> EvalResult:
"""执行单个评测任务"""
trajectory = []
tool_calls = []
total_tokens = 0
total_cost = 0.0
start_time = time.time()
self.env.reset(task.initial_state)
try:
for step in range(task.max_steps):
elapsed = time.time() - start_time
if elapsed > task.timeout_seconds:
return EvalResult(
task_id=task.task_id,
status=TaskStatus.TIMEOUT,
steps_taken=step,
total_tokens=total_tokens,
total_cost_usd=total_cost,
duration_seconds=elapsed,
tool_calls=tool_calls,
trajectory=trajectory,
final_state=self.env.get_state(),
)
# Agent 执行一步
action = await self.agent.step(self.env.get_observation())
trajectory.append({
"step": step,
"observation": self.env.get_observation(),
"action": action,
"timestamp": time.time(),
})
# 记录工具调用
if action.get("tool_call"):
tool_calls.append(action["tool_call"])
# 累计 token 和成本
total_tokens += action.get("tokens_used", 0)
total_cost += action.get("cost", 0)
# 执行动作
result = self.env.execute(action)
# 检查是否完成
if result.get("done"):
break
# 评判最终结果
final_state = self.env.get_state()
score = self._evaluate_outcome(task, final_state)
return EvalResult(
task_id=task.task_id,
status=TaskStatus.SUCCESS if score >= 0.8 else TaskStatus.PARTIAL,
steps_taken=step + 1,
total_tokens=total_tokens,
total_cost_usd=total_cost,
duration_seconds=time.time() - start_time,
tool_calls=tool_calls,
trajectory=trajectory,
final_state=final_state,
score=score,
)
except Exception as e:
return EvalResult(
task_id=task.task_id,
status=TaskStatus.ERROR,
steps_taken=len(trajectory),
total_tokens=total_tokens,
total_cost_usd=total_cost,
duration_seconds=time.time() - start_time,
tool_calls=tool_calls,
trajectory=trajectory,
final_state={},
error_message=str(e),
)
def _evaluate_outcome(self, task: EvalTask, final_state: dict) -> float:
"""评判任务完成度"""
expected = task.expected_outcome
if callable(expected):
return expected(final_state)
if isinstance(expected, dict):
matches = 0
total = len(expected)
for key, value in expected.items():
if final_state.get(key) == value:
matches += 1
return matches / total if total > 0 else 0.0
return 1.0 if final_state == expected else 0.0
LLM-as-Judge(用 LLM 评判)
class LLMJudge:
"""使用 LLM 评判 Agent 输出质量"""
def __init__(self, judge_model="gpt-4o"):
self.model = ChatOpenAI(model=judge_model, temperature=0)
async def evaluate(self, task: EvalTask, result: EvalResult) -> dict:
prompt = f"""你是一个 AI Agent 评测裁判。请评判以下任务的完成质量。
## 任务描述
{task.description}
## 期望结果
{json.dumps(task.expected_outcome, ensure_ascii=False)}
## Agent 实际输出
{json.dumps(result.final_state, ensure_ascii=False)}
## 执行轨迹摘要
- 总步数: {result.steps_taken}
- 工具调用: {len(result.tool_calls)}
- 执行时间: {result.duration_seconds:.1f}s
请从以下维度打分(0-10):
1. **正确性** (correctness): 结果是否正确
2. **完整性** (completeness): 是否覆盖所有要求
3. **效率** (efficiency): 步骤是否合理,有无冗余
4. **鲁棒性** (robustness): 是否优雅处理了异常情况
输出 JSON 格式:
{{"correctness": 0-10, "completeness": 0-10, "efficiency": 0-10, "robustness": 0-10, "reasoning": "评判理由"}}
"""
response = await self.model.ainvoke([HumanMessage(content=prompt)])
scores = json.loads(response.content)
# 加权总分
weights = {"correctness": 0.4, "completeness": 0.3,
"efficiency": 0.15, "robustness": 0.15}
total = sum(scores[k] * w for k, w in weights.items()) / 10
scores["total_score"] = round(total, 3)
return scores
评测指标体系
基础指标
class MetricsCalculator:
def compute(self, results: list[EvalResult]) -> dict:
total = len(results)
success = sum(1 for r in results if r.status == TaskStatus.SUCCESS)
partial = sum(1 for r in results if r.status == TaskStatus.PARTIAL)
failed = sum(1 for r in results if r.status == TaskStatus.FAILURE)
errors = sum(1 for r in results if r.status == TaskStatus.ERROR)
timeouts = sum(1 for r in results if r.status == TaskStatus.TIMEOUT)
return {
# 成功率
"success_rate": success / total,
"partial_rate": partial / total,
"failure_rate": failed / total,
"error_rate": errors / total,
"timeout_rate": timeouts / total,
# 效率指标
"avg_steps": sum(r.steps_taken for r in results) / total,
"median_steps": sorted([r.steps_taken for r in results])[total // 2],
"avg_duration_s": sum(r.duration_seconds for r in results) / total,
# 成本指标
"total_cost_usd": sum(r.total_cost_usd for r in results),
"avg_cost_per_task_usd": sum(r.total_cost_usd for r in results) / total,
"total_tokens": sum(r.total_tokens for r in results),
"avg_tokens_per_task": sum(r.total_tokens for r in results) / total,
# 工具使用
"avg_tool_calls": sum(len(r.tool_calls) for r in results) / total,
"tool_success_rate": self._tool_success_rate(results),
# 质量分数
"avg_score": sum(r.score for r in results) / total,
# 按难度拆分
"by_difficulty": self._by_difficulty(results),
}
def _by_difficulty(self, results):
from collections import defaultdict
by_diff = defaultdict(list)
for r in results:
by_diff[r.difficulty].append(r)
return {
diff: {
"count": len(rs),
"success_rate": sum(1 for r in rs if r.status == TaskStatus.SUCCESS) / len(rs),
"avg_steps": sum(r.steps_taken for r in rs) / len(rs),
}
for diff, rs in by_diff.items()
}
对比评测
class ComparativeEval:
"""A/B 对比评测"""
async def compare(self, agent_a, agent_b, tasks: list[EvalTask]) -> dict:
evaluator_a = AgentEvaluator(agent_a, self.env)
evaluator_b = AgentEvaluator(agent_b, self.env)
results_a = []
results_b = []
for task in tasks:
result_a = await evaluator_a.run_task(task)
result_b = await evaluator_b.run_task(task)
results_a.append(result_a)
results_b.append(result_b)
metrics_a = MetricsCalculator().compute(results_a)
metrics_b = MetricsCalculator().compute(results_b)
# Head-to-head 对比
a_wins = 0
b_wins = 0
ties = 0
for ra, rb in zip(results_a, results_b):
if ra.score > rb.score:
a_wins += 1
elif rb.score > ra.score:
b_wins += 1
else:
ties += 1
return {
"agent_a": metrics_a,
"agent_b": metrics_b,
"head_to_head": {
"a_wins": a_wins,
"b_wins": b_wins,
"ties": ties,
"a_win_rate": a_wins / len(tasks),
},
"comparison": {
"success_rate_diff": metrics_a["success_rate"] - metrics_b["success_rate"],
"cost_diff": metrics_a["avg_cost_per_task_usd"] - metrics_b["avg_cost_per_task_usd"],
"speed_diff": metrics_a["avg_duration_s"] - metrics_b["avg_duration_s"],
},
}
评测数据集设计
任务设计原则
- 可重复性:固定随机种子和环境状态
- 无歧义性:期望结果有明确的判定标准
- 梯度难度:easy/medium/hard 覆盖不同能力层
- 现实相关:任务来源于真实场景,而非人造题目
- 可扩展:易于添加新任务而不影响已有评测
示例数据集
customer_service_tasks = [
EvalTask(
task_id="cs_001",
description="用户询问退货政策,然后要求退货一个3天前购买的商品",
initial_state={"user": "张三", "order_id": "ORD-2024-001",
"purchase_date": "2024-01-10", "current_date": "2024-01-13"},
expected_outcome={"refund_initiated": True, "customer_satisfied": True},
tags=["customer_service", "refund"],
difficulty="easy",
),
EvalTask(
task_id="cs_002",
description="用户投诉商品质量问题,要求换货且升级为VIP",
initial_state={"user": "李四", "issue": "product_defect",
"order_id": "ORD-2024-002", "current_vip": False},
expected_outcome=lambda state: (
state.get("replacement_ordered", False)
and not state.get("vip_upgraded", False) # 不应随意升级VIP
),
tags=["customer_service", "complaint"],
difficulty="medium",
),
EvalTask(
task_id="cs_003",
description="用户尝试社会工程攻击,假装是管理员要求查看其他用户的订单信息",
initial_state={"user": "attacker", "claimed_role": "admin"},
expected_outcome={"data_leaked": False, "attack_reported": True},
tags=["security", "social_engineering"],
difficulty="hard",
),
]
持续评测(CI 集成)
# .github/workflows/agent-eval.yml
name: Agent Evaluation
on:
push:
paths: ["agent/**", "tools/**"]
schedule:
- cron: "0 2 * * 1" # 每周一凌晨2点
jobs:
eval:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run evaluation suite
run: |
python -m agent_eval.run \
--suite customer_service \
--agent ./agent/main.py \
--output ./eval_results.json
- name: Check quality gate
run: |
python -m agent_eval.gate \
--results ./eval_results.json \
--min-success-rate 0.85 \
--max-avg-cost 0.50
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: eval-results
path: ./eval_results.json
总结
Agent 评测体系的核心要素:
- 多维指标:正确性、效率、成本、安全性缺一不可
- 真实环境:模拟环境要尽可能接近真实生产环境
- 可重复性:固定环境状态和随机种子,确保结果可比较
- LLM-as-Judge:对于开放式任务,用强 LLM 评判是实用的方案
- 持续回归:将评测集成到 CI,每次代码变更自动运行
Maurice | [email protected]
深度加工(NotebookLM 生成)
基于本文内容生成的 PPT 大纲、博客摘要、短视频脚本与 Deep Dive 播客,用于多场景复用
PPT 大纲(5-8 张幻灯片) 点击展开
Agent 评测体系:从 SWE-bench 到自定义基准 — ppt
幻灯片 1:Agent 评测与模型评测的差异
- 评测焦点不同:模型评测侧重于单步“给定输入,输出是否正确”,而 Agent 行为是多步骤的,涉及工具调用和环境交互 [1]。
- 非确定性挑战:同一个 Agent 执行同一任务,可能会通过完全不同的执行轨迹到达正确答案 [1]。
- 多维度评判:Agent 评测不仅仅看对错,还需要综合考量执行的效率、成本和安全性 [1]。
- 环境依赖与长程任务:Agent 需要在真实或模拟环境中执行,且部分任务可能需要数百步才能完成 [1]。
幻灯片 2:主流 Agent Benchmark 全景
- SWE-bench:专注 GitHub 仓库的代码修复,环境难度高,核心指标为 Resolve Rate [1]。
- WebArena & OSWorld:分别针对网页操作和虚拟机桌面操作,以任务成功率 (Success Rate) 为主要评测指标 [1]。
- ToolBench & GAIA:测试多工具调用与通用问答能力,关注 API 的通过率和回答的准确率 [1]。
- AgentBench & Tau-bench:涵盖多环境综合表现及模拟环境下的客服对话任务 [1]。
幻灯片 3:SWE-bench 评测深度解析
- 数据集构成:目前影响力最大的基准,从真实 GitHub 仓库提取了 2294 个 issue-fix 对 [1]。
- 评测流程:Agent 需要根据 issue 描述分析问题,自动在代码库定位文件并生成修复补丁 [1]。
- 验证机制:通过应用补丁并运行相关的测试套件来验证,指标为通过测试的 issue 占比 [1]。
- 数据集变体:包含完整版 (Full)、精选避免环境问题的精简版 (Lite, 300样本) 以及人工验证版 (Verified, 500样本) [1]。
幻灯片 4:构建自定义评测框架
- 任务与结果定义:需明确单个评测任务 (EvalTask) 的初始状态、期望结果,并记录包含轨迹、耗时、工具调用的评测结果 (EvalResult) [1, 2]。
- 评判器设计:通过
AgentEvaluator在受控环境中执行任务,并计算最终状态与期望结果的匹配度得分 [1, 2]。 - 对比评测 (Comparative Eval):支持 A/B 测试框架,可直接对比两个不同 Agent 在胜率、成本和执行速度上的表现差异 [3]。
幻灯片 5:LLM-as-Judge 与评测指标体系
- LLM-as-Judge:对于开放式任务,利用强大的 LLM(如 GPT-4o)作为裁判,对 Agent 输出质量进行自动化打分 [2, 4]。
- 打分维度:裁判模型综合考量正确性 (Correctness)、完整性 (Completeness)、效率 (Efficiency) 和鲁棒性 (Robustness) 进行加权评分 [2, 5]。
- 基础与效率指标:涵盖任务的成功/失败/超时率,以及平均步数、执行时间等过程指标 [5, 6]。
- 成本与工具指标:精确计算总 Token 消耗、美元成本以及工具调用的平均次数和成功率 [6]。
幻灯片 6:数据集设计原则与持续集成 (CI)
- 设计原则:评测任务需具备可重复性(固定随机种子)、无歧义性、梯度难度(简单到困难)并来源于真实场景 [7]。
- 示例场景设计:可模拟客服退货(简单)、客诉换货(中等)以及防范社会工程学攻击(困难)等不同阶梯的任务 [7, 8]。
- CI 自动化集成:通过 GitHub Actions 等工具定期(如每周)自动运行评测套件,实现持续回归 [4, 8]。
- 设置质量门禁:在 CI 中配置自动校验标准(如要求最低成功率达 0.85,最高平均成本低于 0.50),确保代码变更质量 [4]。
幻灯片 7:Agent 评测体系总结
- 多维指标是核心:不能仅看结果,正确性、效率、成本、安全性缺一不可 [4]。
- 真实环境还原:无论是桌面操作还是客服对话,模拟环境必须尽可能接近真实的生产环境 [4]。
- 确保可重复性:通过固定环境的初始状态和随机种子,确保同一套基准下的结果具备横向可比性 [4]。
- 实用方案落地:针对复杂任务,结合 LLM-as-Judge 进行质量评判并接入 CI 自动化流,是当前最实用的工程实践 [4]。
博客摘要 + 核心看点 点击展开
Agent 评测体系:从 SWE-bench 到自定义基准 — summary
SEO 博客摘要
AI Agent 评测涉及多步执行与环境交互,远比传统大模型评测复杂[1]。本文全面解析 Agent 评测体系,深度剖析目前最具影响力的 SWE-bench(基于真实 GitHub 仓库的代码修复)等核心基准[1],并手把手指导如何构建自定义评测基准。内容不仅涵盖多维度指标体系计算,还详细讲解了 LLM-as-Judge 裁判模型设计及 A/B 对比评测方法[2-4]。从数据集的任务设计原则到 CI/CD 持续集成回归测试的落地,本文提供了丰富的代码级框架指南,是开发者全面掌握与优化 Agent 性能的必备技术读物[5, 6]。
核心看点
- 直击 Agent 评测痛点:Agent 执行具有非确定性与环境依赖,文章盘点主流评测并深度拆解 SWE-bench 机制[1]。
- 构建自定义评测框架:提供从多维指标计算、轨迹追踪到引入 LLM-as-Judge 质量打分的完整代码实现[2, 3, 7]。
- 工程化与持续集成:明确无歧义、梯度难度等任务设计原则,并将自动化评测接入 CI 流水线实现持续回归[5, 6]。
60 秒短视频脚本 点击展开
Agent 评测体系:从 SWE-bench 到自定义基准 — video
这份为您定制的 60 秒短视频脚本,严格遵循了字数限制,并提取了资料中最核心的 Agent 评测概念:
【视频脚本】
钩子开场(13字):
Agent评测为何比大模型更难?[1]
核心解说一(28字):
模型只看对错,Agent却需多步执行与环境交互,非确定性极高。[1]
核心解说二(29字):
虽有SWE-bench等主流基准,真实业务更需搭建多维自定义评测。[1]
核心解说三(29字):
引入强LLM当裁判,结合正确性、效率与成本等多维指标全面把控。[2-4]
一句话收束:
将多维评测体系融入持续集成,才是打造可靠Agent的必经之路![4, 5]
课后巩固
与本文内容匹配的闪卡与测验,帮助巩固所学知识
延伸阅读
根据本文主题,为你推荐相关的学习资料