语言建模的新时代已经到来,大型语言模型(LLM)能力非凡,不仅能理解自然语言,甚至能根据用户需求生成定制代码。
因此,越来越多的软件工程师选择查询大型语言模型来解答编程问题,比如使用 API 来生成代码段或检测代码中的 bug。相比于搜索 Stack Overflow 等 *** 编程论坛,大型语言模型可为编程问题检索到更加合适的定制版答案。
LLM 的速度很快,但这也掩盖了其代码生成中的潜在风险。从软件工程的角度看,即便已经有许多研究成果问世(涉及避免句法错误以及提升对生成代码的语义理解等方面),LLM 的生成代码能力的稳健性和可靠性还没有得到透彻的研究。
不同于 *** 编程论坛的情况,LLM 生成的代码没有得到社区同行的审查,因此可能出现 API 误用问题,例如在文件读取和变量索引中缺少边界检查、缺少文件 I/O 关闭、交易完成失败等。即使生成的代码样本可以执行或者能正确执行功能,误用也可能导致产品出现严重的潜在风险,比如内存泄漏、程序崩溃、垃圾数据收集失败等。
更糟糕的是,提出这些问题的程序员还是最容易受到打击的人,因为他们更有可能是 API 新手,无法辨别生成的代码段中的潜在问题。
下图展示了一个软件工程师向 LLM 询问编程问题的示例,可以看到 Llama-2 能给出句法正确、功能正确、语法对齐的代码段,但却存在不够稳健可靠的问题,因为其中没有考虑到文件已存在或文件夹不存在的情况。
因此,在评估大型语言模型的代码生成能力时,必须考虑代码的可靠性。
在评估大型语言模型的代码生成能力方面,大多数现有基准关注的重点是所生成代码的执行结果的功能正确性,这意味着只要生成的代码能够满足用户的功能需求,用户就能接受。
但在软件开发领域,代码光是能正确执行可不够。软件工程师需要的是代码能正确且可靠地使用新 API,长期运行也不会有潜在风险。
此外,当前大多数编程问题的范围都与软件工程相距甚远。其数据源大都是网上的编程挑战赛 *** ,比如 Codeforces、Kattis、Leetcode 等。尽管成就非凡,但这还不足以为实际应用场景的软件开发工作提供帮助。
为此,加州大学圣迭戈分校的 Li Zhong 和 Zilong Wang 提出了 RobustAPI,该框架可以评估大型语言模型生成的代码的可靠性和稳健性,其中包含一个编程问题数据集和一个使用抽象语法树(AST)的评估器。
论文地址:https://arxiv.org/pdf/2308.10335.pdf
其中数据集的目标是创建一个接近真实软件开发的评估设置。为此研究者从 Stack Overflow 收集了有关 Java 的代表性问题。Java 是更流行的编程语言之一,得益于其一次编写到处运行(WORA)的特性,被广泛用于软件开发。
对于每一个问题,研究者都提供了详细的描述和相关的 Java API。他们还设计了一套用于调用大型语言模型来生成代码段及相应解释的模板。
研究者还提供了一个评估器,其能使用抽象语法树(AST)分析所生成的代码段并将它们与预期的 API 使用模式进行比较。
研究者也按照 Zhang et al. (2018) 的 *** 将 AI 使用模式形式化地表示成了结构化的调用序列。这种结构化的调用序列能表明可以如何正确使用这些 API 来消除潜在的系统风险。从软件工程的角度看,任何违反这种结构化调用序列的现象都将被视为失败。
研究者从 Stack Overflow 收集了 1208 个真实问题,其中涉及 24 个代表性的 Java API。研究者也进行了实验评估,其中不仅实验了闭源的语言模型(GPT-3.5 和 GPT-4),也实验了开源的语言模型(Llama-2 和 Vicuna-1.5)。对于模型的超参数设置,他们使用了默认设置,未进行进一步超参数调节。他们也设计了两种实验形式:零样本(zero-shot)和单样本(one-shot),即分别在 prompt 中提供零个或一个演示样本。
研究者全面分析了 LLM 生成的代码并研究了常见的 API 误用情况。他们希望借此让人们了解 LLM 在生成代码时误用 API 的重要问题,同时这项研究也能为 LLM 的评估提供一个新的维度,而不只是常用的功能正确性。此外数据集和评估器还将开源。
本论文的贡献总结如下:
提出了一种用于评估 LLM 代码生成的可靠性和稳健性的新基准:RobustAPI。提供了一个完善的评估框架,其中包括一个由 Stack Overflow 问题构成的数据集和一个使用 AST 的 API 使用情况检查器。研究者基于此框架分析了常用 LLM 的性能表现,包括 GPT-3.5、GPT-4、Llama-2 和 Vicuna-1.5。全面分析了 LLM 生成代码的表现。他们总结了每种模型常见的 API 误用情况,并指出了可供未来研究改进的方向。RobustAPI 是一个用于全面评估 LLM 生成代码的可靠性和稳健性的框架。
下面将描述构建该数据集时的数据收集过程和 prompt 生成过程,然后将给出 RobustAPI 中评估的 API 误用模式并讨论误用的潜在后果,最后还将给出用 RobustAPI 检测 API 误用情况的静态分析,其中使用的 *** 是抽象语法树。
结果发现,相比于关键词匹配等基于规则的 *** ,新 *** 能以更高的准确度评估 LLM 生成代码的 API 误用情况。
数据收集
为了利用软件工程领域的已有研究成果,研究者构建 RobustAPI 时立足的起点是来自 ExampleCheck (Zhang et al. 2018) 的数据集。ExampleCheck 是用于研究 *** 问答论坛中常见 Java API 误用情况的框架。
研究者从该数据集选取了 23 个常见的 Java API,如下表 1 所示。这 23 个 API 覆盖 5 个领域,包括字符串处理、数据结构、移动端开发、加密和数据库操作。
prompt 生成
RobustAPI 还包含一个 prompt 模板,可使用数据集中的样本来填充。然后研究者收集 LLM 对该 prompt 的响应,再通过一个 API 使用检查器来评估其代码可靠性。
在该 prompt 中,首先会给出任务介绍和所需的响应格式。然后,如果执行的实验是少样本实验,则还会给出少样本的演示。下面是一个示例:
演示样本
演示样本已被证明有助于 LLM 理解自然语言。为了透彻地分析 LLM 的代码生成能力,研究者设计了两种少样本设置:单样本无关演示和单样本相关演示。
在单样本无关演示设置中,为 LLM 提供的演示示例使用的 API 是无关的。研究者假设这种演示示例能消除生成代码中句法错误。RobustAPI 中使用的无关示例如下:
在单样本相关演示设置中,为 LLM 提供的演示示例使用的 API 与给定问题所用的 API 一样。这种示例包含一对问题和答案。这种演示示例中的问题并不包含在测试数据集中,而且研究者人工修正了其中的答案以确保其中不存在 API 误用情况并且答案和问题的语义很好地对齐了。
Java API 误用
研究者为 RobustAPI 中的 23 个 API 总结了 40 条 API 规则,它们在这些 API 的文档中得到了验证。这些规则包括:
(1) API 的守卫条件,这应该在 API 调用之前进行检查。举个例子,在 File.createNewFile () 之前应检查 File.exists () 的结果。
(2) 所要求的 API 调用序列,即应当以一定顺序调用 API。比如,应在 File.write () 之后调用 close ()。
(3) API 的控制结构。比如,应把 SimpleDateFormat.parse () 包含在 try-catch 结构中。
下面给出一个例子:
检测 API 误用情况
为了评估代码中 API 使用的正确性,RobustAPI 可根据 API 使用规则检测 API 误用情况,其做法是从代码段中提取调用结果和控制结构,如下图 2 所示。
代码检查器首先会检查生成的代码段,看这段代码是某个 *** 中的一段代码,还是来自某个类的一个 *** ,以便它可以封装该代码段并使用其构建抽象语法树(AST)。
然后该检查器会遍历该 AST 并按顺序记录所有的 *** 调用和控制结构,这会生成一个调用序列。
接下来,该检查器会将这个调用序列与 API 使用规则进行比较。它会推断每个 *** 调用的实例类型,并将该类型和 *** 用作键来检索相应的 API 使用规则。
最后,该检查器会计算这个调用序列和 API 使用规则之间的最长公共序列。
如果这个调用序列和预期的 API 使用规则不匹配,则该检查器就报告出现了 API 误用。
研究者在 4 个 LLM 上评估了 RobustAPI:GPT-3.5、GPT-4、 Llama-2 和 Vicuna-1.5 。
实验中所使用的评估指标包括:API 误用率、可执行样本百分比、总体 API 误用百分比。
实验的目的是试图回答以下问题:
问题 1:这些 LLM 在解答真实世界编程问题时的 API 误用率是多少?问题 2:无关的演示样本会对结果产生什么样的影响?问题 3:正确的 API 使用示例能降低 API 误用率吗?问题 4:为什么 LLM 生成的代码无法通过 API 使用检查?具体的实验过程请参阅原论文,这里给出研究者得到的 5 个发现:
发现 1:当前更佳的大型语言模型对真实世界编程问题的答案普遍存在 API 误用问题。
发现 2:在所有包含可执行代码的 LLM 答案中,57-70% 的代码段都有 API 误用问题,这可能给生产带来严重后果。
发现 3:无关样本示例无助于降低 API 误用率,但会触发更有效的答案,这能有效地用于对模型性能的基准评测。
发现 4:某些 LLM 可以学习正确的使用示例,这能降低 API 误用率。
发现 5:GPT-4 包含可执行代码的答案数量最多。对于基准 API,不同的 LLM 的误用率趋势也不同。
此外,研究者还在论文中展示了一个基于 GPT-3.5 的典型案例:模型在不同的实验设置下有不同的反应。
任务是要求模型帮助使用 PrintWriter.write API 将字符串写入一个文件。
在零样本和单样本无关演示设置下,答案稍有不同,但都出现了 API 误用问题 —— 没有考虑例外情况。在给模型提供了正确的 API 使用示例后,模型学会了如何使用 API 并给出了可靠的代码。
更多细节请参阅原论文。