• 程序员真的会被ChatGPT取代吗?
  • 发布于 2个月前
  • 314 热度
    0 评论
Auto-GPT
最近,在 GitHub(全球最大的开源代码平台)上,一个名为「Auto-GPT」的项目一度爆火。它并非是什么全新的 AI 模型,也不是什么具有革命性的全新基础框架,它只是一个基于 GPT-4 的、核心理念很简单的应用层项目,但是它却在极短的时间里吸引了大到恐怖的流量。不仅仅是中文互联网,全球互联网上的媒体、大 V 都在争先恐后地鼓吹这个项目,一时间 AI 圈再度陷入到了新的狂热之中。

目前这个项目在 GitHub 上的 Star(星标)数量已经超越了 110k,这是一个相当恐怖的数字,要知道 AI 行业的很多基础框架,比如很多 AI 模型的基础、知名的深度学习框架 —— PyTorch,它的 Star 数量只有 65.9k。

Auto-GPT 之所以如此火爆,是因为它率先实现了让 GPT 模型全自动运行的效果,一瞬间,本是只能和用户进行对话交流的模型像是有了自我意识一般,可以在给定某个目标的前提下自主地思考问题,并主动地通过各种方式(如联网搜索资料、编写/执行代码等)尝试达到这一目标。


不得不说的是这个效果确实非常惊艳,也真的有很多人在看了演示之后认为,现在的 AI 已经有了一定的自主意识,已经具备了独立思考的能力。但实际上,Auto-GPT 只是一个相当简单的、基于 Prompt Engineering(提示语工程)的应用,它并没有让 GPT-4 真正地拥有「自我意识」。虽然一切看起来非常神奇、令人感到震撼,但他们做的工作只是让 GPT-4 能够自我进行链式调用。

具体来说,他们利用了一个经过精心编写的 Prompt,告知 GPT-4 需要达成的目标,并引导与限定它输出特定格式的 JSON(一种结构化数据),这个 JSON 数据可以被预先编写好的程序解析,其中包含了搜索、编写代码、执行代码等诸多动作指令,在程序执行完指令后,这个指令会被包装成下一次的输入送给 GPT-4。对于 GPT-4 来说,用户的输入变成了执行指令的回显,由于 Prompt 的限制和要求,它在接受到这个「回显」后会进一步进行后续的问题规划,输出某一动作指令,如此反复。

在这一流程下,GPT-4 能够持续不断地输出和达成既定目标相关的内容,看起来像是在自我思考一般。但实际上,在与 GPT-4 正常的对话流程中,你一样可以输入基于搜索得到的信息,或者某个代码的执行结果,这和 Auto-GPT 做的事情是没有本质区别的。Auto-GPT 只是取代了用户去自动化了用户本来应该要做的一些动作,比如搜索、执行代码、输入信息等,它并没有改变 GPT-4 的本质,也没有激活 GPT-4 的所谓「自我意识」,GPT-4 也仍然没有脱离其既定的工作模式与底层原理,而产生了某种「意识」。

实际上,在一些情况下,当你长时间运行 Auto-GPT 的时候,你会发现 Auto-GPT 有时候会循环往复地执行某一组动作,陷入死循环,看起来不太聪明的样子。

AI 编码
虽然我们上面有提到,Auto-GPT 只是实现了一个简单的链式调用,技术含量并不算高,但它将 AI 执行流程自动化的思路还是颇具实践与参考意义的。比如说编写代码,基于类似 Auto-GPT 的链式调用,GPT 等大型文本生成模型可以在短时间内生成大量的代码,并根据输入所反馈的代码执行结果对代码进行调试与修改。如果 Prompt 是精心编排过的,GPT 甚至可以连续生成分别位于多个模块内的代码,并实现模块与模块之间的导入和导出。

在软件开发中,多个软件模块连接之后自然而然就形成了一个「工程」,在合适的 Prompt 下,大型语言模型(Large Language Model,LLM)是有能力去自动编写整个简单工程的,甚至可以做到全程不需要用户介入。

这就引出了我们今天讨论的焦点:既然当下的 LLM 具备了一定编写代码的能力,而且在经过一定的设计和引导下能够完成简单工程的代码编写,未来程序编写会不会变得非常简单,就像《流浪地球 2》里 550 系计算机能够自动生成操作系统和用户界面一样,我们只需要给定 AI 一个既定的目标,剩下的所有事情是不是 AI 都能自己自动完成?

或者说,程序员在未来是不是也有可能会被 AI 淘汰?
对于这个问题,我们在深度剖析当下的 AI 模型后给出的答案是:

「有可能,但是以目前 AI 的水平来说,想要达成这件事还有非常远的距离。」

底层原理
现有的 AI 确实具备了一定的代码编写能力,一些媒体也有报道一些案例,比如 Auto-GPT 自主完成了一个计算器的编写等,这一点我们不否认。甚至在多模态 LLM 上,AI 已经可以实现根据一张草图编写与之对应的前端代码,就像 GPT-4 发布会时展示的那样。但是,这些看起来令人震撼的效果并不意味着 LLM 「真正学会了怎么写代码」。

目前 LLM 的底层原理仍然脱离不了 Transformer [1],在这个既定的架构下,面对用户的输入,LLM 总是会根据过往的学习(这些学习实际上固化成了模型内各个参数的权重)对输入进行推理。关于这个模型的详细介绍,可以参考我们团队的另外一位成员所制作的 B 站视频:

这里的推理实质上是一个黑盒,我们并不知道这中间具体发生了什么,但是模型会根据其经过重重训练固化下来的参数权重对输入进行特定的计算,得到一份全新的内容。在语言模型的场景下,这一份内容往往是「最适合接续输入内容的下一个词」。

LLM 的训练其实和我们在学校里学习英语很类似,我们都知道英语试卷里有一种题目叫「完形填空」,一篇文章里被人为去掉了很多单词,我们需要选择一个合适的词或词的变形填到这些空白的地方。想要做对这一类题目,我们必须要理解空白处的前后写了一些什么,否则我们没办法判断空白处到底要填入什么内容。

也许一开始碰到某种词法、句型,你可能做不出来、选不对,但是多做几次,凭借记忆和逻辑推理,你就知道这个地方该选什么了。LLM 的训练采用的方法与上面我们举的这一个例子类似,用于训练的数据里会被抠掉一些内容,LLM 需要做的就是根据上下文准确地把被抠掉的推理出来,在训练过程中,程序会不断地优化模型参数、评估推理的准确性,最终得到一个相对稳定的、能够进行准确推理的权重参数集。

当然,这里只是一种相当简化的描述,实际上的训练机制会更复杂不少。在这种训练模式下,LLM 的学习会更加全面,它不单单能学习到「什么样的字母能组成一个单词」,「什么样的单词拼起来是一个句子」这一类基础内容,它还能理解与记忆上下文之间的关系,即「在某一内容为前提下,某个句子或某个单词是最合适的」。

基于这一训练模式,当参数量足够大的时候,LLM 便会展现出对上下文的优秀理解。由于这种理解在训练时就已经逐步固化到了模型的参数权重上,因而当用户提出某个问题时,LLM 能立刻给用户呈现出与之对应的回答。这正是为什么在 ChatGPT 上,AI 可以和用户谈笑风生,因为模型在长期的训练中早就学会了在面对用户输入的内容(上文)时,输出什么样的内容(下文)是最合适的。

用于训练 LLM 的数据往往是容量高达 PB 级别的文本,代码(纯粹的代码或内嵌有代码片段的文章等等)自然也会被包括在内,所以 LLM 在学习的过程中不只单单只是学习到了人类语言范畴内的诸多上下文关系,它还同时能学习到编程语言中的诸多上下文关系。
因而在用户给出某一确切需求的时候,有学习过代码的 LLM 便可以快速地吐出与之对应的代码片段。即使这个需求 LLM 从来没有遇到过,它也会主动地猜测你可能想要的内容,并根据过往的学习给出一个尽可能符合要求的下文。

基础能力局限
LLM 的各类泛化能力是一种量变达到质变的体现,这种能力只在参数量达到一定规模的模型上才会逐渐体现出来,参数量较小的模型是不具备这一类能力的。在我们看来,LLM 的这种被称为能力「涌现」的现象 [2] 其实可以被看作是语言模型训练时出现的一个意外的「附加效果」。

我们可以这么去理解它:
语言模型的原始目标是完成对人类语言的学习,实现自然的人机交互。很显然的是,我们不可能用一堆随机文本去训练它,我们期望它学会人类的语言,必然得用一些真材实料给它学习,因而在训练语言模型时,训练数据都是来自真实人类世界的、有意义的文本,这样一来语言模型经过推理组装出来的文本才会更贴近人类。

很巧妙的是,在真实人类世界中,我们阅读的文本绝大多数都不是一段毫无意义的废话,它或多或少都有一些实际的意义,甚至承载着人类世界的知识。对于模型来说,这些内容中抽象的逻辑推理能力、抽象能力、实践学习能力等被人类认为是「智能」的根本的能力很有可能会被模型的庞大参数网络所内化,进而表现出一些无法用简单的语言模型所解释的具体能力,如高级逻辑编程、视觉等等。

在大参数量的加持下,这种表现会变得更加明显,因为在这种情况下,LLM 能够抽象出来的上下文关系更多,使其相较于一般的预训练语言模型在面对用户提出的各类问题时体现出更强的「泛化能力」。

这样的能力实际上与人类经过相似学习路径所获得的能力有很大差异。例如,所有 GPT 系模型在逻辑思考上容易偏离轨道,出现显而易见且难以自我纠正的错误的通病,或者是对于训练集缺乏的内容容易出现的「幻觉」(编造根本不存在的内容与关系)。

通过前文我们可以知道,这种能力的本源是训练数据。对于科技公司而言,即使他们手握大量的数据,拥有可以从互联网上不断爬取各类用户数据的技术,但是这个数据终究是有限量的,其极限最多也就是全互联网上可以获得的所有公开数据。

在有限的数据下,LLM 只能学习到有限的上下文关系,其解决问题的能力也终究是有限的。如果用户提出的诉求和用于训练 LLM 的数据重合度非常低,这个时候 LLM 就不能很好地完成用户提出的任务了。

这也就直接导致了一个局面 —— 现在的 LLM 确实会写代码,但是它们之所以会吐出这段代码,只是因为这段代码恰好契合用户的输入,而不是因为 LLM 能够像人类一样,先理解了要怎么样正确编写代码,再根据学习到的这一部分原理去举一反三,产出新的代码。

如果你问 LLM 要怎么样编写代码,它会给出你正确的回答,因为类似的上下文存在于它的历史学习中,但是这和它能根据用户描述输出某一段代码没有直接的关联。

这也是为什么在大多数情况下,当你提出一个有创造性的需求,或者是一个比较复杂的需求时,LLM 并不能生成正确、可用的代码。

拥有这一局限的不仅仅是 GPT 这一类语言模型,当下所有使用有限数据集进行预先训练的 AI 模型几乎都存在着这样的局限,想要打破这个局限,模型的评估算法必须要拥有能够评估自生成内容的能力,这样模型的训练数据才有可能达到真正意义上的「无限」。用一种通俗的说法来说,在这种情况下 AI 就不再只是表面上的内容,它会从 0 开始去理解、去学习,进而探索出真正的「本质」,打破束缚。

这一方法在围棋这样的领域是很奏效的,AlphaGo Zero 就是一个很好的例子。它没有引入训练数据,在自对弈的过程中,AI 完全是从 0 逻辑开始下的,最开始是随机,之后随着经验的积累越来越快,这使得 AlphaGo 成功脱离了人类棋手的束缚,借助几乎无限的数据集达到了比人类更高的高度,自我探索出了对围棋的一套理解。

围棋这样的游戏,本质上是一个博弈论问题,是可以用非常成熟的理论和经验模型逼近局部最优解的,因此简单的规则就能为 AI 树立一个需要达到的标杆。但在语言模型上,这一点几乎不可能实现:深度的语言输出必然包含思想,而思想是没有对错,不能用简单的算法评价分数的。

当然,这一问题也不是没有希望:LLM 的「涌现」能力本身就是在模型参数扩容中发现的,鉴于目前基于 Transformer 的模型都是一个「力大砖飞」的发展趋势,我们很难预测 GPT 这种大模型会不会在未来可以实现自增数据、自我训练,甚至拥有足够的抽象能力来改写自己的模型基础。

训练数据局限
如果我们给 GPT 这一类 LLM 模型引入足够多的、与代码和技术相关的语料内容,再结合适当的 Prompt 进行引导,它确实有可能能够对编写代码有更多的理解,使其可以处理更复杂的技术需求。然而,这距离 AI 完全取代程序员还有很长一段距离。

LLM 的训练往往需要大量的文本信息,在训练数据内,与代码相关的文本主要来自于各类公开渠道,比如 GitHub,软件框架或开发标准的官方文档和一些公开的、与软件开发相关的社区等等。从这些训练数据内,LLM 确实能够学习到非常多与编码相关的知识,以及各类编程语言下许多共性问题的解法,但是这对于实际的软件开发来说并不能起到太大的用处。

在实际的软件工程中,绝大部分的代码都需要根据产品需求定制化编写,整个工程的架构设计以及各个模块的具体实现都和需求密切相关。如果是一个比较复杂的工程,我们可能还要考虑到模块之间的相互作用,工程本身的技术背景与历史包袱,以及一些在产品内已经约定俗成的规则等等。

很显然的是,这些内容大概率不会被 LLM 的训练数据包含在内,它们基本上是非公开的。除非你的项目恰好和已有的某个开源项目十分近似,或者模型本身有针对这些非公开数据进行过特别的 finetune,否则面对这些专有问题,LLM 只能基于其 zero-shot 的能力去基于过往学习经验尽可能给出它认为可行的代码,而这种代码的可用度就比较低了。即使逻辑可行,这样的代码也会因为格式、组织逻辑等等的问题显得格格不入,在未来变成代码维护的技术债。

这也是为什么媒体在宣传 LLM 能够自动编程的案例基本上都是一些非常简单的、或者是非常普遍的独立工程,比如计算器、博客、个人主页等等。使用 LLM 的自动编程能力去维护大型、特大型项目,尤其是一些重点依赖的开源库等等是非常少见且成果不明的。

另外,受限于训练数据,LLM 目前并不能解决定制化程度高的需求,它只能解决比较常见的共性问题,完成一些比较普遍的技术需求。毕竟如上文所说,LLM 目前的逻辑能力依然有较大的缺陷。一旦上升到一些对创意性或者专业性有较高要求的问题,LLM 的表现就会有比较明显的滑坡,在这一点上,Stable Diffusion 等非语言领域的大模型也存在类似的问题。

现阶段很多代码助手在面向企业售卖时会推荐企业给助手接入内部的代码仓库,并且允许用内部仓库的代码对助手的模型进行 finetune,为的就是尽可能规避因训练数据和实际工程代码重合度低、代码风格差异大导致的不理想效果。

上下文局限
上述内容中提到的局限性只是 LLM 局限性中的一面。由于现在的 LLM 普遍都采用的是 Transformer 架构,这导致它不可避免地会继承一些来自 Transformer 架构的局限性,例如上下文局限。

即使是 GPT-4,它也不可避免地存在着上下文局限,它最长能够输入的上下文是 32k,也就是说它在输入上能够支持最长 32k 个 token。在 ChatGPT(gpt-3.5-turbo)上,这一限制更是只有 4096 个 token。

这个局限是其底层架构带来的,它不可避免会有一个处理能力的上限,一旦超出了这个上限,LLM 就不再能处理输入的内容。而当前针对代码逻辑能力的不足,尤其是面对语言的非常见依赖库的能力都是通过上下文学习的方式[3] 来解决的。这样的信息量输入必然会受限于其上下文长度局限。

虽然这个问题也有解法,例如利用 LLM 自身的能力去压缩信息,将超长的输入分段、分层地浓缩,再将浓缩后的信息进行组装与输入,但是这种对信息熵的滥用的解法并不能真正地破局,它只是一个权宜之计,信息并不能无限地压缩,而且对于超长信息来说,这种压缩也必然是有损耗的。尤其是对于具体的代码,其使用方式几乎不可能被抽象总结,必然要保留原始代码以供查阅。

在软件工程领域,稍微大一些的工程背后都是海量的信息,甚至连人类都难以很好地去理解。在一个复杂的工程中,某一个代码片段背后可能牵涉到很复杂的作用机理,或者牵涉到各种各样的需求背景、技术背景等,如果要将这一系列的背景连同代码、用户需求一起输入到 LLM,32k 的上下文也仍然是不够用的。

尤其是在我们期望 GPT 可以基于链式调用自动运行的情况下,与自动链式调用相关的输出格式化 Prompt 和需要反复送入 GPT 的历史对话数据本身就需要吃掉大量的上下文空间,留给我们去描述编程任务目标的上下文空间就更加不足了。

更别提现阶段的 LLM 都不具备可靠的、介于预训练内容和上下文学习间的中长期记忆。一旦内容离开了输入的上下文,AI 就会永远地忘记它,这使得 AI 更难去理解一个完整的软件工程,给出正确、贴切的可用代码。

代码知识产权与安全问题
现阶段来说,在商业产品中大片段地使用 AI 生成的代码是有一定法律风险的,和将 AI 生成的艺术作品用于商业用途可能存在侵权风险是一样的。

相较于一些专门针对代码补全开发出来的 AI 助手,LLM 在这方面可靠性要更差一些。因为专门用于代码补全的 AI 助手,例如 Codeium,它们所用的训练数据都是来自开源平台的公开代码;而且在训练之前,开发团队会出于对知识产权、隐私泄露等相关问题的考虑对数据进行一些必要的清洗和预处理,例如去除代码中含有的一些隐私信息(个人邮箱、人名等等)、去除使用了 GPL 协议的代码等等,以此避免 AI 生成一些可能会对用户带来潜在风险的代码。

而 LLM 则不同,作为一个具有通用性的模型,它所使用的训练数据是非常多而复杂的,其中包含的代码可能不一定来源于 GitHub,它还有可能来源于某篇从网络上爬取博文、某个社区的帖子,甚至是用户的输入数据。对于开发团队来说,面对用于训练 LLM 的海量数据,他们也很难去逐一地追溯、审查代码是否在知识产权上没有问题,以至于相较专门用于代码补全的 AI 助手来说,LLM 生成的代码具有更高的风险。

目前全球都在逐步完善与 AIGC 相关的法律法规,特别是其训练用例和生成内容的版权问题一直是备受关注。在现阶段而言,使用 LLM 去生成代码可能确实很方便快捷,但是这种方便和快捷所带来的隐患很有可能变成工程里的地雷。

在代码安全方面,LLM 也并不能保证自己生成的代码是坚不可摧、没有漏洞的。如上文我们提到的,LLM 并没有真正的「学会代码」,代码和普通的文字一样,在 AI 眼里这些都只是文本而已,它并不知道什么样的代码是安全的,什么样的代码是存在风险、存在漏洞的。

这也就意味着 AI 有可能会吐出含有安全漏洞的代码,如果开发者本身经验不丰富,或者出于疏忽,没有对代码进行进一步的检查就直接使用了,那么这段代码就很有可能会对线上的服务产生致命的威胁。实际上,根据最近的一些研究[4],当前的 ChatGPT 生成的大部分代码都存在漏洞,并且是「有意识」的存在漏洞(在后续 Prompt 介入的情况下,它能很快地意识到自己的错误并自我改正,但不会在首次生成时就避免这些问题)。

对于一些拥有在线搜索功能的 AI,例如 New Bing、Auto-GPT 等,由于它们会主动去执行网络搜索,并将搜索结果整合到上下文中进行输入,由这些服务生成的代码,其安全性和知识产权上的合法性就更难保证了。尤其是在代码安全方面,由于互联网搜索服务返回的结果会被混入上下文输入给 AI,这使得有心之人可以借助互联网搜索服务来发起一些特定的攻击,例如将有问题的代码混入到一些特定关键词的搜索结果里,一旦 AI 从搜索结果中捕捉到了这些内容,那么这些内容将会流入 AI 的上下文,进而混入 AI 的输出,实现攻击。这样的攻击已经有了先例,一位研究者通过在自己的简历页面混入白色的提示词呼唤 New Bing 从而在其输出中插入了内容。

对于企业来说,他们没有必要去冒这样的风险来试图用 AI 取代程序员,规模越大的企业,在这方面实际上会越谨慎,因为他们面临着更严格的监管、合规与内控压力。即使是在互联网行业内,情况也是如此,因为和一般的文本、图片素材不同,代码可以说是公司业务的核心资产了,大型企业会更加看重风险控制而不是经济效益。万一造成了一些重大事故,很有可能这一切都得不偿失。

结语
AI 确实给这个世界带来了非常多的震撼和改变,但是在「写代码」这个领域,我们还是得实事求是地说,出于种种限制,现阶段的 AI 距离能完全取代程序员还有非常遥远的距离。一些演示和媒体报道的案例看似惊人,好像明天程序员们就要失业了一样,但当我们实际深入去剖析的时候,我们会自然地发现,问题其实非常复杂,远没有我们看到的那样简单,而 AI 也并没有我们所看到的那般神奇,很多东西只是被夸大渲染了。

当然,阅读到这里,你仍然可能会说,AI 的发展是很迅速的,即使今天做不到,它明天或许也可以做到,AI 现在已经有了「写代码」的能力,那么未来它必然有可能让程序员失业。

对于这种可能性,我们并不否认,因为在未来某天如果 AI 真的突破了技术瓶颈,往 AGI 的方向大步跃进,在潘多拉魔盒打开之后,一切皆有可能。但就我们目光所及的未来来看,即使现在 LLM 发展得特别迅速,但只要它没有跳脱出现有的基础架构和训练模式,它仍然还是会具有一定的局限性。
用户评论