论文阅读《RepairAgent: An Autonomous, LLM-Based Agent for Program Repair》

摘要

        RepairAgent:基于大模型的自主代理解决程序修复挑战的工作,将LLM视为能够自主规划和执行操作的代理,调用合适的工具来修复错误。通过收集有关错误,修复成分和验证修复的信息,先前修复尝试的反馈来决定调用哪些工具。

        贡献:一组对程序修复有用的工具,动态更新的提示格式,允许LLM与这些工具交互。

        实验:Defects4J 数据集证明修复的有效性。

一、介绍

        APR:通过以自动化方式解决有效和高校错误解析的关键需求来减少修复工作量。

        相关技术:基于手动设计,半自动提取,修复模式的技术,基于符号约束,基于机器学习的方法。

        APR围绕LLM的相关研究:第一代接受包含错误代码的提示并生成固定版本。第二代引入迭代方法,基于先前修复尝试获得的反馈重复查询LLM。

        迭代的基于LLM的修复技术:限制是硬编码反馈循环不允许模型收集有关错误或可以提供修复错误成分的现有代码的信息。相反修复了Prompt中提到的代码文本并针对错误代码详细说明一些失败的测试用例,在反馈循环中对错误代码的不同变体执行测试,将任何编译错误,测试失败或其他输出添加到下一次迭代的prompt中。不同于人类开发人员修复错误的方式(收集信息以理解错误的时间交错,搜索可能有助于修复错误的代码以,可以调用,及实验候选修复)。

        RepairAgent:自治基于大模型的自动程序修复代理。为LLM配备一组特定于修复错误的工具,可以调用以与人类开发人员类似的方式与代码库交互。(例如通过阅读特定行代码来提取有关错误信息的工具,通过搜索代码库来收集修复成分,应用补丁和执行测试用例提出和验证修复。)让LLM自主决定接下来调用哪些工具。

        方法包含三个组件。通用的LLM,一组14种工具,协调LLM和工具之间的通信的中间件。

        通用的LLM:GPT-3.5,用动态的更新提示反复查询,新颖的提示格式,通过错误修复过程指导LLM,根据LLM调用的命令和先前命令执行的结果进行更新。

        一组14种工具:涵盖人类开发人员在修复错误时采取的不同步骤(阅读特定的代码行,搜索代码库和应用补丁)

        中间件:通过有限状态机指导工具调用的新技术。

        RepairAgent的迭代循环一直持续到代理声明找到合适的修复,或者直到耗尽迭代预算。

        数据集:Defects4J(835个错误)

        贡献:(1)自主的基于LLM的程序修复代理

                   (2)动态更新的提示格式,通过错误修复过程指导LLM

                   (3)一组工具,使得LLM能够在修复Bug时执行人类开发者采取的步骤

                   (4)一个中间件。能够协调大模型和工具之间的通信

                   (5)经验证据,修复代理通过成功修复164个错误来建立新的技术水平,包括先前工作未修复的39个错误。

二、相关工作

        基于LLM的代理:LLM自主计划并执行一系列操作来实现这一目标,而不是响应硬编码的查询或在硬编码算法中查询。LLM能够调用外部工具使LLM与外部环境交互。基本思想是用包含当前状态的提示查询LLM。要实现的目标以及接下来可以执行的一组动作,LLM决定要执行哪些动作,执行动作的反馈被集成到下一个提示中。

        通过API调用工具的LLM代理

三、方法

3.1 架构

        RepairAgent(架构图):三个部分组成

        LLM代理(左边),一组工具(右边)和编排两者之间通信的中间件(中间)

        给定一个要修复的错误,中间件使用包含任务信息和指令的指示来初始化LLM代理,以便如何使用提供的工具执行它(1);LLM通过建议调用可用工具之一来响应(2);该工具中间件解析然后执行(3);将工具的输出集成提示中(4),以便下一次调用LLM,该过程迭代持续,直到错误固定或预定义的预算耗尽。

3.2  术语

        RepairAgent多次迭代或循环进行。

        定义1(循环):一个循环表示与LLM代理进行一轮交互,包括以下步骤:

      (1)查询代理

      (2)后处理响应

      (3)执行代理建议的命令

      (4)根据命令的输出更新动态提示。

        在每个循环中,方法查询一次LLM,模型输入是根据LLM调用的命令及其结果更新的,在之前的循环中,我们将模型输入动态提示:

        定义2(动态提示):动态提示是文本部分的一个序列P=\left \{ s_0,s_1...s_n \right \},每一个s_i是以下内容之一,其中s_i(c)指的是循环c中的部分。

      (1)一个静态的部分,在所有周期中保持不变。

      (2)异地动态部分,可能因周期而异,即可能存在

3.3  修复代理的动态提示

        动态提示由一系列静态和动态部分组成。

        (1)角色(Role):提示的这一部分定义了代理的专业领域,即解决java代码中的错误,并概述了代理的主要目标:理解和修复错误。该提示强调代理的决策过程是自主的,不应依赖于用户辅助。

        (2)目标(Goals):为代理定义了五个目标来追求,这在所有周期中保持不变。

                定位错误:执行测试并使用故障定位技术来定位信息时跳过这个目标。

                收集有关bug的信息:分析与bug相关的代码行,以了解bug。

                为bug提供简单的修复:从建议简单的修复开始

                建议复杂的修复:简单的修复被证明无效,探索并提出更复杂的修复

                迭代之前的目标:继续收集信息并建议修复,直到找到一个修复。

        (3)方向(Guideline):我们提供了一套指导方针,通知模型存在多种错误(单行问题、可能需要更改删除或添加行的多行错误)。提供重复修复模式列表,基于先前对java中的单语句错误的工作中描述的模式。对每个模式提供一个简短的自然语言描述和错误以及修复代码的示例,指示模型在修改后的代码中插入评论(增强模型解释和推理能力,帮助人类开发员理解编辑,指示模型以明确定义的工具调用结束推理)。最后描述了工具调用预算有限,突出效率在选择工具中的重要性。最大循环设置为40

        (4)状态描述(State Description):约束给定时间点可用的工具。

        

        设计它来模拟人类开发人员在修复错误时会经历的状态,每个状态都与代理可用的一组工具相关联。代理通过实用工具可以自由地在任何时间节点转换状态。

        understand the bug:代理从这个状态开始,收集与失败的测试用例和Bug位置相关的信息。一旦代理有对错误的理解,它会制定一个假设来描述错误的性质和背后的原因。修复过程中代理会反驳早期假设并表达新的假设,在表达假设后,代理将自动切换到下一个状态。

         collect information to fix the bug:在这种情况下,代理收集有助于建议修复假设表达的错误信息(通过搜索特定的修复成分或通过阅读可能相关的代码)

        Try to fix the bug:代理试图修复错误根据当前假设和收集到的信息。每一个修复尝试修改代码库并通过执行测试用例进行验证。如果必然,代理可以返回到先前状态之一以建立新假设或收集附加信息。

        (5)可用工具(Available Tools):提示词的这一部分描述了代理在当前状态下可以调用的一组工具。

        (6)收集信息(Gathered Information):收集有关错误和代码库的信息,保持一个prompt列出不同工具调用收集的信息。

        (7)输出格式规范:给定动态提示词,大模型代理每个周期提供一个响应,指定预期的输出格式:thoughts字段在决定下一个命令时提供了对代理推理文本描述。要求代理表达其想法会增加方法的透明度和可解释性。command字段指定要执行的下一命令,由调用的工具名称和参数集组成。图4显示了LLM代理的响应,该模型表达了收集更多信息以了解错误的必要性,并提出了一个命令,使用关键字列表搜索代码库。

(8)最后执行的命令和结果:提示词的这一部分包含执行最后一个命令和它产生的输出。提醒代理采取的最后一步和在命令执行期间会产生的任何问题。此外提醒代理已经执行多少循环,留下多少循环。

3.4  代理使用的工具

        让LLM自动决定调用哪些工具来修复错误。

        提供的工具如下:

        (1)阅读和提取代码(Read and extract code):让代理根据四种工具决定要阅读的代码的哪些部分。rea_range:允许代理从特定文件中提取一些列行。get_classes_and_methods: 获得代码结构的概述给定文件中所有类与方法名称。extract_method:代理可以检索与给定文件中给定方法名称匹配的方法的实现。extract_tests:提取了导致失败测试用例的代码。

        (2)搜索和生成代码(search and generate code):受人类开发人员经常搜索代码的启发,提出允许代理搜索特定代码片段的工具。search_code_base:使代理能够定位整个代码库中特定关键字的实例(代理可以使用该工具来查找变量,方法和类的出现次数。根据驼峰情况、下划线和周期将每个关键字拆分为子标记,在代码中搜索每个子标记例如搜索fastSortArray会产生sortArray、quickSort、arrayQuicSort等相关变体的匹配。输出是嵌套字典,由文件名、类和方法名组织、提供与方法内容匹配的关键字)find_similar_api_calls:允许代理识别和提取方法的用法,没有这样的工具,LLM往往会幻觉代码库中不存在的方法调用。给定一个包含方法调用的代码片段,提取调用方法的名称,搜索调用具有相同名称的方法。代理可以将搜索限制为特定的文件或搜索整个代码库。generate_method_body:要求LLM生成方法主体。

        (3)测试和修补(Testing and patching):有关运行测试和应用补丁。run_tests:允许代理执行项目的测试套件。产生一个报告,表明测试是否经过了或失败,失败的情况下删除当前项目之外堆栈跟踪的条目。(通过删除当前项目之外堆栈跟踪的条目。)设计原因:因为LLM提示大小有限,不相关信息会混淆模型。run_fault_localization:对于理解代码哪些部分可能包含错误很有用。write_fix:代理使用修复工具将补丁应用于代码库。RepairAgent旨在修复任意复杂的错误,包含多行甚至多文件错误。该工具以特定json格式的补丁,指示在每个文件中插入、删除和修改。补丁格式如图:

        给定一个补丁,该工具将更改应用于代码库并运行测试套件。测试失败:write_fix工具恢复更改让代理成为尝试另一个修复的干净代码库。该工具要求LLM对建议的修复的多个变体进行采样。

(4) Control:允许代理在状态之间移动。express_hypothesis:使代理能够阐明关于错误性质的假设并过渡到“Collect information to fix the bug”状态。discard_hypothesis:允许代理丢弃不再可行的假设,从而导致“Understand the bug”状态。总之,两个命令强制执行假设公式的结构化方法。Collect_more_information:允许代理恢复到“Collect information to fix the bug”状态。goal_accomplished:一旦代理找到了至少一个通过所有测试的修复,调用该工具,终止RepairAgent。

3.5  中间件

        编排LLM代理和工具之间的通信。执行定义1的步骤:

        (1)解析和细化LLM输出:在每个循环开始时,中间件使用当前提示词查询LLM。理想情况下,响应完全符合预期格式(图3)。例如LLM可以提供“路径”参数。RepairAgent试图通过三个步骤将输出映射到预期格式来启发式地纠正类问题。1)试图将响应中提到的工具映射到可用工具之一(检查预测工具名称npredicted是否是任何可用工具nactual的名称的子字符串。若是,则认为nactual是所需工具,若匹配失败,检查npredicted和任何nactual之间的levenshtein距离是否低于阈值)2)方法试图按照与上述相同的逻辑将响应中提供的参数名称映射到工具的参数。3)通过启发式地映射或替换他们来处理无效的参数值(通过用有效的文件路径替换预测的文件路径)

        还检查具有相同参数的相同工具的重复调用,如果代理建议与前一个循环完全相同的命令,通知代理重复并进入一个新的循环。

        (2)调用工具:给定来自LLM的有效命令,调用相应工具,防止工具执行干扰主机环境或RepairAgent本身。

        (3)更新提示词:·给定工具的输出,中间件更新下一个 周期的提示词的所有动态部分。它更新状态描述和可用工具,将工具的输出附加到收集的信息中,并替换显示最后一个执行命令的部分。

      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值