Original 李建忠 李建忠研思
最近ChatGPT及基于大语言模型(Large Language Model,以下简写为LLM)的Github Copilot等工具出来之后,在软件开发领域也带来了非常大的震撼。著名的观点有Fixie创始人、前Google工程总监Matt Welsh在ACM通讯上发表的《The End of Programming:编程的终结》,以及OpenAI网红研究科学家Andrej Karpathy的“The hottest new programming language is English”,这些言论在海外也是非常有争议性的。比如我和C++之父Bjarne Stroustrup的交流,他老人家对LLM能替代程序员就相当不以为然。这些专家观点,很多时候不是简单的Yes or No的结论,因为LLM冲击的范围太大,而且很多时候大家谈的都不是同一件事情。
以Andrej Karpathy为代表谈的“The hottest new programming language is English”,是对其2017年发表的著名文章《Software 2.0》的延续。其主要观点是未来用“神经网络计算替代传统计算”,那么这时候对“神经网络”的编程就是自然语言。而传统程序员使用高级语言来编程的方式,会逐渐式微。这一观点足以颠覆整个自1944年冯诺伊曼以来的计算机体系架构、包括程序理论、编译原理、操作系统等等整个计算机科学体系。这个观点,虽然惊世骇俗,我觉得也足够深刻,但它的影响不是短时间能显现的,需要整个AGI产业相当的成熟和繁荣,同时需要解决巨大的能源和算力需求。因篇幅有限,这个我会放到下一篇文章中谈。
而以Matt Wels为代表的,谈的其实是使用LLM来生成代码、需求文档、设计文档、测试代码等一系列活动,它是对传统程序员工作方式的变革,仍然建立在冯诺伊曼体系架构上,遵从现有计算机科学体系。它也是目前正在我们眼前就发生的事情。
但这些专家观点,加上技术社区一些极端言论的鼓噪,在程序员群体造成了一种某名奇妙的“被提示工程师淘汰”的恐慌感,甚至最近在某些高考家长群体中也造成了一些误导——“听说程序员将来也要被ChatGPT给替代了,所以建议不要报计算机相关学科”。
作为一个还算资深的计算机专业人士,我深感有责任说点什么。先说我的观点,我认为在LLM生成代码的语境下,Prompt不等于编程,所谓的LLM“提示工程师”淘汰程序员也是一个伪命题。我分以下七个部分来阐述我的观点。
一、确定性计算 VS. 概率计算
在前面《AGI时代的产品版图和范式》的文章中,我曾提出【计算1.0 和 计算2.0】的范畴和重要特征。其中提到神经网络的概率计算特点,如果拿它和传统计算机的确定性计算来对比的话,可以看下图(该图来自于我今年4月份在上海的SDCon 2023全球软件研发技术大会上的演讲稿):
对于计算1.0时代的数字逻辑电路来讲,做的都是确定性计算(左图),即给定一个结构化输入X,那么结果Y则是确定的。但对于计算2.0时代的数字神经网络(也就是LLM的原理),做的都是概率性计算(右图),即给定一个自然语言输入u(也就是所谓的提示词Prompt),那么结果是一个概率分布:Y1, Y2, Y3, Y4, Y5……可以有很多。
概率计算是计算2.0时代,也就是LLM非常重要的基本特征。
二、LLM 生成代码的基础原理
不仅自然语言,计算机编程语言也是人类知识的载体,而且是逻辑性更强的语言载体。如果借用OpenAI 首席科学家Ilya Sutskever的话“LLM(大语言模型)是对人类知识的压缩”,那么我们可以说计算机编程语言是对人类逻辑的压缩。
无论ChatGPT,还是Github Copilot等代码生成工具,其原理都是通过海量代码数据学习(主要来自Github开源代码),从而使模型掌握压缩后的编程知识和逻辑。实际上很多研究都表明,在训练了代码数据之后,LLM的泛化能力使得它的逻辑推理显著增强——这和一个人学习了编程语言后,逻辑能力大为提升是一个道理。
然后,通过Prompt的方式,就可以让LLM自动生成包含一定知识和逻辑的代码。这种代码生成,仍然具有LLM的“概率计算”特点。下面和“传统编程”做一个对比。
在传统编程下,高级语言(即program) 通过编译器(计算1.0时代的确定性逻辑)转换为汇编语言。而在LLM代码生成下,自然语言(即prompt) 通过LLM (计算2.0 时代的概率性逻辑) 转换为高级语言。
这里面有两阶段的概率性:第一层 自然语言prompt阶段,大家都知道自然语言表述有巨大的随意性,虽然当前各种 prompt技巧甚至prompt patterns发展的如火如荼,但它本质上还是自然语言,不可能再走回到结构化编程语言的老路上,所以只要是自然语言prompt,它的随机属性就永远存在;第二层 LLM经过神经网络推理生成代码,这个阶段前面谈过,LLM是个计算2.0时代的概率性逻辑,它的输出当然是概率性的。
这两阶段的概率性,使得LLM生成的高级语言代码,具有相当的不确定性。这也是为什么很多程序员朋友使用了Copilot等工具后,并不能得到预期稳定的代码输出。
三、只做提示词工程,LLM是否能完成软件编写?
有些朋友可能会说,程序员编写代码,也是生物神经网络计算,也有很大不确定性啊?同样一个任务,A程序员和B程序员编写的代码肯定不一样,即使A程序员放不同的时间,编写的代码也不同啊?
其实程序员“生成”代码之后,还有一个不断通过“逻辑校验”、“编译器校验”、“ 各种测试校验”的过程,这是一个从概率性逻辑向确定性逻辑的逐步收敛过程。这样一个收敛过程,通常伴随着语义正确性推演、内存和资源使用正确性确认、设计符合良好耦合原则确认、单元测试结果正确性确认等一系列过程。不是“生成完代码”就大功告成了。
用一个简单的公式表示:编码 = “代码生成”+“确定性收敛过程”
其实整个编码活动中,这个“确定性收敛过程”常常是比“生成代码”更为重要、耗时更长、也更有价值的活动。当然,这些也可以让LLM来辅助(比如LLM帮助debug、生成单元测试等)。但是注意我用的词是“辅助”,而不是“完成”,因为LLM本质是概率性计算,而这些“收敛活动”最后都要求“确定性计算”。最终的收敛点如果没有程序员“介入矫正”和“最终裁决”,是无法彻底完成的。
因此仅在“编码”这一环节,提示词工程师都是完全不够的。必须程序员不断介入。如果说一个“提示词工程师”完全不懂某一门编程语言和技术栈,所谓 Prompt就大概只是花拳绣腿,想独立完成该语言下的软件开发工作,就有点异想天开了,匡论“淘汰”程序员?
四、LLM的劣势,程序员的技能优势——“抽象”
很多软件项目实践都表明LLM在细颗粒度、抽象层次较低的任务上,表现非常好;但在大颗粒度、抽象层次较高的任务上,表现比较差。而大颗粒度、高抽象的设计才是软件开发中核心的核心——抵抗软件的复杂性。
正如面向对象大师Grady Booch在回复Andrej Karpathy的“The hottest new programming language is English”争论时,也鲜明地指出“整个软件工程的历史就是不断提升抽象层次”。
而这一点和LLM将人类知识“不断压缩、进而抽象”的发展路径不谋而合。
所以在即将到来的AGI时代,软件开发中比较难被LLM替代的部分主要包括以下抽象层次较高的任务:需求分析、领域建模、架构设计、详细设计、模块耦合性设计、接口设计、开发者测试设计等。而具体的类型实现、函数实现、算法实现、单元测试实现等这些抽象层次较低的任务则是LLM特别胜任的。所以,AGI时代,程序员最重要的技能要聚焦在上述抽象层次较高的任务,才有号令LLM的资本。
同样用一个简单的公式表示:软件开发=抽象层次较高的任务 + 抽象层次较低的任务(编码)
如果套用上面的编码公式,可以推演如下:软件开发= 抽象层次较高的任务 + “代码生成”+“确定性收敛过程”
其中代码生成是目前LLM最为擅长的,而抽象层次较高的任务 和 “确定性收敛过程”都是离不开程序员的。
不过,对于抽象层次高的任务,LLM未来一定无能为力吗?理论上来讲,人类大脑的生物神经网络可以掌握的,基于LLM的数字神经网络一定也可以。能不能实现主要看LLM训练数据的质量、RLHF中的人类反馈、FineTune、Prompt等环节是否能将软件行业积累这么多年的各种“抽象”的优秀实践都学习掌握到?至少目前以GitHub开源代码为主要训练数据来源的LLM在这方面表现还有相当大的距离。
我相信这也将是软件领域今后长期活跃的研究方向。但这一定是一个渐进、漫长的过程。
五、LLM没有改变什么?
有些朋友因为媒体的各种鼓噪产生了对AGI(通用人工智能)强大的幻想症,觉得LLM无所不能,LLM会改变世界的一切规则。甚至觉得有一天LLM会不会发展到不需要生成高级语言、不需要编译器,给Prompt就能直接生成计算机程序?
这要看大家在什么前提下谈,如果不抛弃冯诺伊曼体系架构,那么这种设想就不可能。
因为LLM本质上是一个大语言模型,它接受的是语言输入,输出的也是语言。在冯诺伊曼体系架构下,它不会改变数字电路“与或非”的原理、不会改变计算机程序的基本逻辑、不会改变编译原理、不会改变操作系统的规则、也不会改变算法、数据结构、网络协议……等等自图灵、冯诺伊曼以来计算机科学近八十年所积累的所有的“Law”。
六、LLM将会改变什么?
那么LLM在软件开发领域到底会改变什么?它改变的是,以“语言”为载体,由人参与的“经验性活动”,大量需要“各种语言载体”进行沟通、协调、对接、传授的部分。比如:需求分析、软件设计、代码编写、开发者测试、代码评审、重构、整洁代码、缺陷调试等等。
说到“各种语言载体”,其实除了自然语言和编程语言外,软件活动中还有很多种“语言”,例如:各种 结构化文档、数据文件、图表(Diagram) 、XML、Schema、Table…… 这些都是LLM可以大力发挥“大语言模型”神力的地方。
这些“经验性活动”组成了我们通常所说的软件工程,都是LLM会引起剧烈变革的地方。比如我的朋友、来自同济大学的朱少民教授就提出软件工程3.0,对这方面有很多阐述。
七、LLM是程序员的效能倍增器
站在软件工程的角度,LLM会大幅提升原来软件开发过程中的每一个环节。因此学习掌握一定的Prompt技巧是有必要的,但前提是首先要掌握好“编程语言”和相关技术栈本身——这也是做好Prompt的前提。没有“编程语言”和技术栈本身的掌握,再多的Prompt技巧只是缘木求鱼。实际上有些朋友在软件项目中已经发现,花费在反复Prompt和调错上的时间代价有时候比手工编程还要高很多。
但我也反对一些老派程序员“致命的自负”,总是认为自己手搓代码比LLM生成代码快、质量好,面对LLM对软件开发的变革而无动于衷。就像有了社交网络之后,一个人能够管理朋友的数量,是没有社交网络之前的好多倍。同样,有了 LLM 之后,一个程序员的效能提升,也会成倍增长。
有些朋友可能会从“结果”的角度来推演,LLM既然让程序员效能提升了数倍之后,那原来需要30个程序员,现在是不是只需要5个程序员就可以了,其他程序员不会被淘汰吗?
这是站在“总需求量固定”的思维定势下的结论。实际上我认为,假如有了LLM对程序员的赋能之后,整个社会对软件的数量、复杂度、规模的需求都会出现井喷效应,从而会更大程度上创造出更多程序员岗位。比如飞行技术的发展,迎来了航空业的大发展,促进了更多飞行员的需求,而不是相反。
总结我的结论,在不抛弃冯诺伊曼体系架构前提下。
在AGI时代,掌握编程语言和其背后抽象层次较高的部分、以及相关技术栈,仍然是优秀程序员的基本功。“Prompt Engineering提示工程”对软件开发可以起到效率倍增的作用,但它不是软件开发的全部,“提示词工程师”也替代不了程序员的作用。