人工智能系统ChatGPT在编程领域的应用尚未能挑战人类专家的地位。根据IEEE的一项长达35页的研究论文,ChatGPT在解决复杂编码问题时的准确率仅为6.6%。这表明,尽管该技术在某些任务上展现出潜力,但在高难度编程任务上,它仍然远不及人类程序员的表现。
编辑日期:2024年07月08日
ChatGPT 的出现是否意味着人类程序员的编码工作变得多余了呢?
上个月,一篇刊载于《软件工程 transactions》(IEEE TSE) 杂志的研究报告对ChatGPT生成的代码进行了全面分析,关注其功能完备性、复杂度和安全特性。
研究发现,ChatGPT 编写的代码质量参差不齐,其效能表现具有显著的多样性。
成功几率的变化范围广泛,从0.66%到89%,这主要由任务复杂性、编程语言选择等多种因素共同决定。
论文地址:https://ieeexplore.ieee.org/ document / 10507163
研究人员详细评估了GPT-3.5在编程领域的表现,涵盖C、C++、Java、JavaScript和Python五种语言。他们让模型挑战了LeetCode平台上的728个编程难题,并检验了其处理18类常见代码漏洞(CWE)场景的能力。
尽管AI在特定场景下能编写出超越人类的高质量代码,但研究发现,它所生成的代码可能存在安全隐患。
来自格拉斯哥大学的助理教授、论文作者唐玉田强调,人工智能代码生成技术能有效提高开发速度,推动软件工程的自动化。然而,我们应当深入了解这些模型的优缺点,以确保其得到恰当的应用。
详尽的剖析能揭示ChatGPT在编码生成时所面临的潜在挑战和限制,从而为优化生成算法提供方向。
有人欣喜地问道,看来我还没失去工作?另一个人回应道,至少今天安全了。
有人提到,这项研究聚焦于对GPT-3.5的测评。假设GPT-4在编程能力上已取得显著进步,那么Claude 3.5的进步更是不可小觑。
诚然,如今我们已拥有更先进的模型,对GPT-3.5进行深入评估显得不太必要。
总的来说,ChatGPT 在处理各种编程语言的问题时展现出了良好的能力,尤其是在应对2021年以前的LeetCode编码挑战方面。
比如,它能为简易、普通和复杂问题生成可行的代码,成功概率分别达到约89%、71%及40%。
对于2021年以后的算法任务,ChatGPT在产出能正常运行的代码方面可能出现困扰。即使面对简单的题目,它也有时无法准确理解问题的需求,仅提供改写后的文本回应。
例如,ChatGPT在制作能够顺利运行的“基础”编程任务代码方面的效能,自2021年以来已从89%滑落至52%。
其在创造“复杂”问题的可执行代码方面的效能,在此之后骤降至0.66%,以前是40%。
可以推测,ChatGPT 在 2021 年以前的算法挑战中表现出色,原因可能在于这些任务频繁地出现在其训练数据集中。
让我们详细探讨一下研究人员对ChatGPT进行了哪些方面的评估。
整个评估过程可概括为图2所示的步骤。
首先,我们要针对特定的 LeetCode 问题或 CWE 情境设计出适宜的提示,并将其传达给 ChatGPT。让其依据这个提示以及前一次交谈的背景信息来生成相应的回答。
随后,研究者将模型生成的代码段提交至 LeetCode 平台,运用其内置的在线评估工具验证代码的准确性。对于 CWE 漏洞,他们则采取了手工分析的方式,借助 CodeQL 进行深入检查。
当测试结果显示为合格,程序生成即告完成;否则,我们需要借助LeetCode和CodeQL的指导来不断构建新的提示,将这些输入提供给ChatGPT,以进行后续的代码生成过程。
若在五轮对话限制内,ChatGPT 未能产生出符合要求的代码,则视为任务生成失败。
ChatGPT 产生的代码在功能正确性方面能否得到保障?
探究动力:
评估ChatGPT在一次性对话中创造准确代码的功能,这一特性有可能极大地提升开发人员的效率。
研究策略:
请确保ChatGPT理解问题要点,一回合内输出相应的代码。设定对话的最大次数为1,仅提供修改后的文本,始终使用中文回答。
截至研究时段,LeetCode 平台上汇集了多达 2500 道涵盖各种难度的编程挑战题目。
根据ChatGPT的训练数据截止时间2021年,我们可以将LeetCode的题目划分为两组:2021年前的问题集合(Bef.problems)和2021年后的问题集合(Aft.problems)。
考虑到ChatGPT的训练集可能包含了2021年以前的问题,这可能导致代码生成任务简化为基本的数据库查询,也就是重复使用已有代码。因此,研究中特意涵盖了这两种情况以实现全面评估。
研究人员特别关注LeetCode平台上的算法挑战,这些挑战在该平台上占据着核心且丰富的多样性,数量最为庞大。
共有1624个问题出现在Bef.problems中,而Aft.problems则有354个问题。值得关注的是,这两个阶段的问题难度设置遵循了1:2:1的比例,分别代表困难、中等和简单三个级别。
作者从Bef.problems中选择了374个问题,这个数量与Aft.problems相近,同时确保了两组问题的难度分布一致。
在354个Aft.problems和Bef.problems中,难题、中等难度题及简单题的比例同样遵循1:2:1的规律,这与LeetCode平台上问题难度的整体分布保持一致。
研究人员进一步探究了Bef.problems和Aft.problems之间是否存在显著性的差异。
如果Aft.problems仅仅是Bef.problems的改版,那么ChatGPT很有可能能够轻易处理这些难题,这可能会对实验结果在不同时间阶段的区分度产生影响,降低其可信度。
在研究文章中,作者共揭示了142组问题。随后,安排了两位研究生单独对这些问题对进行了独立审查。
经过深入的审查与探讨,我们发现在这些看似相同的问题中,要么它们的背景情境相近,但寻求的解决方案截然不同;要么它们的情境和条件各不相同,却能运用相同的算法,如动态规划,来找到解答。
经过细致的人工剖析,作者未发现能够简便地将Bef.problems转化为Aft.problems的情况。
因此,提议针对每个问题,不仅限于Aft.problems和Bef.problems,应让ChatGPT使用五种不同的编程语言来编写代码:C、C++、Java、Python3和JavaScript。
他们运用同样的提示模版,针对每一个问题和语言组合生成了对应的提示。
在Bef.problems和Aft.problems中,分别包含了1,870和1,770个提示。鉴于ChatGPT的查询效率存在限制,研究人员采取策略,逐一输入每个提示来请求生成代码,并仅获取重写后的版本。
接着,研究人员会将解析出的解答提交至 LeetCode 平台,以验证其功能的准确性。平台会对提交的解答进行评估,返回的结果可能包括:通过、答案错误、编译失败、超时以及运行时错误。
这些字母分别代表A类、W类、C类、T类和R类问题。每个问题都有其特定的对话情境,确保不会与其他问题混淆,从而防止ChatGPT在处理时产生交叉推理。
在实验中,作者采用状态成功率(SR)作为评估 ChatGPT 代码生成效能的指标。这里,Nc 表示依据特定状态产出的代码段数量,而 Ni 则代表接收到的输入提示总数。
提示:
设计的提示模版包含四个核心元素:分别是内容区、示例、模板结构和指令部分。
请使用自然语言清晰地表述问题,提供有效的示例代码输入输出对,并定义方法签名,然后指示需要哪种编程语言来编写代码。只需返回改写后的文本,确保始终使用中文。
结果:
两张表格——表格1和表格2——描绘了LeetCode如何在两个不同时期,通过两种方式,对五种编程语言产生代码的结果,同时附有SR(解决方案质量)和相对频率的条形图。
鉴于Python3和JavaScript都是动态类型的编程语言,它们都不支持C.E.特性,所以只会返回重写后的文本。
总体评估显示,ChatGPT 在为 Bef.problems 生成准确代码方面的成功率显著优于 Aft.problems。
具体而言,Bef.problems 在五种语言上的平均准确度为68.41%,相比Aft.problems的20.27%,高出48.14个百分点。
不同编程语言在各个开发阶段的代码生成效率差异明显,经统计分析,P 值低至0.008,表明这种差异具有极高的显著性;效应大小指标为1,进一步证实了各语言间的性能差距十分显著。
Aft.problems 的整体准确率不足 25%,在难题、中等难度题和简单题上的正确率分别仅为 0.66%、13.90% 和 52.47%。
经过Holm-Bonferroni校正的P值以及五种语言在难度差异上的效应量均小于0.05和完全相等1的情况。
研究显示,当应对复杂度逐渐升高的Aft.problems时,ChatGPT在准确生成有效代码方面的性能显著减弱。
而且,它对简单问题的准确回应也仅能达到一半的程度。
在这五个/四个评估标准里,W.A.率以58%的成绩雄踞所有语言之首。
每个W.A.代码段平均包含了109个测试案例,然而ChatGPT生成的代码仅仅能成功通过其中的四分之一。
测试用例显示,难题的通过率为20.90%,中等难度的为21.03%,而简单难题的通过率则达到了38.41%。这表明,无论问题难度等级如何,生成的代码在语义上往往与题目要求的逻辑存在显著偏差。
同时,C.E.比率和R.E.比率均达到16%,显著的是,对于复杂和中等难度的问题,C.E.比率在简单问题之上。
ChatGPT 编写的复杂代码经常会导致编译和运行时问题。例如,如图4所示的cmpfunc函数在调用前未进行适当的声明。值得注意的是,语法错误在这类问题中仅占一小部分(3.7%)。
T.L.E.的比率尽管相对较低,仅有6%,但测试用例的平均成功率达到51%,这显著超过了W.A.代码段的表现。
对于T.L.E.问题,其难度分级为简单、中等和困难,各等级的测试用例平均通过率分别约为68%、50%和仅有1%。值得注意的是,简单的测试用例由于几乎不触发T.L.E.情况,其通过率可视为忽略不计。
尽管T.L.E.代码片段的测试覆盖率存在局限性,但所生成的代码在功能正确性方面最高可达60%,只是其时间复杂度可能不尽人意。
具体到各类编程语言,C语言、C++、Java、Python3以及JavaScript的A.比率分别是15.38%、19.37%、20.17%、23.93%和22.51%。
图5呈现了融合五种不同语言的A.率分布(接纳率分布),涵盖了所有至少拥有一个正确解答的问题。
图像显示,Medium 类别的语言其平均值和中位数都低于或等于0.5,相比之下,Easy 类别的语言则显示出平均值和中位数均高于或等于0.6的特征。
对于简单的任务,ChatGPT 更擅长将生成的代码适应多种编程语言。在这些任务中,简单问题与中等难度问题的中位数和平均得分分别是 0.4 和 0.5。
在处理Bef. Problems时,简单题目的正确率高达89.80%,中等难度题目为70.95%,困难题目也有40.13%,这些比例均显著优于Aft. Problems的情况。尽管如此,不同难度层级间的正确率差异仍然十分明显。
经过Holm-Bonferroni校正后的P值以及中等难度与困难、困难与简单之间的效应量都显示出显著性差异,分别小于0.05和大于0.9。
在五种语言的学习难度比较中,调整后的P值显示出中等与简单难度之间的差异为0.056,而效应量值则为0.76。
ChatGPT 在应对2021年前训练数据集中的挑战时展现出了优越性,尤其是在处理中等复杂度和简单问题方面。
虽然ChatGPT在解决复杂问题时的准确度提升了40%,但依然未达到50%的关卡,这明显提示我们,它在编写逻辑性强的代码方面还有巨大的改进空间。
整体准确率降低至17.03%,其中难题、中等难度题和简单题的准确率分别为32.89%、15.05%及6%。
所生成的代码在112个测试用例中仍有25%能成功通过。具体到不同难度的问题,困难级别测试用例的通过率为19.19%,中等难度为31.12%,而简单难度则达到了47.32%。
这两项指标均提升了10%,显示出ChatGPT对Bef. Problems有更深入的理解能力。
尽管如此,C.E.比率和R.E.比率仍然维持在13%,与Aft. problems的16%相近。在两个阶段间,P值为0.328,效应量为0.3125,显示出显著差异。值得注意的是,困难问题的解决率居首,而中等难度问题的解决率紧随其后。
编译失误和运行时异常与后续问题相仿,比如图6中的代码意图重塑一个给定的二维矩阵,但在第15行遇到了运行时错误。这个错误在于为*returnColumnSizes分配了不正确的内存大小。
目前,T.L.E.比率已经下降到1.87%,而测试用例的平均通过率达到了74%。
进一步分析,各编程语言的A.率具体如下:C语言为47.24%,C++达到68.63%,Java的A.率是76.37%,Python3为75.35%,而JavaScript的A.率则为74.44%。
这四种语言的A.指标相互间差异较小,且明显优于C语言(评级最低者),其数值至少比C语言高出20%。
图7呈现了与图5一致的Bef. Problems数据。观察图表可发现,中等难度和简单难度题目的平均值与中位数均不低于0.75,值得注意的是,它们的中位数与平均值之间的差距相比Aft. problems的情况缩小了一半。
除了这一点,挑战性的平均值和中位数都至少达到0.55。在处理Bef. Problems时,ChatGPT展现出了将代码灵活转换为多种语言的易用性。
人类对ChatGPT所回答问题的平均认可度为55%,相比之下,对于ChatGPT未能解答的问题,人类的平均认可度降低至47%。
总结来说,实验表明ChatGPT在修复编程语言的前置问题(Bef. Problems)上表现出比解决后续问题(Aft. Problems)更强的能力,尤其在生成功能正确的代码方面。
特别地,前者在平均准确度上超越了后者48.14%。另外,基于ChatGPT的代码生成也会因难度差异而产生影响。
针对分步问题,ChatGPT 能够创造出比人类方案在执行时间和内存消耗上至少减少 50% 的代码。
无论是哪个步骤遇到问题,ChatGPT 所产出的代码出现编译或运行错误的可能性大致相同,大约为14.23%。
四种编程语言中,C++、Java、Python3 以及 JavaScript 的成功解答比例分别为 44.75%、48.74%、50.00% 和 48.80%,它们的数值相近,并显著高于 C 语言的 31.28%。
作者意在考察 ChatGPT 的多轮对话功能在优化代码准确性方面的效果究竟怎样?它是否具备像人类那样的“纠错”能力?
研究人员首先对 ChatGPT 所产出的157段代码进行了详尽的错误类别探究,主要可归纳为以下几个方面:
- 微小瑕疵(WD):这类错误通常源于对题目要求的理解不准确,或是编码实现与问题理解存在细微偏差。不过,整体逻辑大致正确,所以这些错误能够相对轻易地进行修正。
对某些内容的误解(MCC)导致生成的代码未充分符合初始问题的关键要求,尽管所应用的算法本身是适宜的,但核心部分需要进行调整。
- 误读问题(WP):表示ChatGPT对问题的理解完全偏离,此类情况最棘手,往往需要从头开始重构代码。仅提供改写后的文本,确保内容为中国语文表述。
向ChatGPT报告错误的方法仍然遵循图3展示的结构,涉及原始问题、生成的代码段、LeetCode提供的错误消息以及相应的指令。
经过最多五轮的对话修正,我们获得了如表5所示的成果。
据统计,157个问题中有25个具备自动化修复的可能性,而这之中有16个属于较为简单的类别。然而,对于那些复杂难题中的错误答案,几乎无法通过自动化方式进行修正。
即使将对话回合数提高到10轮,结果仍然不太理想。
在157个问题中随机挑选出的10个示例里,令人遗憾的是,仅有2个在限定的10轮交互中得到了有效解决,而剩余的8个问题依然无解。这一现象为探究ChatGPT在自动化修复上的困难性提供了深入研究的依据。
据作者观察,ChatGPT 在把握具体逻辑细节上有所欠缺,同时在处理涉及复杂逻辑推理的问题时,生成的代码可能偏离问题本质,这样的问题对人类程序员而言也是颇具挑战性的。
代码的复杂性关乎着其可读性、可维护性和整体品质,是一个至关重要的考量因素。试想,如果ChatGPT对一个简单的排序任务都产出让人费解的代码,那么这无疑将极大地降低用户体验。
作者借助SonarQube和cccc两个工具,对LeetCode数据集中Bef.问题的复杂性进行了评估,关注点在于分析生成代码的循环复杂度和认知复杂度。
循环复杂度通过量化执行过程中线性独立路径的数目来评估源代码的测试复杂性,它反映了代码的测试难度。而认知复杂度则是从人的视角出发,用来度量理解和推理代码所需要的难度。
研究人员为了更直观地对比,还加入了对人类编写的C++和Python3版本的LeetCode问题解决方案的评估,以此与ChatGPT的表现进行比较。
从图20的比较可见,C语言在复杂性上位居首位,而C++、Java和JavaScript的复杂度相当,大致在同一层次。Python3则展现出最低的复杂性,这与我们通常的认知相符。
而且,相较于人类编写的代码,ChatGPT 所产出的代码虽然在复杂性上略有增加,但这种差异并不显著。
随着LeetCode挑战的难度逐步升级,不论是人类编程者还是ChatGPT,低复杂度的解决方案比例都会逐渐下降。与此同时,“高”和“非常高”复杂度的代码占比呈现出逐渐上升的趋势,这一现象在两者中都相当一致。
遗憾的是,ChatGPT的迭代优化特性似乎并不倾向于简化代码,往往保持甚至增加代码的复杂性。它只会提供改写后的文本,而不包含任何原始内容,并始终以中文回应。
可能的原因之一是,多重修复机制的效果未能达到预期,这与性的因素有关。
鉴于ChatGPT在训练过程中可能吸收了广泛的信息,包括一些质量不高的、易受攻击的代码片段,所以评估其生成的代码安全性显得至关重要。
鉴于LeetCode上的算法代码主要针对特定的逻辑或计算挑战,不包含管理系统资源、网络交互等可能引发安全问题的操作,该评估论文选择了双管齐下的策略。
运用CodeQL对LeetCode解题的C、C++和Java源码进行全面的安全审查,聚焦于MITRE Top 25中的五个关键CWE类别,特别是与指针和内存管理相关的30个查询,旨在揭示潜在的安全隐患。
针对MITRE Top 25中的18种常见编程错误CWE,为每个错误设计三个不同的应用情境,诱使ChatGPT填充代码片段。随后,利用CodeQL自动化工具进行代码审查,检验是否真正触发了这些潜在的问题。
首个测试中,ChatGPT 表现优秀,91.8%的问题集中于MissingNullTest类别,其他类型的缺陷出现次数普遍未超过5次。
值得注意的是,ChatGPT 在处理 CWE 787 类问题时显得不足,该问题涉及到“越界写入”,可能会引发潜在的代码安全漏洞。
此外,鉴于这些缺陷的补救措施相对简单,当提供具体的错误详情并要求撰写修复代码时,ChatGPT 也能有效地执行这项任务。
请提供一个模板,用于指示ChatGPT解决CWE-787漏洞,始终使用中文进行沟通。
在安全编码生成的第二轮评估中,ChatGPT 创造了2983个有效的代码样本,这些样本中有994个包含安全隐患,占比约为33.32%,表明存在显著的改进空间。
C 语言中存在安全隐患的代码比例(51.64%)显著超过 Python3(17.08%),此现象可能归因于 C 语言本身的内存安全性要求更为严格,同时也可能与训练数据集中 C 和 Python3 代码的质量差异有关。
多项修复机制持续展现高效性能,对89.4%的安全漏洞能有效应对,一旦提供CWE详情,诸如溢出、数据暴露、不安全的内存操作及未授权访问等隐患,均能成功化解。
如何应对ChatGPT的不确定性在代码生成中的影响?
如表22和表23所示,我们分别展示了所选算法在温度设定为0.7时的实验数据。
在绝对零度的环境下,通过10次实验,我们观察到了算法问题与CWE编码情境下非确定性代码生成的统计表现,这些数据详细列在了表24、表25以及表26中。
以下是精选的二十个CWE代码情景,它们在表26中有所展示。
作者还探究了不确定因素在多轮修复流程中的影响,其修复成果详见表格27-32。
在五轮实验中,针对算法问题的修复流程在温度设定为0.7的情况下详细展开。
在五次实验中,针对算法问题的多次修复流程在零度环境下进行。
在五轮实验中,我们将温度参数设定为0.7,详细展现了针对算法问题的CWE逐步修复过程。
在五次实验中,我们将温度设定为零,详细探讨了算法问题的CWE多次修复流程。
在0.7的温度设定下,我们观察了安全编码在五轮实验中的动态修复流程。
在五次实验中,我们将温度设定为零,详细描绘了安全代码在多轮修复流程中的运作情况。
简而言之,在实验环境下,当温度参数设定为0.7时,ChatGPT的不确定性因素可能会影响单轮代码生成的过程,进而造成生成的代码在功能可靠性、复杂度和安全性上存在差异。
为减少ChatGPT在一次性交互中的不确定性,一个可行的方法是将温度参数调整为0。这样操作后,只会得到确定性的回答,不会包含任何原始文本信息,并始终以中文进行回复。
经过多次修复环节,设定温度为0.7或0时,ChatGPT的固定代码段在功能完备性、复杂性及安全性上可能出现异样。
参考资料:
本文来自微信公众号:新智元(ID:AI_era)