Coding Agent Benchmark 实操:怎样在自己的仓库比较不同 Agent
公开 Leaderboard 适合做初筛,但要给自己的仓库选择 Coding Agent,必须先固定成功标准、环境、预算、权限和重置方式,再用一小组来自真实仓库的可复现任务,把功能结果、Diff、失败形态与人工 Review 负担分开记录。
一、Leaderboard 回答了什么,没回答什么
每隔一段时间,评测榜单就会刷新一次。某个系统在 SWE-bench 上拿到了最高 Resolved 率,某个研究团队发布了新数据。翻完这些结果,我们很容易产生一种感觉:选型问题已经有答案了,按榜单找第一个、读一下 README、接入、完事。
然而我每次想这么干,又会被自己拉回来。
问题不在于公开 Benchmark 数据不真实。SWE-bench 的设计思路是严谨的——它以 GitHub 仓库加 Issue 定义 Coding 任务,要求系统生成 Patch,并在基于 Docker 的隔离环境里执行对应测试,判断用例是否从失败翻转为通过(fail-to-pass)、原本通过的用例是否仍然通过(pass-to-pass)。公开数据字段包括 Repository、base_commit、Problem Statement、Test Patch 和相关测试列表。这套评测是有现实锚点的,不是凭空打分。
问题在于,榜单能告诉我一个系统在那些固定任务上达到了什么结果,却没办法告诉我:
- 它进入我这个仓库之后,会不会遵守我们已有的目录约定?
- 一次任务产生的 Diff 会不会溢出需求范围,把我不打算改的东西也改掉?
- 在我们团队限定的权限边界内,它能不能完成任务,还是会绕路升级权限?
- 一次看似省时的调用,最终会不会变成更长的 Review?
换句话说,公开 Benchmark 是标准测试场——提供统一参照,让系统按同一任务与评分规则测量。而我们面对的是每天真正要走的路线:具体的代码库、具体的约束、具体的维护成本和具体的团队习惯。标准测试场跑出的成绩是选型的参考,但它不替我们收拾最终的 Diff。
读懂这一点,真正该问的问题就变了:我要固定哪些条件,才能为这个仓库做选择?
二、把候选对象定义清楚,再开始比较
排行榜上的名字往往是一个品牌或模型系列,但实际跑任务的是一套完整配置。如果比较过程里忽略版本、工具集、上下文设置或权限策略,得到的结论几乎没有可复现性——同一个品牌、不同配置,可以产生完全不同的行为。
所以在任何 run 开始之前,每个候选对象应该被记录为一张完整的配置单,至少包括以下字段:
| 字段 | 说明 |
|---|---|
| Agent/Client 名称与版本 | 具体版本号,不能只写产品名 |
| Model 名称与版本 | 包括 API 版本或快照 ID |
| Harness / 调用方式 | CLI、API、IDE 插件,以及具体版本 |
| 上下文文件 | 项目规则或等价上下文文件,内容版本 |
| Tools / Skills | 开启了哪些工具,关闭了哪些 |
| 权限与网络策略 | 文件访问范围、网络访问、shell 执行权限 |
| 任何额外注入的系统提示 | 如有,完整记录 |
如果某个字段在比较中所有候选对象里完全相同,记一次就够;如果有差异,逐列标注。不记录这些信息,"我们比较过 A 和 B"这句话就没有可查的含义。
三、先写决策问题,再挑任务
选型的起点是一个决策问题,不是一个榜单位置。决策问题越清晰,后续的评分标准越容易对齐。
一个具体的决策问题长这样:
对于这个仓库,哪个配置能在我们设定的权限范围内,可靠地完成 Bug 修复和小型功能任务,同时把 Review 负担和返工比例控制在可接受范围内?
然后是一票否决项。这是必须在任何加权评分之前先判断的硬性条件,一旦触发就不参与后续比较。常见的否决项包括:
- 在任务要求范围外修改了不相关的文件,且没有任何解释
- 在未经授权的情况下发起了网络请求或尝试提升权限
- 功能测试全部失败
- 引入了已知的安全风险
- 在试点阶段产生了无法核查的黑盒操作
不要用一个加权总分把这些失败藏起来。一个在某个维度表现很好的系统,如果在否决项上失败,就应该在否决项上失败,而不是被整体分数平均掉。
四、从真实 Backlog 里挑任务形态
任务来源决定了评测结果对这个仓库的相关性。为了让试点可执行,先选 3–5 个任务形态——这个数量是为了让你能在合理时间内完成 Pilot,暴露适配问题和明显的失败形态,但不能支撑统计上充分的排名,也不能外推到其他仓库。
以下是几种值得覆盖的任务形态示例,均只作为形态描述,不暗示已经运行:
-
带回归测试的局部 Bug 仓库里已有现成的失败用例,任务是在不破坏相邻功能的情况下让它通过。这类任务适合测试 Agent 对已有测试框架的理解,以及 Diff 是否克制。
-
小型跨模块功能 需要同时改动两个以上模块,但需求描述是完整的。观察 Agent 如何规划改动顺序,以及是否把改动控制在需求范围内。
-
行为不变的重构 输入输出不变,内部结构调整。这类任务特别适合检验 Diff 范围——任何行为层面的改变都是问题。
-
诊断任务 给出一个症状,要求 Agent 定位原因并输出诊断报告,不需要直接修复。重点看它是否能在不越权的情况下完成检查。
-
仓库特有的维护任务 更新配置、整理依赖、补全特定格式的注释——这类任务最能暴露 Agent 是否真正读取了仓库约定,还是按通用惯例操作。
这几种形态可以覆盖"改代码"以外的常见场景,让比较结果更贴近实际工作分布。
五、在任何 run 之前写 Task Card
这是评测里最容易被跳过、代价也最高的一步。Task Card 是每个任务在运行之前就写好的规格说明,它同时约束了 Agent 和评测者自己。
Task Card 必须包含:
- 来源:从哪个 Issue、哪次 PR Review 或哪段历史记录里来的
- 类型:对应上一节里的任务形态
- 冻结 Commit:运行开始时仓库的精确 Commit Hash
- 原始 Prompt:逐字记录,不允许事后修改
- 允许范围:明确列出 Agent 可以修改哪些文件或目录
- 必须通过的检查:具体的测试命令和期望结果
- 回归检查:运行前已通过的测试列表,要求运行后仍然通过
- 禁止修改项:明确不允许改动的文件或配置
- 重置方法:每次 trial 开始前如何还原到干净状态
- 预算:Token 上限或费用上限,超出即中止
- 权限/网络:文件访问范围、是否允许网络访问、shell 命令白名单
- 重复次数:这个任务运行几个 trial
Task Card 写好之后不再修改。如果发现 Prompt 需要调整,那是一个新的任务,不是原任务的"修正"。
六、公平协议:让差异可见,不是抹掉差异
公平不是让所有候选对象都表现得一样好,而是让它们在相同条件下暴露出真实差异。具体来说:
相同的起点 每个候选对象从同一个冻结 Commit 开始,接收相同的任务要求和原始 Prompt。若不同产品需要不同格式的上下文文件,就固定其中承载的仓库事实,并逐项记录格式和注入方式的差异。
每个 trial 干净重置 Anthropic 的评测建议指出,遗留文件、缓存、资源和历史都可能污染结果,因此每次 trial 必须从干净且隔离的状态开始。更稳妥的做法是使用一次性 Worktree 或容器,从冻结 Commit 重新创建环境,而不是在仍有人工改动的工作目录里执行破坏性清理。
预先声明预算 预算必须在 run 开始前写入 Task Card。不能因为某个候选对象"感觉快了很多"就允许它多跑几轮。
保存版本 每次 trial 的产物——Diff、日志、测试输出——都保存下来,归档到可查的位置。不能只记"通过了"或"没通过"。
记录无法消除的差异 如果某个候选对象在某个任务上天然有优势(例如它的上下文窗口更大,能一次加载整个仓库),这种优势应该被记录,而不是被忽略。公平的记录不是假装条件完全相同,而是把不同的地方写清楚。
七、按顺序收集证据
每次 trial 结束之后,按以下顺序收集证据。顺序很重要——先判功能,再看资源,最后看人工负担。
第一层:功能结果
- 必须通过的检查:通过 / 失败 / 超时
- 回归检查:全部通过 / 哪几条新失败
- 功能实现是否完整
Anthropic 的建议是,优先用确定性的 outcome grader 检查功能,不应因为 Agent 没有复刻某个预想路径就判错——最终产物才是判断依据。
第二层:Diff 与行为
- 修改了哪些文件,共多少行;行数只用于观察范围,不能单独代表质量
- 是否出现了与任务无关的改动
- 工具调用是否出现失败或重试
- 是否尝试越出权限边界
- 是否有需要保留的产物(诊断报告、新生成的测试文件等)
第三层:资源
- 耗时(分钟)
- Token 使用量(若平台提供)
- 单次调用成本(若平台提供)
- 若工具没有暴露这些数字,写
N/A,不能按文本长度猜测
第四层:人工负担
- Review 花了多少分钟
- 返工花了多少分钟
- 是否需要人工干预才能完成任务
- 最终 Accept 还是 Reject,以及阻塞原因
记录人工 Review 与返工分钟数,因为一次调用便宜,不等于最终交付便宜。一个 Token 成本很低但 Diff 需要反复清理的系统,综合成本可能远高于调用成本高一些但 Diff 干净的系统。
八、重复 trial:为什么需要,怎么用
Anthropic 在评测方法里明确指出,模型输出会随运行变化,因此单次观察不够稳定。对同一个任务、同一个配置运行多次 trial,可以观察它是否反复成功或失败,以及失败形态是否一致。
但重复 trial 不等于生成通过率。
"通过率"需要足够多的样本才有统计意义。3–5 个任务上的几次重复,只能帮助你观察这个配置是否反复成功或失败,以及失败时出现了什么形态。这些是有价值的观察,但不能外推为精确的可靠性数字。
每个任务运行几个 trial,由下面的空白 Protocol 填写;结果保持空白,由运行者自行记录。
九、Protocol 总览
在开始实验之前,用一张表确认所有关键参数已经对齐:
| 参数类别 | 字段 | 状态 |
|---|---|---|
| 实验标识 | 实验 ID、日期、负责人 | 填写前 |
| 决策问题 | 具体问题陈述 | 填写前 |
| 仓库 | 仓库地址 + 冻结 Commit | 填写前 |
| 候选配置 | 每个候选完整配置表 | 填写前 |
| 共享上下文 | 上下文文件版本与内容 | 填写前 |
| 权限/网络 | 每个候选的权限与网络策略 | 填写前 |
| 预算 | Token 上限 / 费用上限 | 填写前 |
| 重复次数 | 每个任务跑几个 trial | 填写前 |
| 重置规则 | 具体还原命令或脚本 | 填写前 |
| 一票否决项 | 列出所有否决条件 | 填写前 |
| 任务列表 | 3–5 个 Task Card(Pilot) | 填写前 |
十、用一票否决项和多维矩阵做仓库内决策
所有 trial 完成之后,先过否决项,再看维度矩阵。
否决项只有两种结果:触发 / 未触发。触发否决项的候选配置退出后续比较,原因保留在记录里。
通过否决项的候选配置,进入多维矩阵比较:
| 维度 | 候选 A | 候选 B | 候选 C |
|---|---|---|---|
| 功能可靠性(Pass/Regression) | |||
| Diff 范围与无关改动 | |||
| 工具失败与权限行为 | |||
| 运行适配(Timeout/Error 率) | |||
| 资源可见性(Token/成本) | |||
| 人工 Review 与返工负担 |
每个维度独立记录,不合并成一个总分。最终决定写在矩阵下方,格式是:
对于这个仓库,在这次 Pilot 覆盖的任务范围内,选择 [候选配置],原因是 [具体原因],已知限制是 [具体限制]。
这是仓库内的选择,不是行业排名。随着仓库变化、任务分布变化、产品版本迭代,结论可以更新。
十一、可复用空白评分卡
以下是可以直接复制到自己仓库的空白评分卡,分为四个部分。所有应填写结果的单元格保持为空,由运行者在实验过程中逐步填入。
Part 1 — Protocol Header
## 实验基本信息
| 字段 | 内容 |
|------|------|
| 实验 ID | |
| 日期 | |
| 负责人 | |
| 决策问题 | |
## 仓库
| 字段 | 内容 |
|------|------|
| 仓库地址 | |
| 冻结 Commit | |
## 候选配置
| 字段 | 候选 A | 候选 B | 候选 C |
|------|--------|--------|--------|
| Agent/Client 名称与版本 | | | |
| Model 名称与版本 | | | |
| Harness / 调用方式 | | | |
| 上下文文件(版本) | | | |
| Tools / Skills | | | |
| 权限与网络策略 | | | |
| 额外系统提示 | | | |
## 共享参数
| 参数 | 值 |
|------|----|
| 共享上下文文件与版本 | |
| Token 上限 / 费用上限 | |
| 每个任务 trial 次数 | |
| 重置命令 / 脚本 | |
## 一票否决项
| 否决条件 | 说明 |
|----------|------|
| 1. | |
| 2. | |
| 3. | |
| (按需增加) | |
Part 2 — Task Card
每个任务复制一份,共 3–5 份(Pilot 规模)。
## Task Card
| 字段 | 内容 |
|------|------|
| Task ID | |
| 来源(Issue / PR / 历史记录) | |
| 任务类型 | |
| 冻结 Commit | |
### 原始 Prompt
```
(逐字粘贴,运行后不修改)
```
### Setup
| 字段 | 内容 |
|------|------|
| 起始环境描述 | |
| 依赖安装命令 | |
| 其他初始化步骤 | |
### 允许范围
| 字段 | 内容 |
|------|------|
| 可修改的文件 / 目录 | |
| 明确禁止修改的文件 / 目录 | |
### 必须通过的检查
| 检查命令 | 期望结果 |
|----------|----------|
| | |
| | |
### 回归检查
| 测试命令 | 运行前状态(全部通过) |
|----------|----------------------|
| | |
### 禁止行为
-
-
### 保留产物
-
-
### 重置方法
```
(具体命令,确保每次 trial 从干净状态开始)
```
Part 3 — Per-trial Record
每个 trial 复制一行或一个区块。
下面三列只展示排布方式,请按 Protocol 中预先声明的重复次数增减,不代表建议固定运行三次。
## Per-trial Record
| 字段 | Trial 1 | Trial 2 | Trial 3 |
|------|---------|---------|---------|
| 候选配置 | | | |
| 开始时间 | | | |
### 功能结果
| 检查 | Trial 1 | Trial 2 | Trial 3 |
|------|---------|---------|---------|
| 必须通过的检查(Pass/Fail/Timeout) | | | |
| 回归检查(Pass/新失败列表) | | | |
| 功能完整性(Pass/Partial/Fail) | | | |
### 运行状态
| 指标 | Trial 1 | Trial 2 | Trial 3 |
|------|---------|---------|---------|
| Timeout / Error | | | |
| 耗时(分钟) | | | |
| Token 使用量(或 N/A) | | | |
| 单次成本(或 N/A) | | | |
### Diff 与行为
| 指标 | Trial 1 | Trial 2 | Trial 3 |
|------|---------|---------|---------|
| 修改文件列表 | | | |
| 修改行数(+/−) | | | |
| 无关改动(有/无,说明) | | | |
| 工具失败 / 重试(有/无,说明) | | | |
| 权限升级尝试(有/无,说明) | | | |
### 产物链接
| 产物 | Trial 1 | Trial 2 | Trial 3 |
|------|---------|---------|---------|
| Diff 文件路径 | | | |
| 测试输出路径 | | | |
| Trace / 日志路径 | | | |
### 人工负担
| 指标 | Trial 1 | Trial 2 | Trial 3 |
|------|---------|---------|---------|
| Review 分钟数 | | | |
| 返工分钟数 | | | |
| 人工干预(有/无,说明) | | | |
| Accept / Reject | | | |
| 阻塞原因(如有) | | | |
Part 4 — Decision Matrix
## Decision Matrix
### 一票否决项状态
| 否决条件 | 候选 A | 候选 B | 候选 C |
|----------|--------|--------|--------|
| 1. | | | |
| 2. | | | |
| 3. | | | |
| 退出比较 | | | |
*触发否决项的候选退出,原因记录在下方。*
### 多维比较(通过否决项的候选)
| 维度 | 候选 A | 候选 B | 候选 C |
|------|--------|--------|--------|
| 功能可靠性(必须通过 + 回归) | | | |
| Diff 范围与无关改动 | | | |
| 工具失败与权限行为 | | | |
| 运行适配(Timeout/Error) | | | |
| 资源可见性(Token/成本或 N/A) | | | |
| 人工 Review 与返工负担 | | | |
*每个维度独立记录,不合并为总分。*
### 否决项触发记录
| 候选 | 触发的否决条件 | 具体描述 |
|------|--------------|----------|
| | | |
### 仓库内决策
> 对于这个仓库,在此次 Pilot 覆盖的任务范围内,选择:
>
> **[ 填写候选配置 ]**
>
> 原因:
>
> 已知限制:
>
> 下次复审时间 / 触发条件:
### 保留的失败原因与取舍
*在这里记录哪些候选被排除以及取舍逻辑,供下次决策参考。*
结语:怎样为这个仓库做决定
公开 Leaderboard 是好的起点——它能帮你缩短候选列表。但选型的终点在你自己的仓库里。
流程本身不复杂:写清楚决策问题和否决项,把候选对象记录成完整配置,从真实 Backlog 里挑 3–5 个任务形态组成 Pilot,在任何 run 之前写好 Task Card,用干净重置保证公平起点,按功能、Diff、资源、人工负担的顺序收集证据,先过否决项、再看维度矩阵,最后写下针对这个仓库的决定和已知限制。
结论是仓库内的结论,不是行业排名。随着仓库成长、任务分布变化、产品版本迭代,这份记录本身就是下一次决策的起点。
如果你打算把其中的几个任务长期维护成持续集成里的质量门禁——在每次合并或每次工具版本升级时自动运行——那是一个值得单独展开的话题,可以参考 Coding Agent Evals Guide 里关于任务夹具和自动化门控的部分。
但在那之前,先完成这次 Pilot。Badge 不替你收拾最终的 Diff。
方法参考:SWE-bench · Anthropic — Demystifying Evals for AI Agents · OpenAI — Evaluation Best Practices · Harbor Tasks