跳到主要內容
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 資料集(在新視窗中開啟)中無法完成。

在最初的躍升之後,頂尖模型在 SWE‑bench Verified 上的進展已放緩,過去 6 個月僅由 74.9% 提升(在新視窗中開啟)至 80.9%。這衍生出一個問題:其餘的失敗反映出模型的限制,還是資料集本身的特性?

在一項新的分析中,我們發現 Verified 資料集存在兩個主要問題,顯示在現今的效能水平下,該基準測試已不再適合用於衡量前沿發佈的自主軟件工程能力進展:

  1. 測試拒絕正確的解決方案:我們審核了資料集的一個 27.6% 子集,該子集包含模型經常無法解決的問題,並發現至少 59.4% 的已審核問題包含瑕疵測試案例,會拒絕在功能上正確的提交,儘管我們在最初建立 SWE-bench Verified 時已盡量改善此問題。
  2. 在解決方案上訓練:由於大型前沿模型可以從其訓練中學習資訊,因此這些模型絕對不能在其評估的問題和解決方案上進行訓練。這就好比在考試前,先把接下來的考試題目和解答分享給學生,他們未必會死記硬背答案,但看過答案的學生肯定會比沒看過的學生表現得更好。SWE-bench 問題源自許多模型供應商用來訓練的開源程式碼庫。在我們的分析中,我們發現所測試的所有前沿模型都能夠重現作為真實參考依據的原始人手撰寫錯誤修正(稱為黃金修補),或在某些任務中逐字呈現問題陳述的具體細節,表示這些模型均至少在訓練期間看過部分問題及解決方案。

我們亦發現,有證據顯示在訓練期間曾經看過這些問題的模型成功機會更大,因為它們擁有透過這些未有明確規格的測試所需的額外資訊。

這意味著在 SWE-bench Verified 上的改進,不再反映模型在現實世界軟件開發能力方面的有意義提升。相反,它們越發反映模型在訓練時接觸該基準測試的程度。因此我們已停止報告 SWE-bench Verified 分數,並建議其他模型開發商亦停止報告。

我們正在建立全新、未受污染的評估方式,以更有效地追蹤編碼能力,而我們認為這是值得廣大研究社群重點關注的重要領域。在此之前,OpenAI 建議為 SWE-bench Pro 報告結果。

背景

原始 SWE-bench(在新視窗中開啟) 評估於 2023 年發布。每個問題都源自 12 個開源 Python 程式碼庫之一中已解決的 GitHub 問題,並與對應的 pull request (PR) 配對。如要判斷模型生成的程式碼更改是否正確,每個問題都附有兩組測試:

  • 在未修改的程式碼庫上失敗但在正確修復問題後通過的測試
  • 在修復前後均通過的回歸測試,以確保不相關的功能保持完整。

模型看不到測試。其必須僅根據原始問題文字以及修復前的程式碼庫狀態,產生一個代碼變更。只有在套用程式碼變更後通過所有測試,才算通過一個問題。

我們發現該評估存在許多問題,可能導致低估模型的能力。

  • 部分單元測試過於具體或與任務不一致,導致正確的修正可能會被拒絕。
  • 許多任務陳述的規格不夠明確,可能導致多種合理的詮釋,而測試只涵蓋其中一種特定詮釋。
  • 視乎環境的設定(例如 Linux 對比 Windows,或 Python 版本),部分測試可能出現非預期失敗

我們於 2024 年建立 SWE-bench Verified,以解決這些問題。我們與資深軟件工程師合作,審查 1,699 個 SWE-bench 問題,並篩選出存在這些問題的題目。每個問題均由三位專家獨立審核。此審查流程產生了 SWE-bench Verified,此為一套包含 500 個問題的精選集。

測試過於狹隘或過於寬泛

雖然 SWE-bench Verified 與初始版本相比有很大改進,但仍然存在一些殘留問題。我們審核了 138 個 OpenAI o3 在 64 次獨立運行中無法穩定解決的 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,其處理 `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、描述、黃金修補及 PR 測試。在超過 15 個回合中,我們讓 GPT‑5 變更系統/開發商提示詞、用戶提示詞,以及助理預填內容和不同的誘發策略。每個回合結束後,評判模型都會標記出現了多少新的特定任務資訊,而每個回覆都會標記出從「無」到「嚴重」的污染嚴重程度。GPT‑5 獲允許根據先前回合調整其策略,以逐步還原特定任務的細節。對於每個嚴重污染的例子,我們會與另一位評判核實,確保 GPT‑5 沒有向目標模型洩漏過多資訊。最後,我們再對構成本文逐字稿的「嚴重」例子進行人手審核。

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

GPT‑5.2

因應任務描述中的一段簡短片段,GPT‑5.2 會輸出完全一致的黃金修補。具體而言,其知道確切的類別和方法名稱,以及所引入的新提前傳回條件 `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 行程式修改,以及其觸及的特定檔案名稱和方法,還會逐字引用差異中包含的內嵌註解。

污染誘發

用戶提示詞

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 之外未獲提供任何關於任務的進一步資訊時,仍能逐字輸出任務描述及黃金修補中的細節。當中包括用於驗證用戶名稱的新正則表達式公式,以及變更的確切行號。

污染誘發

問題陳述

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 的審核中,我們觀察到兩個關於評估設計的更廣泛啟示。首先,源自公開可用資料的基準測試存在污染風險,因為訓練資料曝光可能會在不知不覺中推高分數。如果在基準測試構建中使用公開檢索的資料,模型開發商應進行額外的污染測試。公開發布的基準測試,甚至其解決方案,最終都可能會納入訓練資料。在資料集發布方式(即密碼保護)及訓練資料篩選方面(即嚴格遵守 canary 字串)都應格外謹慎。

其次,自動計分難以正確掌握;理想的測試案例應能完整驗證功能正確性,既不依賴特定且不重要的落實細節,又能抵禦捷徑式的解決方案。這些問題本質上很複雜,而且難以解決。要發現這些問題,需要進行多次大規模的人手標註工作。

我們已將這些發現納入我們近期的評估工作中。在過去幾個月,我們已選擇報告來自 SWE-Bench Pro 公開分組的結果。我們建議其他模型開發商亦同樣處理。SWE-bench Pro 並不完美,但從實證結果來看,其似乎較少受到污染問題影響。我們的污染管線發現一些污染案例,但這些案例明顯比 SWE-bench Verified 更罕見且較不嚴重,而且沒有任何模型能夠產生完整的逐字黃金修補。

我們將繼續投資於原創、私人撰寫的基準測試,並邀請業界和學術界協助一同投資。在 GDPVal 中,任務由領域專家私人撰寫,降低曝光風險,而解決方案則由經過訓練的審核員以整體方式評分。這種方法耗費資源較多,但對於衡量真正的能力改進而言,這種方法變得越來越重要。

作者

OpenAI