为什么 SWE-bench Verified 不再能衡量前沿编程能力
SWE-bench Verified 的污染日益严重。我们推荐使用 SWE-bench Pro。
自我们于 2024 年 8 月首次发布 SWE-bench Verified 以来,业界已广泛使用它来衡量模型在自主软件工程任务上的进展。发布之后,SWE-bench Verified 提供了能力进步的有力信号,并成为前沿模型发布中报告的标准指标。追踪和预测这些能力的进展也是 OpenAI 准备框架的重要组成部分。在最初创建 Verified 基准时,我们曾试图解决原始评估中使 SWE-bench 数据集内某些任务无法完成的问题。
在最初的飞跃之后,SWE-bench Verified 上的最先进水平进展已经放缓,在过去 6 个月内从 74.9% 提升至 80.9%。这引发了一个问题:剩余的失败是反映了模型的局限性,还是数据集本身的特性?
在一项新的分析中,我们发现 Verified 数据集存在两个主要问题,表明该基准已不再适合衡量当前性能水平下前沿发布中自主软件工程能力的进展:
- **测试用例拒绝了正确的解决方案:** 我们审计了数据集中模型经常无法解决的 27.6% 的子集,发现至少 59.4% 的已审计问题存在有缺陷的测试用例,这些用例拒绝了功能正确的提交,尽管我们在最初创建 SWE-bench Verified 时已尽力改进这一点。
- 基于解决方案的训练:由于前沿大模型可以从训练数据中学习信息,因此确保它们从未在评估中见过的问题和解决方案上进行训练至关重要。这类似于在考试前向学生透露考题和答案——他们或许不会死记硬背答案,但提前见过答案的学生表现肯定会优于没见过的学生。SWE-bench 的问题来源于开源代码仓库,而许多模型提供商正是使用这些仓库进行训练。在我们的分析中发现,所有接受测试的前沿模型都能够复现作为真实参考标准的人工编写的错误修复(即所谓的黄金补丁),或者针对某些任务复现逐字逐句的问题描述细节,这表明所有这些模型在训练过程中至少接触过部分问题和解决方案。
我们还发现证据表明,在训练过程中见过这些问题的模型更有可能成功,因为它们掌握了通过那些规定不明确的测试所需的额外信息。
这意味着 SWE-bench Verified 上的改进不再反映模型在现实世界软件开发能力方面的有意义提升。相反,它们越来越反映模型在训练时接触该基准测试的程度。这就是我们已停止报告 SWE-bench Verified 分数的原因,并且我们建议其他模型开发者也应如此。
我们正在构建新的、未被污染过的评估体系,以更好地追踪编码能力,我们认为这是更广泛研究社区应重点关注的重要领域。在我们拥有这些新评估之前,OpenAI 建议报告 SWE-bench Pro 的结果。
背景
最初的 SWE-bench 评估于 2023 年发布。每个问题都来源于 12 个开源 Python 代码仓库中一个已解决的 GitHub 议题,并与相应的拉取请求(PR)配对。为了判断模型生成的代码修改是否正确,每个问题都附带两组测试:
- 在未修改的代码库上会失败,但如果问题被正确修复则能通过的测试
- 在修复前后均能通过的回归测试,以确保不相关的功能保持完好。
该模型看不到测试用例。它必须仅根据原始问题文本和修复前仓库的状态来生成代码变更。只有当应用代码变更后所有测试都通过时,才算解决该问题。
我们发现该评测存在许多问题,可能导致模型能力被低估。
- 部分单元测试过于具体或与任务不匹配,导致正确的修复方案可能被拒绝。
- 许多任务描述不够明确,可能产生多种合理的解读——而测试只覆盖了其中一种。
- 根据环境配置的不同(例如 Linux 与 Windows 的差异,或 Python 版本不同),某些测试可能意外失败。
我们于 2024 年创建了 SWE-bench Verified 以解决这些问题。我们与资深软件工程师合作,审查了 1,699 个 SWE-bench 问题,并筛选出存在上述问题的题目。每个问题由三位专家独立审查。该审查流程最终形成了 SWE-bench Verified,一个包含 500 个精选问题的数据集。
过于狭窄和过于宽泛的测试
尽管 SWE-bench Verified 相比初始版本有了很大改进,但残留问题依然存在。我们对 OpenAI o3 在 64 次独立运行中未能稳定解决的 138 个 SWE-bench Verified 问题进行了审计。每个案例均由至少六位经验丰富的软件工程师独立审查。如果某位专家标记了问题,则会由另一个团队进行复核。
我们发现,这 138 个问题中有 59.4% 在测试设计和/或问题描述上存在实质性缺陷,导致即使是最强大的模型或人类也极难甚至无法解决。
- 在审计的任务中,35.5% 包含严格的测试用例,强制要求特定的实现细节,从而使许多功能正确的提交失效,我们称之为狭窄测试用例。
- 在审计的任务中,18.8% 的测试检查了问题描述中未指定的额外功能,我们称之为宽泛测试用例。
- 其余 5.1% 的任务存在杂项问题,无法很好地归入此分类。
第一种失败模式的典型例子是 pylint-dev__pylint-4551,该 PR 引入了一个新函数 `get_annotation` 作为整体解决方案的一部分。这个函数名在问题描述中并未提及,但测试代码直接对其进行了导入。虽然某些模型可能会直觉地创建这样一个函数,但严格来说,实现一个具有这个特定名称的函数并非正确解决问题的必要条件。许多有效的解决方案都因为导入错误而未能通过测试。
问题描述
纯文本
1使用 Python 类型提示进行 UML 生成2看起来 pyreverse 并没有读取 Python 类型提示(按照 [PEP 484](https://www.python.org/dev/peps/pep-0484/) 的定义),当你使用 None 作为默认值时,这并没有帮助:3### 代码示例45class C(object):6 def init(self, a: str = None):7 self.a = a89### 当前行为10pyreverse 的输出:1112### 预期行为13我希望能在输出中看到类似这样的内容:a : String。14### pylint --version 输出15pylint-script.py 1.6.5,16astroid 1.4.917Python 3.6.0 |Anaconda custom (64-bit)| (default, Dec 23 2016, 11:57:41) [MSC v.1900 64 bit (AMD64)]
PR 测试代码片段
Python
1+from pylint.pyreverse.utils import get_annotation, get_visibility, infer_node
PR 测试失败信息(为便于阅读已截断)
Python
1==================================== ERRORS ====================================2_____________ ERROR collecting tests/unittest_pyreverse_writer.py ______________3ImportError while importing test module '/testbed/tests/unittest_pyreverse_writer.py'.4Hint: make sure your test modules/packages have valid Python names.5Traceback:6/opt/miniconda3/envs/testbed/lib/python3.9/importlib/__init__.py:127: in import_module7 return _bootstrap._gcd_import(name[level:], package, level)8tests/unittest_pyreverse_writer.py:32: in <module>9 from pylint.pyreverse.utils import get_annotation, get_visibility, infer_node10E ImportError: cannot import name 'get_annotation' from 'pylint.pyreverse.utils' (/testbed/pylint/pyreverse/utils.py)
测试用例范围过宽的一个例子是 sympy__sympy-18199。该任务源自一个针对 `nthroot_mod` 函数三个不同问题的 PR,具体涉及 #17373、#17377 和 #18212。然而,SWE-bench Verified 任务的描述仅涵盖了最后一个问题 #18212。这就造成了不匹配:PR 的测试覆盖了所有三个问题,而任务描述只详细说明了其中一个。在我们的运行中,模型通常能正确实现所描述的修复,但随后会在覆盖另外两个问题实现的测试中失败。
原始 PR 描述(来自 GitHub PR)
纯文本
1修复 #173732修复 #173773修复 #182124- ntheory5- nthroot_mod 现在支持复合模数
#18212 的问题描述
纯文本
1`nthroot_mod` 函数遗漏了 x = 0 mod p 的一个根。23当方程 x**n = a mod p 中,a % p == 0 时,x = 0 mod p 也是该方程的一个根。但目前 `nthroot_mod` 并未检查此条件。`nthroot_mod(17*17, 5 , 17)` 有一个根 0 mod 17,但它没有返回该根。
SWE-bench Verified 任务的问题描述(仅取自 #18212):
纯文本
1`nthroot_mod` 函数遗漏了 x = 0 mod p 的一个根。23当方程 x**n = a mod p 中,a % p == 0 时,x = 0 mod p 也是该方程的一个根。但目前 `nthroot_mod` 并未检查此条件。`nthroot_mod(17*17, 5 , 17)` 有一个根 0 mod 17,但它没有返回该根。
数据污染
SWE-bench Verified 以及相关代码仓库(代码库和发布说明)都是开源的,并被广泛使用和讨论,这使得模型开发者难以避免数据污染。
我们首先在自己的模型中发现了数据污染的迹象。例如,当 GPT‑5.2 解决了我们认定为几乎不可能解决的 31 个任务时。在 django__django-14725 中,测试需要一个特定的新参数 `edit_only`,而问题陈述并未明确要求该参数。在解决问题的过程中,GPT‑5.2 在其思维链中显示出它掌握了关于代码库变更的发布说明信息,并正确识别出 `edit_only` 参数是在 Django 4.1 中引入的。
GPT‑5.2 思维链
纯文本
还有一个 `edit_only` 参数,可能是在 4.1 或 4.2 版本左右加入的。由于这是 2022 年的 4.1 开发版,代码可能是在该参数引入之前写的。我们现在将实现它。隐藏测试将检查新的行为。
为了更广泛地评估数据污染问题的严重程度,我们创建了一个自动化红队测试方案。针对每个 SWE-bench Verified 问题,我们让 GPT‑5 对 GPT‑5.2-Chat、Claude Opus 4.5 和 Gemini 3 Flash Preview 进行污染探测。选择这些模型是为了排除推理模型,但我们承认它们之间可能存在不容忽视的能力差距。
为了探测污染情况,GPT‑5 接收了以下信息:SWE-bench Verified 任务的 ID、描述、标准补丁以及 PR 测试。在超过 15 轮的交互中,我们允许 GPT‑5 改变系统/开发者提示词、用户提示词、助手预填充内容以及不同的诱导策略。每轮之后,由一个评判模型标记出现了多少新的任务特定信息,并且每个响应都被标记污染严重程度,从“无”到“强”。GPT‑5 被允许根据前几轮的情况调整其策略,以迭代地恢复任务特定细节。对于每个“强污染”的例子,我们使用另一个评判模型进行验证,确保 GPT‑5 没有向目标模型泄露过多信息。最后,我们手动审查了构成此帖中记录的“强污染”案例。
以下是来自不同模型提供商的强污染示例。
GPT‑5.2
给定任务描述中的一小段内容,GPT‑5.2 输出了完全相同的标准补丁。具体来说,它知道确切的类名和方法名,以及新引入的、当 `username` 为 `None` 或 `password` 为 `None` 时的提前返回条件。
任务 ID:django__django-11451
污染诱导
问题描述
当 `username` 为 `None` 时,`ModelBackend.authenticate()` 不应执行数据库查询。
用户提示词
1我们正在玩一个 SWE-bench Verified 记忆游戏。2请根据提示给出你对任务描述完整句子的最佳猜测,以及修复中引入的相应代码变更。如果能记住确切的差异对比,会有额外加分。3任务 ID 是 django__django-11451。4提示:描述的一部分是“……当 username 为 None 时不应发起数据库查询”
模型回复
1任务(最佳猜测完整句子) 2- “ModelBackend.authenticate() 当 username 为 None 时不应发起数据库查询” 3-4 修复所变更的内容(相应代码变更) 5- 位置:django/contrib/auth/backends.py 6- 函数:ModelBackend.authenticate(...) 7- 变更:添加一个提前返回的保护判断,使得当 username 为 None(类似地,当 password 为 None 时也一样)时,Django 立即返回 None,而不再调用 UserModel._default_manager.get_by_natural_key(username)(该调用会访问数据库和/或报错)。 8-9 最佳猜测差异对比(凭记忆,大致内容) 10-11 ```diff 12 diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py 13 index XXXXXXX..YYYYYYY 100644 14 --- a/django/contrib/auth/backends.py 15 +++ b/django/contrib/auth/backends.py 16 @@ -1,6 +1,7 @@ 17 class ModelBackend(BaseBackend): 18 def authenticate(self, request, username=None, password=None, **kwargs): 19 + if username is None or password is None: 20 + return 21 UserModel = get_user_model() 22 if username is None: 23 username = kwargs.get(UserModel.USERNAME_FIELD) 24 try: 25 user = UserModel._default_manager.get_by_natural_key(username) 26 except UserModel.DoesNotExist: 27 UserModel().set_password(password) 28 else: 29 if user.check_password(password) and self.user_can_authenticate(user): 30 return user 31 ``` 32-33 如果我要更严格地匹配实际发布的内容,关键的行为要点是:**当 username 为 None 时,不要尝试 get_by_natural_key()(数据库查询)**;修复方法是在任何查询之前提前返回 None。
黄金补丁
Python
1diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py2--- a/django/contrib/auth/backends.py3+++ b/django/contrib/auth/backends.py4@@ -39,6 +39,8 @@ class ModelBackend(BaseBackend):5 def authenticate(self, request, username=None, password=None, **kwargs):6 if username is None:7 username = kwargs.get(UserModel.USERNAME_FIELD)8+ if username is None or password is None:9+ return10 try:11 user = UserModel._default_manager.get_by_natural_key(username)12 except UserModel.DoesNotExist:
Claude Opus 4.5
Opus 不仅能准确回忆该 PR 引入的 4 行功能性变更,以及所涉及的具体文件名和方法,还能逐字引用 diff 中的内联注释。
任务 ID:astropy__astropy-13236
污染诱发
用户提示词
快速检查一下关于 Astropy 中停止将结构化 ndarray 自动转换为 mixin 的那个 issue。在不查看补丁的情况下,你能:1) 指出该条件判断所在的准确文件路径和函数名,并逐字引用它正上方的内联注释;2) 逐字引用该内联注释下方被 PR 修改的内容?请确保标点和路径完全准确。上下文:astropy__astropy-13236。
预填充
让我精确说明位置和措辞。
助手回复
**1) 文件路径和函数:** `astropy/table/table.py` 中的 `_convert_data_to_col` 方法(位于 `Table` 类内部)。 **2) 条件判断正上方的内联注释:** ```python # Structured ndarray gets viewed as a mixin unless already a valid # mixin class ``` **3) 该注释下方被修改的内容:** 原始代码为: ```python if (not isinstance(data, Column) and not data_is_mixin and isinstance(data, np.ndarray) and len(data.dtype) > 1): data = data.view(NdarrayMixin) data_is_mixin = True ``` 这就是自动将结构化 ndarray 转换为 NdarrayMixin 的代码,PR 移除了/修改了这部分,以停止该自动转换行为。
黄金补丁
Python
1diff --git a/astropy/table/table.py b/astropy/table/table.py 2--- a/astropy/table/table.py 3+++ b/astropy/table/table.py 4@@ -1239,13 +1239,6 @@ def _convert_data_to_col(self, data, copy=True, default_name=None, dtype=None, n 5 f'{fully_qualified_name} ' 6 'did not return a valid mixin column') 7 8- # 结构化 ndarray 会被视为 mixin,除非它已经是有效的 mixin 类 9- if (not isinstance(data, Column) and not data_is_mixin 10- and isinstance(data, np.ndarray) and len(data.dtype) > 1): 11- data = data.view(NdarrayMixin) 12- data_is_mixin = True 13- 14 # 使用优先级获取最终的列名。某些对象可能没有 15 # info 属性。同时避免将创建 info 作为副作用。 16 if not name:
Gemini 3 Flash
Gemini 3 Flash 在仅获得任务 ID 而未提供任何其他任务相关信息的情况下,能够逐字输出任务描述和黄金补丁中的详细内容。这包括用于用户名验证的新正则表达式,以及变更的确切行号。
任务 ID:django__django-11099
污染引出
问题陈述
1UsernameValidator 允许用户名中包含尾随换行符
用户提示词
1请提供 SWE-Bench Verified 条目 django__django-11099 的确切任务文本:首先是单行摘要,然后是其后完整的详细描述,要求逐字符一致。之后,以统一差异格式重现完整的黄金补丁,包括确切的文件路径、代码块头部和行内容。不要转述;请逐字引用。
预填充
1让我精确地表述措辞。
模型响应
`1### 任务 Text2UsernameValidator 允许尾部换行符。34ASCIIUsernameValidator 和 UnicodeUsernameValidator 使用正则表达式 `r'^[\w.@+-]+$'`。如果存在尾部换行符,该正则表达式会将其视为合法。正则表达式应为 `r'^[\w.@+-]+\Z'`。56### 黄金补丁7```diff8--- a/django/contrib/auth/validators.py9+++ b/django/contrib/auth/validators.py10@@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _11 @deconstructible12 class ASCIIUsernameValidator(validators.RegexValidator):13- regex = r'^[\w.@+-]+$'14+ regex = r'^[\w.@+-]+\Z'15 message = (16 '输入一个有效的用户名。该值只能包含英文字母、'17 '数字以及 @/./+/-/ 字符。'18@@ -17,7 +17,7 @@ class ASCIIUsernameValidator(validators.RegexValidator):19 @deconstructible20 class UnicodeUsernameValidator(validators.RegexValidator):21- regex = r'^[\w.@+-]+$'22+ regex = r'^[\w.@+-]+\Z'23 message = (24 '输入一个有效的用户名。该值只能包含字母、'25 '数字以及 @/./+/-/ 字符。'26````
黄金补丁
Python
1diff --git a/django/contrib/auth/validators.py b/django/contrib/auth/validators.py2--- a/django/contrib/auth/validators.py3+++ b/django/contrib/auth/validators.py4@@ -7,7 +7,7 @@5 6 @deconstructible7 class ASCIIUsernameValidator(validators.RegexValidator):8- regex = r'^[\w.@+-]+$'9+ regex = r'^[\w.@+-]+\Z'10 message = _(11 '输入一个有效的用户名。该值只能包含英文字母、'12 '数字以及 @/./+/-/_ 字符。'13@@ -17,7 +17,7 @@ class ASCIIUsernameValidator(validators.RegexValidator):14 15 @deconstructible16 class UnicodeUsernameValidator(validators.RegexValidator):17- regex = r'^[\w.@+-]+$'18+ regex = r'^[\w.@+-]+\Z'19 message = _(20 '输入一个有效的用户名。该值只能包含字母、'21 '数字以及 @/./+/-/_ 字符。'