【新智元简介】代码能否运行并不是判断可靠性的标准。 使用语言模型编写代码还需要考虑生产环境中的意外输入。
大型语言模型(LLM)在理解自然语言和生成程序代码方面表现出了非凡的性能。 程序员也开始在编码过程中使用Copilot工具来辅助编程,或者要求LLM生成解决方案。
经过多次迭代,目前LLM生成的代码语法错误很少,与用户输入的文本更加一致,符合预期的语义。 然而,对于LLM代码生成的可靠性和鲁棒性仍然缺乏深入的研究。
可执行的代码不等于可靠,软件开发环境和部署环境都存在很大的不确定性。
如果直接使用LLM生成的代码,可能会因为AP误用(误用)而导致更严重的问题,比如资源泄漏、程序崩溃等; 最糟糕的是,大多数 LLM 代码生成服务的用户都是新手开发人员。 很难识别“看似可运行的代码”下隐藏的问题,这进一步增加了漏洞代码在现实中应用的风险。
现有的代码评估基准和数据集主要关注小任务,例如面试中的编程问题,可能与开发人员工作中的实际需求不匹配。
近日,来自加州大学的两名中国研究人员发布了一个用于评估生成代码的可靠性和鲁棒性的新数据集 RobustAPI,其中包括从 StackOverflow 收集的 1208 个编码问题,涉及 24 个主流 Java API。 评价。
论文链接:
研究人员总结了这些 API 的常见误用模式,并在常用的 LLM 上对其进行了评估。 结果表明,即使对于 GPT-4,生成的代码也有高达 62% 包含 API 误用问题。 如果代码实际上 Deployment 可能会导致意想不到的后果。
与该论文相关的数据和估计器将很快开源。
方法
数据采集
为了利用软件工程领域的现有研究,RobustAPI并不是从头开始构建的,而是基于在线问答论坛中经常出现的Java API滥用数据集ExampleCheck。
研究人员从数据集中选择了 23 个流行的 Java API,涵盖字符串处理、数据结构、移动开发、加密和数据库操作。
然后从Stack Overflow上抓取与上述API相关的问题,并且只选择包含在线答案的问题。 这可以确保RobustAPI是负责任的,并且可以更有效地评估LLM在“人类容易出现的问题”上的表现。 编码能力。
收集数据后,将问题转换为JSON格式,其中包含四个字段:
1. id,分配给样本的唯一标识符
2.api,用于针对大型语言模型问题提示相关API
3.问题,包括问题的标题和描述
4. origin,样本的原始URL
提示生成
研究人员设计了一个提示模板,并用数据集中的样本填充其中,收集了法学硕士的回复,并实现了 API 使用检查器来评估代码的可靠性。
在少样本演示下进行实验时,每个示例都提供了响应的格式,然后将问题放在数据集中,并在最后给出相应的API提示,以模拟新手用户提出的问题。
LLM可以识别对话过程中特殊标签的结构,因此研究人员封装了问题和答案,并指示LLM生成问题的答案。
演示样品
为了深入分析法学硕士的代码生成能力,研究人员设计了两个小样本实验:
1. One-shot-irrelevant,使用不相关的API(例如Arrays.stream)作为语言模型的提示示例。
研究人员假设该示例消除了生成代码中的语法错误。
2. one-shot-relevant,使用相同的API作为示例,包括一组问题和答案。
JAVA API 滥用
研究人员在使用API时,需要充分了解API的使用规则,才能达到理想的API效果。
一个典型的例子就是文件操作。 通过RandomAccessFile打开和写入文件时,需要注意两个使用规则:
1、读取文件可能会抛出异常。
如果在读取预期字节之前达到缓冲区限制,API 将抛出 IndexOutOfBoundsException 异常; 当文件同时被其他进程关闭时,API 将抛出 ClosedChannelException。
为了处理这些异常,正确的实现应该将 API 包装在 try-catch 块中。
2、文件通道使用后应关闭。 否则,如果这段代码片段是在多个实例并发运行的长期程序中,则文件资源可能会被耗尽,代码需要在所有文件操作完成后调用close API。
另一个容易被误用的 API 使用规则的例子是特殊的数据对象 TypedArray,它需要开发人员调用 recycle() 来手动启用垃圾收集。 否则,即使不再使用此 TypedArray,Java 虚拟机中的垃圾回收也将无法进行。 不会被触发。
在没有垃圾回收的情况下使用此 API 会导致未释放的内存消耗,在生产环境中部署后,在大工作负载和高并发下会导致软件系统变慢甚至挂起。
在RobustAPI数据集中,研究人员总结了40条API使用规则,包括:
1、调用API前应检查API保护条件,例如调用File.createNewFile()前应先调用File.exists();
2、API调用顺序,如File.write()后调用close();
3. API 控制结构,例如 SimpleDataFormat.parse() 应该被 try-catch 结构包围。
检测 API 滥用
现有的评估LLM生成代码的研究通常使用手动编写或自动测试生成的测试用例,但即使是高覆盖率的测试用例也只能覆盖语义正确性,无法模拟生产环境中的各种意外输入。 无法对代码的可靠性和鲁棒性进行完美的评估。
为了解决这个问题,研究人员使用静态分析方法,通过代码结构来分析代码误用,而不需要运行测试用例,这样可以保证对整个程序的全面覆盖,并且比测试解决方案更加高效。
为了评估代码中API使用的正确性,首先从代码片段中提取调用结果和控制结构,然后根据API使用规则检测API滥用。
代码检查器首先检查代码片段以确定它是方法片段还是类方法。 然后它可以封装代码片段并从代码片段构造抽象语法树(AST)。
然后检查器遍历AST并按顺序记录所有方法调用和控制结构,从而生成调用序列; 检查器将调用顺序与API使用规则进行比较,确定每个方法调用的实例类型,并以类型和方法为key检索对应的API使用规则。
最后,检查器计算调用序列和 API 使用规则之间的最长公共序列:如果调用序列与预期的 API 使用规则不匹配,则报告 API 误用。
实验结果
研究人员使用 4 种语言模型(GPT-3.5、GPT-4、Llama-2、Vicuna-1.5)对 RobustAPI 进行评估。
将包含 API 误用的可编译答案除以所有可编译答案后,计算出每种语言模型的误用率。
从实验结果来看,即使是最先进的商业模型,例如GPT-3.5和GPT-4,也存在误操作的问题。
尽管大多数 Llama 答案不包含代码,但 Llama 在零样本设置中的 API 误用率最低。
一个违反直觉的发现是,虽然 OpenAI 官方声称 GPT-4 相比 GPT-3.5 在代码生成方面有 40% 的性能提升,但 GPT-4 的代码误用率实际上更高。
这一结果也表明,实际生产中代码的可靠性和鲁棒性并未受到业界的重视,这个问题还有巨大的改进空间。
参考: