Home / 大语言模型 / SWE-bench:会写函数之后,还要能修好真实仓库

081|SWE-bench:会写函数之后,还要能修好真实仓库

返回目录 · 发展时间线

论文:Carlos E. Jimenez 等,SWE-bench: Can Language Models Resolve Real-World GitHub Issues?,2023,ICLR 2024。采用论文 v3;该版本包含后补的模型和 Lite 结果,不能将所有表项都标作 2023 年首版成绩。数据和执行工具见官方项目与官方仓库。

图表来源:Carlos E. Jimenez 等,2023,原文;CC BY 4.0。本篇展示做了图形区域裁切,图中数据与标签未改动。

先接住前作的问题

Codex把单函数候选交给测试,却没有覆盖定位文件、理解调用关系和保持仓库旧行为。本篇是任务与评价路线的推进:从真实issue和修复历史建立可执行问题,后续SWE-agent再把求解过程改为交互闭环。

五个前置概念

五个前置概念:基础提交固定修复前代码状态;补丁描述增删修改;BM25依赖词项匹配检索文件;回归测试检查既有行为;Oracle 消融借助真实答案的一部分信息诊断瓶颈。

一、问题设定:函数测试之外,怎样验证真实仓库修复且没有回归

真实issue可能只描述某个输入组合异常,求解器必须在历史仓库中定位并提交补丁。评价既要确认新问题被解决,也要确认原有行为没有破坏;一个合理diff或很高的平均测试通过率,都不足以单独宣布修复成功。

二、把历史任务构造与补丁接受的逻辑条件分开

一个任务包含问题描述 II、修复前代码库 CC、参考修复 δ\delta 和从参考 PR 中分离出的测试改动 TT。求解器得到的是 II 和 CC,输出预测补丁 δ^\hat\delta;参考解及评测测试属于判题依据,不能当作普通求解输入。

基准本身不规定训练算法。可以用纯提示、检索增强、监督训练,或让 Agent 在仓库里阅读与执行。原论文基线主要先检索文件,再单次生成补丁,因此不是充分利用全部可交互环境的上限。

任务结束是提交补丁,成功由测试决定。若后来把它作为强化学习环境,可将终局测试结果作为奖励,但那是使用方式,不是原论文已经训练了一个测试奖励驱动的 Agent。

其关键假设是:合并 PR 对应有效问题,新增或修改测试能表征该问题,历史版本及依赖可以重建。每个假设都需要工程验证;仅从 GitHub 抓下标题和 diff,并不能得到可靠基准。

1. 数据构建流程

论文先选择 12 个流行 Python 仓库,再筛选已合并、关联 issue、修改测试文件的 PR。将测试部分与生产代码修改分离,先在旧代码上运行新测试,再施加参考修复重跑。至少要有一个测试由失败变成功,同时环境必须能够安装和运行。

这说明“自动收集”仍需要环境和日志解析的人工工程投入。附录 A.3 为仓库版本建立执行环境,兼顾每任务单独配置的成本与一个最新环境无法运行所有历史代码的问题。

2. 求解与判题流程

BM25 以 issue 为查询,检索文件内容与路径,将预算内文件放入提示,让模型生成补丁。Oracle 实验则直接提供参考修复实际改过的文件,仅用于诊断定位瓶颈。Oracle 并不提供修复代码,但已经泄露了目标文件范围,明显强于普通问题输入。

F2P 是参考修复前失败、修复后通过的测试;P2P 是此前通过、修复后仍通过的测试。成功率可写为

Resolved=1N∑i=1N1[δ^i可应用]∏t∈Fi∪Pi1[t通过].\mathrm{Resolved}=\frac1N\sum_{i=1}^N \mathbf1[\hat\delta_i\text{可应用}] \prod_{t\in F_i\cup P_i}\mathbf1[t\text{通过}].

NN 是任务数,FiF_i、PiP_i 分别是该任务两类测试集。这是指标定义,不是优化损失。一个任务通过 99% 测试仍可能记 0;这种严格聚合迫使我们同时关心新行为与回归。

从测试分数到任务成功,中间还有两个逻辑门

把补丁能否应用记为 ai∈{0,1}a_i\in\{0,1\},新行为全部通过记为 fif_i,旧行为全部保持记为 pip_i,则任务标签是 ri=aifipir_i=a_if_ip_i。三个条件是逻辑“与”,不能用 (ai+fi+pi)/3(a_i+f_i+p_i)/3 取代。附录 C.5 特别区分“修好新问题但破坏旧行为”和“没修好但也没破坏”;它们都不是 Resolved,却要求完全不同的下一步。

原创教学账本。 某任务有2项 F2P、100项 P2P,且补丁可应用。方案甲通过2项 F2P与99项 P2P,测试总通过率为 101/102≈99.02%101/102\approx99.02\%,但 ri=0r_i=0,属于带回归的修复;方案乙通过1项 F2P与全部 P2P,同样是99.02%,却属于未完全修复。方案丙通过全部102项,才得 ri=1r_i=1。这说明相同的“几乎全通过”隐藏着不同故障,也说明汇报执行日志比只汇报一个平均分更有诊断价值。

还有一个不能越过的边界:ri=1r_i=1 只说明这个版本的判题集合接受了补丁。若 issue 要求对任意输入保持性质,而测试只覆盖有限输入,测试接受不等于数学上的规格证明。扩展评测时应保留原测试并添加针对新反例的检查,不能靠改掉失败测试来制造成功。

SWE-Llama 则另有监督损失:给 issue 和参考文件,最大化参考补丁 token 的概率。它训练的是代码编辑能力,不能把其交叉熵下降等同于 Resolved 上升。

自构例子。 一个 URL 解析器把空端口处理成异常。模型在入口处捕获所有异常,新测试通过,但原先应报告非法端口的回归测试失败:这属于修复目标却破坏已有行为,不能算 Resolved。若它只修改注释、旧测试仍通过而新测试仍失败,则是无作用修改。这个例子展示 F2P 与 P2P 的不同职责,并非原文实验样本。

实例均值与仓库均值回答不同问题

自构仓库甲有90题、修好72题,乙有10题、修好2题。按实例平均为74%,先算仓库成功率再等权平均则为(80%+20%)/2=50%。前者反映抽到一个基准实例的表现,后者给每个仓库同等权重;二者都可报告,但不能不声明单位就互换。

三、安装历史环境、应用补丁并执行F2P与P2P

输入:候选仓库及其 issue、已合并 PR、历史提交
对每个 PR:
    若没有关联 issue,或没有测试改动,则跳过
    确定修复前代码 C,分离测试 T 与参考代码修改 delta
    在匹配历史版本的环境中安装 C
    应用 T 并执行测试,记录 before
    应用 delta 后执行同一组测试,记录 after
    若环境不可用,或不存在 fail -> pass,则跳过
    保存 issue、基础提交、测试、参考修改及状态映射
输出:经执行验证的任务实例
输入:issue I、基础代码库 C、文件检索器、模型
检索并组合预算内的代码上下文
模型生成一个补丁 prediction
判题端在独立副本恢复基础版本并应用测试改动
应用 prediction;必要时按既定规则修正补丁格式
运行对应测试并解析结果
仅当所有 F2P 和 P2P 测试均存在且通过,记为解决
输出:补丁应用状态、各类测试状态、是否解决

四、用检索、oracle和可应用率拆解低修复率

先分检索输入、补丁可应用和最终Resolved,再看oracle;更强定位信息改变了任务条件,不能直接加入普通排名。

项目 原文设置及意义
主测试集 2,294 个任务、12 个 Python 仓库;不是任意语言或任意规模项目的均匀样本
任务结构 表1:平均 3,010 个非测试文件、438K 行非测试代码;参考补丁平均改 1.7 文件、3 个函数、32.8 行增删
构建筛选 表10:93,139 PR 经属性筛选剩 11,407,再经验证剩 2,294
SWE-Llama 数据 37 个不重叠仓库约 19K 训练对;移除超过 30K token 序列后约 10K 实际实例
微调预算 附录 B:注意力 Q/K/V/O 的 LoRA,r=16,α=16r=16,\alpha=16;批量 32、学习率 6×10−46\times10^{-4}、最多 4 epoch;7B 为 4 A100 上 20 小时,13B 为 8 A100 上 47 小时
检索预算 13K、27K、50K 上下文;各模型只运行可容纳的配置;tokenizer 不同,token 数并非统一字符量
解码预算 附录 D.2:每实例一个补丁、贪心解码;不是多次采样后挑选成功答案
评价与重复 统计应用率及解决率;部分 GPT-4 结果只测 574 个随机任务;未给全部系统多种子训练置信区间

训练仓库与测试仓库不重叠,降低的是这份监督微调数据的直接重叠风险。它不能证明基础模型从未见过测试仓库、issue 或后来的修复。时间切分分析是辅助证据,也无法替代未知预训练数据的完整审计。

证据一|表2、表3:检索更多不一定解决更多。 Claude 2 在 13K、27K、50K BM25 上下文中的解决率为 1.96%、1.87%、1.22%;BM25 对参考文件的平均召回率却从 29.58% 升至 44.41%、51.06%。这支持检索覆盖与上下文利用之间存在张力,不能简单地把失败都归给没找到文件。增加上下文同时引入干扰和长度变化,未单独确定二者的因果贡献。

SWE-bench不同BM25上下文长度下的仓库问题解决率
实验结果表摘引:Carlos E. Jimenez 等,2023,表2,PDF第5页;核对原文。原版权保留。

证据二|表18 与表2:定位帮助明显,但还不够。 Oracle 下 Claude 2 解决率为 4.80%,SWE-Llama 13B 为 3.97%;后者在 BM25 最佳配置为 0.70%。文件定位是重要因素,但即便获得目标文件,大多数任务仍未解决。Oracle 还可能遗漏理解调用关系所需的其他文件,因此也不是完美信息的理论上界。

证据三|表5:能应用补丁远不等于修复成功。 v3 后补的 Claude 3 Opus 在主集应用率 46.56%、解决率 3.79%;SWE-Llama 13B 为 53.62%、0.70%。这将“格式合法”和“行为正确”分开,也说明不能凭编辑器里出现了合理 diff 宣称任务完成。表5 属于更新结果,不能与摘要仍保留的初期最强 1.96% 叙述混成同一次比较。

证据四|表6 与附录 C.5:定位到行仍有能力边界。 将 Oracle 文件进一步收缩到真实修改行附近 ±15\pm15 行后,Claude 2 的解决率为 5.93%。这比完整 Oracle 的 4.80% 高,但输入含有更强的答案位置信息。附录将失败拆成部分修复、修复却破坏旧功能、无作用及回归等类型,提供比单一总分更好的诊断语言。

论文 v3 中 Claude 2 的表2 为 1.96%,表5 为 1.97%;正文还夹有更新前后的模型叙述。这里保留各表原值和实验定位,不自行解释成某个确定的四舍五入原因。复现实验应先锁定数据、模型及评测脚本版本。

五、有限测试与筛选后的Python任务不覆盖全部工程

它使检索、长上下文、编辑表示、工具交互与回归控制可以在同一任务上比较。

筛选过程同时引入偏差:流行 Python 仓库、可安装历史环境、带测试的合并 PR 更容易留下。对没有好测试的问题、架构设计、需求协商、性能优化和长期维护,覆盖有限。按实例平均也会让任务多的仓库贡献更大,不是每个仓库等权。

测试通过说明这些检查覆盖的行为满足要求,不保证代码具有最佳可维护性、完整边界行为或参考作者期待的设计。一个不同于参考补丁的解可以完全合理;相反,硬编码测试样例也可能在有限测试下侥幸通过。还应检查测试之外的语义与补丁质量。

六、让静态补丁生成变成定位、编辑和执行闭环

SWE-agent直接把这类任务改为多步定位、编辑和测试。任务判据保持时,可以研究交互预算和接口增益;本篇检索加单次补丁基线不构成所有代理的能力上限。

自测:能否读懂一个“修复率”

1. 为什么只看 F2P 通过率不够?

答案:修复当前问题可以通过删除检查、粗暴捕获异常等方式实现,却损害原本正常的行为。P2P 提供回归约束,两类测试都通过才符合基准成功定义。但它们仍只覆盖已写出的检查,不能代替完整需求验证。

2. Oracle 文件输入为何不能与普通 BM25 成绩直接排名?

答案:Oracle 使用参考补丁提供的目标文件信息,普通求解者并不知道这一点。它用于诊断“若定位更好能怎样”,而非公平模拟实际任务。同时目标文件未必包含所有相关依赖,Oracle 也不是保证可解的完整上下文。

3. 某系统解决率更高,至少还需核对哪些条件?

答案:先核对 Full、Lite 等数据划分与版本,再核对模型、候选数量、工具调用、执行时间和是否使用参考信息;同时看测试隔离、应用失败处理及训练数据污染。单次补丁生成与多轮执行搜索消耗的预算不同,不能只将两个百分数解释为基础模型能力差距。