Redis 创始人 antirez 写下了自己 2024 年的第一篇博文,他从一名普通程序员的角度谈了谈对大语言模型的感受,虽然他的成就并不普通。他在文章里犀利评价 Google 引擎已经成为垃圾的海洋,并客观评价了现在的 AIGC 能力:愚蠢但通晓古今。
通过长期使用,他认为现阶段的生成式 AI 只会让已经很强的程序员变得更强。目前大多数编程任务都是在重复工作,根本不需要大模型有太高的推理水平,大模型很适合那些“用完就扔”的程序。我们对 antirez 的博文进行了翻译,并在不改变作者原意基础上进行了一些删减。
自从 ChatGPT 横空出世以来,包括后面以本地方式运行的各种大模型,生成式 AI 已然得到了广泛应用。我个人的目的一方面是想依靠大模型提高编码能力,另外还希望把宝贵的精力从繁琐且价值有限的工作中解放出来。相信很多朋友也像我一样,花费了无数时间搜索没什么启发性的技术文档、被迫学习各种过于复杂的 API、编写过短时间内就沦为垃圾的程序。工作不该是这样的,开发也不该是这样的。现如今,Google 引擎已经成了垃圾的海洋,我们得费尽心思才能在其中找到一点有用的内容。
另外,我本人并不是编程新手。哪怕不借助任何外部资源,我也能够编写代码,甚至可以说具备一定开发水平。只是随着时间推移,我开始越来越多地用大模型协助编写高级代码:Python 代码最多,但在 C 语言中则应用较少。
大语言模型最让我印象深刻的一点,就是我能准确意识到何时可以使用、而哪些情况下盲目使用只会拖慢进度。我还发现,大模型其实很像维基百科和 YouTube 上的各种视频课程:对于有意愿、有能力、更自律的使用者来说效果拔群,但对本就业务能力不足的朋友来说则边际收益递减。所以我很担心,至少在现阶段,生成式 AI 只会让已经很强的程序员变得更强。
下面让我们一步步开始讨论。
大语言模型:全知全能还是鹦鹉学舌?
机器学习新浪潮中最令人忧心的现象之一,就是 AI 专家对于大模型的认知还相当有限。我们虽然发明了神经网络,但在实质上发明的仅仅是一种自动优化神经网络参数的算法。硬件已经能够训练出越来越大的模型,并使用提取自待处理数据(先验素材)的统计知识,再通过大量迭代试验排除错误、逼近正确答案。必须承认,大模型确实要比以往其他架构效果更好。但总体来讲,神经网络本身仍然极不透明。
由于无法解释大模型为何具备某些新兴能力,预计科学家们的态度将更趋谨慎。但在另一个极端上,也有不少人都严重低估了大语言模型,认为它们只不过是某种更先进的马尔可夫链,最多只能重现在训练集中见到过的有限变化。但大量事实证据表明,这种大模型只是在“鹦鹉学舌”的理论根本站不住脚。
也有不少热心群众觉得大语言模型获得了某种实际上不存在的超自然力量。没那么玄乎,大模型最多只能对自己在训练期间接触过的数据表示空间进行插值,而这并不是什么新鲜成果。而且哪怕单论插值,其能力也相当有限(但足以超出人类预期,甚至带来惊喜)。如果能够更进一步,在接触过的所有代码围成的空间当中进行连续插值,那么大模型哪怕无法创造出真正新奇的事物,也足以取代 99% 的程序员。
好在现实没这么夸张,我们开发者们仍有生存的空间。大语言模型确实能编写出自己没有原样接触到的程序形式,也表现出通过融合训练集内不同出现频率的思路来引导开发方向的初步能力。只是这种能力目前还存在很大的局限性,而种种微妙的推理任务总会令大语言模型遭遇灾难性的失败。但必须承认,大语言模型已经代表着 AI 技术从诞生至今最伟大的成就,这一点应该成为所有讨论的前提。
既愚蠢,却又通晓古今
此言不假:大语言模型最多只能进行最基本的推理,这种推理还不够准确,很多时候充满了事实层面的幻觉和捏造。但它们同样拥有着渊博的知识。
以编程领域及其他能够获取高质量数据的场景为例,大模型就像那种通晓古今的愚蠢学者。与这样的合作伙伴进行结对编程 并不明智(当然,在我看来哪怕是跟人做结对编程也不明智):它们往往会抛出荒谬的想法,而我们则需要在开发中不断努力强调自己的思路。
但反过来,如果把这个博学的傻瓜当成可支配的工具、由它提出问题以作为我们激发灵感的素材,那么效果将完全不同。目前的大模型还无法引领人类跨越知识的鸿沟,但如果我们想解决某个自己不太熟悉的问题,它们往往可以帮助我们从一无所知快速前进到具备完全自学能力的程度。
在编程领域,之前二、三十年间的程序员们可能对大模型的这种能力评价不高。毕竟那时候我们只需要掌握几种编程语言、特定的经典算法和那十来套基础库,余下的就纯粹是自我表达、发挥才智、运用专业知识和设计技能的部分了。只要拥有这种能力,我们就是当之无愧的专业程序员,具备了解决一切难题的潜质。
但随着时间推移,各种框架、编程语言和库开始轮番上阵,爆发式的增长令开发难度激增,也给程序员的日常工作带来了既无必要、又不合理的诸多困扰。在这样的现实和背景之下,大模型这样一位通晓古今的白痴队友就成了最宝贵的前进指引。
举个例子:我自己的机器学习实验在整整一年间都是靠 Keras 完成的。后来出于种种原因,我转而使用 PyTorch。当时我已经学习了什么叫嵌入和残差网络,但我实在不想逐字逐句去研究 PyTorch 文档(当初我在学 Keras 时就是这么硬啃下来的,如果能有 ChatGPT 肯定可以帮我回避很多痛苦的回忆)。如今有了大语言模型,我可以非常轻松地编写出使用 Torch 的 Python 代码,唯一的前提就是对想要组合的模型拥有清晰的思路、同时能够提出正确的问题。
用案例说话
请注意,我这里说的可不是那些简单的需求,比如“X 类是怎么实现 Y 的?”如果只是这类场景,那大语言模型的作用其实相当有限,甚至可以说跟搜索引擎和技术论坛区别不大。相反,复杂模型能做到的要多得多,包括那些短短几年前我们还无法想象的功能。
现在我可以告诉 GPT-4:“看看,这是我在 PyTorch 实现的神经网络模型。这些是我设置的批任务。我想调整张量大小,保证批函数与神经网络的输入相兼容,同时想以这种特定方式来表示。你能告诉我需要怎样的代码进行重写吗?”提示完成之后,GPT-4 就会编写代码,而我要做的就是在 Python CLI 中测试张量结果的维度是否满足需求、数据布局是否正确。
再来看另一个例子。前段时间,我需要为某些基于 ESP32 的设备开发 BLE 客户端。经过一番研究,我发现多平台蓝牙编程绑定大多无法直接使用,而解决方案非常简单,使用 macOS 的本机 API 在 Objective C 中编写代码即可。这就要求我同时处理两个问题:学习 Objective C 那繁琐的 BLE API,适应种种毫无意义的模式(我属于那种极简主义者,而 Objective C 的 BLE API 绝对是“优秀设计”的典型反例);同时学会如何用 Objective C 编程。我上次用它编程还是在十年之前,如今早就忘了事件循环、内在管理等技术细节。
最终结果就是以下代码,虽然不够优雅简洁,但至少能够正常起效。在大模型的帮助下,我只用了很短时间就完成了开发,这在以往根本就无法想象:
https://github.com/antirez/freakwan/blob/main/osx-bte-cli/SerialBTE.m
这些代码主要由 ChatGPT 生成,而我的工作就是把自己想做、但不太确定要怎么实现的要求粘贴进去。如此一来,大模型就能向我做出解释,包括问题的实质是什么、应当如何解决。
的确,大模型并没有实际编写多少代码,但却帮助我显著加快了开发速度。如果没有 ChatGPT,我能不能把项目做下来?当然也行,但最重要的并不是我要额外投入多少时间,而是我可能干脆就放弃了:毕竟这么麻烦的事情,已经不值得我浪费精力。
在我看来,这才是真正决定性的因素。如果没有大模型,我在衡量工作量和收益之后压根不会编写这样一个程序。大模型甚至还帮我完成了一项比程序本身更重要的调整:在项目中,我修改了 linenoise(我使用的行编辑库)以使其能在多路复用中生效。
即抛型程序
像前文提到的这类案例还有很多,这里就不再过多重复了,毕竟类似的故事基本都是一样的套路和效果。在日常工作中,我还经常面临另一类问题,就是想要快速获得某些可以验证的成果。在这种情况下,同样可以使用大模型来提升探索效率。
对于此类场景,我往往会让大模型负责编写所有代码。例如,当我需要编写某些即抛型程序时,比如下面这个:
https://github.com/antirez/simple-language-model/blob/main/plot.py
我想要对小型神经网络学习过程中的损失曲线进行可视化,因此向 GPT-4 展示了 PyTorch 程序生成的 CSV 文件格式,然后提出如果我在命令行内指定多个 CSV 文件,希望能对不同实验所验证的损失曲线进行比较。而以上链接就是 GPT-4 生成的结果,前后只用了短短 30 秒。
同样的,我还需要一个程序来读取 AirBnB CSV 报告,并按月份和年份对各处公寓进行分组。之后,结合清洁费用以及单次预订的住宿天数,由它来统计一年中不同月份的平均租金价格。这款程序对我来说确实有用,但编写过程又极其无聊:因为里面根本没什么新奇有趣的功能。于是乎,我选取了一部分 CSV 文件并粘贴进 GPT-4 当中,之后描述了一下希望大模型解决的问题。输出的程序一次运行成功。但我们自己得正确理解具体的数据分组方式,否则会感觉这些数据既分散又无序。
通过简单的推理,我认为大模型绝对不是简单从接触过的训练素材中照搬来的解决方案。没错,GPT-4 在训练期间肯定观察到过类似的程序,只是这些程序所对应的具体分组要求跟我的提示有所不同,特别是要求分组成特定格式的 CSV 文件。所以在我看来,大模型应该能在一定程度上对训练集中不同程序描述的空间进行插值。
让我自己浪费时间编写这类简单程序实在是不太明智。事实证明大模型可以承接此类任务,帮助我将精力集中在真正重要的工作上,这无疑变相提高了我的代码生产效率。
大模型搞不定的典型任务:系统编程
虽然我的大模型编程尝试取得了不小的成功,但在使用 C 语言编写程序时,我发现大模型更多只能作为便携的文档记录助手。我本人是系统编程方面的专家,在这类用例中,大模型由于缺乏复杂的推理能力而几乎帮不上什么忙。相信各位朋友也有类似的感受。
下面我们一起来看这段实验性的提示词:
“为 bloom 过滤器生成一条优雅、短小且有效的 C 语言实现。应重点关注哈希函数处理,然后用高质量 C 语言进行编写。另须考虑,这条实现的大小应可存储 10 万个元素,误报概率不得超过 5%。添加的元素是以 null 结尾的字符串。“
GPT-4 给出的答案说不上好。Bloom 过滤器其实相当普遍,涉及的数据结构也不特殊。但很明显,编写一个像样的 bloom 过滤器需要更强大的抽象能力:例如找到一种有效方法对同一字符串进行 N 次哈希处理,并确保各哈希值得到充分的去相关处理。如果换个思路,明确要求 GPT-4 修改哈希函数,使其产生 N 个去相关输出,那么它给出的解决方案就靠谱多了。如果它能自己发现这个思路,就会以不同的方式编写 bloom 过滤器,使用单个哈希函数一次设置 K 个 bits。
事实就是,GPT-4 能够独立编写出适当也更加通用的哈希函数,但在编写 bloom 过滤器这类更大的项目时,它却未能表现出良好的推理能力,而是给出了两个不同但却高度相似的哈希函数。
总而言之,当前大语言模型的推理能力仍然孱弱,再加上关于这个问题的资源可能比较稀少,甚至存在大量低质量资源,于是导致其给出的结果不尽如人意。而且这绝不是孤立的案例,我还多次尝试在算法或系统编程当中使用大模型,结果也非常差。哪怕是下调对推理能力的预期,它也没法重现 Python 编程环境中的代码生成水平。
但与此同时,GPT-4 能够反编译它所输出的函数(需要通过单独的会话),也能准确理解这样做的意义,因此,大模型在系统编程场景下还是具有一定作用的,只是非常有限。
另一个有趣且令人期待的点,是在上述情况下,较小模型和较大模型间的表现有着显著差异。
虽然 Mixtral 是一套适合多种用途的优秀模型,但考虑到大模型本就孱弱的推理能力,目前能够总结出的规律明显是体量越大、效果越好。另外,本地模型 deepseek-coder 设置为 4 bits 量化精度,因为本地设备的内存不足以在更高的精度上运行模型。哪怕如此,凭借 340 亿参数,它在同一问题上的推理能力还是更强一些。
在尝试中,我给出了关于问题的解决线索,而模型则正确得出了答案、确定了引发问题的真正根源,并最终给出了行之有效的替代方案。这类应用在任何文档、书籍或者 Google 搜索中都没有直接答案。
无论是从原始插值的角度、还是其他思路来看,模型都已经掌握了某种形式的推理能力。也只有借助这份推理能力,AI 才能找到问题的根源并发现潜在的解决方案。所以我觉得没必要再争论了,大语言模型对于程序员们确实具备积极的辅助意义。
但与此同时,过去几个月间的使用体验表明,在系统编程领域、特别是对于经验丰富的程序员们,大模型几乎无法给出任何可以拿来就用的解决方案。
我目前负责的 ggufflib 项目要求编写一个读取和写入 GGUF 格式文件的库,也就是 llama.cpp 加载量化模型的格式。最初,为了理解量化编码的工作原理,我尝试使用过 ChatGPT,但最后还是决定对 llama.cpp 的代码进行逆向工程——这样速度还更快些。
理想中的大语言模型应该能根据接触到的数据编码“结构”声明和解码函数,还原出关于数据格式的说明文档,借此帮助系统程序员理解设计思路。可虽然 llama.cpp 的函数不大,完全可以塞进 GPT-4 的上下文窗口,但输出的结论却毫无意义。
对于这类情况,我们就只能像最传统的程序员那样:掏出纸和笔,一行行阅读代码,查看解码器提取的 bits 在哪里注册。
正确看待大语言模型
虽然怀着深深的遗憾,但我不得不承认:目前大多数编程任务都是在以略有不同的形式重复着相同的工作,根本不需要太高的推理水平。而大语言模型在这方面表现出色,只是仍然受到上下文规模的硬性约束。
而这也应当引起我们程序员的思考:这样的程序,真值得我们花费时间和精力动手编写吗?没错,这活能给我们带来相当丰厚的报酬,但如果大语言模型逐渐接手了这部分任务,那么五年、最多不超过十年,就会有很多程序员同行丢掉饭碗。
再有,大语言模型到底具不具备一定程度的推理能力,还是说仍然是在鹦鹉学舌、只是学得更加惟妙惟肖?我认为某些情况下它们确实具备推理能力,也就是掌握了符号学家们所说的“能指”概念,即实质上并不存在的意义。
相信每一位跟大模型经常打交道的朋友,都能在理解它们局限性的同时,感受到其中体现出的推理之力:它们对以往接触过的内容的融合能力,远远超出了随机输出单词的范畴。尽管其学习过程主要是在预训练阶段完成,但在预测下一个 token 时,大模型还是会根据目标建立起某种形式的抽象模型。这个模型虽然还很脆弱、不够完备和完美,但通过实际观察,我们会意识到这种能力的客观存在。正所谓耳听为虚、眼见为实,哪怕可能挑战数学专业的确定性原理、与最伟大的技术专家观点相背,我也仍然对大模型表现出的认知水平抱有信心。
最后,希望大家能够积极拥抱大模型,尝试用它解决编程中的各种问题。向大模型提出正确问题将成为一项基础性的开发技能,而且演练的次数越多,AI 就越是能更好地改进工作效果。哪怕不考虑 AI 因素,这种明确清晰的问题描述能力也有助于我们更好地跟他人沟通。毕竟大语言模型并不是唯一跟不上我们思维过程的会话对象。相信大家也有体会,很多程序员虽然在自己的特定领域里非常出色,但沟通能力却很差,这也成为限制其职业发展的瓶颈。
现如今的 Google 引擎已经变得不那么好用,所以哪怕是从浓缩和提炼文本内容的角度,大模型也肯定具备巨大的现实意义。就个人而言,我也将继续使用大模型、了解大模型。我向来不喜欢学习晦涩的通信协议细节,也不愿跟那些炫技式的复杂库编写方法打交道。对我来说,这些只是白白浪费时间和精力的“垃圾知识”。感谢大语言模型,把我从这些曾经的泥潭当中解救出来。
参考:
http://antirez.com/news/140