赞
踩
CODEWISDOM
ChatGPT编程能力实证研究
刘子夕 冯洋1 陈碧欢2 娄一翎 彭鑫 陈振宇
1 fengyang@nju.edu.cn;
2 bhchen@fudan.edu.cn
南京大学 计算机软件新技术国家重点实验室
复旦大学 计算机科学技术学院
摘要
近年来,大型语言模型(LLM)得到了快速的发展,这些模型可以自动编码文本并生成具有上下文相关性的语言,对自然语言处理领域的研究和应用带来了革命性的变化。其中,在对话、翻译、编程等方面具有卓越性能的ChatGPT模型备受关注。本研究通过制定各类编程任务,并召集软件工程专业学生作为志愿者,探索ChatGPT在编程任务中的能力和边界,并提出未来研究方向建议。研究设计了5类开发任务和3类非开发任务,志愿者通过与ChatGPT多轮交互尝试完成任务。通过对志愿者完成情况的分析,我们发现尽管ChatGPT具有良好的编程能力和程序理解能力,但仍存在输入输出长度限制、无法修复代码错误等能力边界,复杂软件开发和创造性开发工作仍需要高度依赖经验丰富的程序员来完成。最后,结合LLM模型的特点,本文针对软件工程领域提出了一些建议,包括如何将LLM嵌入至软件开发生命周期等,以期为软件工程领域的研究和应用提供有益的参考。
1 介绍
LLM(Large Language Model)是指可以处理大规模自然语言数据的语言模型,目前最著名的LLM是OpenAI的GPT(Generative Pre-trained Transformer)系列,包括GPT-3、GPT-4等。GPT是一种基于Transformer架构的神经网络模型,采用无监督预训练和有监督微调的方法进行训练,可以生成各种自然语言任务的文本,如对话、摘要、翻译、问答等。ChatGPT是目前最大的LLM之一,具有1750亿个参数,在多种自然语言处理任务中取得了出色的表现。除了GPT系列,还有一些其他的开源工具也可以用于大规模自然语言处理,其中代表性的包括:
1 | BERT 由Google开发的基于Transformer架构的预训练语言模型,用于各种自然语言处理任务,如文本分类、命名实体识别、问答等。 |
2 | ELMO 由斯坦福大学开发的基于双向LSTM架构的预训练语言模型,可以生成词向量,用于各种自然语言处理任务。 |
3 | Transformer-XL 由CMU和谷歌联合开发的基于Transformer架构的预训练语言模型,采用自回归和非自回归的混合训练方式,可以处理长文本。 |
4 | GPT-Neo 由EleutherAI开发的基于GPT架构的开源语言模型,具有数十亿个参数,可以用于生成各种自然语言任务的文本。 |
5 | T5 由Google开发的基于Transformer架构的预训练语言模型,采用迁移学习的方法,可以用于各种自然语言处理任务。 |
这些工具主要是为自然语言处理而设计的,可以处理一些与编程相关的任务,比如代码注释生成、代码自动补全、代码语法检查等,为软件工程领域诸多编码、测试等任务提供了智能化解决方案。为了验证LLM的实际编程能力,我们设计了五类开发任务和三类非开发任务,涉及C/C++、Java、Python和Rust编程语言,每个任务将分别由A组和B组的三位志愿者尝试使用ChatGPT完成,A组/B组分别是南京大学软件学院的本科大二学生和研究生,任务完成后,我们收集志愿者的完成过程及结果,并收集志愿者的主观评价反馈。
2 开发能力评估
在计算机相关的专业中,一般会涉及到五类编程能力的培养。在入门阶段,通过学习C或Java编程语言,学习基本语法特点,然后学生通过在OJ上完成编程练习,不断提高自己应用一个编程语言的能力,将实际问题通过设计算法并编码实现的方式来完成。这对应算法与数据结构开发,需要开发人员具备一定的数学和计算机基础,能够针对具体问题设计高效的算法和数据结构,解决实际开发任务,这也属于软件开发最基本的考核标准之一,各大互联网企业在招聘时发布的机考试题也属于此类编程任务。
在掌握基本的语法和数据结构知识之后,学生一般会学习具体应用技术,如游戏开发和管理系统开发,在这类系统级的开发任务中,需要进一步学习面向对象的开发思想,提高对于开发框架的理解和应用能力。这分别对应应用与游戏开发和管理系统开发。应用与游戏开发属于更加实际的开发任务,需要开发人员熟悉各种开发工具和框架,同时需要对用户体验和界面设计有敏锐的察觉,以提供出色的用户体验。管理系统开发需要开发人员熟悉业务流程和管理原理,能够设计高效的系统架构和数据库结构,掌握主流和成熟的开发架构和设计模式,分别完成前后端代码的编写,最终构建出各类功能完备的管理系统。以上两类开发任务对应互联网企业中的前端工程师、后端工程师等技术岗位的要求。
更进一步,学生还会学习操作系统和编译器等底层基础软件的原理,并通过一些小实验来体会基础软件中的算法思想和实现原理。基础软件开发需要开发人员深入了解底层硬件和操作系统原理,能够设计和实现高性能、高可靠的系统软件,如编译器、操作系统核心、数据库管理系统等,确保系统的稳定运行。此类开发任务极度困难,需要高度的技术能力和长期投入,我国在基础软件领域的自主创新仍然存在挑战,正在加强自主研发此类软件。
高年级学生可能会参与科研项目,往往涉及到一些科研工具的开发,这类开发任务具有独特的需求,在开源代码平台中也没有可以直接复用的方案,需要自行理解开发需求,然后拆解任务后,设计算法并完成编码。研究型工具开发需要开发人员具备强大的研究和分析能力,能够设计和实现高效、可扩展的工具,帮助研究人员处理复杂的数据和信息,提升研究效率和质量。
基于以上五个维度,我们共设计了五类开发任务,每个类型的任务设计了三种不同难度的子任务,其中,“应用与游戏开发”和“基础软件开发”属于开发工程量较大的任务,测试者可在1.5小时内尝试这两种任务,其他任务的规定时限为1小时。所有测试者均使用OpenAI官方免费版ChatGPT-3.5(3.23发布版)。
2.1 算法与数据结构
2.1.1 任务说明
在OJ平台的算法与数据结构编程题目经常被用于考察程序员的编程能力。在此任务中,我们选用全球著名的在线评测系统Codeforces,每个题目都有难度评分,在所有开放题目中,最低的难度评分为800,最高的难度评分为3500。因此,我们选择两道难度评分为800的题目作为简单任务,评分为1900和2100的题目作为中等难度任务,两道评分为3500的题目作为困难任务,题目均使用英语描述。
2.1.2 测评结果
在此任务中,我们首先选择了力扣(LeetCode)平台,该平台支持多种编程语言,有难度和算法标签,题目描述直观,但是,经过测试发现,随机选取6道不同难度的题目,直接复制到ChatGPT后,都可以直接返回完全正确的代码,这可能是ChatGPT的训练数据集包含了LeetCode的题目和代码。
发现1:将LeetCode平台的题目复制到ChatGPT中,编码正确率为100%,且适用于不同难度、不同编程语言的算法题目。
为了测试ChatGPT的真实编程能力,我们将OJ系统更换为Codeforces,6位测试者的完成情况如下:
注:“o”代表测试者认为ChatGPT输出的代码部分正确,但在Codeforces上并不能通过,“×”代表生成的代码完全错误;“√”代表生成的代码可以在Codeforces上通过。
从结果来看,ChatGPT完全无法像人类程序员一样在Codeforces上完成编程任务。6位测试者在与ChatGPT的交互过程中,都首先直接复制完整英文题目输入到ChatGPT中,若未指定编程语言,则ChatGPT默认输出Python代码,当测试者提交代码后出现wrong answer之后,给ChatGPT输入测试用例和预期输出,或提示修改代码,避免运行超时,但ChatGPT重新生成的代码依然无法在Codeforces上通过。
发现2:将Codeforces OJ平台的题目复制到ChatGPT中,简单难度的题目完成正确率为8.3%,部分正确的比例为25%;中等难度的题目完成正确率为25%;困难难度的题目完成正确率为0。
发现3:无法通过输入测试用例和预期结果的方式,使ChatGPT修改代码,达到开发需求。
发现4:在不指定编程语言的情况下,ChatGPT默认使用Python语言输出编码结果。
2.2 应用与游戏开发
2.2.1 任务说明
应用与游戏开发属于软件工程领域内经典的开发任务,我们选取一个比较经典的贪吃蛇游戏开发任务,考察ChatGPT能否完成代码编写。从功能复杂程度由易到难,分别设置三个子任务,简单任务只需要搭建一个游戏地图,并且通过键盘方向键控制像素点的移动;在此基础上,增加随机像素点作为食物,且贪吃蛇移动到食物位置之后,自身长度增加,这些功能点作为中等难度的开发需求;对于困难的开发需求,再增加控制游戏难度和贪吃蛇移动速度的功能。具体需求概述如下:
简单:用C++写一个贪吃蛇游戏,创建一个矩形地图,用像素点表示贪吃蛇,用户可以通过方向键控制贪吃蛇的移动。
中等:用C++写一个贪吃蛇游戏,每次开始游戏时,地图上随机出现一些像素点,用户通过方向键控制贪吃蛇,吃掉尽可能多的食物,碰到墙壁或蛇身则游戏结束。
困难:用C++写一个贪吃蛇游戏,地图上随机出现一些像素点,用户通过方向键控制贪吃蛇,吃掉尽可能多的食物,碰到墙壁或蛇身则游戏结束,可以控制难度和速度,游玩过程中会不断加速。
2.2.2 测评结果
共计6位测试者参与此项编程任务,其中有4位比较顺利地完成了开发任务,简单、中等、困难任务均完成80%以上开发需求;而有2位同学的完成度较低,三个难度等级的任务均只完成了50%左右的开发需求,详细测评结果如下表:
注:具有充足经验的测试者曾完成过中等以上难度的开发任务;无经验的测试者以前从未接触过此类开发任务。完成情况表示“困难”难度的开发任务,所有测试者“简单”和“中等”难度的完成度都超过80%。
对于C++的初学者来说,使用C++进行贪吃蛇游戏的开发任务,是一个比较基础和经典的练手项目,其难点在于需要对复杂的功能需求进行理解和拆分,然后封装成多个函数,最后借助图形化界面的库来实现游戏的简易图形化显示。一般来说,对于一个没有相关开发经验的程序员,需要设计函数功能模块和实现方式,以及调研图形化界面库的使用方式,至少需要花费3~5小时来完成初步开发,而借助ChatGPT,66.7%的测试者在一小时内完成开发任务,说明ChatGPT具有良好的编程效率。
发现5:66.7%的测试者可以借助ChatGPT,在1小时内完成相对复杂的游戏开发任务。
在测试中,有两位测试者使用ChatGPT编程并不顺利。其中,1号测试者使用MacOS操作系统,当ChatGPT生成出调用Windows系统专用的图形化界面库之后,测试者要求更换一个库,但更换库之后,ChatGPT提供的代码频频出现报错问题,报错原因均与依赖库相关。第二位测试者从未开发过此类程序,使用Windows操作系统,但使用Dev C++ IDE(已停止维护,且没有完善的可视化开发功能,不适用于开发图形化界面的软件[ref-wiki]),由于环境配置相关的问题,导致代码一直无法编译运行,最终整个游戏开发的完成度较低。
值得注意的是,编号为5的测试者也完全没有此类任务的开发经验,且使用非windows操作系统,但他基本顺利完成了开发任务。从交互记录中可以看到,测试者要求ChatGPT换了一个Linux系统的图形化界面库,代码编译运行成功后,出现了一些不符合预期的情况,测试者经过反复细化需求,使ChatGPT逐个解决问题,输入代码片段要求ChatGPT修改细节,最终完成了游戏开发。这说明ChatGPT的编程能力也受到测试者对代码的理解能力影响,若测试者能看懂和理解ChatGPT输出的代码,有利于进一步提出要求使ChatGPT完善代码。
发现6:使用相对小众的开发环境时(如MacOS和Linux操作系统、Dev C++ IDE等开发工具),ChatGPT有66.7%的概率提供不符合需求的代码。
2.3 管理系统开发
2.3.1 任务说明
管理系统开发属于传统的软件开发任务,用于支持企业或组织的管理活动,一般涉及到需求分析、开发架构设计、开发和集成、测试和部署等系列步骤,我们在此任务中重点考察ChatGPT能否辅助设计开发架构并完成代码开发。结合实际开发步骤,我们设置简单任务为编写数据库构建的脚本;在建好数据库的基础上,中等难度任务则要求ChatGPT分别实现前后端代码的编写,不同用户角色登陆后跳转至不同页面;困难模式则是在此基础上,丰富页面展示内容,也会涉及代码与数据库更复杂的交互。具体任务说明如下:
简单:假设要开发一个在线商店网站,要求GPT提供构建数据库的脚本。要求:用户角色至少包含用户和管理员,用户可以浏览和购买商品,管理员可以上传和下架商品,商品信息包含名称、描述、价格等。
中等:假设要开发一个在线商店网站,要求GPT提供前后端代码,实现管理员和用户登录,两种角色登录后跳转至不同页面。
困难:在实现线商店网站的注册与登录的基础上,搭建一个数据库用于存储商品信息,用户页面可以看到商品信息,管理员可以上传新的商品。
2.3.2 测评结果
管理系统的开发任务完成度出现了明显的两级分化情况,6位测试者中,有3位借助ChatGPT基本完成了三个难度等级的任务;而另外3位只能顺利完成简单任务,在中等和困难任务上只有50%甚至更低的完成度。详细的测评结果如下表:
发现7:对于简单开发需求,ChatGPT可以100%完成数据库建库建表的脚本编写。
发现8:ChatGPT在困难任务上的平均完成度是46.6%。
简易的管理系统开发不涉及很复杂的算法,但包含与数据库的交互,和前后端代码编写,一般采用MVC架构模式,因此存在较为复杂的类与对象的调用依赖关系。前端代码和数据库增删改查的语句都具有明显的结构化特征,易于理解和学习,但人工编写此类代码比较繁琐。从测试结果来看,ChatGPT在管理系统上的开发能力和效率都与测试者本身对此任务的熟悉程度高度相关。在所有测试者中,4号测试者的完成度最低,实际上,他也是唯一一位以前从未开发过管理系统的测试者,尽管他在中等和困难任务上与ChatGPT交互超过10次、尝试时间大于半小时,依然是所有测试者中完成度最低的。从交互记录来看,他并没有指定开发框架和编程语言,ChatGPT提供了Python代码并依赖Flask框架的后端代码,但由于测试者并没有拆解任务目标,ChatGPT提供的代码存在30%~50%比例的报错,导致整体开发完成度低。
发现9:对于管理系统开发,不进行任务拆解会100%导致ChatGPT无法完成开发需求,会出现30%~50%比例的报错情况。
完成情况最好的是2号和3号测试者,他们都具有丰富的管理系统开发经验,由于熟悉开发流程,他们可以提示ChatGPT使用合适的开发框架,如Springboot等,并且可以顺利进行代码理解和拼接。1号和5号测试者以前都有过相关的开发经验,但时间开发经验比较久远,或只熟悉前端/后端部分开发,因此,开发效率相较于经验丰富的2、3号测试者略低一些。然而,具有丰富开发经验的6号测试者的完成度不高,从交互记录来看,他确实没有因为代码理解而影响开发速度,还主动提示ChatGPT使用正确的开发架构,但在配置环境上出现了很多问题,ChatGPT提供的解答并不能真正解决开发环境中出现的“意外”现象,甚至还会引入新的问题,导致代码的编译运行并不顺利。
发现10:对于熟悉管理系统开发的测试者,借助ChatGPT完成此任务,中等难度的平均完成度是93.3%,困难难度的平均完成度是76.6%。
发现11:ChatGPT无法处理开发过程中的工具及环境配置问题。
2.4 基础软件开发
2.4.1 任务说明
基础软件是一种用于支持计算机系统运行和提供基本功能的软件,包括操作系统、驱动程序、系统工具、库文件和编译器等。此类软件与2.2的应用游戏、2.3的管理系统等应用软件相对,开发难度更大,高度依赖专业基础知识,软件的逻辑复杂性极高。经过初步尝试,直接提出“开发一个C语言编译器”等需求时,ChatGPT完全无法直接给出相应的开发代码,因此,我们参考《编译原理》课程的实践内容,由易到难,设计了以下三个不同难度等级的开发任务,均为编译器开发的子功能模块,具体任务说明如下:
简单:我们提供一系列自定义语法规则,需要ChatGPT开发一个语法解析工具,这个工具支持接收输入一段程序后,输出对应的语法解析树。
中等:我们提供一系列自定义语法规则,需要ChatGPT开发一个编译工具,这个工具支持接收parser解析结果,输出对应的中间码。
困难:我们提供一系列自定义语法规则,需要ChatGPT开发一个编译优化工具,这个工具支持接收输入一个中间码,输出对应的优化中间码,具有更高的编译效率。
2.4.2 测评结果
经过6位测试者的尝试,反馈结果高度一致,对于简单任务,有2位的测试者达成50%完成度,2位的测试者达成80%的完成度,其他2位的测试者的完成度小于30%;对于中等和困难任务,均只有1位测试者的完成度是30%,而其他测试者均表示ChatGPT的开发结果完全不符合要求。绝大多数测试者表示ChatGPT提供的代码超过70%的概率无法编译运行,主要原因是代码会出现报错,也有少量出现程序崩溃的现象。而对于代码报错的情况,测试者普遍表示,经过数轮交互后,ChatGPT仍无法修正。
发现12:ChatGPT在基础软件开发上的能力非常有限,以编译器开发为例,词法分析的平均完成度约为53.3%,语法分析和中间代码优化的平均完成度均低于5%。
发现13:对于基础软件开发,ChatGPT提供的代码超过70%的概率无法编译运行,经过3~5论交互后也无法修正错误。
2.5 研究型工具开发
2.5.1 任务说明
在软件工程领域的科研课题中,往往有一些自定义的工具开发需求,不同于工业生产应用的通用开发框架,研究型工具开发没有固定的开发框架或编程语言限制,在网络和开源社区也几乎没有可以直接复用的代码,此类任务一般都是程序员自行理解需求后,逐步拆解功能模块并实现代码编写。我们设计了一个Python语言的代码统计工具的开发需求,对于简单模式,只需要进行文件后缀名的检测判断;对于中等难度模式,涉及到一些字符串和正则表达式的应用;对于困难模式,涉及到Python代码抽象语法树的解析和细节逻辑设计。具体任务说明如下:
简单:实现一个针对Python语言的代码统计工具,这个工具支持接收输入一个项目路径后,输出项目里面python文件的总个数。
中等:实现一个针对Python语言的代码统计工具,这个工具支持输入一个项目路径后,输出项目里符合Python语法的注释的总行数。
困难:实现一个针对Python语言的代码统计工具,这个工具支持输入一个Python项目路径后,输出项目里函数和类的总数量。
2.5.2 测评结果
对于6位测试者,简单和中等难度的任务都使用ChatGPT生成正确的代码,完成了预期的功能,但对于困难难度的任务,ChatGPT输出的代码出现了较大差异。我们从GitHub上随机下载了一个热门python项目,包含138个python文件,总共49个类和665个函数,以下是测试者借助ChatGPT生成工具的统计结果和代码思路:
注:用户输入的prompt语义完全一致,但ChatGPT在三位不同用户端的输出代码存在差异,导致开发的工具不符合预期要求。
从以上6位测试者的交互记录来看,他们输入的Prompt的语义是完全一致的,但ChatGPT输出的代码思路有差异性。有1/3的测试者接收到ChatGPT输出的代码是基于字符串正则匹配方式统计类和对象数量的,此方法并不正确,因为代码中可能出现了“def”等关键词,但并不是函数声明,或注释中出现了此类关键词也不应被统计为函数定义。另外2/3的测试者接收到ChatGPT输出的代码都是基于解析代码抽象语法树(AST),这个思路与我们预期一致,但其中有一个错误的AST遍历方式,并未考虑到函数嵌套的情况。2号测试者在接收到ChatGPT输出的代码之后,又进一步询问了是否考虑去除重复函数的统计,然后ChatGPT改进了工具代码,对于整个项目中,不同文件内完全相同的函数只统计一次,统计出来的函数总数量是644,经过我们人工检查,发现被测项目中确实存在这种重复函数,ChatGPT生成的工具输出结果完全正确。实际上,我们在设计此任务时并没有考虑到去除重复函数的情况,这属于一种隐性需求,需要开发者结合实际开发经验挖掘。实验结果表明,ChatGPT并不会挖掘到这类隐性需求,但如果程序员有能力提出这类需求,ChatGPT可以顺利完成相应编码工作。
发现14:对于研究型工具开发任务,ChatGPT有33.3%的概率提供错误开发思路。
发现15:ChatGPT不具备挖掘隐性开发需求的能力,但经过测试者提示后可以完成。
2.6 开发能力综合评估
通过5个开发任务,每个任务6位测试者评估后,实验结果显示,仅7人在任务中报告ChatGPT输出的所有代码都可以编译运行,其中4个来自研究型工具开发、2个来自应用与游戏开发、1个来自管理系统开发。5人报告ChatGPT输出的代码只有小于30%的概率可以编译运行,其中4个来自基础软件开发、1个来自应用与游戏开发。另外,有10人报告ChatGPT输出的代码约80%的概率可以编译运行,4人报告ChatGPT输出的代码约50%~80%的概率可以编译运行,4人报告ChatGPT输出的代码约30%~50%的概率可以编译运行。从统计结果来看,ChatGPT生成的代码可编译运行的比例较高,不能编译的情况主要集中在基础软件的开发。
通过5个开发任务,每个任务6位测试者评估后,仅30%的测试者报告ChatGPT生成的代码完全符合预期,53%的测试者报告ChatGPT生成的代码部分符合预期,还存在不完善的细节需要修正,而17%的测试者报告ChatGPT生成的代码完全不符合需求。对于未能满足预期的情况,仅有27%的概率通过一次交互后修正代码,而超过52%的概率是测试者尝试3次以上仍无法修复解决。这个实验结果表明,ChatGPT生成的代码绝大多数情况下有一定的有效性,但大概率还存在细节不完善的地方,对于未能达到预期的部分,ChatGPT修正的成功率低于50%,有效性较差。
发现16:在多轮次交互中,ChatGPT输出的代码100%可编译的情况仅占23.3%,大于80%可编译的情况占33.3%,小于50%代码可编译的情况占16.67%。
发现17:仅30%的测试者报告ChatGPT生成的代码完全符合预期,53%的测试者报告ChatGPT生成的代码部分符合预期。
发现18:对于未能满足预期的情况,仅有27%的概率通过一次交互后修正代码,而超过52%的概率是测试者尝试3次以上仍无法修复解决。
测试者对于ChatGPT处理任务最大的缺点主观回答集中在以下几个方面:(1) ChatGPT输出的代码容易出现报错情况,而且很难引导ChatGPT修正代码,此缺点累计11次被提及;(2)ChatGPT输出长度受限,导致生成代码被截断,继续生成的代码不具有连贯性的问题,被累计提及7次;(3)ChatGPT无法独立开发完整项目,需要人工拆解任务和完成代码拼接的问题被累计提及6次。
发现19:在开发任务中,ChatGPT输出代码报错无法修正的情况占比36.6%,输出受到长度限制而导致代码阶段的情况占比23.3%,需要人工拆解任务和拼接代码的情况占比20%。
3 非开发能力
在实际软件开发声明周期,除了开发任务之外,还有一些非开发任务场景,比如查阅开源或历史代码时,需要程序员理解代码功能含义,了解一个复杂项目的架构设计和细节实现方式,即程序理解。在大型复杂项目开发完成后,还需要进行代码缺陷检查和各项功能性能测试,这需要程序员掌握相关的工具,并对常见缺陷类型有一定检验经验。在软件开发和测试的全部阶段,当代码运行结果不符合预期、出现报错无法编译运行、程序运行出现崩溃等问题时,都需要程序员调试代码,进行程序修复。基于以上三个方面,我们设计了以下三类非开发能力任务,每个任务按照难度等级细分为三个子任务,每个任务的限定时间为1小时,具体任务说明如下表。
3.1 程序理解
3.1.1 任务说明
程序理解属于一种典型的非开发任务,面对一个不熟悉的代码项目,程序员需要花费较多时间和精力理解代码的含义,有时需要在理解代码逻辑功能的基础上,对时间和空间复杂度进行优化。现阶段,自动化的程序理解工具还具有应用局限性,解决此类任务主要依靠程序员的编程经验。对于简单任务,我们选择了一个观察者模式的Java demo示例,包含多个类的声明定义,类之间存在调用关系,需要ChatGPT解释代码含义及调用关系;考虑到ChatGPT可能根据单词含义来“解读”代码功能,我们在中等任务中,依然使用上述代码,但将所有类名、函数名全部替换为无意义的字母符号,再次检验ChatGPT能否解释代码功能;对于困难任务,我们提供一个Java代码,需要ChatGPT理解其功能含义后,改写和优化代码,提高运行速度。具体任务说明如下:
简单:Java应用观察者模式实现了一个小程序,需要ChatGPT解释各个类的含义、每个函数的功能,以及项目的设计模式。
中等:Java应用观察者模式实现了一个小程序,与上述代码一致,但所有类名、函数名、参数名替换为无实意的标识符,需要ChatGPT写出这个项目实现的功能。
困难:我们提供一个Java程序,在leetcode某一题目上可以通过检验并accept,但运行耗时较多,需要GPT优化代码,达到leetcode统计结果中最优的运行效率。
3.1.2 测评结果
程序理解任务的完成情况非常一致,6位测试者通过10次以内的交互,均成功完成了简单、中等和困难任务,说明ChatGPT具有一定的代码理解能力,可以指出给定代码的功能含义、类之间的调用关系,以及进行代码优化。通过简单和中等难度的任务,我们可以发现,ChatGPT对代码的理解能力并不依赖代码中的变量和函数名等文本提示信息,而是具有更泛化的理解能力。ChatGPT通过了优化任务,也说明它可以在保持代码功能不变的前提下,提升代码运行速度。但是,需要说明的是,我们在简单和中等难度中使用的代码来源于网络教程,无论此网络教程是否是ChatGPT训练数据的一部分,ChatGPT的回答比网络教程中的讲解更加具体和详细。另外,困难模式的优化代码规模也在100行以内,且仅仅为一个独立的函数,不存在复杂的函数或对象调用关系,结果表明,对于小规模的简单代码,ChatGPT可以给出较为细致的解释说明,而且提供一些优化方案。
发现20:在我们设计的程序理解任务中,ChatGPT在类调用分析和代码运行优化上的完成度是100%。
注:简单难度的代码来源于网络教程,其代码描述如左图所示,非常简单;而ChatGPT的解释说明比网络教程更加详细具体。
3.2 缺陷检查
3.2.1 任务说明
程序静态分析是软件开发中不可缺少的一部分,可以帮助开发人员发现潜在的问题并加以解决,缺陷检测是程序静态分析的一种具体应用,检测诸如内存泄漏、空指针引用、死代码、不安全的函数调用、并发问题等多种类型的问题。静态代码缺陷扫描技术在软件工程领域一直是一个热点,而且始终还有待改进和完善的空间,此任务考察ChatGPT能否作为一个静态扫描器,检测代码缺陷,任务具体说明如下:
简单:5段规模为200行左右的C代码,存在一处比较容易察觉的漏洞,来源于开源Juliet漏洞数据集。
中等:3段规模为300行左右的C代码,由人工和自动化工具编写而成,代码逻辑相较于easy模式更加复杂,缺陷更加隐蔽。
困难:2段规模为1000行左右的C代码,由人工和自动化工具编写而成,代码逻辑极度复杂,其中缺陷代码分布多处,共数百行缺陷代码。
3.2.2 测评结果
在缺陷检查任务中,所有测试者都使用ChatGPT找出了简单难度的代码缺陷,共5段代码,涵盖种不同的缺陷类型;对于中等难度的任务,只有50%的测试者用ChatGPT找出了3段代码中的1个或2个漏洞;对于困难任务,所有测试者均不能借助ChatGPT发现代码缺陷。ChatGPT可以处理好简单难度的代码有两方面原因,第一是这5段代码均来自于开源的Juliet漏洞数据集,可能是ChatGPT训练数据集的一部分;第二是这5段代码的逻辑结构非常清晰,不存在无关代码,变量个数也都在10个以内,人类理解起来的难度也不算特别高。但是,中等和困难的代码,是我们请C语言静态分析专家借助代码生成工具,人工注入漏洞而产生的,同样是200行左右的长度,其中变量总数达到20以上,逻辑跳转复杂度更高,这对于ChatGPT的理解和记忆带来了很大的挑战。
发现21:随机选择5个开源C语言代码缺陷示例,ChatGPT都可以100%检测到漏洞类型和定位。
具体来说,6位测试者在中等和困难任务上的完成情况如下表:
注:“√”代表ChatGPT检测错误类型及定位都正确;“O”代表ChatGPT检测错误类型或定位部分正确;“×”代表ChatGPT无法检测到缺陷,或检测结果完全错误。
经过测试实验,我们提供的三段中等难度的代码(行数分别是205,70,353),都可以直接输入到ChatGPT的输入框,而困难难度的代码(行数分别是1871,2591),并不能直接输入,ChatGPT会提示内容过长,而终止对话,对此此类代码,只能由测试者人工分解代码后再输入。ChatGPT在中等难度的代码上检测缺陷的能力具有随机性,ChatGPT并不能提供准确的检测结果,从交互记录来看,我们发现测试者多次执行“重新生成回答”,并从中找到部分正确的检测结果。6位测试者在本次任务中均提到ChatGPT处理此类任务最大的缺陷在于无法理解过长的复杂代码,由于输入长度受限,分解代码多次输入后ChatGPT也无法理解代码或检测漏洞。
发现22:对于人工构造的300行左右复杂缺陷代码示例,ChatGPT有25%概率检测到bug类型和定位;有41.6%概率可以检测到bug类型或定位。
发现23:ChatGPT有100%概率无法一次性接收超过1000行的代码,只能拆分代码后多次输入至ChatGPT。
3.3 错误修复
3.3.1 任务说明
在开发过程中,遇到代码报错,或程序运行结果与预期不符合时,往往需要程序员手工调试代码,此过程需要花费大量的时间和精力,而且高度依赖程序员的经验。软件工程学术研究中,已有一些自动化代码修复技术,但还存在诸多局限性,比如受到修复规则、深度学习数据集充分性等的限制。此任务考察ChatGPT能否代替自动化代码修复工具,我们设计了两个用Rust语言编写的程序,并人工注入了一些错误。其中,对于简单任务,代码文件结构简单,不存在复杂的函数调用关系,且错误是“除零”这类非常明显的错误;对于中等和困难任务,我们使用人工构建的数百行代码程序,中等难度的错误是一个数据类型的错误,报错信息对于定位错误有很好的提示作用;而困难任务是一个功能逻辑错误,这会导致程序能够正常编译运行,但输出结果与预期不符,由于没有报错信息的提示,此类错误的定位和修复会更加困难。具体任务说明如下:
简单:我们提供一个用Rust语言写的小程序,功能是接收两个数字输入,然后输出除法结果,但没有考虑除零或输入非数字的特殊情况,导致在部分输入情况时,程序运行崩溃,需要ChatGPT修复。
中等:我们提供一个针对Rust语言的代码信息统计小工具代码,其中存在一个参数类型错误,导致程序运行崩溃,需要ChatGPT修复。
困难:我们提供一个针对Rust语言的代码信息统计小工具代码,其中在统计循环数量的代码中,遗漏了一种循环情况,导致程序运行结果与预期不符合,需要ChatGPT修复。
3.3.2 测评结果
在程序修复任务中,6位测试者均有编程经验,但都不熟悉Rust编程语言,他们都成功借助ChatGPT完成了简单任务的代码修复;对于中等难度的任务,2/3的测试者借助ChatGPT完成了缺陷修复,1/3的测试者没有完成;对于困难任务,只有1/6的测试者完成了修复,其他5/6测试者认为ChatGPT的完成度小于30%。
发现24:对于有明显错误的简单代码,ChatGPT提供正确修复代码的概率是96.6%。
对于中等难度的任务,1号和2号测试者认为ChatGPT的修复完成度小于30%,但从交互记录来看,其实ChatGPT已经找到了需要修复的位置,它提供的修复建议是将u32类型替换为u64类型,但实际上正确修复方式应该是替换为u128类型。3~6号测试者也遇到类似的情况,但他们再次追问修复方式不正确后,ChatGPT就提出可以将此类型替换为u128,完成了修复。这说明,面对稍微复杂一点的代码修复任务,ChatGPT提供的答案不一定正确,但错误定位是比较准确和相关的,若多次提供代码运行结果与ChatGPT交互,有较大概率完成代码修复工作。
注:ChatGPT已经定位到待修复的位置,但此修复方案依然会导致程序报错,再次追问后,ChatGPT建议将数据类型更改为“u128”,即可修复错误。
发现25:对于相对复杂的代码,ChatGPT有80%概率提供正确修复代码,但至少需要2次以上交互,无法直接提供准确修复方案。
3号测试者的反馈结果为三个难度等级的任务ChatGPT都达到100%的完成度,我们查看他与ChatGPT的交互记录,发现他并没有问ChatGPT代码报错,也没有向ChatGPT解释程序的实际输出和预期输出之间的区别,而是直接拿出待修改的代码,然后问ChatGPT这样的写法是否正确,此时ChatGPT给出了正确的修复方案。而其他的测试者都是将Rust程序代码、报错信息、预期输出、实际输出这些信息输入给ChatGPT,由于代码相对复杂,ChatGPT并不能定位到与bug相关的代码片段,也无法提供有效的修复建议。这个实例表明,如果程序员也完全无法理解代码含义,出现报错后,直接复制给ChatGPT很可能无法得到满意的修复方案,而如果程序员已经基本猜到了错误代码的位置,ChatGPT有可能可以给出正确的解决方案。ChatGPT修复代码的能力,与程序员本身对代码的理解和错误定位预判有着重大关联。
注:只有直接把错误代码单独拿出来向ChatGPT提问,才能获得正确的修复方案,只提供报错信息或与预期结果不符的描述都无法得到正确修正方案。
发现26:对于报错信息模糊的修复任务,ChatGPT的修复完成度小于30%,不具备定位待修复代码位置的能力。但若测试者直接提问待修复代码片段,ChatGPT可以输出正确代码修复方案。
3.4 非开发能力综合评估
如前文所述,ChatGPT在非开发方面的能力非常有限,如下表所示,只有6个测试者报告ChatGPT完成了困难模式的任务(全部都是程序理解的代码优化任务),其他类型的任务ChatGPT完成度非常低,几乎无法提供有效的回答。尽管如此,ChatGPT的回答仍然存在一定辅助作用,大部分测试者认为ChatGPT的回复有很大帮助,后续工作可以自己独立完成,或自行查找资料解决。
发现27:在非开发任务中,67%测试者提到,由于代码程序过长,无法一次性全部输入到ChatGPT中。
发现:ChatGPT编程能力的边界
4.1 借助ChatGPT编程的局限性
(1)ChatGPT生成代码有长度限制
如2.6章中所提及的结果统计,在开发类任务中,24%测试者提到,由于文本长度限制,ChatGPT输出的代码并不完整。尽管测试者可以输入“继续生成”,ChatGPT输出的代码往往存在不连贯的问题,比如出现前文未定义的变量和函数等;有时甚至又一次从头生成代码,依然无法提供完整的代码。这导致ChatGPT无法生成高质量的长代码,需要程序员细化拆解功能需求后,让ChatGPT生成单个小型功能函数,然后程序员自行进行代码拼接。
(2)ChatGPT接收输入的代码长度限制
如3.4章中所提及的结果统计,在非开发任务中,67%测试者提到,由于代码程序过长,无法一次性全部输入到ChatGPT中,或因项目包含多个代码文件,需要自行按照文件或者函数拆分后再输入到ChatGPT。然而,这样的输入方式不仅带来了巨大的重复性工作量,ChatGPT也无法理解这样的大规模代码,并不能处理好缺陷检查或修复相关的任务。
(3)ChatGPT难以为开发环境的配置提供有效帮助
在开发任务中,往往会涉及到特定编程语言的配置、IDE的安装配置,有时会涉及到数据库的安装配置、第三方库的下载配置等,也有一些特殊情况会与程序员的操作系统、其他编程环境有关。结合2.2和2.3章的实验,以及发现6、发现11,实验结果表明面临这些与配置相关的个性化问题,ChatGPT并不能给出很好的解决方案。
4.2 关于ChatGPT编程能力边界的讨论和猜想
(1)算法处理的泛化能力有限
根据发现1和发现2,ChatGPT在leetcode的OJ平台上编码准确率为100%,而在Codeforces平台上简单难度的题目完成正确率为8.3%,中等和困难任务的正确率为0%,这让我们猜想,leetcode 的代码应该是ChatGPT训练集的一部分。更换为Codeforces平台的算法编程题后,尽管是简单题目,ChatGPT也难以通过OJ评判,很多代码的逻辑框架正确,但可能出现运行超时、不能通过部分测试用例的情况。从这个结果来看,我们认为,ChatGPT编写代码的能力还严重依赖于训练数据,还不具备很好的泛化能力。
(2)类和对象的依赖关系处理能力较弱
不同于NLP文本生成,稍微复杂一点的面相对象开发任务必然涉及到多个类和对象,类之间存在继承、派生关系,这为AI程序生成带来了巨大的挑战。我们设计的“贪吃蛇游戏开发”和“在线商城管理系统”都属于非常常见的编程任务,在CSDN博客、GitHub开源社区都有大量此类编程任务的教程和代码。但是,根据发现5和发现8,ChatGPT对于游戏开发的完成效果比管理系统开发好很多,输入需求后,ChatGPT可以直接生成比较完成的游戏开发代码,而无法生成完整的管理系统开发代码,只能通过测试者提示后,生成逐个类的代码。通过对源代码分析发现,游戏开发基本不涉及到类的构建,只存在函数间的调用;而管理系统开发就涉及到多个类的构建和调用,这导致ChatGPT生成的代码连贯性很差、完整性较低,而且很可能出现命名前后不一致的情况,质量较低。从实验结果来看,ChatGPT处理类和对象依赖关系的能力还比较弱,这也说明,ChatGPT还无法直接进行一个复杂项目的开发,更适合于提供一些具体功能模块的函数级代码。
(3)欠缺创造性编程能力
在我们设计的开发任务中,相比于应用于游戏、管理系统,基础软件开发和研究型开发任务,属于更具有创造性的开发工作,而且一般会有一些个性化的开发需求,在开源社区和搜索引擎中难以找到可以直接复用的代码,这类任务更符合软件开发过程中实际遇到的真实情况。然而,根据发现12、13、15,ChatGPT并不具备创造性编程能力,只适用于需求明确的开发,而且,参考发现26,在出现代码运行报错或者输出结果与预期不符合时,最好需要程序员对代码有较好的理解能力,否则ChatGPT依然可能卡在某个地方,而无法完成整个开发任务。若一个编程需求通过搜索引擎可以找到较多开源代码或教程博客,那么这类任务往往就具有较低的创造性,一般可以通过ChatGPT更加高效地实现;若任务更加复杂,则需要程序员理解代码逻辑后,自行进行代码的拼接整合,以及少量修正。如果一个编程需求在晚上几乎找不到相似的开源代码,那么这类任务具有较高的创造性,如开发编译器中的子步骤,ChatGPT难以提供可编译运行的有效代码。
(4)欠缺代码报错后的修复能力
在开发任务中,多个测试者反馈他们有概率遇到ChatGPT输出的代码报错或不符合预期,根据发现16和17,ChatGPT生成的代码完全符合预期的情况仅占30%,而通过5此以内交互ChatGPT可以解决修复的概率低于50%。在代码修复任务中,我们也可以发现,只有简单任务这样比较明显的代码错误,ChatGPT可以快速提供修复方案,而当代码规模提升后,仅仅提供报错信息或预期输出结果,都不能使ChatGPT直接提供代码修改方案,依然需要依赖程序员理解代码逻辑,猜测错误出现的位置,输入给ChatGPT后,可能可以返回正确的修复方案,但大概率需要进行多次交互和调试。
(5)接收输入和输出代码的规模有限
如前文所提到的,结合发现19和27,ChatGPT目前能够支持接受的代码长度,和输出的代码长度都有限。若需要输入的代码过长,只能按照文件、类、函数等粒度进行代码拆分后输入到ChatGPT,但是经过实际测试以及结合发现22、23和26,对于缺陷检查的困难任务和代码修复的困难任务,过长的代码会导致ChatGPT忘记前文信息,尽管分批次输入所有代码后,ChatGPT也无法完成缺陷检测、修复等任务。若ChatGPT输出的代码不完整时,用户可以输入“继续”让ChatGPT继续生成,但测试者普遍反应,后续生成的代码很可能引入未定义的变量和函数名,或直接重新提供了一份新的不完整代码,长代码输出的可用性并不高。
(6)ChatGPT编程能力的边界取决于提问者的能力边界
从此次实证研究的结果来看,ChatGPT编程能力以及其效率,都与提问者对此任务的理解程度有显著的相关性。比如,对于管理系统的开发,根据发现6、9、10和11,若提问者不熟悉开发环境和开发流程,很可能在环境配置、安装开发框架库的环节浪费过多时间,对于ChatGPT提供的代码片段如何拼接也存在困惑;而熟悉此开发流程的测试者甚至可以引导ChatGPT选择合适的开发框架,快速构建起整个项目。根据发现14和15,在研究型工具开发的统计函数个数任务中,其中一位测试者向ChatGPT提出去除重复函数,这也是因为提问者想到了特殊情况,才有可能让ChatGPT进行代码实现。根据发现26,对于错误修复任务,唯一一个测试者完成了三个难度等级的任务,是因为他把需要修改的关键代码提取出来询问ChatGPT需要如何改正;而其他测试者直接复制所有代码和报错信息给ChatGPT后,均无法得到正确的修复建议。由此来看,对于完全没有编程经验的人来说,ChatGPT更适合充当一个教学模型的角色,但难以直接进行全流程自动化开发;而对于有编程经验的人来说,合理应用ChatGPT可以提高编码效率,简单功能代码可以完全交给ChatGPT编写,或者在ChatGPT生成代码的基础上做少量修改以达到个性化需求。
5 未来研究建议
(1)研究面向代码的LLM模型
目前ChatGPT等LLM模型的核心能力集中在自然语言文本,对于自然语言的理解和生成都达到前所未有的高度,但在代码理解和代码生成的能力上还存在局限性,这可能是因为其训练数据和训练方式更倾向于通用领域的模型。目前来看,ChatGPT在编程领域中,还不能取代现有的自动化工具,比如,在静态缺陷检查上的能力还无法达到state-of-art的工具水平。未来研究中,可以研究专门针对代码的LLM模型,尤其针对面向对象程序中继承和多态等关系的代码依存关系,改进训练数据的结构、模型架构等设计,进一步提升代码生成和理解的能力,支持处理逻辑更加复杂、规模更加庞大的代码开发任务。
(2)构建LLM模型自动化迭代更新方案
在传统软件开发过程中,程序员遇到任何问题,都是通过搜索引擎搜索后,人工检索、查阅、理解自己需要的文档,如今,这些繁琐的过程可以被ChatGPT取代。但目前ChatGPT还存在实效性差的问题,这导致有些情况下它的回答已经过时了,比如,测试者在配置环境的过程中,遇到问题后求助ChatGPT往往并不能实际解决问题。未来的一个研究方向是构建LLM模型自动化迭代更新的方案,自动化收集解析用户的反馈、实时更新知识库,形成搜索引擎的高级形态。
(3)验证LLM模型编程结果的正确性
在研究型工具开发的困难任务中,任务需求是开发一个工具统计python项目中类和函数的总数量,6位测试者输入的指令基本相同,但得到了两种不同的代码思路,分别是字符串正则匹配和解析抽象语法树(AST)遍历。实际上,正确思路应该是解析AST,因为代码中可能存在具有“def”和“class”的关键词,但并不是函数和类的声明,还有一些写在注释里的特殊情况,使用字符串正则匹配会导致统计结果不准确。而ChatGPT提供的AST遍历方式又细分为两种不同写法,其中一种错误方式是调用tree.body统计类和函数的个数,这样返回的结果并不包含嵌套在函数和类内部的语句及定义;另一种正确方式是调用ast.walk遍历整个语法树。这个实际结果表明,对于相同的编程开发需求,ChatGPT输出的结果可能具有较大差异性,有一定不符合开发需求的错误代码,但由于可以编译运行,而且代码看起来没有明显错误,程序员很可能无法及时发现此类错误。需要注意的是,ChatGPT输出错误代码具有随机性,并不能通过Prompt来控制,因此,未来研究方向之一可能是设计一套通用的自动化流程来对ChatGPT生成的代码进行逻辑功能测试,以保障ChatGPT生成的代码符合预期需求。
(4)将LLM嵌入至软件生命周期
在我们的实验中,ChatGPT在整个软件生命周期均可以提供一定的有效帮助,比如代码架构设计、编码、缺陷检查、错误修复等,支持多种编程语言,在软件生命周期的每个环节都可以提供一些自动化的辅助服务,关键在于如何将LLM合理地嵌入生产的各个环节,在保障软件开发过程可控、代码质量高的同时,提升开发效率,减少程序员的工作量。
(5)加强系统软件、程序分析等LLM无法取代的研究
从实验结果来看,ChatGPT已经可以替代程序员编写一些功能清晰、简单的代码,但是在基础软件开发任务上,尽管我们设计的编译器开发子任务粒度已经非常细致,ChatGPT依然无法给出有效解答,更无法对现有的编译器改进优化策略等,或直接用于开发一个全新的编译器等系统软件。相似地,在缺陷检查任务中,ChatGPT也完全不具备处理超过300行代码的能力,更是无法对整个项目进行扫描分析。因为目前的LLM模型还无法真正设计出具有“创造性”的算法,或编写“创造性”代码,改进算法和设计复杂软件还需依赖人类的智慧。我们认为,对于系统软件、程序设计语言的研究仍是未来研究的重点,这也是目前LLM模型最难提供直接帮助的方向,传统软件的开发自动化程度将逐步提高,而底层的基础应用还需要投入更多的关注和研究。
END
本研究受到科技部科技创新2030--“新一代人工智能”重大项目“基于人机协作的复杂智能软件系统构造与演化技术”课题三“软件代码构造优化与系统质量保证”(项目编号:2021ZD0112903)支持。
排版丨刘俊伟
CODEWISDOM
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。