跳至主要內容
OpenAI

2026年2月23日

研究研究發表

為何 SWE-bench Verified 不再衡量前沿程式設計能力

SWE-bench Verified 的污染情況日益嚴重。我們建議使用 SWE-bench Pro。

載入中…

自從我們於 2024 年 8 月首次發布 SWE-bench Verified 以來,業界已廣泛使用它來衡量模型在自主軟體工程任務上的進展。在發布後,SWE-bench Verified 提供了能力進展的強烈訊號,並成為前沿模型發布中常見的標準指標。追蹤並預測這些能力的進展也是 OpenAI 的 應變整備框架的重要組成部分。當我們最初建立 Verified 基準測試時,我們嘗試解決原始評估中的一些問題,這些問題使得 SWE-bench dataset(在新視窗中開啟) 中的某些任務無法完成。

在初期大幅躍進之後,SWE-bench Verified 的最先進進展已放緩,過去 6 個月僅從 74.9% 提升(在新視窗中開啟)至 80.9%。這就引發了一個問題:剩餘的失敗究竟反映的是模型的限制,還是資料集本身的特性?

在一項新的分析中,我們發現 Verified 集合存在兩個重大問題,這些問題顯示,在當今的性能水準下,該基準已不再適合用於衡量前沿發佈的自主軟體工程能力進展:

  1. 測試拒絕正確解答:我們稽核了資料集的 27.6% 子集(該子集是模型經常無法解出的部分),並發現至少 59.4% 的受稽核問題包含有瑕疵的測試案例,會拒絕功能上正確的提交,儘管我們在最初建立 SWE-bench Verified 時已盡最大努力改善此問題。
  2. 針對解決方案的訓練: 由於大型前沿模型可以從其訓練中學習資訊,因此重要的是,絕不可在它們被評估的問題與解決方案上對其進行訓練。這就像是在考試前,把即將到來的考試題目與解法先分享給學生——他們也許不會把答案背起來,但看過答案的學生肯定會比沒看過的學生表現得更好。SWE-bench 的問題來源於許多模型供應商用於訓練目的的開放原始碼程式碼庫。在我們的分析中,我們發現我們測試的所有前沿模型都能重現作為基準真值參考的原始人類撰寫錯誤修補(稱為 gold patch),或在某些任務中逐字重現問題陳述的具體細節,這表示它們在訓練期間至少看過部分問題與解法。

我們也發現證據顯示,在訓練期間看過這些問題的模型更有可能成功,因為它們具備通過規格不夠明確的測試所需的額外資訊。

這表示,SWE-bench Verified 上的改進不再反映模型在真實世界軟體開發能力上的有意義提升。相反地,它們愈來愈反映出模型在訓練時接觸該基準測試的程度。這就是為什麼我們已停止回報 SWE-bench Verified 分數,並建議其他模型開發者也這麼做。

我們正在建立全新、未受污染的評測,以便更妥善追蹤程式設計能力,我們也認為這是更廣泛研究社群值得重點關注的重要領域。在我們取得那些之前,OpenAI 建議回報 SWE-bench Pro 的結果。

背景

原始的 SWE-bench(在新視窗中開啟) 評估於 2023 年發布。每個問題都源自 12 個開源 Python 程式碼庫之一中已解決的 GitHub issue,並與對應的 pull request (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
Use Python type hints for UML generation
2
It seems that pyreverse does not read python type hints (as defined by [PEP 484](https://www.python.org/dev/peps/pep-0484/)), and this does not help when you use `None` as a default value :
3
### Code example
4
`
5
class C(object):
6
def __init__(self, a: str = None):
7
self.a = a
8
`
9
### Current behavior
10
Output of pyreverse :
11
![classes_test](https://user-images.githubusercontent.com/22218701/27432305-f10fe03e-574f-11e7-81fa-e2b59e493360.png)
12
### Expected behavior
13
I would like to see something like : `a : String` in the output.
14
### pylint --version output
15
pylint-script.py 1.6.5,
16
astroid 1.4.9
17
Python 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 ______________
3
ImportError while importing test module '/testbed/tests/unittest_pyreverse_writer.py'.
4
Hint: make sure your test modules/packages have valid Python names.
5
Traceback:
6
/opt/miniconda3/envs/testbed/lib/python3.9/importlib/__init__.py:127: in import_module
7
return _bootstrap._gcd_import(name[level:], package, level)
8
tests/unittest_pyreverse_writer.py:32: in <module>
9
from pylint.pyreverse.utils import get_annotation, get_visibility, infer_node
10
E ImportError: cannot import name 'get_annotation' from 'pylint.pyreverse.utils' (/testbed/pylint/pyreverse/utils.py)

過於寬泛的測試案例的一個例子是 sympy__sympy-18199(在新視窗中開啟)。此任務源自一個 PR,該 PR 針對 `nthroot_mod` 函式處理了三個不同的問題,分別是 #17373(在新視窗中開啟)#17377(在新視窗中開啟),以及 #18212(在新視窗中開啟)。然而,SWE-bench Verified 任務的描述僅涵蓋最終的問題 #18212(在新視窗中開啟)。這會造成不一致:PR 測試涵蓋了全部三個問題,但描述只詳述其中一個。在我們的執行中,模型往往能正確實作所描述的修正,接著卻在涵蓋另外兩個問題實作的測試中失敗。

原始 PR 說明(來自 GitHub PR)

純文字

1
Fixes #17373
2
Fixes #17377
3
Fixes #18212
4
- ntheory
5
- `nthroot_mod` now supports composite moduli

#18212 的問題描述

純文字

1
nthroot_mod function misses one root of x = 0 mod p.
2

3
When in the equation x**n = a mod p , when a % p == 0. Then x = 0 mod p is also a root of this equation. But right now `nthroot_mod` does not check for this condition. `nthroot_mod(17*17, 5 , 17)` has a root `0 mod 17`. But it does not return it.

SWE-bench Verified 任務的問題描述(僅取自 #18212):

純文字

1
nthroot_mod function misses one root of x = 0 mod p.
2

3
When in the equation x**n = a mod p , when a % p == 0. Then x = 0 mod p is also a root of this equation. But right now `nthroot_mod` does not check for this condition. `nthroot_mod(17*17, 5 , 17)` has a root `0 mod 17`. But it does not return it.

污染

SWE-bench Verified 以及這些程式碼庫(程式碼基底與發行說明)皆為開放原始碼,且被廣泛使用與討論,這使得模型開發者難以避免污染。

我們最先在自家的模型中發現污染的跡象。例如,當 GPT‑5.2 解決了我們認定幾乎不可能解決的 31 項任務時。在 django__django-14725(在新視窗中開啟) 中,測試需要一個特定的新參數 `edit_only`,但問題陳述並未明確要求此參數。在解決問題的過程中,GPT‑5.2 在其思路鏈中顯示它掌握了關於發行說明的資訊,這些發行說明詳述了程式碼庫的變更,並且正確指出 `edit_only` 參數是在 Django 4.1 中引入的。

GPT‑5.2 CoT

純文字

1
There is also `edit_only` parameter maybe added around 4.1 or 4.2. Since this is 4.1 dev 2022, the code might be before introduction. We will implement now. Hidden tests will check new behavior.

為了更廣泛地評估污染的嚴重程度,我們建立了一套自動化的紅隊演練設定。針對每個 SWE-bench Verified 問題,我們指派 GPT‑5 去探查一個 GPT‑5.2‑Chat,Claude Opus 4.5 和 Gemini 3 Flash Preview 用於污染。選擇這些模型是為了排除推理模型,但我們承認它們之間很可能存在不容小覷的能力差距。

為了探查污染,GPT‑5 收到 SWE-bench Verified 任務的 ID、描述、gold patch 和 PR 測試。在超過 15 個回合中,我們讓 GPT‑5 變更系統/開發者提示詞、使用者提示詞、助理預填內容和不同的引導策略。在每一輪之後,judge 模型會標示出出現了多少新的特定任務資訊,且每個回應都會依污染嚴重性從「none」到「strong」進行標示。GPT‑5 可根據先前的回合調整策略,以反覆迭代的方式找回任務特定的細節。針對每個強污染的範例,我們與另一位評審確認 GPT‑5 沒有向目標模型洩漏過多資訊。最後,我們接著人工審查了構成本篇貼文逐字稿的「強」範例。

以下是不同模型供應商之間嚴重污染的範例。

GPT‑5.2 

給定任務描述中的一小段片段,GPT‑5.2 會輸出完全相符的 gold patch。特別是,它知道確切的類別與方法名稱,以及所引入的新提前返回條件 `if username is None or password is None`

污染引導

問題陳述

1
ModelBackend.authenticate() shouldn't make a database query when username is None

使用者提示

1
We're playing a SWE-bench Verified memory game.
2
Please give your best guess of the full sentence of the task description based on the hint, and the corresponding code change introduced in the fix. Bonus points if you remember the exact diff.
3
The task ID is django__django-11451.
4
Hint: Part of the description was "... shouldn't make a database query when username is None"

模型回應

1
Task (best-guess full sentence)
2
- “`ModelBackend.authenticate()` shouldn’t make a database query when `username` is `None`.”
3

4
What the fix changed (corresponding code change)
5
- Location: `django/contrib/auth/backends.py`
6
- Function: `ModelBackend.authenticate(...)`
7
- Change: add an early-return guard so that if `username` is `None` (and similarly if `password` is `None`), Django returns `None` immediately instead of calling `UserModel._default_manager.get_by_natural_key(username)` (which would hit the DB and/or error).
8

9
Best-guess diff (approximate, from memory)
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
If I had to be stricter about matching what actually shipped, the key behavioral point is: **don’t attempt `get_by_natural_key()` (DB query) when `username` is `None`**; the fix is an early `return None` before any lookup.

金色補丁

Python

1
diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py
2
--- a/django/contrib/auth/backends.py
3
+++ b/django/contrib/auth/backends.py
4
@@ -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
+ return
10
try:
11
user = UserModel._default_manager.get_by_natural_key(username)
12
except UserModel.DoesNotExist:

Claude Opus 4.5

Opus 不僅能夠回想起該 PR 引入的精確 4 行功能變更,以及它所觸及的特定檔名與方法,還能逐字引用差異 (diff) 中包含的內嵌註解。

污染誘發

使用者提示詞

1
Quick memory check on the Astropy issue about stopping the automatic conversion of structured ndarrays into a mixin. Without seeing the patch, can you: 1) name the exact file path and function where that conditional lived, and quote the inline comment immediately above it word-for-word, and 2) quote verbatim the content that was beneath the inline comment that was changed by the PR? Please be exact on punctuation and paths. Context: astropy__astropy-13236.

預先填入

1
Let me be precise about the location and wording.

助理回應

1
**1) File path and function:**
2
`astropy/table/table.py` in the `_convert_data_to_col` method (which is inside the `Table` class).
3

4
**2) The inline comment immediately above the conditional:**
5

6
```python
7
# Structured ndarray gets viewed as a mixin unless already a valid
8
# mixin class
9
```
10

11
**3) The content beneath that comment that was changed:**
12

13
The original code was:
14
```python
15
if (not isinstance(data, Column) and not data_is_mixin
16
and isinstance(data, np.ndarray) and len(data.dtype) > 1):
17
data = data.view(NdarrayMixin)
18
data_is_mixin = True
19
```
20

21
This was the code that automatically converted structured ndarrays to `NdarrayMixin`, which the PR removed/changed to stop that automatic conversion behavior.
22

黃金修補

Python

1
diff --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
- # Structured ndarray gets viewed as a mixin unless already a valid
9
- # mixin class
10
- if (not isinstance(data, Column) and not data_is_mixin
11
- and isinstance(data, np.ndarray) and len(data.dtype) > 1):
12
- data = data.view(NdarrayMixin)
13
- data_is_mixin = True
14
-
15
# Get the final column name using precedence. Some objects may not
16
# have an info attribute. Also avoid creating info as a side effect.
17
if not name:

Gemini 3 Flash

Gemini 3 Flash 在除了 ID 之外未提供任何關於任務的進一步資訊時,仍能逐字輸出任務描述和 gold 修補程式中的細節。這包括用於使用者名稱驗證的新正規表示式公式,以及變更的確切行號。

污染誘發

問題陳述

1
UsernameValidator allows trailing newline in usernames

使用者提示

1
Please provide the exact task text for the SWE-Bench Verified item django__django-11099: first the single-line summary, then the full detailed description that follows, character-for-character. After that, reproduce the complete gold patch as a unified diff, with exact file paths, hunk headers, and line content. Do not paraphrase; quote verbatim.

預先填入

1
Let me be precise about the wording.

模型回應

1
### Task Text
2
UsernameValidator allows trailing newlines.
3

4
ASCIIUsernameValidator and UnicodeUsernameValidator use the regex r'^[\w.@+-]+$'. This allows a trailing newline if it's there. The regex should be r'^[\w.@+-]+\Z'.
5

6
### Gold Patch
7
```diff
8
--- a/django/contrib/auth/validators.py
9
+++ b/django/contrib/auth/validators.py
10
@@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _
11
@deconstructible
12
class ASCIIUsernameValidator(validators.RegexValidator):
13
- regex = r'^[\w.@+-]+$'
14
+ regex = r'^[\w.@+-]+\Z'
15
message = _(
16
'Enter a valid username. This value may contain only English letters, '
17
'numbers, and @/./+/-/_ characters.'
18
@@ -17,7 +17,7 @@ class ASCIIUsernameValidator(validators.RegexValidator):
19
@deconstructible
20
class UnicodeUsernameValidator(validators.RegexValidator):
21
- regex = r'^[\w.@+-]+$'
22
+ regex = r'^[\w.@+-]+\Z'
23
message = _(
24
'Enter a valid username. This value may contain only letters, '
25
'numbers, and @/./+/-/_ characters.'
26
```

黃金修補

Python

1
diff --git a/django/contrib/auth/validators.py b/django/contrib/auth/validators.py
2
--- a/django/contrib/auth/validators.py
3
+++ b/django/contrib/auth/validators.py
4
@@ -7,7 +7,7 @@
5
6
@deconstructible
7
class ASCIIUsernameValidator(validators.RegexValidator):
8
- regex = r'^[\w.@+-]+$'
9
+ regex = r'^[\w.@+-]+\Z'
10
message = _(
11
'Enter a valid username. This value may contain only English letters, '
12
'numbers, and @/./+/-/_ characters.'
13
@@ -17,7 +17,7 @@ class ASCIIUsernameValidator(validators.RegexValidator):
14
15
@deconstructible
16
class UnicodeUsernameValidator(validators.RegexValidator):
17
- regex = r'^[\w.@+-]+$'
18
+ regex = r'^[\w.@+-]+\Z'
19
message = _(
20
'Enter a valid username. This value may contain only letters, '
21
'numbers, and @/./+/-/_ characters.'

討論

從這次對 SWE-bench Verified 的稽核中,我們看到評估設計的兩個更廣泛的啟示。首先,來自公開可取得資料的基準測試存在汙染風險,因為訓練資料的接觸可能會在不知不覺中抬高分數。如果在基準測試建構中使用公開爬取的資料,模型開發者應進行額外的污染測試。基準測試,甚至是其解決方案,若公開張貼,最終可能會進入訓練資料。在資料集的發布方式(亦即密碼保護) 和訓練資料篩選 (i.e.嚴格遵守金絲雀字串)。 

其次,自動化評分很難做到正確;完美的測試案例應能完整驗證正確功能,既不依賴特定且不重要的實作細節,同時也能對捷徑解法保持穩健。這些問題本質上很複雜,且難以解決。發現這些問題需要多次大規模的人工標註活動。

我們已將這些發現納入近期的評估工作中。在過去幾個月中,我們選擇回報來自 SWE-Bench Pro 公開拆分的結果。我們建議其他模型開發人員也這麼做。SWE-bench Pro 並不完美,但經實證顯示,其受污染問題影響似乎較小。我們的資料污染管線發現了一些資料污染案例,但這些案例相較於 SWE-bench Verified 明顯更罕見且情節較不嚴重,而且沒有任何模型能夠產生完整的逐字 gold patch。

我們將持續投資原創、由私人撰寫的基準測試,並請產業界與學術界協助採取相同的方式。在 GDPVal 中,任務由領域專家以私密方式撰寫,降低曝露風險,且解答由受訓審查員以整體方式評分。這種方法相當耗費資源,但為了衡量真正的能力改進,正變得愈來愈必要。

作者

OpenAI