这是一篇来自arXiv的论文,属于对使用大模型进行缺陷定位的一次探索,题目为"A Preliminary Evaluation of LLM-Based Fault Localization"。
大型语言模型(Large Language Model,LLM)在多个软件工程问题上表现出令人惊讶的性能水平。本文关注自动化软件工程中的一个分支——缺陷定位(Fault Localization,FL)。在缺陷定位中,从业者必须从潜在的大型代码库中找到存在缺陷代码元素。相比于传统模型,LLM在性能和可解释性方面更有优势。本文提出了一种基于LLM的自动化缺陷定位技术——AutoFL。
在缺陷定位中,给定一个bug的特征(比如一个失败的测试或者一个bug报告),任务是识别造成bug的代码元素[1]。缺陷定位的一个关键输入是整个软件存储库,但这个输入对于LLM来说太大了,LLM模型很难简单地对其进行处理。根据作者调研,一次可以处理最多令牌的LLM,OpenAI的gpt-4-32k,只能处理32000个令牌,而目标项目可以有96000行代码。因此,这对于LLM应用于FL是一个技术障碍。
尽管如此,能够利用LLM进行缺陷定位可能会让开发人员受益。首先,在程序修复和测试中,给定相同的软件工件(artifacts)和计算资源,LLM显示出比传统技术更好的性能[2,3,4]。开发者经常需要更大的关于FL结果是如何得出的上下文或解释。现有的自动FL技术以明显不同于人类的方式得出它们的答案,因此不适于生成可理解的解释;另一方面,LLM可以生成对其调试过程的解释[5],因此基于LLM的FL可以帮助开发人员理解模型给出的结果。
为此,本文提出了AutoFL,一种结合OpenAI LLMs的函数调用能力的技术,并为LLM提供查看repository选定部分的工具,以及将LLM结果与实际代码元素匹配的后处理管道,大大降低了提示要求,促进LLM有效地定位缺陷。具体来说,给定一个测试及其失败堆栈(stack),作者允许LLM通过调用函数来导航到(定位到)特定的源代码;这些函数返回关于覆盖类、它们的覆盖函数以及任何覆盖函数的实现和Javadoc的信息。给定一个请求,要求LLM使用可用的函数找到答案;在此过程中LLM将通过一个函数调用序列来收集相关信息,并得出关于bug如何出现的结论。最后,输出一个最有可能导致bug的方法作为缺陷定位的结果。AutoFL模型的框架如图1所示。模型的流程如下:
在第一阶段:
① AutoFL向LLM提供一个提示(可以理解为输入),其中包含失败的测试信息和对LLM调试可用函数的描述。
② LLM自主地与所提供的函数进行交互,以提取调试给定缺陷所需的信息。
③ 根据收集的信息,LLM生成一个关于观察到的缺陷的根本原因的解释。
在第二阶段:
④ 用户查询已识别bug的位置。
⑤ LLM通过提供缺陷方法(FL的输出)做出响应。
在整个过程中,Listing 1中显示的系统消息用于指导LLM扮演调试助手的角色;其中,LLM环境中的系统消息指的是为指导模型行为而提供的消息,该消息可以包括期望语言模型在对话期间遵循的指令。其实就是给GPT上下文。
AutoFL分为两个阶段:
为了向LLM提供关于失败测试的信息,AutoFL自动生成一个对LLM的查询,其中包含错误的详细信息,比如:失败的测试及其错误堆栈。Listing 2显示了提示的示例,失败细节用蓝绿色突出显示。
该提示指定失败测试的名称,并提供测试代码片段(第1-9行)。测试代码片段用三个反斜线(即:```)括起来,表示它是一个代码块。为了只提供必要的信息,作者将代码片段最小化,使之只包含失败发生之前的语句,并用注释//error occurrence here
明确标记。如果失败在嵌套块中,则包含错误的整个最外层语句。此外,任何前面的断言语句都会被检测并删除。例如,Listing 2中的第384行被删除,因此不可见。
在代码片段之后,提示符显示了由错误消息和堆栈跟踪组成的缺陷症状(第13-14行)。通过仅保留与目标库相关的信息(例如,省略与外部库相关的行),以最小化堆栈跟踪。此外,出现五次以上的重复子序列会被压缩,以提高可读性和简洁性,这有助于处理长堆栈跟踪,例如StackOverflow错误。
最后,提示结束时建议LLM调用get_covered_classes函数(第16行),以鼓励其在生成答案时使用函数(这里没懂呀)。虽然AutoFL在其提示中使用单个测试,但是通过连接每个测试的信息,可以很容易地扩展提示以处理多个失败的测试。
此外,LLM还提供了四个专门的调试功能(如图1所示)。图中用红色表示的前两个函数允许LLM获得与失败测试相关的类级和方法级覆盖率信息。有了这些功能,LLM可以缩小与观察到的缺陷相关的方法范围,从而能够有针对性地分析根本原因。后两个函数在图中用蓝色表示,构成了通用的代码导航工具。这些函数将可疑方法的签名作为输入,并返回代码片段和相关文档。
总的来说(参照图1),AutoFL将初始提示和函数描述一起提供给LLM,并允许它“决定”是请求函数调用还是解释bug。如果LLM请求一个函数调用,AutoFL将执行该函数,并通过将结果添加到消息历史中来将返回值返回给模型。一旦LLM生成了对根本原因的解释,而没有请求进一步的函数调用,阶段1就结束了。如果LLM耗尽了它的函数调用预算,AutoFL就直接进入阶段2。在这种情况下,LLM不再被允许请求函数调用,必须使用可用信息生成响应。
第一阶段结束后,LLM会被提示根据可用的信息预测问题方法。这个请求的提示如Listing 3所示。在这个阶段,与阶段1不同,AutoFL不向LLM提供任何功能。相反,AutoFL假设LLM已经识别了缺陷位置,同时理解了缺陷的根本原因,强制模型立即响应。最后,整个FL过程以LLM提供包括潜在缺陷位置的响应而结束。
例如,给定第1阶段中关于Lang-48(Listing 2)的初始提示,LLM依次进行四次函数调用:首先,获取失败测试覆盖的类和方法,然后检索EqualsBuilder的两个方法isEquals()和append(Object,Object)的代码片段。然后,LLM确定错误的根本原因:错误地将equals方法用于BigDecimal对象,导致基于reference而不是append方法中的value进行比较。在第2阶段,LLM确定EqualsBuilder.append(Object,Object)为缺陷代码。
为了解决LLM固有的可变性,作者建议重复AutoFL过程_R_次。重复后,将这些结果合并成一个单一的FL结果。值得注意的是,如果存在多个失败的测试,需要对AutoFL的每次运行使用不同的失败测试用例。具体来说,如果只有一个失败的测试用例,那么所有的迭代都是用那个特定的测试用例进行的。当有多个失败的测试用例时,采用循环法,为每次运行选择一个失败的测试用例,以确保迭代的均匀分布。如果失败测试用例的数量超过预定义的最大重复计数_R_,则将选择限制为只有_R_失败测试用例。
给定从AutoFL生成的_R_个预测,聚合输出以驱动可疑方法的排序列表。首先,根据方法是否出现在R次运行生成的最终预测中对AutoFL标记为可疑的方法进行评分。具体来说,如果一个最终的预测包含总共个_n_个方法,AutoFL会给每个确定的方法一个分。这些单独的分数之后在所有的_R_个预测中结合起来。例如:假设5次运行的最终预测是{m1,m2}、{m2}、{m2,m3}、{m3}和{m2,m4},方法m2的分数将被计算为:0.5 + 1.0 + 0.5 + 0.0 + 0.5 = 2.5。在分数相等的情况下,出现早的预测方法优于其他方法。例如,在给定的示例中,得到的排序列表将是[m2,m3,m1,m4]。
如果有一些方法不是最终AutoFL结果的一部分,但是被失败的测试用例所覆盖,则将它们添加到排序列表的末尾,以确保列表包括所有与失败相关的方法。这些方法按照涵盖每种方法的失败测试数量的降序排列。优先考虑在AutoFL的函数交互过程中更频繁提到的方法,这是基于这样的直觉,即:被LLM检查的方法或者与被检查的方法相关的方法比在调试过程中从未被观察到的方法更有可能出错。
这篇文章读下来给我的感觉是:它更多的是对LLM的应用。算是入门LLM的起步吧。
参考文献
[1] Wong W E, Gao R, Li Y, et al. A survey on software fault localization[J]. IEEE Transactions on Software Engineering, 2016, 42(8): 707-740.
[2] Jiang N, Liu K, Lutellier T, et al. Impact of code language models on automated program repair[J]. arXiv preprint arXiv:2302.05020, 2023.
[3] Kang S, Yoon J, Yoo S. Large language models are few-shot testers: Exploring llm-based general bug reproduction[C]//2023 IEEE/ACM 45th International Conference on Software Engineering (ICSE). IEEE, 2023: 2312-2323.
[4] Xia C S, Wei Y, Zhang L. Practical program repair in the era of large pre-trained language models[J]. arXiv preprint arXiv:2210.14179, 2022.
[5] Kang S, Chen B, Yoo S, et al. Explainable Automated Debugging via Large Language Model-driven Scientific Debugging[J]. arXiv preprint arXiv:2304.02195, 2023.