仓库历史能提升智能体自动程序修复吗?

历史上下文对较弱模型帮助最大,三种历史启发式修复的缺陷集合互补。

直接答案

能,但提升幅度高度依赖基础模型。在 HAFixAgent 中,把由 git blame 推导出的仓库历史注入修复循环后,在完美故障定位下,最强模型 DeepSeek-V3.2-Exp 上最佳历史启发式相对无历史配置仅提升 +4.4%(Defects4J)和 +1.1%(BugsInPy),而较弱的 Qwen3-Coder-Next 上提升达到 +64.3% 和 +31.9%。

1篇文献引用

本文由 WisPaper 驱动的搜索和论文分析生成。

历史主要帮助较弱模型

论文要回答的是:在“最后修改缺陷行的提交往往就是引入缺陷的提交”这一单行缺陷场景之外,仓库历史是否、在多大程度上、以及在什么条件下能提升智能体式自动程序修复。作者构建了 HAFixAgent,把由 git blame 推导出的仓库上下文注入修复循环,并在全部 854 个 Defects4J(Java)缺陷和全部 501 个 BugsInPy(Python)缺陷上评估。

核心结果是有条件的。在完美故障定位下,最佳历史启发式相对无历史配置,在 DeepSeek-V3.2-Exp 上仅提升 4.4%(Defects4J,545 对 522 个缺陷)和 1.1%(BugsInPy,377 对 373),且两项差异都不显著(p=0.12 和 p=0.79)。在两个较小模型上,同一比较幅度大且显著:Devstral-Small-2 在 Defects4J 上提升 +51.4%、在 BugsInPy 上提升 +35.6%,Qwen3-Coder-Next 分别为 +64.3% 和 +31.9%,均满足 p<0.01。

这一分化是论文的核心实践信息:历史并非普遍增益,基础模型的基线修复率越低,历史的价值越大。

blame 上下文包含什么

历史信号来自 git blame:它为缺陷快照中的每一行标注最后一次修改该行的提交。研究先确认这类历史是否可得:对 854 个 Defects4J 和 501 个 BugsInPy 缺陷的预研显示,与缺陷相关的历史在两个基准上都广泛存在。

作者随后定义三种启发式,把选定的 blame 提交转成提示上下文。fn_all 提供该提交中被修改函数的名称,fn_pair 提供某个函数修改前后的形态,fl_diff 提供细粒度的编辑本身。缺陷还按 blame 可得性分类:可 blame 的缺陷至少有一条已存在的行,故障定位能指向它、git blame 也能标注它;不可 blame 的缺陷只插入新行或新文件,改用最近行回退策略。不可 blame 的缺陷占 Defects4J 的 28.9% 和 BugsInPy 的 12.6%,因此回退并非边缘情况。

两个基准的历史分布差异明显:Defects4J 的 blame 几乎全部集中在单个提交,而 BugsInPy 的复杂类别常涉及多个提交(SFMH 的 49.0%、MFMH 的 71.4%)。对多提交情形,智能体用 LLM 作为评判者选出最相关的一个提交。

Plausible@1 与故障定位设定

成功与否用 Plausible@1 衡量,即生成的单个补丁能编译并通过全部测试的缺陷占比,温度设为 0.0。论文还报告 #Pass(通过测试的缺陷绝对数)和 #Unique Pass(历史配置修复而对应无历史配置未修复的缺陷数)。这些是不同的量:百分比变化与唯一救回缺陷的计数不能互相替代。

默认设定是完美故障定位,即直接告诉智能体 oracle 修复所修改或删除的行。这能把历史上下文的作用与定位误差分开,但偏乐观。因此论文又在现实的基于频谱故障定位(SBFL)下重跑全部四种配置:Java 用 GZoltar、Python 用 FauxPy,采用行粒度的 Ochiai 公式,取排名前 10 的行。这种定位噪声很大:Defects4J 只有 30% 的缺陷(827 个中的 245 个)、BugsInPy 只有 30%(361 个中的 107 个)能在前 10 行中命中至少一条开发者修补过的行。

三种启发式修复不同缺陷集

对决策最有价值的发现不是某个启发式的平均增益,而是它们的互补性。在 DeepSeek 上,每种历史启发式都额外修复了无历史配置漏掉的 106 至 111 个 Defects4J 缺陷和 59 至 67 个 BugsInPy 缺陷,而无历史配置也修复了数量相当的历史配置漏掉的缺陷。在 BugsInPy 的 SFMH 上,四种配置共有 89 个缺陷,但每种历史启发式仍修复了无历史配置漏掉的 22 至 31 个。

由于每种启发式救回的是不同子集,三者取并集后修复的缺陷显著多于无历史配置。汇总全部缺陷,混合方案修复了 854 个 Defects4J 缺陷中的 684 个(80.1%),无历史为 522 个(61.1%);BugsInPy 为 501 个中的 463 个(92.4%),无历史为 373 个(74.5%)。两个基准上均满足 p<0.001,检验为 McNemar 精确检验并做 Bonferroni 校正。作者把这一互补归因于三种启发式捕捉不同信号:细粒度编辑模式、函数修改前后的语义,以及跨函数的协同演化模式。

这种互补性在切换到现实 SBFL 后依然存在,混合方案在两个基准上仍优于无历史配置。这一点很重要,说明并集结果并非理想化定位的产物。

胜过基线不等于历史的功劳

在最强模型上,HAFixAgent 也优于两种已有修复技术:最佳配置修复 545 个 Defects4J 缺陷,RepairAgent 为 348 个(+56.6%);在 BIRCH 评估的 371 个多 hunk 缺陷上,HAFixAgent 修复 175 个,BIRCH-feedback 为 119 个(+47.1%)。作者明确指出,这一差距不能当作历史的证据,因为 HAFixAgent 自己的无历史配置就已修复 522 个缺陷,比 RepairAgent 高 +50.0%(p<0.001),并修复 172 个多 hunk 缺陷,同样胜过 BIRCH-feedback。

论文把这一差距归因于框架差异:HAFixAgent 让模型通过自由形式的 bash 命令行动,而 RepairAgent 用有限状态机驱动一套固定工具。在两个较小模型上,基线保持竞争力——Qwen 上 RepairAgent 与 HAFixAgent 最佳配置相当(207 对 212,p=0.80),BIRCH-feedback 在 Qwen(60 对 54,p=0.58)和 Devstral(80 对 75,p=0.70)上都与之相当——作者将此与这些模型原生的工具调用接口联系起来。历史比较本身在固定接口内进行,因此不受这一差异干扰。

混合方案成本约为单次运行两倍

在完美和现实故障定位下,单个历史启发式在智能体步数或 token 上通常都不比无历史配置更贵。混合方案是例外:以级联方式实现,即按固定顺序运行各启发式并在首个通过测试的补丁处停止,成本约为单次运行的两倍,或单个启发式的 1.4 至 2.0 倍。作者认为考虑到性能提升,这仍然可行,并指出暴力变体也能达到同样的 684 和 463 个修复。

论文还按结果对成本分层,统计比较使用 Friedman 检验,并配合成对 Wilcoxon 符号秩检验和 Bonferroni 校正,因为同一批缺陷在不同配置下运行,且不假设分布为正态。

多余历史会稀释提示

历史并非总是有益。在 Defects4J 上,作者观察到 32 个案例,历史配置表现不如无历史配置,或漏掉了无历史配置找到的修复。例如在 MFMH 中,无历史配置达到 50,而 fn_all、fn_pair、fl_diff 分别为 47、43、48,尽管每种都贡献了 12 至 13 个无历史配置未解决的唯一修复。

论文的解释是,额外的历史片段会稀释显著上下文,这与“模型容易被无关内容干扰”“相关事实位于长提示中部或更深处时性能下降”的证据一致。这是作者的解释而非实测机制,但它指出了加入历史反而净损失的场景:不需要历史上下文的缺陷。

智能体依据提交推理而非回放

为确认增益不是记忆,作者阅读了仅由历史配置修复的 194 个 Defects4J 和 99 个 BugsInPy 缺陷的保存轨迹。在多数抽样缺陷中,智能体并不回退 blame 提交;注入的历史指向出错函数或揭示缺陷背后的早期改动,智能体自行写出修复。对 Cli_37,提交列出了统一解析器的函数,指出应编辑哪些内部实现;对 Jsoup_60,提交点出了承载该缺陷的选择器求值函数。

最清晰的例外是 fn_pair 下的 pandas_59:注入的 corr() 修改前后形态显示,早期版本在 other 为 None 时把 pairwise 设为 True,而缺陷代码丢掉了这一默认值,智能体将其恢复。由于智能体从未看到开发者的修复,这些轨迹是论文反对简单记忆的证据。

另一项检查针对指标本身:作者人工核验了 144 个通过测试补丁的分层随机样本,发现 59.7% 是正确的(95% 置信区间 52% 至 67%),并报告历史优势在按正确性评分时同样成立,而不只是在通过测试这一指标上。

历史收益值得付费的场景

研究覆盖两种语言和 34 个项目,作者指出结果未必能迁移到项目规模、测试充分性和仓库实践不同的生态;他们自己的两个基准之间历史分布就已不同。在 SWE-bench 等仓库级基准上的评估留作未来工作,且智能体只用一个循环、一套窄 bash 工具集和固定的步数、成本与时间上限。

在这一范围内,论文的优先级排序很具体。若基础模型较强,单个历史启发式收益很小,且与无历史配置在统计上无法区分,此时支持使用历史的理由在于混合方案对互补修复的并集,而非任何单一启发式的平均增益。若基础模型较弱,单个启发式在两个基准上就已带来大幅且显著的提升。混合方案约翻倍的级联成本,是为收集每种启发式唯一救回的缺陷所付的代价;当目标是最大化修复缺陷数而非最小化单缺陷成本时,论文的证据支持支付这一成本。

本文引用的文献

1

HAFixAgent:历史感知的程序修复智能体

把由 git blame 推导出的仓库历史注入智能体修复循环,对较弱基础模型的提升最大(Qwen3-Coder-Next 在 Defects4J 上 +64.3%),对最强模型提升有限(DeepSeek-V3.2-Exp 上 +4.4%);而三种历史启发式的并集修复的缺陷显著多于无历史配置。