论文精读 05|SWE-bench:用真实仓库与测试验证软件 Agent
论文档案
| 项目 | 内容 |
|---|---|
| 论文 | SWE-bench: Can Language Models Resolve Real-World GitHub Issues? |
| 作者 | Carlos E. Jimenez 等 |
| 发表 | ICLR 2024 |
| 原文 | OpenReview / arXiv |
| 代码与数据 | princeton-nlp/SWE-bench |
| 本文定位 | 把代码 Agent 的成功条件从“生成像补丁的文本”提升为“真实仓库测试通过” |
为什么它改变了软件 Agent 研究
早期代码生成常给模型一个函数签名和短描述,再用隐藏单元测试评估。真实软件维护完全不同:issue 用自然语言描述,相关实现分散在数十万行代码中,修复要理解项目惯例,还不能破坏已有行为。
SWE-bench 把一个任务定义为:
GitHub issue + 指定仓库 base commit
│
▼
模型读取仓库并生成 patch
│
▼
在可重建环境中应用 patch
│
▼
运行 fail-to-pass 测试 + regression tests
│
▼
全部通过才记为 resolved关键跃迁是 evaluator 不再询问模型“你修好了吗”,也不靠另一个 LLM 看补丁像不像,而是执行真实测试并检查环境终态。
数据集怎样从 GitHub 历史构造
三阶段筛选
作者从约 9 万个 pull request 出发,经过三类约束:
- 仓库与 PR 抓取:选择活跃、可安装的 Python 项目,关联 issue 与合并 PR;
- 测试关联:要求 PR 不只是修改代码,还增加或修改测试,并能找到至少一个能证明 issue 被修复的测试;
- 执行过滤:在 base commit 上安装依赖、运行测试,确认测试在旧代码失败、应用 gold patch 后通过。
最终测试集包含 2,294 个 issue,来自 12 个流行 Python 仓库。训练集另从 37 个互不重叠仓库构造约 19,000 个实例;论文用于微调时进一步筛到 10,000 个上下文不超过 30k token 的实例。
任务为何难
论文统计一个 issue 平均约 195.1 个词,代码库平均约 43.8 万行;参考补丁平均修改 1.7 个文件、3 个函数、32.8 行。目标改动并不大,真正困难的是从巨型仓库中找到它。
每个任务中位数有 51 个额外回归测试,约 40% 的实例有两个或更多 fail-to-pass 测试。也就是说,“让一个测试变绿”不代表没有引入回归。
评估协议:Resolved 到底意味着什么
对于预测 patch,harness 需要完成:
- 在正确 base commit 上重建环境;
- 应用 patch,记录是否能干净应用;
- 运行 fail-to-pass tests,确认目标 bug 被修复;
- 运行 pass-to-pass tests,确认已有行为没有回归;
- 处理超时、依赖失败与基础设施错误;
- 汇总为单个
% Resolved指标。
因此至少要区分四个结果:
| 状态 | 含义 |
|---|---|
| patch 无法应用 | 输出连语法/上下文条件都没满足 |
| patch 可应用、测试未通过 | 格式正确但功能错误 |
| 目标测试通过、回归失败 | 修了局部问题却破坏其他行为 |
| 全部测试通过 | 按基准定义 resolved |
论文中可应用 patch 的比例远高于 resolved rate,直接证明“生成 diff”与“解决 issue”是两个层次。
基线系统如何工作
原论文还没有今天常见的长程 coding agent。基线主要是一次性生成补丁:
- 用 BM25 从仓库检索与 issue 相关的文件;
- 在 13k、27k 或 50k token 预算内拼接代码;
- 把 issue 和代码交给模型;
- 让模型一次输出 patch;
- 应用并执行测试。
还设置 Oracle retrieval:直接给模型参考补丁涉及的文件,用于估计定位瓶颈。论文也训练 SWE-Llama 7B/13B,对 Llama 系列注意力层做 LoRA 微调。
关键结果的正确读法
论文初版结果非常低:Claude 2 在 BM25 检索设置下约 1.96% resolved,ChatGPT 约 0.17%,SWE-Llama 13B 约 0.70%。后续论文版本表中还包含 Claude 3 Opus 约 3.79%、GPT-4 Turbo 约 1.31%。
Oracle 文件显著提升但远未解决问题:Claude 2 约 4.8%,在进一步压缩无关代码的 oracle-collapsed 设置中约 5.93%。这说明:
- 定位是大瓶颈;
- 即使知道正确文件,理解 issue、设计改动和验证仍很难;
- 更长上下文不等于更高成功率。
BM25 在 27k token 设置下约有一半任务没有检索到任何参考补丁文件。另一方面,扩大到 50k 也可能因噪声而降低性能。问题不只是“窗口够不够长”,而是上下文选择是否精确。
数据集背后的 Harness 设计
环境快照是一等资产
任务不能只保存 issue 文本,必须绑定仓库 commit、依赖、操作系统、测试命令和超时。任何一项漂移都会让同一 patch 得到不同结果。
成功判定必须独立
Agent 可以请求提交,但无权决定成功。Harness 接管 patch、在隔离环境运行测试,并将结构化结果反馈给 Agent 或基准报告。
观察要支持定位,而不是倾倒仓库
一次把完整代码库送进上下文既昂贵又嘈杂。适合 Agent 的接口应提供文件搜索、符号搜索、局部查看、测试运行和增量 diff。SWE-agent 后来正是沿这个方向改造 ACI。
测试是证据,也不是绝对真理
测试覆盖可能不足,参考补丁也未必唯一。某个预测 patch 通过现有测试,不代表生产质量完全正确;失败也可能来自环境构建问题。评测报告要保留测试明细与基础设施错误,而不只是一个二元标签。
数据泄露与时效性
SWE-bench 来自公开 GitHub 历史,模型可能在预训练中见过 issue、PR 或补丁。论文检查 issue 时间和性能关系,但无法完全排除污染。随着基准流行,公开测试集更容易进入后续训练数据。
复现或做新比较时应:
- 使用精确、可审计的模型版本;
- 报告 cutoff 与任务创建时间;
- 优先加入更新、更难或私有保留集;
- 检查输出是否复制 reference patch 的异常特征;
- 不把排行榜增量自动解释为泛化能力提升。
一个现代复现协议
完整 2,294 题成本很高,可先做分层样本:
- 按仓库、issue 长度、patch 文件数和测试数分层抽取 50–100 题;
- 为每题构建固定容器镜像和依赖缓存;
- 记录模型、harness commit、prompt、工具 schema、预算和随机种子;
- 每题至少运行 3 次,报告 resolved、apply rate、测试错误和成本;
- 保存每步搜索、打开文件、编辑、测试与最终 diff;
- 失败归类为定位、理解、实现、编辑、验证、预算或环境;
- 把基础设施失败从模型失败中单独剥离。
若比较两个 harness,必须使用相同模型、任务样本、预算、容器和重试策略。否则所谓 Harness 增益可能只是更多 token 或更多尝试。
论文局限
- 仅覆盖 12 个 Python 仓库,不能代表所有语言与开发流程;
- PR 与测试筛选偏向有良好测试文化的项目;
- issue 可能含图片、链接或上下文,纯文本抽取会丢信息;
- 依赖和测试环境复杂,基础设施噪声不可忽略;
- 公开历史带来训练污染风险;
% Resolved不衡量代码可维护性、安全性和潜在未测回归;- 原论文的一次性生成基线不代表现代交互式 coding agent 上限。
SWE-bench 最重要的结论不是“模型只能解决 1% 的问题”,而是建立了一个此后可持续改进的执行式契约:给定真实仓库状态,Agent 必须产生可应用、可测试且不回归的改变。这个契约后来成为 coding harness 的核心验收面。