SWE-bench: Can Language Models Resolve Real-World GitHub Issues?

元信息

TL;DR

SWE-bench 把"语言模型能不能做软件工程"变成一个可量化、可回归、可持续更新的 benchmark:从 12 个热门 Python 开源仓库里扒出 2,294 条 issue + PR + 测试三元组,让模型只看 issue 和整个代码库,输出一个 unified diff patch;应用后必须通过 PR 附带的 fail-to-pass 测试以及原有回归测试才算解决。发布时前沿模型一片惨淡——BM25 检索下 Claude 2 只能解 1.96%,Claude 3 Opus 也才 3.79%——揭穿了 HumanEval 时代"LLM 会写代码"的错觉,并为之后的 coding agent 竞赛定下了评测范式。

问题与动机

传统代码评测(HumanEval、MBPP、APPS)都有几个共性问题:

而真实的软件工程场景恰好相反:

作者希望找到一个既困难又好验证的任务。GitHub 恰好是理想的数据源:merged PR 自带"修复后的代码"作 gold,自带 regression test 作评测器,并且能无限产出新样本避免被训练数据污染。

方法

数据集构造:3 阶段 pipeline

  1. Stage I — 仓库采集:选 12 个热门 Python 仓库(django、sympy、matplotlib、sphinx、scikit-learn、pytest、requests、flask、pylint、astropy、seaborn、xarray),抓约 9 万条 PR,每条附带 base commit。
  2. Stage II — 属性过滤:只保留同时满足 (a) merged、(b) 关联至少一个 issue、(c) 修改了测试文件 的 PR —— 这是"作者顺手写了回归测试"的代理信号。
  3. Stage III — 执行过滤:对每条候选,分别执行 PR 的 test 部分 "在应用代码改动之前" 和 "之后",只留下至少一条测试从 fail 变成 pass(记为 fail-to-pass)且无安装/运行时错误的样本。

经过三步,9 万 → 2,294 条。作者还额外发布 SWE-bench Lite(300 条更自包含、聚焦功能性 bug fix)和 SWE-bench-train(37 个不同仓库、1.9 万条,去掉 Stage II 的 test-file 限制,用作 SWE-Llama 训练集)。

任务形式

核心指标:% Resolved(解决率)。辅助指标:% Apply(patch 至少能干净应用的比例,反映模型生成格式正确性)。

检索策略

代码库塞不进任何模型的 context,作者固定两种检索方案作为公平的对比基线:

关键观察:27K token 下 BM25 的 recall 对 oracle 文件是 44.4% 平均、26.1% 全命中、51.3% 任意命中;50K 再提升也只到 51.1%。近一半实例下 BM25 连一个关键文件都没捞到。

SWE-Llama:开源 baseline

作者基于 CodeLlama-Python 7B / 13B 做 LoRA 微调(只训练 attention 子层),训练集是上面提到的 19K SWE-bench-train。由于长度约束(>30K tokens 的样本扔掉),实际训练样本 10K。训练时用 oracle 检索格式:给 issue + 被 gold patch 修改的文件 → 让模型输出 gold patch。

这个选择埋了个坑:推理时如果换成 BM25 检索,上下文里会混进"不该改的文件",和训练分布不匹配 → 性能大幅下降。

实验设置

主要结果

BM25 retrieval(主表)

Model SWE-bench % Resolved SWE-bench % Apply Lite % Resolved
Claude 3 Opus 3.79 46.56 4.33
Claude 2 1.97 43.07 3.00
GPT-4-turbo 1.31 26.90 2.67
ChatGPT-3.5 0.17 26.33 0.33
SWE-Llama 13B 0.70 53.62 1.00
SWE-Llama 7B 0.70 51.74 1.33

Oracle retrieval(上界分析)

Claude 2 从 1.97% 跳到 4.8%;进一步把 oracle 文件压到"只留真正改动的行 ±15 行"(oracle-collapsed),GPT-4 1.3 → 3.4%、Claude 2 4.8 → 5.9%。上下文里少塞无关内容是比多塞关键内容更重要的。

BM25 上下文长度的反常曲线

Model 13K 27K 50K
Claude 2 1.96 1.87 1.22
SWE-Llama 7B 0.70 0.31 0.00
SWE-Llama 13B 0.70 0.48 0.00

随着 max context 变大、BM25 召回率上升,解决率反而下降。模型在更多无关代码里迷路得更厉害。

时间切片:没有"刷旧题"

Model Before 2023 After 2023
Claude 2 4.87 4.23
GPT-4* 1.96 0.00
SWE-Llama 3.98 / 2.95 3.85 / 3.46

除 GPT-4(且只测了 25% 子集)外,2023 前后差异不显著——即便训练数据包含了仓库旧版本,模型也没有"背答案"。

关键发现与分析

  1. 模型不会定位。 几乎所有错误都发生在"找不到该改的函数/文件"这一步,而不是"找到了写错了"。所以 oracle retrieval 和 oracle-collapsed 都能明显提升分数——这意味着后续工作最重要的方向不是 coding,而是 grounding / localization

  2. 上下文越多越差。Lost in the Middle 观察一致:注入 27K / 50K 的 BM25 上下文后,模型的注意力反而被稀释。这是"retrieval-augmented"的反面案例——信号/噪声比比检索召回率更关键。

  3. diff 比整文件重写更可靠。 模型生成的 patch 通常比 gold 短一半(30.1 vs 74.5 行),rarely edit >1 file。让模型重写整文件反而降分(Claude 2 oracle 设置下 2.2% vs 4.8%)——尽管 patch 格式在 pretraining 里少见,但输出少 = 犯错面小。

  4. 微调模型对输入分布极敏感。 SWE-Llama 在 oracle 下能追平 Claude 2(13B 解出 91 个,Claude 2 解出 110 个),但 BM25 下只有 0.7%——因为它被训练成"你给我的每个文件都要改",一旦上下文含噪立刻失效。微调数据的检索格式必须和推理一致。

  5. 解对的题集不重合。 oracle 下 Claude 2 和 SWE-Llama 13B 数量接近,但 Claude 2 只覆盖了 SWE-Llama 解出实例的 42%。说明这些模型各有盲区,做 ensemble / 多候选 + 验证是有意义的。

  6. 模型写的代码"只解表症"。 定性分析中,SWE-Llama 在 sphinx-doc 的一个例子里定位到了正确函数,但只是把 if use_param: ... 改成"永远走 use_param 分支"——gold 则是正确地沿用 _parse_parameters_section 的 config 检查逻辑。模型倾向于 greedy 满足眼前的测试,不做结构性改造,不调用库内已有工具,不遵循代码风格。

  7. 图文混排是隐藏难度。 matplotlib 32%、seaborn 10% 的 issue 包含截图。纯文本模型在这些实例上近乎不可解——预示了多模态 coding agent 的必要性。

局限性与开放问题

与同类工作的关系

影响力与后续

SWE-bench 发布后迅速成为 coding agent 领域的事实标准。18 个月内,基于前沿模型 + 工具使用的 agent 系统(SWE-agent、Aider、OpenDevin、Anthropic Claude Code、Cognition Devin 等)把 SWE-bench Verified 的解决率从 < 2% 推到 50%+、Lite 推到 70%+。作者后来发布的 SWE-bench Verified(OpenAI 联合清洗出 500 条人工审核过的可靠题目)、SWE-bench Multilingual 也是对本文局限性的直接回应。

我的评论

这篇本身没有新模型、没有新架构,价值完全在 benchmark 的设计——尤其是"fail-to-pass 测试 + 执行判定"的判别器选择,让评测既严格又可自动化更新,这是把 LLM coding 从玩具题推向工程任务的关键一步。从方法论角度看,它也是"benchmark 即研究"的典范:好的评测比好的算法对社区推动更大。唯一遗憾是对多文件推理、长程工具使用等维度没有单独拆解——但这恰好留给了社区去填。