保持对话继续:使用ChatGPT修复337个bug中的162个,每个0.42美元

互联不一般哥 2024-05-28 21:26:36

Keep the Conversation Going: Fixing 162 out of 337 bugs for $0.42 each using ChatGPT

Chunqiu Steven Xia, Lingming Zhang

University of Illinois Urbana-Champaign

引用

Xia C S, Zhang L. Keep the Conversation Going: Fixing 162 out of 337 bugs for $0.42 each using ChatGPT[J]. arXiv preprint arXiv:2304.00385, 2023.

论文:https://arxiv.org/abs/2304.00385

摘要

自动程序修复(APR)旨在自动为有错误的程序生成补丁。传统的 APR 技术缺乏补丁多样性,因为它们严重依赖手工或挖掘的错误修复模式,并且不能轻易推广到其他错误/修复类型。为了解决这一限制,最近的 APR 工作重点是利用现代大型语言模型 (LLM) 直接生成 APR 补丁。这种基于 LLM 的 APR 工具的工作原理是,首先构建使用原始错误代码构建的输入提示,然后查询 LLM 以在错误位置填写(完型式 APR)正确的代码,或者生成一个全新的代码片段作为修补。虽然基于 LLM 的 APR 工具能够实现最先进的结果,但它仍然遵循经典的生成和验证 (GV) 修复范例,即首先通过从相同的初始提示中采样来生成大量补丁,然后验证每个补丁之后的一个。这不仅会导致许多不正确的重复补丁,而且还会错过测试失败以及看似合理的补丁中的关键但之前被忽略的信息。为了解决上述限制,我们提出了 ChatRepair,这是第一个完全自动化的对话驱动的 APR 方法,它将补丁生成与即时反馈交织在一起,以对话方式执行 APR。 ChatRepair 首先向 LLM 提供相关测试失败信息,然后从同一错误的早期修补尝试的失败和成功中学习,以获得更强大的 APR。对于未能通过所有测试的早期补丁,我们将不正确的补丁与其相应的相关测试失败信息结合起来,构建一个新的提示,供LLM生成下一个补丁。这样,我们就可以避免犯同样的错误。对于通过所有测试的早期补丁(即合理的补丁),我们进一步要求LLM生成原始合理补丁的替代变体。通过这种方式,我们可以进一步借鉴早期的成功经验,生成更合理的补丁,从而增加获得正确补丁的机会。虽然我们的方法是通用的,但我们使用最先进的基于对话的 LLM – ChatGPT 来实现 ChatRepair。我们对广泛研究的 Defects4j 数据集的评估表明,ChatRepair 能够在修复性能方面达到最先进的水平,在 Defects4j 1.2 和 2.0 上分别实现 114 和 48 个正确修复。通过计算访问 ChatGPT 的成本,我们可以修复 337 个错误中的 162 个,每个错误 0.42 美元!

1 引言

自动程序修复 (APR) 是一种自动生成软件错误补丁的有前途的方法。传统的 APR 工具通常使用生成和验证 (GV)范例,首先生成大量候选补丁,然后根据原始测试套件验证每个补丁,以发现一组合理的补丁(通过所有测试)。然后将这些看似合理的补丁提供给开发人员,以找到正确修复潜在错误的正确补丁。传统的APR技术可以分为基于模板的,基于启发式的和基于约束的APR工具。在这些传统技术中,基于模板的 APR 工具,使用手工制作或挖掘的修复模板来匹配和修复有缺陷的代码模式,被认为是最先进的。然而,基于模板的工具缺乏补丁多样性,因为它们无法轻松泛化到预定义模板列表之外的错误和模式。为了解决传统 APR 技术的局限性,研究人员提出了利用深度学习进步的基于学习的 APR 方法。基于学习的方法主要基于神经机器翻译(NMT)或大型语言模型(LLM)。基于 NMT 的 APR 工具将修复视为一项翻译任务,通过使用历史错误修复数据集训练 NMT 模型将有错误的代码转换为正确的代码。然而,这种基于 NMT 的 APR 工具严重依赖于其训练数据,这些数据是通过抓取开源存储库来进行错误修复提交而获得的。这意味着不仅训练数据集可能有噪音(即包含不相关的提交/更改),而且这些基于 NMT 的方法可能无法推广到在有限的训练数据中未见的错误修复类型。

最近,研究人员开始直接利用高级LLM进行 APR。现代LLM接受了数十亿个开源代码片段的训练,在许多与代码相关的任务上展示了令人印象深刻的性能,并且可以学习在给定周围上下文的情况下直接生成代码(由于代码自然性)。 AlphaRepair提出了第一个完形填空式(或填充式)APR 方法,其中有错误的代码被删除,并且 LLM 在给定前缀和后缀上下文的情况下直接预测正确的代码。最近的工作还应用基于 LLM 的 APR 来自动完成单个正确行或生成完整的固定函数。一项更广泛的研究研究了将更大的 LLM 和不同的 LLM 架构(即生成式和填充式)应用于 APR,并证明基于 LLM 的 APR 工具可以在许多 APR 任务上实现新的最先进的性能。同时,现有的基于LLM的APR渠道仍然存在以下局限性:

1)缺少测试失败信息。当前基于 LLM 的工具没有考虑原始 bug 暴露测试中的丰富信息。这些信息不仅可以帮助LLM理解被测源代码的含义,还可以通过具体的代码片段提供帮助和提示。图 1 显示了错误修复示例以及原始测试失败信息。我们看到解决方法是将附加字符串交换为“\\000”。对于基于 LLM 的方法来说,这可能是一个极其困难的修复,因为这个独特的字符串是这不是预训练期间常用的字符串,并且当前函数上下文中也没有其他三重字符串(“\\XXX”)的示例。然而,从测试中的失败行和相应的错误消息中,我们看到测试期望输出包含三个零,甚至包含直接在补丁中使用的代码片段(“\\000”)!LLM在处理/利用测试失败日志等非结构化/复杂信息方面表现出了强大的能力。如果不考虑它们,基于 LLM 的工具可能会浪费大量时间来生成不相关的补丁。

2)重复采样。当前基于 LLM 的方法首先使用原始有缺陷的代码构建输入提示,然后要求 LLM 填写正确的代码(即完型填空式 APR)或生成全新的固定函数。使用初始提示,基于 LLM 的技术将对 LLM 进行多次采样以生成许多补丁,类似于传统的程序修复 GV 范例。然而,由于每个样本都是完全独立的,LLM 不知道任何先前生成的补丁。因此,基于 LLM 的工具可能会生成许多重复或类似的补丁,这些补丁已被确定为不正确,从而浪费 API 访问的成本或 GPU 执行的时间。此外,这种重复采样过程也与人类开发人员修复错误的方式截然不同,人类开发人员在知识的基础上迭代构建,并尝试从之前失败的尝试中提出下一个可能的补丁。

3)对有价值的合理补丁的无知。除了无法使用过去的错误补丁之外,当前基于 LLM 的 APR 工具也无法有效利用之前生成的合理补丁。合理的补丁已被证明是有价值的,因为它们通常与实际正确的补丁共享相似的位置。此外,我们进一步假设合理的补丁可能还包括通过所有测试的关键代码成分,并且还可以帮助LLM更好地学习如何通过所有测试以生成更合理的补丁(从而增加生成正确补丁的机会)。通过忽略这些有价值的合理补丁信息并在生成合理补丁后从头开始,现有的基于 LLM 的 APR 可能会错过正确修复更多错误的机会。

我们的工作。我们推出 ChatRepair – 一种完全自动化的对话驱动的 APR 方法,它将补丁生成与即时反馈交织在一起,以对话方式执行补丁生成。虽然我们的想法很笼统,但为了构建 ChatRepair,我们使用最近开发的、当前最先进的基于对话的 LLM – ChatGPT,它不仅经过数十亿代码片段的训练,而且还经过设计以对话方式使用,以更好地理解说明。 ChatRepair 首先提取相关测试失败信息作为初始提示,为 ChatGPT 提供更多 APR 上下文信息。此外,ChatRepair 进一步从早期修补的失败和成功中学习尝试相同的错误以获得更强大的 APR。对于未能通过所有测试的早期补丁,我们将不正确的补丁与其相应的测试失败信息结合起来,构建一个新的提示,供 LLM 生成下一个补丁。这样,我们就可以避免犯同样的错误。对于通过所有测试的早期补丁(即合理的补丁),我们进一步要求LLM生成原始合理补丁的替代变体。通过这种方式,我们可以进一步借鉴早期的成功经验,生成更合理的补丁,从而增加获得正确补丁的机会。由于我们的方法使用 ChatGPT 模型,因此我们还计算用于修复错误的 ChatGPT API 查询的美元成本。令人惊讶的是,我们发现通过使用 ChatRepair,我们可以修复 337 个错误中的 162 个,每个错误 0.42 美元。

本文做出以下贡献:

维度。我们为全自动程序修复开辟了对话驱动范例的新维度。我们的工作首次证明,我们可以有效地利用以前被忽略的测试失败信息,以及以对话方式进行的早期补丁尝试,以提示LLM生成更正确的补丁。此外,我们展示了利用基于对话的LLM进行 APR 的广阔前景。技术。我们使用最新的ChatGPT 模型开发了ChatRepair,这是一种完全自动化的对话驱动的APR 工具。更具体地说,我们自动提取有关初始测试失败以及早期补丁尝试的简洁相关信息,以提示 ChatGPT 进行有效的 APR。评估。我们在广泛研究的 Defects4j 1.2、2.0和 QuixBugs数据集上针对当前最先进的基于学习的传统 APR 工具评估 ChatRepair。 ChatRepair 在 Defects4j 1.2 和 2.0 上分别获得了 114 个和 48 个正确错误修复(比之前的最佳基线多 15 个和 17 个)的新的最先进修复结果。此外,我们进行了广泛的消融研究,以证明利用丰富的语义测试失败信息和 ChatRepair 的对话范例进行修复所获得的改进。

2 技术介绍

我们提出了 ChatRepair,一种完全自动化的对话驱动的 APR 技术,它结合了多个维度的反馈信息来迭代查询模型以生成补丁。 ChatRepair 不像现有基于 LLM 的 APR 技术那样直接根据有缺陷的代码生成补丁,而是另外提供有价值的测试失败信息,以进一步帮助 LLM 生成补丁。此外,ChatRepair 并没有像之前基于 LLM 的 APR 技术那样从相同的提示中连续采样,而是跟踪对话历史记录,并通过提示从先前失败和成功的同一错误修补尝试中进一步学习。通过这种方式,ChatRepair 既可以避免以前的失败,又可以在早期的成功(例如合理的补丁)的基础上构建更有效的 APR。因此,ChatRepair 最大限度地提高了获得正确修复潜在错误的真正正确补丁的能力。虽然我们的方法是通用的,可以使用不同的 LLM 并应用于各种不同的修复场景,但在这项工作中,我们使用专为对话交互设计的最先进的 ChatGPT 模型,如图1所示。

图1:ChatRepair整体工作流程

2.1 初始输入

首先,我们使用原始的bug项目和bug来构建ChatGPT的初始提示,以启动修复过程。我们遵循先前基于学习的APR工具,并主要关注线级修复(特别是填充或封闭型APR,因为它已被证明是最先进的[58])。同时,ChatRepair通常也可以用于各种不同的修复场景,我们将在后面的部分中更详细地对其进行评估。

ChatRepair使用来自失败测试的各种信息,包括1)它的名称,2)触发测试失败的相关代码行,以及3)产生的错误消息。失败测试的名称可以作为被测函数的简短摘要。在图2的例子中,失败的测试是testGreatestSubtypeUnionTypes5(),它告诉我们,我们正在测试一个与从联合类型中确定最大子类型相关的功能。相关的测试代码和错误消息给出了关于测试失败原因的具体信息。在示例中,相关的测试代码和错误消息告诉模型,我们正在比较No_OBJECT_TYPE,但源代码函数错误地返回了一个None对象。这样失败的测试信息不仅在源代码的功能方面为模型提供了更多的解释,而且在预期输出和函数使用方面提供了具体的信息,以帮助模型生成正确的修复。注意,如果有多个失败的测试,ChatRepair只提供其中一个的信息,以保持简洁的初始提示。最后,我们通过给model生成正确的行来替换填充位置的有bug的代码来结束我们的初始提示。设C为输出生成序列概率的ChatGPT,preandsufas为删除错误行后的错误代码的前缀和后缀,Ifillas为替换错误行的填充令牌,f0为构造的失败测试信息,Ifillas为填充指令提示符。补丁pgenerated可以形式化的条件概率:C(p|pre,infill,suf,f0,Ifill)

据我们所知,ChatRepair是第一个通过结合故障信息的自然语言描述(例如,代码在此测试中失败:{failure_test})作为输入到强大的ChatGPT模型中,以纯提示方法应用这些测试失败和错误消息的工作。与之前使用的修复测试执行信息不同[61],它依赖于自定义编码或手工制作的启发式,通过使用ChatGPT通过提示进行ChatRepair不仅是跨越不同编程语言但也不受测试信息类型的限制。

2.2 会话修补

我们首先使用创建的初始提示来查询ChatGPT以获得模型输出并提取候选补丁。然后,我们转移到方法的对话部分,我们将patch生成与测试验证反馈交织在一起,以对话的方式提示未来的生成。每个由模型生成的补丁之后,都立即有一个补丁验证步骤,以在测试套件上编译和运行补丁。如果补丁未能通过测试,我们将使用不正确的补丁和失败的测试构建详细的反馈信息,作为下一个补丁生成提示的一部分。与初始提示类似,测试失败信息可以帮助模型了解失败原因,并为生成正确修复提供指导。在对话步骤中,我们进一步将测试失败信息与之前不正确的补丁结合起来,不仅可以避免生成更多类似的不正确补丁,还可以从前几代的错误中学习。我们重复这个过程,直到生成一个通过整个测试套件的可信补丁。

2.3 貌似合理的补丁生成

在前一步之后,ChatRepair应该获得一个可以通过整个测试套件的貌似合理的补丁。然而,一个似是而非的补丁可能并不总是能够正确地修复底层bug,因为测试套件可能是不完整的,因此无法覆盖底层代码的所有可能的预期用法。因此,开发人员必须手动检查合理的补丁以确定正确的补丁。合理的补丁和最终正确的补丁都有一个相似的特点:它们都可以通过整个测试套件。因此,ChatRepair不是从头开始),而是直接利用现有的可信补丁来创建更可信的补丁。简而言之,为了增加我们能够生成正确补丁的概率,ChatRepair采用之前生成的可信补丁,并要求模型生成替代变体并产生额外的候选补丁。

首先,我们采用最初使用的提示符,其中包含原始的有bug的代码功能以及有用的测试失败信息。然后,我们在提示符后面添加生成的合理补丁列表。在开始时,该列表将只包含上一步中单个合理的补丁,但是随着我们继续生成额外的合理补丁,它会增长。接下来,我们在提示符中指出我们想要解决的任务-请生成一个替代修复行。然后,我们使用这个提示符作为ChatGPT的输入,并获得一个候选补丁,我们将再次编译并运行测试套件,以检查它是否确实是另一个合理的补丁。我们不断地查询ChatGPT并更新提示符,以包含生成的新的可信补丁,以避免再次重复生成相同的可信补丁,并进一步构建早期的可信补丁。再次设C为输出生成序列概率的ChatGPT模型,Ibe为初始提示符,Iplas为任务指令,PL<n={pl1,…,pln−1}是之前生成的可信补丁。生成的下一个似是而非的补丁可以形式化为条件概率:C(pli|I,PL<i,IPL)。

最后,我们得到一个似是而非的补丁列表,这些补丁可以交给开发人员进行人工检查。与之前的APR工具(仅对原始错误代码进行操作以生成补丁)不同,ChatRepair利用每个可能的补丁中额外的有用信息来获得更多可能的补丁。一个合理的补丁通常包含有用的成分/模式,允许它通过原始测试套件;因此,ChatGPT不是从头开始(即再次修复错误),而是在现有的可信补丁的基础上构建,通过其强大的理解指令的能力,可以获得额外的可信补丁,以增加我们的最终补丁列表中包含修复错误的正确补丁的可能性。

3 实验评估

RQ1 最先进的比较

我们首先将 ChatRepair 与最先进的 APR 工具进行比较。表 1 显示了顶级基线工具以及 BaseChatGPT 在 Defects4j 1.2 和 2.0 上修复的错误数量——仅使用 ChatGPT,没有任何测试失败信息和对话。我们首先观察到,ChatRepair 可以在仅使用 ChatGPT 模型的基础上进行改进,分别在 Defects4j 1.2 和 2.0 上修复了 34 个和 23 个错误。这一改进是通过成功利用 ChatGPT 模型的对话方面来实现的,使用以前不正确或合理的补丁以及测试失败信息来提供即时反馈。有趣的是,我们还观察到,在 Defects4j 2.0 上的单行修复等情况下,与纯代码填充相比,由于使用了特定于修复的模板,AlphaRepair 等使用更小的 LLM (CodeBERT) 的现有工具可以比 CodexRepair 表现得更好。事实上,ChatRepair 首次证明基于 LLM 的 APR 无需任何修复模板即可在 Defects4j 上实现最佳性能。总的来说,ChatRepair 能够分别在 Defects4j 1.2 和 2.0 上实现 114 个和 48 个正确的错误修复,比当前最先进的 APR 工具多 15 个和 17 个。计算查询 ChatGPT 的总成本,我们可以修复 337 个错误中的 162 个错误,每个错误 0.42 美元!虽然 114 和 48 个修复是通过将三种修复设置组合在一起来实现的,但与之前基于学习的工具(每个错误最多可以生成 10,000 个补丁)相比,ChatRepair 生成的补丁仍然少得多(每个错误总共 <500 个)[22, 39] 。类似地,在表 2 中,ChatRepair 能够正确修复 QuixBugs-Java 和 -Python 数据集中的所有错误,击败了所有性能最佳的技术。

表1:对缺陷4j的正确修复

RQ2 修复场景

接下来,我们更详细地了解三种修复设置(单线、单块和单功能)。在本节中,我们将重点针对 BaseChatGPT 进行分析,使用 ChatGPT,无需任何测试失败信息或对话,而 CodexRepair 是性能最佳的基于 LLM 的 APR,并且还对我们使用的三种修复设置进行了评估。我们首先观察到基础 ChatGPT 模型在 Defects4j 1.2 的真实基准测试中的表现甚至比 CodexRepair 稍差。我们推测这是因为 ChatGPT 并不是像 Codex 那样为代码生成而设计或直接微调的。因此,以与之前基于 LLM 的 APR 工具类似的方式直接使用 ChatGPT,这些工具仅从相同的初始提示中进行采样,而无需额外的操作信息并没有带来令人印象深刻的改进[63]。另一方面,通过使用ChatRepair,将ChatGPT强大的对话/指令理解能力与动态反馈相结合,ChatRepair能够更好地利用之前被忽略的测试失败信息和早期的补丁尝试来更好地执行APR。相反,Codex 主要是为了代码补全而设计的,缺乏以对话方式使用的能力。总之,对于每个单独的修复设置,与最先进的 CodexRepair 和运行的基础 ChatGPT 相比,ChatRepair 能够实现最高数量的错误修复。此外,更正确修复的改进不仅来自对话和验证反馈方面,而且还来自我们合理的补丁生成步骤。回想一下,一旦生成了合理的补丁,我们就可以通过要求 ChatGPT 提供该补丁的其他变体来直接使用该补丁来生成更合理的补丁。总之,合理的补丁生成平均能够额外添加 9.4、16.6、5.5 个合理的补丁,并将单线、单块和单功能修复场景中正确修复的错误数量分别提高 4、7、2关于 Defects4j 1.2。这一改进证明了我们提出的方法在利用合理补丁中的重要信息来生成更多补丁以实现正确修复方面的有用性。

RQ3 ChatRepair配置

我们研究了 ChatRepair 的不同配置。具体来说,我们检查以下重要参数:(1) 使用的初始提示、(2) 提供的反馈响应和 (3) 最大对话长度。由于针对消融研究的每个维度多次调用 ChatGPT API 的成本很高,因此我们重点关注 Defects4j 1.2 中的 80 个单行错误。此外,由于补丁检查涉及大量的手动工作,我们在此 RQ 中分析了产生的合理修复的数量,而不是正确修复的数量。我们的每个消融实验都使用第 4.1 节中描述的默认设置,除了默认情况下我们使用零样本(不提供任何先前的错误修复示例),因为它可以最好地说明各个组件的效果,并更容易研究少数组件的影响-

转述:朱民笑

0 阅读:0

互联不一般哥

简介:感谢大家的关注