想象一下,你是一名正在解决谜题的软件侦探。一位开发者说:“我的代码有个 Bug!”但他还没有修复它。在你帮助他修复之前,你需要证明这个 Bug 确实存在。为此,你需要编写一个特殊的“陷阱”测试——这种测试的设计初衷是:现在因为 Bug 而失败,但在 Bug 被修复后会通过。
这篇论文介绍了一个名为 EvoOtter 的新工具,它就像一个智能的进化育种程序,可以自动创建这些陷阱测试。以下是它的工作原理,我们使用简单的类比来解释:
问题:寻找正确的陷阱
编写一个因“正确原因”而失败的测试是非常困难的。这就像试图在黑暗的池塘里捕捉一种特定的鱼。如果你只是扔出上千张网(一种被称为“推理缩放”的常用方法),你可能会抓到很多鱼,但成本很高,而且你可能会抓错种类。此外,你还没有拿到“修复后的代码”,所以无法检查你的测试是否真的有效。
解决方案:一个进化的动物园
EvoOtter 将测试生成视为一场捕食者与猎物的游戏。
- 捕食者(测试): EvoOtter 从一组候选测试(捕食者)开始。
- 猎物(有 Bug 的代码变体): EvoOtter 不仅仅是对原始代码进行测试,它还创建了许多略微损坏的版本(突变体)。把这些想象成“伪 Bug”或“假靶子”,捕食者需要猎杀它们。
- 适应度评分: 如果一个测试能够成功捕捉(杀死)这些伪 Bug,那么它就被认为是“强壮的”。如果一个测试是因为正确的原因而失败,它对这些伪 Bug 的反应会与因错误原因而失败的测试有所不同。
EvoOtter 如何节省金钱和时间
该论文介绍了三个聪明的技巧,使这个过程既快速又廉价:
连续减半(“优胜劣汰”过滤器):
想象你有 8 个测试候选者。与其让它们永远测试下去,不如让 EvoOtter 进行一轮快速测试。它会立即淘汰掉表现最差的 50%(弱小的捕食者)。然后,它会增加“伪 Bug”(猎物)的数量,让下一轮变得更难。这样一来,反馈会变得更加精准,但由于你在用更少的测试去对抗更多的 Bug,总成本保持不变。
批处理交叉(“集体头脑风暴”):
通常,为了改进一个测试,你可能会要求 AI(大语言模型)一次修复一个测试。这就像要求一位厨师做完一顿饭,再做下一顿,再做下一顿。EvoOtter 则要求 AI 同时观察所有剩余的优秀测试,并说:“这是整批全新的、改进后的测试。”这节省了大量的资金,因为它只需要一次“调用”AI,而不是多次。
基于规则的突变体(“玩具士兵”):
与其要求昂贵的 AI 来创建伪 Bug(猎物),不如使用简单的、廉价的计算机规则以可预测的方式破坏代码。这让昂贵的 AI 可以全身心地投入到最困难的工作中:创建测试。
结果
论文在现实世界的软件问题上测试了 EvoOtter。
- 它发现,通过使用这种进化的“育种”方法,它能以比以往方法更便宜的价格生成高质量的陷阱测试。
- 当使用强大的 AI 模型(Claude-Opus-4.7)配合其“批处理”方法时,它在一个主要基准测试上达到了 75.3% 的成功率,在另一个基准测试上达到了 66.3%。
- 至关重要的是,它完成这项任务的成本仅为其他尝试生成数千个测试并从中挑选最佳测试的方法的一小部分。
简而言之
EvoOtter 就像一名聪明的体育教练。与其让每个队员都跑马拉松来选拔最强者(这既累又贵),教练会设置一系列训练赛,让弱者及早被淘汰。剩下的队员随后会进行一次集体辅导以共同进步。最终的结果是一支冠军队伍(一个完美的 Bug 再现测试),而且寻找这支队伍的过程既快速又省钱。
技术摘要:EvoOtter
问题陈述
缺陷重现测试(Bug Reproduction Tests, BRTs)的生成是软件工程中的关键步骤,其作用是在应用修复之前确认缺陷的存在。与旨在生成通过测试的传统测试生成不同,BRT 必须是“从失败到通过”(fail-to-pass, F2P)的:它必须在当前的错误代码(cold)上失败,但在未来的修复后代码(cnew)上通过。
BRT 生成的主要挑战在于缺乏可靠的反馈。由于在生成过程中无法获得已修复的代码(cnew),因此很难确定候选测试失败的原因是否正确,也难以从众多候选者中选出最优解。以往的方法依赖于“推理缩放”(inference scaling)——即生成大量候选者并使用大语言模型(LLMs)或执行反馈来进行选择和改进。然而,这些方法通常由于高昂的 LLM 调用次数而成本高昂,且面临反馈不可靠或测试过拟合的问题。
方法论:EvoOtter
EvoOtter 通过结合进化编程与 LLMs 来解决这些挑战,并专门针对降低成本和强化反馈信号进行了优化。该工作流运行在候选测试群体和代码变体(mutants)群体之上。
1. 核心进化循环
系统维护两个种群:
- 捕食者(Predators): 候选 BRTs。
- 猎物(Prey): 代码的缺陷变体(mutants)。
进化循环流程如下:
- 初始化: 一个基础生成器通过异构提示(varying issue descriptions and context)创建 n 个初始多样化测试(通常为 8 个)。
- 变体生成(Mutant Generation): 一个基于规则的生成器通过对疑似包含缺陷的局部核心函数应用特定的变体算子(例如:算术交换、常量替换、强制失败)来创建 m 个代码变体。此步骤不使用 LLM。
- 适应度评估: 每个测试都在当前的变体种群上进行执行。适应度得分定义为测试“杀死”的变体数量。
- 关于“杀死”定义的创新点: 由于原始代码本身已存在缺陷,测试杀死一个变体并不简单地定义为测试失败。相反,系统会分析执行日志。如果测试在变体上的失败原因与在原始代码上的失败原因不同(通过日志输出的变化来指示),则认为该变体被“杀死”了。
- 选择(逐次减半法/Successive Halving): 测试按适应度排序,较低的一半被丢弃。为了在保持强反馈信号的同时保持执行成本恒定,系统会在下一代中增加两倍数量的变体(从预生成的池中采样),同时将测试种群减半。此过程重复进行,直到只剩下一个测试。
- 交叉(批处理修复/Batched Repair): 生存下来的测试将作为父代。系统使用单次 LLM 调用来生成整个下一代后代。LLM 被提示在父代测试及其执行日志之间进行语句的交换、添加或删除,以改进它们。这种“批处理交叉”避免了每个测试进行单独 LLM 调用产生的高昂成本。
2. 成本控制机制
- 逐次减半法(Successive Halving): 每一代将测试种群减少一半,同时使变体种群翻倍,从而使每轮迭代的总测试执行次数保持恒定(2m)。
- 批处理交叉(Batched Crossover): 在单次 LLM 调用中生成一整代后代,而不是为每个候选者进行一次调用。
- 基于规则的变体(Rule-Based Mutants): 使用确定性的代码重写规则生成变体而非使用 LLM,从而将 LLM 严格限制在测试生成和进化阶段。
- 单提示模式选项(Single-Prompting Option): 虽然默认使用异构提示来保证初始多样性,但系统也支持“单提示”模式,即通过一次 LLM 调用生成所有初始候选者。这显著降低了成本,并允许使用更强大(但也更昂贵)的推理模型,如 Claude-Opus-4.7。
核心贡献
- EvoOtter 工作流: 首个基于进化编程的 BRT 生成工作流,集成了变体测试(mutation testing)和逐次减半法。
- 基于变体的适应度评分: 一种新型适应度指标,通过计算测试杀死的基于规则的代码变体的数量,利用日志差异来处理“原始代码已存在缺陷”的情景。
- 批处理交叉: 一种利用现代 LLM 能力的技术,通过单次调用进化整代测试,平衡了性能与成本。
实验结果
作者在三个基准测试上评估了 EvoOtter:TDD-Bench-Verified、SWE-Rebench 和 SWT-Bench-Verified。
- 性能: 使用带有异构提示的 Claude-Sonnet-4.5,EvoOtter 在 TDD-Bench-Verified 上实现了 65.9% 的 F2P 率,在 SWE-Rebench 上实现了 51.9% 的 F2P 率,超越了以往仅依赖选择或修复(如 e-Otter)的基准方法。
- 达到 SOTA: 通过使用更强的推理模型 Claude-Opus-4.7 进行单提示,EvoOtter 在 TDD-Bench-Verified 上达到了 75.3%,在 SWE-Rebench 上达到了 66.3%。在 SWT-Bench-Verified 排行榜上,它达到了 77.8%。
- 成本效率: EvoOtter 以以往推理缩放方法的极小部分成本实现了这些结果。标准工作流的平均单实例成本约为 0.17∗∗(不包括初始生成),高性能单提示变体约为∗∗0.88,相比之下,需要单独修复循环的方法成本要高得多。
- 组件分析:
- 选择(Selection): 在进化后期,基于变体的选择优于基于 LLM 和随机的选择,尽管 LLM 在初始阶段表现良好。
- 交叉(Crossover): 移除交叉操作会导致超过 10% 的性能下降,凸显了其关键作用。
- 多样性(Diversity): 单提示虽然略微降低了多样性,但并未阻止进化算子有效地选择和改进测试。
重要性与主张
论文声称,EvoOtter 展示了如何高效且有效地将进化编程与 LLMs 结合用于软件工程任务。其主要意义在于:
- 鲁棒性: 通过变体测试而非仅仅依赖于可能存在噪声的 LLM 判断或仅在错误代码上执行,提供了更可靠的反馈信号。
- 效率: 通过批处理操作和逐次减半法最大限度地减少 LLM 调用,大幅降低了 BRT 生成的成本,使其具有可扩展性。
- 实用性: 在保持低推理成本的同时,在经过验证的基准测试上达到了最先进的结果,表明进化策略可以作为复杂软件工程任务中纯推理缩放方法的有效替代方案。
作者指出,其研究结果目前仅限于 Python 仓库,且设计选择(如单提示模式)是针对近期前沿模型的能力而定制的。
每周获取最佳 machine learning 论文。
受到斯坦福、剑桥和法国科学院研究人员的信赖。
请查收邮箱确认订阅。
出了点问题,再试一次?
无垃圾邮件,随时退订。