数据截至 (上游 commit 7a21e0577295)
SWE-bench — 架构与原理
30 秒导读: SWE-bench 是一个评测基准。它从知名开源仓库(Django、sympy、scikit-learn…)的真实 PR 里造题:每道题给模型一个仓库快照和一段 issue 描述,模型要生成一个
git补丁。评判方式不是看文本像不像标准答案,而是把补丁打进一个 Docker 容器、真的跑那个仓库的测试套件,看「该被修好的测试」是否全部转绿、且「原本就绿的测试」没被弄坏。
本项目较大(5 个子系统、三层镜像模型、多语言判分),按「由浅入深」拆成 1 个索引 + 4 章。先读本页建立全景,再按需下钻。
1. 这是什么(零基础也能懂)
一句话定义: SWE-bench 是「让大模型修真实软件 bug,并用真实测试自动判分」的评测基准 + 评测工具。
它想回答的问题: 论文标题就是问句——Can Language Models Resolve Real-World GitHub Issues?(语言模型能解决真实的 GitHub issue 吗?)。
给谁用:
- 模型 / agent 作者:想知道「我的编码 agent 在真实仓库上到底能修好多少 bug」。
- 研究者:想要一个不靠人工、可复现、难以靠背答案刷分的硬指标。
为什么「真实测试判分」很关键: 写代码这件事天然有「事实裁判」——单元测试。一个补丁对不对,不用人去读,跑测试就知道。SWE-bench 把这个裁判工程化了。
一道题(task instance)由什么组成:
| 字段 | 白话 |
|---|---|
repo + base_commit | 哪个仓库、在哪个提交点(给模型看的代码快照) |
problem_statement | issue 正文(要解决的问题描述) |
patch | 人类工程师当年合并的「标准答案」补丁(gold patch) |
test_patch | 当年随 PR 一起加的测试改动(裁判用的测试) |
FAIL_TO_PASS | 修好之后「应当由失败转成通过」的测试列表 |
PASS_TO_PASS | 修改前后都「应当保持通过」的测试列表(防止改坏) |
字段的完整定义见 swebench/types.py:9-21(SWEbenchInstance)。
用起来什么样: 装好 Docker 后,一条命令就能拿「标准答案」验证整条评测链是否通:
python -m swebench.harness.run_evaluation \
--predictions_path gold \
--max_workers 1 \
--instance_ids sympy__sympy-20590 \
--run_id validate-gold
--predictions_path gold 表示「用 gold 补丁当作模型预测」——既能自检环境,也能确认这道题本身确实可解(README「Set Up」段)。
一句话直觉/类比: 把它想成给 AI 出的「真实工单 + 自动验收」。HR 不看你简历写得漂不漂亮,而是把你的代码改动直接部署进测试流水线,红变绿就算过、把别人弄红就算砸。
2. 顶层全景(它大概怎么转)
SWE-bench 仓库其实是两件事的合体:(A) 怎么把真实 PR 变成题目(数据侧),(B) 怎么给一份模型答案判分(评测侧)。评测侧是日常最常用、也是「SWE-bench」这个名字真正指代的价值核心。
2.1 五个子系统
| 子系统 | 干什么 | 在哪个目录 |
|---|---|---|
harness/ | 评测核心:配对过滤、起容器、打补丁、跑测试、判分 | swebench/harness/ |
image_builder/ | 每题一个 Docker 镜像的规格与本地构建(远程默认拉预建) | swebench/image_builder/ |
task/ | 任务包格式:eval_script 落盘为 eval.sh 等 | swebench/task/ |
types.py | SWEbenchInstance / TestSpec 数据结构 | swebench/types.py |
collect/ | 数据采集:爬 GitHub PR → 过滤 → 造出 task instance(含镜像与 eval 脚 本) | swebench/collect/ |
inference/ | 跑模型生成补丁(OpenAI/Anthropic API 或本地 Llama),以及构造模型输入文本 | swebench/inference/ |
resources/ | 静态资源 | swebench/resources/ |
2026 年中重构: 旧版的
versioning/子系统和「按 (repo, version) 查配方表现场生成 bash」体系已移除——数据集现在每道题自带image(预建镜像名)与eval_script(评测脚本全文),评测侧不再编译脚本。
下面几章聚焦 harness/(评测)与 collect/(造题),这两块是理解 SWE-bench 的主干。
2.2 评测主线一张图
「怎么读:从上到下是一次评测的时间顺序;每道题(instance)独立走一遍,多道题在线程池里并行。」
predictions.json 数据集 (HuggingFace)
(模型给每道题的补丁) (题面 + gold + 测试)
│ │
└──────────────┬──────────────────────┘
▼
① 配对 + 过滤待跑题目
get_dataset_from_preds()
│
▼
② 一道题 → 一份 TestSpec
make_test_spec()
(数据集自带 image + eval_script,直接读字段)
│
▼
③ 每题一个扁平镜像 sweb.eval.*
(默认从 DockerHub 拉预建,可本地构建)
│
▼
④ 起容器,把模型补丁打进去
git apply / patch (多级 fallback)
│
▼
⑤ 跑 eval.sh:先打测试补丁,再跑测试
输出夹在 >>>>> Start/End 标记之间
│
▼
⑥ 解析日志 → status map → 判分
get_eval_report() → resolved?
│
▼
⑦ 汇总成 run report (resolved 多少道)
各步对应的真实符号:
| 步骤 | 函数 / 符号 | 文件 |
|---|---|---|
| ① 配对过滤 | get_dataset_from_preds | swebench/harness/run_evaluation.py:542 |
| ② 读 TestSpec | make_test_spec | swebench/harness/utils.py:251 |
| ③ 建镜像 | build_instance_images / build_instance_image | swebench/image_builder/docker_build.py:115,145 |
| ④⑤ 打补丁+跑测试 | run_instance | swebench/harness/run_evaluation.py:229 |
| ⑥ 判分 | get_eval_report | swebench/harness/grading.py:329 |
| ⑦ 汇总 | make_run_report | swebench/harness/reporting.py:16 |
2.3 主线走一遍(高层,不进代码)
- 你给一个
predictions.json:每条是{instance_id, model_name_or_path, model_patch}。 - 工具按
instance_id把你的补丁和数据集里的题面配上,跳过没补丁/已跑过/空补丁的(步 ①)。 - 每道题从数据集里读出自己的
TestSpec——数据集自带该题的镜像名与评测脚本全文,无需现场生成(步 ②)。 - 起该题的镜像(默认从 DockerHub 拉官方预建的
sweb.eval.*镜像),容器里已经躺着「打好环境、停在 base_commit」的仓库(步 ③)。 - 起容器 → 把模型补丁打进去 → 跑
eval.sh,脚本里会再打测试补丁、然后跑指定测试(步 ④⑤)。 - 测试输出被夹在
>>>>> Start Test Output/>>>>> End Test Output之间,解析成「每个测试 → PASSED/FAILED/…」的 status map,再和FAIL_TO_PASS/PASS_TO_PASS比对,得出这道题resolved与否(步 ⑥)。 - 全部跑完,汇总出一份报告:总共多少道、resolved 多少道(步 ⑦)。
3. 阅读地图(建议顺序)
- 01-data-model.md — 先搞清「一道题长什么样」:
SWEbenchInstance、F2P/P2P 的含义、gold 补丁、以及数据怎么从真实 PR 里采出来(collect/)。这是后面一切的地基。 - 02-harness-pipeline.md — 评测主流程:
TestSpec如何把一道题编译成 bash、三层 Docker 镜像为什么这么分、补丁怎么打、测试怎么跑。 - 03-grading.md — 判分内核:日志解析、F2P/P2P 比对、
resolved三档判定(这是「分数」真正诞生的地方)。 - 04-internals-and-edges.md — 巧妙之处(防数据泄漏、clean diff、缓存键、多级 patch fallback)、边界与局限、多语言扩展、代码地图。
如果你只想知道「分数怎么来的」→ 直接读第 3 章。如果你要复现/调试一次跑批 → 读第 2 章。如果你要造自己的数据集 → 读第 1 章后半。