Back to Writing
Jul 10, 2026·中文·AI & Agent·Engineering Notes

SWE-bench 是怎么造出来的,又是怎么坏掉的

今年 2 月,OpenAI 发了一篇 Engineering Blog,宣布不再报告 SWE-bench Verified 的成绩。他们的建议是:Verified 已经不适合评估 frontier model 了,大家改用 SWE-bench Pro。

过了不到五个月,上周,我在 X 上看到 OpenAI 又发了新 Blog。他们审计了 SWE-bench Pro 的数据,估计大约 30% 的任务存在严重问题,又撤回了之前的推荐。

SWE-bench 我记得 2023 年刚出的时候,最强的模型通过率还不到 2%,当时大家觉得这题够刷好几年。后来发现原始数据集里坏题太多,OpenAI 人工筛了一遍做出 Verified;Verified 快被刷满之后,Scale AI 又出了更难的 Pro。结果这个 Pro,五个月内就从「推荐使用」变成了「约三成题目可能是坏的」。

同一套题目生产方式,修修补补换了三代,问题不只是模型进步太快把旧题刷满,而是更根本的:我们到底是怎么把一段真实的软件工程工作,转换成一份可以自动评分的考题的?

过去几年看 coding model 的发布,我们已经习惯直接找 SWE-bench 的百分比。70%、75%、80%,好像分数越高,模型就越接近一个可以独立工作的 software engineer。但在比较这些数字之前,得先看看这份 benchmark 是怎么造出来的。

SWE-bench 的造题方式:从 GitHub 历史倒推考题

原始 SWE-bench 发布于 2023 年。它最大的贡献,是把 code generation 从 HumanEval 那种「补完一个函数」,推进到了真实 repository 里的 issue resolution。

研究者先从 12 个主流 Python repository 里抓了大约 9 万个 Pull Request,然后一层层筛:

  1. PR 已经 merge,并且明确解决了某个 GitHub issue。
  2. PR 修改了测试相关文件,说明作者很可能为这次修改补了测试。
  3. Repository 能在 PR 之前的 base commit 上成功安装和运行。
  4. 把 PR 中新增或修改的 tests 放到旧代码上时,至少有一个测试失败。
  5. 再应用 PR 的实现代码后,这些测试全部通过,同时原来能通过的 regression tests 不能坏。

9 万个 PR 筛完,剩下 2,294 道题。每道题里有四个部分:

评估时,agent 只拿到 problem statement 和旧代码库。它可以搜索代码、修改文件、运行现有测试,最后提交一个 patch。Benchmark 把 hidden test patch 应用进去,只要所有 FAIL_TO_PASSPASS_TO_PASS tests 都通过,就算解题成功。

这个设计在 2023 年是真的好。有真实代码库、真实 issue、真实开发者写的 solution,还有可以自动执行的评分器。而且它可以规模化生产,GitHub 历史里已经有现成的题目、答案和测试,不需要组织几百个工程师从零出题。

但 SWE-bench 最巧妙的地方,也后来成了它出问题的地方。

问题一:Issue、PR 和 tests 原本就不是一套考题

SWE-bench 隐含地假设了两个等式:

Issue 描述 = 完整需求

原 PR 的 tests = 完整且 implementation-agnostic 的验收标准

真实的软件开发不是这样的。

GitHub issue 只是团队协作过程中的一个切片。大量上下文在 maintainer 的脑子里、repository convention 里、其他 issue 里,甚至线下讨论里。Issue 作者只需要让熟悉项目的人知道他在说什么,从来没打算写成一份陌生人拿到就能完整实现的 PRD。

PR 里的 tests 也一样。它们写出来的目的是证明眼前这一个 implementation 可以 merge,顺便防止这个 bug 复发。原作者已经选好了函数名、模块边界和控制流,测试自然会围绕这些选择来写。

但把它们放进 benchmark 之后,tests 的角色变了:它不再只是验证一个已知实现,而是要给所有未知实现当通用评分器。这两件事之间的距离,比看起来大得多。

OpenAI 后来把常见问题分成了几类:

举一个很典型的 overly strict case:原作者在修复过程中顺手提取了一个 private helper,测试直接 import 这个 helper。Agent 把同样的逻辑写在调用处,外部行为完全正确,却因为没猜中那个函数名,直接编译失败。

反过来的情况也有。原 PR 的 tests 只覆盖新接口的一小部分,agent 把接口搭出来,里面大部分逻辑还是 no-op,照样拿到 pass。

所以 benchmark 想测的是「有没有把需求做对」,实际评分里却混进了「有没有复现原作者的实现形状」。

Verified 和 Pro 都没能修好它

SWE-bench Verified 本来就是冲着这些数据质量问题去的。

2024 年,OpenAI 找了 93 名有 Python 经验的软件工程师,人工审核原始 SWE-bench 中随机抽取的 1,699 个任务。每道题三个人独立标注,检查 problem statement 是否完整、FAIL_TO_PASS tests 会不会拒绝合理答案。三个人里只要有一个认为存在严重问题,这道题就被过滤掉。最后留下 500 道题,组成 SWE-bench Verified

这确实让 benchmark 好了很多。但当 frontier model 的通过率逐渐接近 80%,剩下的失败开始越来越奇怪。

今年 2 月,OpenAI 挑出 138 道 o3 在 64 次独立运行中经常失败的题,做了更深入的审计,每道题至少六名有经验的工程师独立审核。结果是 59.4% 的被审计任务存在实质性的 test design 或 problem description 问题:35.5% 是 tests 过窄,18.8% 是 tests 检查了 prompt 没要求的额外功能。OpenAI 因此停止报告 SWE-bench Verified

这里要小心读这个数字。59.4% 不是说 Verified 的 500 道题里六成是坏题,OpenAI 刻意选的就是模型经常失败的那批,问题率本来就会高。它真正说明的是:当模型已经能解决大部分正常任务时,排行榜上剩下的「难度」,有相当一部分其实是测量误差。

SWE-bench Pro 试图把门槛重新抬高。它扩展到 41 个 repository、1,865 个任务,加入 JavaScript、TypeScript、Go 等语言,也加入 held-out 和 commercial repository。任务更长,往往要改多个文件,还经过了人工补充和审核。发布时看起来是有效的,最强模型只有 23% 左右的通过率。但八个月后,公开 split 上的最高分已经涨到 80.3%。

于是有了开头那篇 blog。今年 7 月,OpenAI 对 SWE-bench Pro 的 731 道公开任务做了审计。Agent-assisted pipeline 判定 200 道题存在严重问题,占 27.4%;另一组有经验的软件工程师独立审核,判定 249 道题有问题,占 34.1%。OpenAI 最终估计,大约 30% 的 SWE-bench Pro public tasks 是 broken 的

Pro 的问题不在于没有增加难度,也不在于完全没有人工审核。它的问题是,底层生产方式没变:任务依然主要从历史 feature change、issue 和 PR 里抽取,再把原本服务于一次具体开发过程的材料,整理成 prompt 和 tests。

如果 prompt、solution 和 verifier 一开始就不是作为一套 evaluation artifact 共同设计的,后面的人工审核只能尽量修补它们之间的缝。缝是很难补完的。

问题二:数据污染

这套造题方式还有第二个更明显的问题:题目和答案本来就在模型的训练数据里。

SWE-bench 的 issue、PR discussion、tests 和 gold patch 全都公开躺在 GitHub 上。而公开 GitHub repository,恰好是目前所有 frontier model 最重要的训练数据来源之一。

OpenAI 用专门的 contamination probe 测了 GPT-5.2、Claude Opus 4.5 和 Gemini 3 Flash,所有被测的 frontier model 都能在部分任务上复述原始修复,或者逐字给出 task-specific 信息。Gemini 只拿到一个 task ID,就能输出 Django username validator 那道题的具体 regex 修改和 gold patch。GPT-5.2 在解决一个几乎不可能从 prompt 推断的任务时,主动提到了对应 Django release note 里的 edit_only 参数。

模型不需要完整背下整个 patch 才能占便宜。只要它见过相关的 release note、PR discussion、函数名或者修复思路,它面对的就不再是一道真正的新题。

污染和 verifier error 是两个独立问题。Verifier error 会把正确答案判错,或者把不完整答案判对;contamination 会让见过答案的模型系统性地多拿分;题目过短、repository 过少还会造成 ceiling effect,把能力不同的模型挤在相近的分数区间里。它们最终都会让 leaderboard 失真,但失真的方向不一样。而且一个模型记忆训练数据的能力,不等于它在陌生代码库里解决问题的能力。


SWE-bench 这条路线的两个问题都摆在桌面上了:verifier 和需求对不上,题目和答案早就泄露。接下来看看新一代 benchmark 分别是怎么应对的。

新 Benchmark 1:DeepSWE,把 prompt、solution 和 verifier 一起设计

今年 5 月发布的 DeepSWE,表面上看就是一套更难的 SWE benchmark:113 道题,覆盖 91 个活跃的开源 repository 和五种语言。平均 prompt 只有 SWE-bench Pro 的一半长,reference solution 却平均多出 668 行代码,约为 Pro 的 5.5 倍。Agent 得自己探索代码库、找到修改位置、决定实现策略,不能照着详细 todo list 写代码。

但我觉得它最重要的变化不是题更长,而是它不再从一个已经 merge 的 PR 倒推出考题。

DeepSWE 的任务由工程师从零编写。有些题会受到尚未解决的 GitHub issue 启发,但 reference solution 是全新的,也不会 merge 回 upstream repository。每道题的 prompt、reference solution 和 verifier 是一起设计的:prompt 描述需要实现的外部行为;reference solution 证明任务确实可解,但不参与最终评分;verifier 通过 public API 和 observable output 检查行为,不依赖 private helper 或作者采用的内部结构。

一套 verifier 入库前还要过专门的 QA。Reviewer 会检查 prompt 和 tests 是否一一对应,是否接受多种合理实现,任务是不是 maintainer 真会交给 agent 的工作,环境和依赖稳不稳定。多个 frontier agent 还会提前试做每道题。那些差一点做对的 rollout 特别有价值,因为它们能暴露 verifier 在边界上的误判。

DeepSWE 自己做过一次 cross-benchmark audit:从 DeepSWE 和 SWE-bench Pro 各随机抽 30 道题,让 10 种 agent configuration 各跑三次,再让一个 LLM analyzer 独立判断 patch 是否真正满足需求。按这套判断,Pro verifier 拒绝了约 24% 的正确答案,又接受了约 8% 的错误答案;DeepSWE 对应的比例是 1.1% 和 0.3%。

这个结果的方向很有说服力(虽然精确数字得打个折)。Analyzer 本身是 LLM judge,没有经过完全独立的人工校准,而且审计方就是 DeepSWE 的发布者。不过他们至少公开了任务、trajectory 和分析结果,别人可以继续复核。

DeepSWE v1.1 又补了一层隔离。Agent 在自己的 container 里工作并 commit,评估系统只提取 committed diff,放进一个全新的 verifier container 运行。未来 git history 会被删除,测试结果也用结构化格式逐项记录。这样 agent 没法通过修改 test runner、删除 tests,或者从 git log 里翻到未来 commit 来骗过评分器。

这套流程当然更贵,它失去了 SWE-bench 从 GitHub 历史自动挖题的规模优势。但它测量的目标也更干净:不是看 agent 能不能猜中原作者怎么写,而是看它能不能实现指定行为。

新 Benchmark 2:CursorBench,让题目分布贴近真实使用

DeepSWE 主要在修复单道题内部的有效性:prompt、solution 和 verifier 必须真的对齐。CursorBench 关注的是另一件事:这些题加在一起,是否代表开发者实际交给 coding agent 的工作。

Cursor 用 Cursor Blame 把已经 commit 的代码追溯到产生它的 agent request,从内部代码库和其他受控来源里拿到一组自然配对:开发者当时说了什么,最后接受了什么代码。

这让 CursorBench 的 prompt 可以保留真实使用中的简短和模糊,不需要被改写成一份事无巨细的 specification。任务范围覆盖 edit、refactor、bug finding、planning、code review、instruction following 和 advanced tool use。

Cursor 也不把 offline benchmark 当最终真相。他们会在 live traffic 上做 controlled experiment,同时观察 interaction 和 output quality 的多种信号,检查 offline 分数更高的 agent 是否真的给开发者带来更好的结果。任务本身每隔几个月更新一轮,跟着 coding agent 的真实用法一起变。

这件事我自己很有共鸣。我之前做过 code migration benchmark generation,当时最直接的问题就是随机从 GitHub 收集的 repository 里有很多 toy project,它们的分布和真实 customer workload 完全不一样。每道测试都能正常运行,不代表最后聚合出来的 success rate 能预测 production。

CursorBench 的代价是可审计性。任务和 grader 大部分是私有的,外部很难独立判断它有没有偏向 Cursor 自己的 harness 或特定模型。私有数据也不等于绝对不会污染,Cursor 当前的 leaderboard 就专门标注了:Grok 4.5 的训练数据曾意外包含一个较早的 Cursor codebase snapshot,因此在 CursorBench 上有无法准确量化的优势。

SWE-bench

从 GitHub 历史自动挖题

  1. 把 issue 当题目,PR 之前的代码库当作答环境

  2. 原 PR 的代码改动当参考答案,测试改动当评分器

  3. 新答案跑一遍原 PR 的测试,全过就算解题成功

优点
有现成的题目和答案,容易规模化
代价
题目和评分器都是从旧 PR 拆出来的,经常把写法不同的正确答案判错

DeepSWE

工程师从零出题

  1. 题目、参考答案和评分测试一起设计,只检查外部行为

  2. 多个 frontier agent 提前试做,暴露评分器的误判

  3. 只把 agent 提交的代码放进干净容器里评分

优点
只看行为对不对,不要求和原作者写得一样
代价
全靠人工出题,成本高、题目少

CursorBench

从真实产品使用中取样

  1. 把开发者的真实请求和最终接受的代码配成一对

  2. 题目保留原话的简短模糊,用 agentic grader 评分

  3. 用线上实验校准离线排名,定期换新题

优点
题目就是开发者真实交给 agent 的工作
代价
题目和评分器不公开,外界无法独立检验
三种 benchmark 的主要区别是题目、答案和评分器从哪里来。

把三套方法放在一起看,它们优化的其实是三个不同问题:

没有哪个设计能同时拿满所有东西。公开 benchmark 容易审计,但迟早进训练集。Private benchmark 更抗污染,却很难获得外部信任。从零人工出题可以把 verifier 做得更干净,但成本高、样本量小。直接从生产环境取样最贴近真实使用,却很难保证任务可复现,还可能把产品 harness 的能力混进模型能力里。

更难,不等于更好

看到一套新 benchmark 把模型分数从 80% 打回 40%,很容易觉得新尺子更准。

其实分数被拉开本身什么都证明不了。把题目做得足够偏、把环境搞得足够脆弱、或者让 hidden tests 检查更多没写进 prompt 的细节,一样可以把所有模型的分数打下来。真正重要的是:被区分出来的到底是什么?

如果一套 benchmark 想测量 autonomous software engineering capability,至少要同时回答几件事:

  1. Task validity:这些任务是不是我们真正关心的软件工程工作,而不是容易收集的工作?
  2. Verifier validity:通过是否意味着需求真的完成,失败是否真的反映能力不足?
  3. Contamination control:模型是否在训练中见过问题、答案或足以还原答案的旁路信息?
  4. Harness clarity:分数测的是 base model、model 加统一 scaffold,还是完整产品?
  5. Temporal validity:任务分布和难度会不会随着 agent 能力和开发者用法变化而过时?

SWE-bench 当年不是一个糟糕的 benchmark。它定义了后来几年评价 coding agent 的基本任务形式。只是模型从 2% 进步到 80% 之后,当初可以忽略的数据噪音,变成了 leaderboard 上最主要的信号。

这也是我读完这些材料后最大的 reflection:benchmark 不是一组一次性发布的题。它更像一套持续运行的测量系统。有人生产新任务,有人审核 prompt 和 verifier,有人检查污染和 reward hacking,有人拿 offline 结果去和真实使用校准。模型在变,agent harness 在变,开发者交给 agent 的工作也在变,这套系统就必须跟着变。

未来真正可靠的 coding eval,大概不会是一份大家反复刷三年的静态 dataset,而是一个持续出题、轮换、审计和校准的过程。

References: