跳到主要内容

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_statementissue 正文(要解决的问题描述)
patch人类工程师当年合并的「标准答案」补丁(gold patch)
test_patch当年随 PR 一起加的测试改动(裁判用的测试)
FAIL_TO_PASS修好之后「应当由失败转成通过」的测试列表
PASS_TO_PASS修改前后都「应当保持通过」的测试列表(防止改坏)

字段的完整定义见 swebench/harness/constants/__init__.py:24-37SWEbenchInstance)。

用起来什么样: 装好 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/评测核心:把一道题变成可跑脚本、建 Docker 镜像、打补丁、跑测试、判分swebench/harness/
collect/数据采集:爬 GitHub PR → 过滤 → 造出 task instanceswebench/collect/
versioning/给每个 instance 标注它属于仓库的哪个版本(决定用哪套安装/测试配方)swebench/versioning/
inference/跑模型生成补丁(OpenAI/Anthropic API 或本地 Llama),以及构造模型输入文本swebench/inference/
resources/静态资源swebench/resources/

下面几章聚焦 harness/(评测)与 collect/(造题),这两块是理解 SWE-bench 的主干。

2.2 评测主线一张图

「怎么读:从上到下是一次评测的时间顺序;每道题(instance)独立走一遍,多道题在线程池里并行。」

predictions.json 数据集 (HuggingFace)
(模型给每道题的补丁) (题面 + gold + 测试)
│ │
└──────────────┬──────────────────────┘

① 配对 + 过滤待跑题目
get_dataset_from_preds()


② 一道题 → 一份 TestSpec
make_test_spec()
(生成 3 段 bash:建仓 / 装环境 / 跑测试)


③ 三层 Docker 镜像
base ──► env ──► instance
(越往下越专用、越可缓存复用)


④ 起容器,把模型补丁打进去
git apply / patch (多级 fallback)


⑤ 跑 eval.sh:先打测试补丁,再跑测试
输出夹在 >>>>> Start/End 标记之间


⑥ 解析日志 → status map → 判分
get_eval_report() → resolved?


⑦ 汇总成 run report (resolved 多少道)

各步对应的真实符号:

步骤函数 / 符号文件
① 配对过滤get_dataset_from_predsswebench/harness/run_evaluation.py:374
② 造 TestSpecmake_test_specswebench/harness/test_spec/test_spec.py:174
③ 建镜像build_env_images / build_instance_imageswebench/harness/docker_build.py:270,399
④⑤ 打补丁+跑测试run_instanceswebench/harness/run_evaluation.py:71
⑥ 判分get_eval_reportswebench/harness/grading.py:235
⑦ 汇总make_run_reportswebench/harness/reporting.py:17

2.3 主线走一遍(高层,不进代码)

  1. 你给一个 predictions.json:每条是 {instance_id, model_name_or_path, model_patch}
  2. 工具按 instance_id 把你的补丁和数据集里的题面配上,跳过没补丁/已跑过/空补丁的(步 ①)。
  3. 每道题被编译成一份 TestSpec——本质是三段 bash 脚本:怎么克隆并 reset 到 base_commit、怎么装依赖、怎么跑测试(步 ②)。
  4. 用这些脚本叠出三层 Docker 镜像,最专用的 instance 镜像里已经躺着「打好环境、停在 base_commit」的仓库(步 ③)。
  5. 起容器 → 把模型补丁打进去 → 跑 eval.sh,脚本里会再打测试补丁、然后跑指定测试(步 ④⑤)。
  6. 测试输出被夹在 >>>>> Start Test Output / >>>>> End Test Output 之间,解析成「每个测试 → PASSED/FAILED/…」的 status map,再和 FAIL_TO_PASS/PASS_TO_PASS 比对,得出这道题 resolved 与否(步 ⑥)。
  7. 全部跑完,汇总出一份报告:总共多少道、resolved 多少道(步 ⑦)。

3. 阅读地图(建议顺序)

  1. 01-data-model.md — 先搞清「一道题长什么样」:SWEbenchInstance、F2P/P2P 的含义、gold 补丁、以及数据怎么从真实 PR 里采出来(collect/)。这是后面一切的地基。
  2. 02-harness-pipeline.md — 评测主流程:TestSpec 如何把一道题编译成 bash、三层 Docker 镜像为什么这么分、补丁怎么打、测试怎么跑。
  3. 03-grading.md — 判分内核:日志解析、F2P/P2P 比对、resolved 三档判定(这是「分数」真正诞生的地方)。
  4. 04-internals-and-edges.md — 巧妙之处(防数据泄漏、clean diff、缓存键、多级 patch fallback)、边界与局限、多语言扩展、代码地图。

如果你只想知道「分数怎么来的」→ 直接读第 3 章。如果你要复现/调试一次跑批 → 读第 2 章。如果你要造自己的数据集 → 读第 1 章后半。