利用动态上下文和静态分析进行基于代理的自动化程序修复

时间:2026年5月18日
来源:IEEE Access

编辑推荐:

摘要:自动化程序修复(APR)旨在降低软件维护成本并提高软件可靠性。尽管大型语言模型(LLMs)的最新进展在代码生成任务上取得了可衡量的改进,但将其应用于程序修复仍面临特定挑战,包括有限的上下文意识、重复的补丁生成以及无法从失败的修复尝试中学习。在本文中,我们提出了一种基于代理的

广告
   X   

摘要:自动化程序修复(APR)旨在降低软件维护成本并提高软件可靠性。尽管大型语言模型(LLMs)的最新进展在代码生成任务上取得了可衡量的改进,但将其应用于程序修复仍面临特定挑战,包括有限的上下文意识、重复的补丁生成以及无法从失败的修复尝试中学习。在本文中,我们提出了一种基于代理的自动化程序修复方法,该方法通过动态上下文管理来协调专门的LLM代理,以迭代地细化和生成补丁。我们的方法引入了一种基于代理的架构,包括上下文更新器、生成器和过拟合检测器,这些组件与一套全面的静态分析工具一起工作,以收集相关的修复上下文、生成多样化的补丁、从失败尝试中学习,并防止过拟合的解决方案。该架构使用由嵌入模型驱动的向量数据库进行语义代码搜索,维护一个上下文池(静态和动态模块)以进行上下文管理,并实现智能假设跟踪以避免冗余修复。我们在Defects4J和SWE-Bench Lite上评估了我们的方法,使用了多种LLM后端,在完美和自动故障定位设置下进行了测试。我们的方法分别在Defects4J和SWE-Bench Lite上正确修复了多达365个和87个错误,能够在不同模型之间泛化,开源模型实现了高达252个正确的修复,并在自动故障定位下保持了69.7%的完美FL性能。该方法在处理复杂的多功能错误时特别有效,在Defects4J上修复了多达53个错误,在SWE-Bench Lite上修复了10个错误。CCBY - IEEE不是该材料的版权所有者。请通过https://creativecommons.org/licenses/by/4.0/遵循说明以获取全文文章和API文档中的规定。

第一节 引言
现代软件系统的复杂性不断增加,加上软件开发速度的加快,对自动化错误检测和修复方法的需求也在增加[1]。自动化程序修复(APR)作为一种有前景的解决方案应运而生,旨在无需人工干预即可自动生成修复软件缺陷的补丁[2]。大型语言模型(LLMs)的最新出现显著推动了自动化程序修复的技术进步。像Codex [3]、CodeT5 [4]和GPT-4 [5]这样的模型展示了出色的代码理解和生成能力,激发了新一代APR方法的发展。最近的基于LLM的系统探索了各种策略,如迭代细化、对话式交互和基于推理的修复,显示出提高修复准确性和效率的潜力。尽管取得了这些进展,当前的基于LLM的APR方法仍面临三个根本性限制。首先,它们通常使用静态上下文表示,无法根据修复反馈进行适应,从而错过了通过失败尝试来细化理解的机会[6]、[7]。其次,它们经常生成看似合理但过拟合的补丁,这些补丁虽然通过了可用测试,但没有解决根本缺陷,因为缺乏验证语义正确性的机制。第三,它们难以有效整合多样化的信息来源,主要依赖于局部代码上下文,而忽略了复杂修复所需的更广泛的程序语义[8]、[9]、[10]、[11]、[12]。在本文中,我们提出了一种基于代理的自动化程序修复方法,通过一种具有动态上下文管理的简化代理架构来解决这些限制。我们的关键见解是,有效的程序修复不仅需要强大的生成能力,还需要智能的信息收集、假设形成和迭代细化过程的协调。通过将修复任务分解为通过综合上下文池协作的专门代理,我们的方法在保持可解释性和可控性的同时实现了卓越的修复性能。至关重要的是,我们评估了这些架构贡献是否可以在不同的LLM后端和故障定位设置中泛化,而不仅仅局限于单一的专有模型。

总结来说,我们方法的贡献如下:(1) 基于代理的修复架构,包含三个专门代理(上下文更新器、生成器和过拟合检测器),它们通过共享的上下文池进行协作。(2) 动态上下文池结合了静态信息(有错误的方法、失败的测试、错误报告)和在迭代过程中积累的动态信息,以维护全面的修复历史。(3) 集成的静态分析工具套件,包括六个互补的工具,通过命令验证器和工具执行器统一起来。(4) 组件级修复,根据执行覆盖率将相关的有错误的方法和失败的测试分组,实现迭代的多功能错误修复。(5) 在完美和自动故障定位设置下,跨两个基准测试和三个LLM后端的跨模型和跨基准测试评估。

上下文更新器根据每种失败类型检索程序分析,生成器从积累的上下文中生成多样化的补丁假设,过拟合检测器通过结构化的诊断反馈来改进看似合理但不正确的补丁。上下文池维护工具输出、尝试的假设、提取历史和已修复的组件记录以及静态错误信息。这些工具通过统一的执行层处理命令解析、标识符解析和输出格式化。这种映射使得每个组件都可以独立跟踪假设和检索上下文,使修复流程能够针对每个有错误的方法及其直接相关的失败测试进行处理。评估涵盖了GPT-4o、QwenCoder-32B和CodeLlama-34B,在完美和自动故障定位设置下进行。

我们在Defects4J [13]和SWE-Bench Lite [14]基准测试上进行了全面实验,与最近的基于LLM的方法进行了比较。实验结果表明,我们的架构使用GPT-4o成功修复了Defects4J上的365个错误(包括53个多功能错误)和SWE-Bench Lite上的87个错误,开源模型也取得了有竞争力的结果,验证了我们架构贡献的模型无关性。在实际的自动故障定位(使用GZoltar [15]和Ochiai [16]排名指标)下,我们的方法从350个错误中正确修复了152个错误,保持了69.7%的完美FL性能。我们的评估包括对所有三个模型的详细消融分析、迭代级分析和实际故障定位实验。

本文的其余部分组织如下:第二节回顾相关工作。第三节介绍我们的基于代理的修复方法。第四节描述实验结果。第五节进行讨论,第六节提出有效性威胁。第七节总结并概述未来方向。

第二节 相关工作
将LLMs集成到自动化程序修复中,使范式从基于模板和搜索的方法转向了神经补丁合成。早期研究表明,像GPT-3 [17]和Codex [3]这样的现成LLMs可以在不需要特定于APR的微调的情况下生成合理的补丁。实证评估表明,尽管这些模型没有经过明确训练,但它们可以在基准数据集上定位和修复错误,其性能与传统APR技术相当,AlphaCode在大规模代码合成方面展示了互补的优势[18]。在这些基础上,最近的基于LLM的APR系统探索了多种上下文利用和修复协调策略。SRepair [19]采用双LLM流程,首先生成自然语言的修复建议,然后合成函数级补丁。ITER [20]通过编译和测试驱动的验证迭代细化部分补丁,实现多位置修复。RepairAgent [21]将单个LLM视为一个自治代理,通过有限状态机调用工具。ContrastRepair [22]通过对比测试用例对增强对话式修复。ChatRepair [23]将修复视为交互式对话,重用轮次间的对话历史。ThinkRepair [24]在代码生成之前使用思维链提示来激发调试推理。D4C [25]通过定制的提示和补丁选择策略来对齐修复目标。RAP-Gen [26]结合了检索增强生成和神经补丁生成,证明有针对性地检索类似的修复示例可以显著提高修复准确性,主要针对单功能错误。

为了澄清我们的架构贡献与现有的基于代理和上下文感知的APR系统的区别,表1总结了我们在比较中使用的六个架构维度。如表1所示,虽然现有方法包含了我们架构的个别元素,但没有一个系统根据我们的比较标准结合了所有六个维度。RepairAgent通过有限状态机(FSM)控制器引入了自治工具使用,但依赖于没有专门用于上下文管理或过拟合检测的单一代理架构。ITER引入了带有测试反馈的迭代细化,但其上下文表示仅限于演变的补丁树,并且没有维护一个单独的动态上下文池来整合外部分析结果或跨迭代的失败模式。SRepair探索了通过建议和生成阶段的双LLM协作,但缺乏迭代细化和跨修复尝试的动态上下文管理。我们工作的新颖之处在于三个先前系统中缺失的机制:(1) 基于反馈的上下文演化,其中上下文更新器的工具选择取决于前一次补丁尝试的具体失败类型;(2) 循环内的过拟合检测器,它通过结构化的诊断反馈将看似合理但不正确的补丁转换为正确的修复,而不是直接丢弃它们;(3) 覆盖率引导的组件分解,将系统的范围扩展到大多数先前系统无法处理的多功能错误[8]、[9]、[10]、[11]、[12]。结合其余的架构维度,即专门的代理角色、集成的工具套件和多模型评估,这些机制形成了一个统一的、模型无关的流程,旨在解决其他方法无法解决的故障。

表1 与相关基于LLM的APR系统的特征比较。

第三节 方法论
A. 架构概述
我们的基于代理的自动化程序修复方法提出了一个基于组件的架构,分为两个主要阶段:(1) 预处理和定位,以及(2) 迭代修复流程(图1)。预处理阶段从标准化基准测试中获取有错误的项目,执行故障定位以识别有错误的方法,并使用LLM嵌入在向量数据库中对所有无错误的方法进行索引,以便进行语义相似性搜索。故障定位和映射组件创建了连接有错误的方法(BMs)及其相关失败测试(FTs)的组,为迭代流程确定修复目标。

图1. 总体架构。SA:静态分析,CU:上下文更新器,G:生成器,OD:过拟合检测器。

迭代流程协调三个专门代理(上下文更新器、生成器和过拟合检测器),它们通过共享的上下文池进行协作,该池维护静态上下文(有错误的方法、失败的测试、错误消息、错误报告)和在迭代过程中积累的动态上下文(工具输出、尝试的假设、结果和之前修复的组件)。上下文更新器通过命令验证器和工具执行器从SA工具套件和向量数据库中检索相关的程序分析。生成器从积累的上下文中生成补丁假设,这些假设随后针对测试套件进行验证。通过的补丁由过拟合检测器进行评估,结果由假设更新器传播回动态上下文,直到找到有效的补丁或满足终止条件。

B. 预处理和定位阶段
预处理阶段将原始错误数据转换为适合修复流程的结构化表示,同时建立用于上下文检索的语义搜索基础设施。
1) 向量数据库构建
我们构建了一个包含正在修复的软件代码库中所有无错误方法的向量数据库,不包含外部项目,以便在修复过程中进行语义相似性搜索。每种方法都使用LLM嵌入模型进行编码,并为高效的k最近邻搜索进行索引。对于超出令牌限制的方法,采用分块策略将它们分割成段,并计算所有段对之间的余弦相似度。
无错误方法集的组成取决于故障定位设置。在完美FL下,所有未被识别为有错误的方法都会被索引。在自动FL下,排除排名前K的疑似方法,所有剩余的方法都被假设为无错误。检索到的方法作为正确代码行为的上下文示例,指导修复过程。
2) 故障定位和自动映射
系统使用故障定位技术来识别有错误的方法。我们的架构与任何故障定位方法兼容:在我们的实验中,我们在完美故障定位(评估纯修复能力)和使用GZoltar [15]与Ochiai [16]的自动故障定位(评估实际适用性)下进行了评估。使用自动FL时,排名前K的疑似方法作为候选的有错误位置,相同的映射算法用于从这些候选者中构建修复组件。
在分析了包含实际世界软件错误的基准数据集中的错误后,我们意识到许多多功能错误可以通过将它们分解成更小的部分来修复。具体来说,许多有错误的方法与某些失败的测试用例有直接关系。此外,一些有错误的方法没有任何相关的失败测试用例。我们定义这些关系如下:当执行覆盖仪器确认FT在其测试运行期间执行BM时,存在有错误的方法BM和失败测试FT之间的直接关系。当两个有错误的方法至少共享一个共同的失败测试时,它们之间存在间接关系,将它们放在同一个连接的组件中。我们执行所有带有覆盖仪器的失败测试,以确定哪些测试实际执行了哪些有错误的方法。这创建了BM(有缺陷的方法)和FT(失败的测试用例)之间的映射关系,形成了相互连接的组件,每个组件代表一个连贯的修复目标。图2展示了一个示例,其中包含三个有缺陷的Java方法和两个带有错误信息的失败测试用例。映射过程确定BM#1与FT#2相关,BM#2与FT#1相关,而BM#3没有相关的失败测试用例。这样就产生了两个组件:GR#1(BM#1, FT#2)和GR#2(BM#2, FT#1),以及单独的BM#3。图2. 映射过程示例。BM(有缺陷的方法),FT(失败的测试用例)。

C. 上下文池架构
上下文池作为中央信息存储库,协调代理活动并在迭代过程中维护修复状态。它实现了两部分结构,分离了静态上下文和动态上下文模块,如图1所示。静态上下文存储关于缺陷和原始程序状态的不可变信息,这些信息在整个修复过程中保持不变。它包括有缺陷的方法源代码、带有错误信息的失败测试用例,以及可用的问题描述或缺陷报告。动态上下文在修复过程中通过静态分析工具的执行积累信息,并使用基于最近性的评分来防止无限制的增长。它维护三个结构:工具执行输出和提取历史(来自六个静态分析工具的结果,以防止重复调用);尝试的假设(用于检测重复和失败模式挖掘的结构化补丁假设记录);以及之前已修复组件的信息(用于指导多功能缺陷中剩余方法的修复)。

D. 静态分析工具套件执行
1) 静态分析工具套件
我们的架构集成了一个全面的静态分析工具套件,包含六个互补的组件,提供多视角的程序理解。该套件通过命令验证器和工具执行器进行操作,确保通过解析代理请求、解决标识符歧义、优雅地处理错误以及格式化结果以供代理使用来可靠执行。该工具套件提供多种粒度和视角的信息:覆盖运行器(τ1)执行路径跟踪以识别方法和语句覆盖情况,从而实现测试方法关系分析;语义搜索(τ2)使用向量数据库相似性检索相似的代码示例,提供修复的实现模式;代码提取器(τ3)在方法、类和文件级别访问源代码,提供关于程序结构的上下文信息;调用图构建器(τ4)通过AST遍历构建依赖关系,映射调用者-被调用者交互;数据流分析器(τ5)跟踪字段访问模式,包括读取、写入和修改,以理解状态变化;API使用挖掘器(τ6)通过分析代码库中的使用情况发现常见的API调用模式。这些工具协同工作,支持上下文更新器代理的自适应信息检索。这些工具不是独立运行的,而是提供互补的视角、执行行为(τ1)、语义相似性(τ2)、结构上下文(τ3, τ4)、数据依赖性(τ5)和使用习惯(τ6),共同实现全面的程序理解。上下文更新器根据修复状态和从之前的尝试中识别出的信息差距动态选择和排序工具调用。

命令验证器和工具执行器组件桥接了代理生成的命令和工具执行之间的差距。它处理命令解析、标识符解析、错误处理和输出格式化,确保即使在代理生成的命令中存在歧义也能可靠执行。

E. 基于代理的修复
我们的修复流程通过算法1中形式化的交互协议协调三个专门的代理(上下文更新器、生成器和过拟合检测器)。图3展示了这三个代理的整合提示架构。三个设计决策塑造了这一协议。首先,第1次迭代绕过上下文更新器(第3行):生成器直接在静态上下文中操作,避免对简单缺陷进行不必要的工具调用。从第2次迭代开始,上下文更新器分析失败的尝试并调用静态分析工具来填补识别出的信息差距。其次,过拟合检测器仅在测试通过的补丁上激活(第10行),作为质量门而不是通用过滤器。第三,细化循环(第13-14行)以过拟合分析作为额外上下文重新调用生成器,使OD能够增加正确补丁的数量,而不仅仅是过滤它们。如果OD没有检测到过拟合,则该补丁被视为有效的修复,迭代就此终止。

算法1. 迭代修复流程
要求:
组件C,上下文池CP
确保:
正确补丁或失败
1: CP.static ← {有缺陷的方法、失败的测试、错误、缺陷报告
2: for i=1 to MAX ITER
do
3: if i>1 then
4: (cmds, updates) ← ContextUpdater (CP)
5: CP.dynamic ← Execute (cmds) + Apply (updates)
6: end if
7: patches[] ← Generator (CP, N)
8: for each patch p in patches do
9: if PassesAllTests(p) then
10: verdict ← Overfitting Detector (p)
11: if ¬ verdict.overfitting then
12: return p
13: else if verdict.can_improvethen
14: p′ ← Generator (CP + verdict.analysis)
15: if PassesAllTests (p′ ) then
16: return p′
17: end if
18: end if
19: end if
20: CP.dynamic.hypotheses ← RECORD (p , test_result)
21: end for
22: end for
23: return Failure

图3. 代理的提示模板:(a) 上下文更新器,(b) 生成器,(c) 过拟合检测器和细化。

表2总结了每个代理在此协议中的角色。上下文更新器根据失败模式做出有针对性的检索决策,例如,在空引用失败后调用数据流分析器(τ5),或在类型不匹配错误后调用调用图构建器(τ4)。它还通过移除低相关性项来管理上下文池的大小,以防止迭代过程中的上下文稀释。生成器每次调用产生n个候选补丁,每个补丁即使在失败时也记录在动态上下文中有一个明确的自然语言假设。相同的架构处理标准生成和OD触发的细化,通过不同的上下文组合。过拟合检测器检查五种模式:(1) 测试特定的条件语句,(2) 与测试期望匹配的硬编码值,(3) 仅修复症状,(4) 缺失的边缘情况,(5) 潜在的回归。这五种模式是从先前APR文献中报告的LLM生成的补丁中的常见过拟合行为分析中得出的。如果OD检测到过拟合并判断可以改进,则不会简单地丢弃补丁,而是将过拟合分析作为额外上下文重新调用生成器(细化循环)。这保留了测试通过的补丁中包含的有用部分推理,而不是完全丢弃它。图3(c)中显示的双提示结构实现了这种分离:检测提示诊断根本原因是否得到解决以及修复是否依赖于硬编码或测试特定的模式,产生结构化的判断;然后细化提示使用该判断来指导有针对性的代码修正。这种诊断和修正之间的分离使OD能够作为积极的修复参与者,而不仅仅是被动过滤器。

F. 假设更新器
假设更新器组件管理假设池,防止冗余探索并允许从失败中学习。首先,在将新假设添加到池中之前,重复检测机制会检查是否已经存在等效的假设,通过变化的相似性来避免冗余;与现有条目具有相同修改行和修复策略的假设被丢弃,以避免过早丢弃潜在有效的修复方向。其次,模式分析模块识别失败假设中的重复模式,包括常见的错误类型(例如,空引用错误、类型不匹配)、相似的更改位置和重复的修复策略,通过对标准化补丁进行序列挖掘并按语义相似性在连续迭代中聚类。当这些重复的失败模式持续存在时,该模块向上下文更新器发出信号,表明当前信息对于相应的错误类别来说是不够的,提示进行更深入的分析,而不是尝试类似的修复策略。第三,历史优化通过选择性保留来维护池的大小,根据以下标准对每个假设进行评分:(1) 来自测试结果的信息增益,(2) 与现有假设的独特性,(3) 与成功修复的接近程度,以及(4) 错误类别的覆盖范围。此外,假设池还维护了之前已修复组件的明确记录;在修复多功能缺陷时,这些记录作为额外上下文提供给上下文更新器和生成器,使它们能够利用已修复组件的成功修复策略来处理剩余未解决的组件。

G. 补丁验证和终止
补丁验证组件应用生成的假设并通过结构化测试进行评估。每个假设都应用于代码库,编译后针对测试套件进行评估,每次尝试后恢复原始状态。成功编译的补丁会进行分阶段的测试执行:首先运行最初失败的测试以快速验证,如果失败测试通过,则进行完整的测试套件以检测回归,整个过程中应用超时机制并收集详细的执行指标。迭代控制器在多个终止标准下管理修复循环:(1) 成功,即补丁通过了所有失败的测试且没有回归;(2) 迭代限制,即达到最大迭代次数;(3) 组件完成,即所有组件都已被处理;(4) 资源限制,即时间或令牌预算被超出;(5) 收敛,即在过去两次迭代中没有生成新的独特假设。

评估标准。我们在评估中报告了两个指标。如果补丁通过了所有最初失败的测试并且没有在完整的测试套件中引起回归失败,则认为该补丁是合理的。如果补丁在语义上等同于开发者编写的补丁,并且通过两位作者的手动检查得到验证,则认为该补丁是正确的;如果有分歧,则通过与第三位作者的讨论来解决。我们在适当的情况下报告合理的和正确的补丁数量。

IV. 实验
A. 设置
1) 基准测试
我们在两个数据集上进行评估:(1) Defects4J v1.2和v2.0 [13],包含来自17个开源项目的835个真实世界的Java缺陷,每个项目都有有缺陷/已修复的版本、触发测试和完整的测试套件;(2) SWE-Bench Lite [14],包含来自12个项目的300个Python仓库问题:astropy、django、matplotlib、seaborn、flask、requests、xarray、pylint、pytest、scikit-learn、sphinx和sympy [27]。这种跨语言评估评估了超出Java领域的架构泛化能力。
2) 基线
我们将我们的架构与最近的基于LLM的APR系统进行比较:SRepair [19]、ITER [20]、ChatRepair [23]、ThinkRepair [24] 和 D4C [25]。这些基线代表了最先进的迭代式、对话式和基于推理的神经修复方法。表3总结了每个基线的已知实验设置,以便读者能够评估可比性。我们与这些系统发布的报告结果进行比较,这是APR研究中的标准做法 [19]、[20]、[23]、[24]、[25]。虽然直接重新实现所有基线是不可行的,但我们通过两种方式确保比较的公平性。首先,我们在不同的LLM后端上评估我们的架构,而不是依赖于单一模型,确保改进可以归因于架构设计而不仅仅是模型本身的强度。其次,消融研究提供了完全受控的内部比较,其中LLM、故障定位、硬件和超参数保持不变,隔离每个组件的贡献;基础LLM配置(不包含OD和CU)作为内部基线,直接衡量每个架构组件相对于单独模型的增益。

表3 基线实验设置比较。

3) 实现细节
我们的系统支持多个LLM后端来评估架构泛化能力。对于GPT-4o(闭源):所有代理都使用OpenAI API,并设置不同的温度,上下文更新器和过拟合检测器的温度设置为0.2以确保确定性分析,而生成器的温度设置为1.0以产生多样化的补丁候选。对于QwenCoder-32B和CodeLlama-34B(开源):模型在两个NVIDIA RTX A6000 GPU上本地部署,使用vLLM [28],温度设置相同(CU/OD为0.2,生成器为0.7),并且提示模板相同,以确保公平比较。所有其他超参数在模型之间保持不变。生成器每次迭代产生10个候选补丁。每个代理使用max_tokens = 8000和指数退避重试逻辑。对于语义检索,我们使用CodeBERT-base(768维)嵌入和FAISS以及余弦相似性搜索构建向量数据库。静态分析为Java(Defects4J)和Python(SWE-Bench Lite)集成覆盖度仪器,以实现准确的BM–FT映射和动态上下文更新。对于Java代码分析,我们使用JavaParser 3.24.0进行AST构建和转换,而Python缺陷依赖于内置的AST检查和我们的自定义依赖分析器来进行调用图和数据流恢复。

故障定位:我们在两种FL设置下进行评估。(1) 完美FL:遵循标准实践 [19]、[20]、[24]、[25],直接提供有缺陷的方法位置,将修复能力与FL准确性分开。所有基线比较都使用此设置。(2) 自动FL:我们使用预计算的GZoltar [15]和Ochiai [16]的怀疑度分数在Defects4J上选择前K(K=10)个可疑方法作为候选的有缺陷位置,评估实际适用性。

4) 实验配置
每个缺陷最多接受5次修复迭代,每次迭代有3600秒的超时时间。实验在Ubuntu 20.04 LTS上进行,使用了Intel Xeon Gold 6248R(48核)处理器、512GB内存以及双NVIDIA RTX A6000显卡,用于模型生成和开源模型推理。为了评估非确定性大语言模型(LLM)输出的稳定性,我们在Defects4J上使用了两种开源模型进行了三次独立运行;对于闭源模型,我们仅报告单次运行的结果。实验的源代码和结果可以在以下链接找到:https://github.com/soft7197/dcsa4apr

**B. 研究问题**

我们的评估围绕五个研究问题展开:

- **RQ1(整体有效性)**:与现有的基于LLM的自动修复(APR)技术相比,我们的架构在不同LLM后端上在正确修复错误方面表现如何?
- **RQ2(迭代优化)**:带有动态上下文更新的迭代修复过程如何有助于成功修复错误?这种模式是否适用于不同的模型?
- **RQ3(多函数错误处理)**:我们的组件级修复策略在处理需要跨多个函数修改的错误时效果如何?
- **RQ4(消融研究)**:每个架构组件对整体性能的贡献如何?这些贡献是否可以在不同模型家族中泛化?
- **RQ5(实际故障定位)**:使用GZoltar+Ochiai在现实故障定位条件下的表现如何?

**C. 结果**

1. **整体有效性(RQ1)**

表4展示了在Defects4J v1.2和v2.0基准测试中,我们的修复性能与三种LLM后端以及基线系统的对比。我们报告了通过手动检查验证的正确修复错误数量。对于开源模型,我们报告了三次独立运行的平均值和标准差;每个项目的具体数据使用了最佳的单次运行结果。

- **GPT-4o**:我们的方法总共正确修复了365个错误(v1.2上187个,v2.0上178个),相比之前的最佳系统SRepair(v1.2上332个错误,v2.0上167个错误),整体提升了9.9%。与ThinkRepair(205个错误)、D4C(180个错误)和ChatRepair(162个错误)相比,分别提升了78.0%、102.8%和125.3%。
- **QwenCoder-32B**:在三次独立运行中,平均正确修复了250.3±2.1个错误(最佳运行中修复了252个错误),CodeLlama-34B平均修复了104.0±3.6个错误(最佳运行中修复了108个错误)。值得注意的是,QwenCoder-32B的表现超过了D4C(180个错误)、ThinkRepair(205个错误)和ChatRepair(162个错误),表明我们的架构使开源模型能够在不依赖API的情况下达到竞争性的性能水平。
- **开源模型**:QwenCoder-32B平均修复了250.3±2.1个错误,CodeLlama-34B平均修复了104.0±3.6个错误。QwenCoder-32B在三次运行中平均修复了250.3个错误,而CodeLlama-34B在最佳单次运行中修复了108个错误。

表4还显示了每个模型的正确修复错误数量。

2. **动态上下文通过迭代的有效性(RQ2)**

表7展示了在Defects4J上,我们的方法在第一次迭代中使用仅带有静态上下文的生成器代理生成了435个合理的补丁,并正确修复了343个错误(94.0%),这表明结构良好的初始信息足以完成大多数修复。后续迭代通过上下文更新器代理引入动态上下文,分别在第二次到第五次迭代中额外修复了16个、4个、2个和0个错误,总计22个错误(6.0%),这些错误需要迭代上下文增强。

3. **多函数错误性能(RQ3)**

图5展示了我们的方法在所有三种LLM后端和两个基线上处理多函数错误的表现。多函数错误历来是自动修复系统面临的挑战,因为它们需要跨多个程序位置进行协调修改。

- **GPT-4o**:正确修复了53个多函数错误,其中42个需要修改两个方法,6个需要修改三个方法,3个需要修改四个方法,2个需要修改六个或十个方法。我们的方法在多函数修复方面显著优于两个基线。
- **开源模型**:QwenCoder-32B正确修复了33个多函数错误,CodeLlama-34B正确修复了11个多函数错误。多函数修复率在所有模型中保持一致,分别为GPT-4o的14.5%、QwenCoder-32B的13.1%和CodeLlama-34B的10.2%。

4. **消融研究(RQ4)**

表8通过系统性的消融分析量化了各个组件对Defects4J的贡献。这种跨模型分析直接证明了我们的架构贡献具有普遍性。

5. **SWE-Bench Lite评估**

- **在SWE-Bench Lite上**,我们的方法使用GPT-4o正确修复了87个Python错误(成功率为29.0%),涉及10个仓库:django(36/114,31.6%)、scikit-learn(10/23,43.5%)、pytest(6/17,35.3%)、astropy(3/6,50%)、matplotlib(4/23,17.4%)、sphinx(4/16,25%)、sympy(20/77,26%)、pylint(2/6,33.3%)、seaborn(1/4,25%)和xarray(1/5,20%)。Flask(0/3)和requests(0/6)没有成功修复任何错误。我们的评估使用了完美的故障定位。

**结论**

我们的架构在不同LLM后端上表现出一致的性能提升,这验证了我们的贡献与模型无关。整个系统相对于基础LLM配置的增益范围从10.6%(GPT-4o)到23.0%(CodeLlama-34B),较弱的模型从架构支持中获益更多。

这些结果表明,高质量的初始上下文应该能够解决大多数错误,而迭代优化则用于处理真正复杂的案例。我们的方法在第一次迭代中集中生成合理补丁,这一策略得益于全面的静态上下文构建。首先,过拟合(OD)的触发率与模型的能力成反比:GPT-4o为46.1%,QwenCoder-32B为62.7%,CodeLlama-34B为79.8%,这表明CodeLlama-34B和QwenCoder-32B的过拟合案例被标记为OD的频率高于GPT-4o,因此更频繁地触发OD,这与自校准的安全机制一致。其次,OD不会降低正确补丁的质量:在所有运行中,没有在已经正确的补丁上触发OD的情况导致过拟合结果(所有模型的错误率为0.0%)。第三,过拟合补丁触发后的转换率为GPT-4o为20.0%(15/75),QwenCoder-32B为35.2%(32/91),CodeLlama-34B为6.2%(8/129)。虽然并非所有触发事件都会导致成功的修复,但这些转换对应于如果没有OD干预将无法修复的错误。在已经正确的补丁上触发OD(分别为146、133和68个案例)会进行额外的修复,但不会改变结果,但能够实现真正的改进(分别为15、32和8个错误)。总体而言,OD提供了持续的安全性(零退化)并贡献了额外的正确修复,尽管其有效性取决于模型利用修复的能力。CodeLlama-34B的低转换率(6.2%)反映了模型能力的上限:较弱的模型可能产生不可靠的过拟合诊断,并且即使提供结构化的修复指导也无法产生改进的补丁,这表明OD的有效性受到模型在检测和修复步骤上的能力的限制。

表9 过拟合检测器:触发和结果分解(每个开源模型的最佳运行)

5) 实用故障定位(RQ5)
为了评估超出完美故障定位的实际适用性,我们使用GZoltar和Ochiai相似性系数进行了实验,这是一种广泛使用的基于谱的故障定位技术。我们没有假设对错误位置有完美的了解,而是采用了一个现实的场景,即FL工具对每个错误排名出最可疑的方法。对于每个错误,我们提取了该技术排名前10的最可疑方法。我们从Defects4J数据集中提取了满足此标准的350个错误。由于我们对单个错误使用了多个错误方法候选者,我们稍微修改了修复提示,要求LLM在候选者中识别并修复错误方法,而不是假设已知的错误位置。在相同的350个错误子集上进行完美FL时,我们的方法生成了278个合理的补丁,并实现了218个正确的修复(正确率为78.4%)(表10)。使用自动化FL(GZoltar前10名),我们生成了232个合理的补丁和152个正确的修复(正确率为65.5%)。这代表了83.5%的合理补丁保留率(232/278)和69.7%的正确修复保留率(152/218)。

表10 实用故障定位性能

6) 重运行稳定性
为了评估非确定性LLM输出的稳定性,表11报告了在Defects4J上进行的三次独立运行中开源模型的每次运行结果。QwenCoder-32B的错误修复数量变化非常小,分别为252、251和248(平均250.3,标准差2.08,变异系数0.83%)。CodeLlama-34B的变化略高但仍可接受:分别为108、101和103(平均104.0,σ=3.61,CV=3.47%)。较小的标准差证实了模型和配置之间的性能差异是有意义的,而不是随机变化的产物。

表11 在Defects4J上进行的三次独立运行中的重运行稳定性

对于QwenCoder-32B,在三次运行中至少修复了一次的所有316个独特错误中,有189个(59.8%)在三次运行中都被修复,57个在两次运行中被修复(任意一次运行1、运行2和运行3的组合),70个仅在一次运行中被修复。对于CodeLlama-34B,在至少修复了一次的所有168个独特错误中,有46个(27.4%)在三次运行中都被修复,52个在两次运行中被修复,70个仅在一次运行中被修复。QwenCoder的更高每次运行重叠率反映了其更大的稳定性,而CodeLlama的较低重叠率表明较弱的模型表现出更多的随机修复行为。在所有运行中,QwenCoder发现了316个独特的正确错误(比最佳单次运行多出25.4%),CodeLlama发现了168个(多出55.6%),这表明多运行策略可以进一步提高修复能力。对于GPT-4o,我们报告了单次运行的结果。由于专有API的非确定性,无法保证完全复制,但我们固定的温度参数和一致的配置最小化了运行间的差异。消融结果和跨模型一致性模式为我们的发现提供了额外的信心。

第五节 讨论
高的一次性成功率(GPT-4o为94.0%,QwenCoder为95.2%,CodeLlama为85.2%)表明,适当构建的初始上下文本身就捕获了大多数修复所需的信息。需要多次迭代的剩余错误涉及微妙的语义违规或仅通过失败尝试和额外检索的上下文才能揭示的隐藏依赖关系。值得注意的是,CodeLlama的一次性成功率较低(85.2%),并且该模型在迭代≥2时生成了30.2%的合理补丁,这表明较弱的模型从迭代上下文丰富中受益较少。

我们的组件级映射将多功能错误分解为具有局部测试关系的较小单元。在Defects4J中,有80个多功能错误,每个错误至少有两个失败测试,我们的基于覆盖率的映射识别出38个错误(47.5%)可以分解为多个独立的修复组件。表12总结了分解分析。在38个被分解的错误中,大多数(31个错误,81.6%)分为2个独立组件,较少错误需要3、4或5个组件(分别为4个、2个和1个)。剩余的42个错误(52.5%)被识别为需要同步修复的单一连贯单元。这种分解揭示了在没有自动化映射的情况下不可见的部分独立结构,使得可以集中检索上下文、独立跟踪每个组件的假设,并进行迭代性的组件级修复。

表12 自动映射分析

过拟合检测机制解决了基于LLM的修复中的一个关键质量挑战,其影响因评估的模型而异。我们的跨模型分析揭示了一个互补模式:OD对QwenCoder-32B的贡献最大,而CU对CodeLlama-34B的贡献最大,后者从额外的上下文检索中受益更多。这种互补模式与观察到的行为一致。QwenCoder-32B表现出更高频率的OD标记过拟合案例,而CodeLlama-34B从迭代上下文丰富中受益更多,因为它完全利用初始上下文的能力较弱。图6通过Lang-19示例说明了OD的修复能力,其中初始补丁添加了hex实体支持,但引入了Java操作符优先级错误,||导致hex分支绕过了end < seqEnd边界检查,在字符串末尾的hex实体上崩溃。补丁通过了所有测试,因为它们只测试十进制实体。OD识别了优先级错误,修复后的补丁将所有数字测试都包含在边界检查范围内。值得注意的是,OD修复后的补丁比开发者的修复更精确,后者通过不在代码中已经存在的isHex标志上进行分支来接受hex字符作为十进制实体。

图6. 过拟合检测器修复示例(Lang-19)

我们架构贡献的跨模型一致性表明,该框架在评估的模型中具有通用性。相对于基础LLM,综合增益范围从10.6%(GPT-4o)到23.0%(CodeLlama-34B)。这些结果表明,所提出的架构有助于解决关键的程序修复挑战,例如结合额外的上下文和减轻过拟合,这在性能较低的模型中更为明显。

表13 总结了所有三个模型的计算成本。GPT-4o平均用312.4秒处理一个错误,每个错误消耗7,849个输入令牌和11,364个输出令牌。开源模型(QwenCoder-32B和CodeLlama-34B)不需要API成本。QwenCoder-32B处理错误的速度较慢(平均555.9秒),令牌消耗量较高(12,294个输入,20,034个输出),而CodeLlama-34B的延迟最高(453.2秒)和令牌使用量最高(21,095个输入,21,334个输出)。未修复的错误需要更多的计算:GPT-4o为835.2秒,QwenCoder为1149.17秒,CodeLama为1238.96秒。总体而言,每个错误的低API成本(0.13)和合理的迭代限制(平均1.29)表明自动化程序修复具有成本效益。

尽管协调了三个专门的代理和一套静态分析工具,但该架构在实践中只带来了适度的计算开销:GPT-4o平均用312.4秒解决一个错误,每个错误的API成本为0.13,而开源后端(QwenCoder-32B:555.9秒;CodeLlama-34B:453.2秒)的API成本为零,从而确认了大规模使用的实际可行性。可扩展性还得到了Context Updater的自适应工具调用策略的支持,它根据需求选择静态分析工具,而不是在每次迭代中全部执行它们,从而限制了每次迭代的开销。部署复杂性也是可管理的:整个系统在一个Docker容器内运行,不需要超出LLM API端点的任何外部服务依赖。

失败分析显示,模型后端之间存在一致的模式。无论模型能力如何,需要严格遵守领域特定算法契约的错误仍然难以修复。JxPath在所有模型中的修复率最低(GPT-4o为4/22,QwenCoder-32B为2/22,CodeLlama-34B为1/22),Time的表现也类似低(GPT-4o为8/26,QwenCoder-32B为4/26,CodeLama-34B为1/26),与结构上相似的项目(如Math和Compress)形成对比。组件分解策略引入了方法级别的偏见:BM-FT映射依赖于覆盖度仪器,向量数据库索引非错误方法,补丁生成在方法粒度上操作。因此,字段声明、类级别初始化或静态块中的错误没有得到一致的优先处理。覆盖度将失败测试与执行这些元素的方法关联起来,而不是与元素本身关联,使得定位偏向于方法体。尽管Generator偶尔可以修改或引入字段,但修复仍然主要以方法为中心,即使错误起源于方法范围之外。另一个限制出现在连贯的多方法场景中。虽然映射组件根据失败测试案例中的共享执行对方法进行分组,但这种基于共同执行的分解并不总是与真实的依赖关系对齐,Generator在没有明确故障隔离的情况下仍然难以共同推理和修改多个相互依赖的方法。这表明,即使相关方法被分组在一起,这种情况对当前的修复策略来说仍然具有挑战性。

第六节 验证性的威胁
A. 外部有效性
我们的评估在两个基准测试上进行了,Defects4J(Java)和SWE-Bench Lite(Python),它们提供了带有可执行测试的真实错误,但仍代表了现实世界软件的一个精选子集。两者都关注维护良好的开源项目,并没有完全涵盖大型工业系统、遗留代码或测试稀疏或不稳定的项目。尽管我们的过拟合检测器减轻了弱测试的影响,但这一威胁仍然存在。

B. 内部有效性
内部有效性的主要威胁是LLM输出的非确定性行为,这可能导致每次运行中成功修复的错误数量发生变化。我们通过三种策略来缓解这一点:(1)在所有实验中固定温度参数(分析导向的代理为0.2,Generator为0.7–1.0);(2)使用开源模型进行三次独立运行,报告平均值±标准差,并且变异系数较低(QwenCoder为0.83%,CodeLlama为3.47%);(3)对所有实验使用一致的配置。对于Defects4J基线,我们依赖于报告的结果,而不是重新运行它们的实现,这可能会由于实验环境的不同而引入轻微的差异。一个相关的担忧是模型版本差距:我们的方法使用了更新、更专注于编码的模型(GPT-4o,QwenCoder-32B),而大多数基线使用了GPT-3.5,这可能会夸大绝对改进幅度。为了缓解这两个问题,表3记录了已知的基线设置,我们的受控消融研究(RQ4)在相同条件下提供了公平的系统内比较。另一个内部有效性问题来自自动化故障定位下的向量数据库构建。由于假设top-K可疑集之外的方法是无错误的,实际上有错误的但排名低于阈值的方法可能会被无意中索引。然而,这种影响预计是有限的,因为向量数据库仅作为上下文参考,LLM合成自己的补丁候选者而不是直接复制检索到的方法。

C. 构造有效性
每个错误的五次尝试限制可能阻止了需要更多迭代的非常复杂案例的修复,尽管我们的迭代分析显示所有模型的迭代次数超过3次后收益递减。我们的SWE-Bench Lite配置允许修复代理利用额外的结构化项目工件(例如,代码上下文和测试执行反馈),超出了自然语言任务描述的范围,使设置更接近开发者的实际工作方式,但与仅依赖描述的更严格配置不直接可比。此外,我们的自动化FL评估假设:如果真实存在问题的方法在问题方法排名中位列前十,而排名较低的方法却没有被当前方法发现,那么这些问题将无法得到解决。这反映了FL工具的局限性,而非我们架构本身的问题。在我们的评估过程中,我们区分了“看似合理”的修复方案和“真正正确”的修复方案,正确性通过两位作者的手动检查来验证,如有分歧则由第三位作者进行裁决。

第七节 结论

本文提出了一种基于代理的自动化程序修复架构,该架构通过动态上下文管理和代理协调机制,解决了当前基于大语言模型(LLM)的修复系统所存在的局限性。该架构整合了三个专门的代理,它们通过一个双组件的上下文池进行协作,从而能够基于修复反馈进行迭代优化,包括对过拟合现象的识别与纠正,以及对复杂错误的逐步理解。评估结果表明,这种方法在Java和Python基准测试中均表现出有效性。该架构成功修复了现有基线方法无法解决的错误,表明其在处理复杂缺陷方面具有更强的能力,这得益于其自适应的信息收集机制。组件级别的映射策略将多功能错误分解为独立的修复目标,优化了工作流程结构,并能够处理那些由多种方法中的不同模式共同导致的故障。跨语言测试的结果表明,动态上下文优化和基于代理的协调机制能够解决程序修复中的根本性问题,而不仅仅是语言特定的问题。消融实验进一步证实,自适应上下文管理对修复性能有显著提升作用,突显了动态信息检索在基于LLM的修复系统中的价值。

尽管该架构具有这些优势,但其以方法为中心的设计以及依赖于覆盖度引导的分解方式可能会限制其捕捉更广泛的结构依赖关系的能力,同时也难以处理紧密耦合的程序元素。此外,该方法依赖于具有明确定义的测试套件的基准环境,这可能无法完全反映现实世界的开发环境。未来的工作将致力于改进代理协调策略、开发更精确的上下文选择机制,并增强对超出方法层级的结构依赖关系的支持。同时,扩展该方法以更好地处理复杂的相互依赖的代码区域,以及降低迭代修复的计算开销,也是未来研究的重要方向。

生物通微信公众号
微信
新浪微博


生物通 版权所有