例如,我曾花了无数个小时搜索那些奇特却无趣的技能文档、曾被迫学习过于繁芜的 API、曾编写过一些几个小时后就被丢弃的程序……这些都是我不想做的事情,尤其现在谷歌搜索引擎也已沦为垃圾信息的海洋,我得费心筛选才能找到一些有用的东西。

与此同时,我在编程方面当然不是新手。
我可以在没有任何赞助工具的情形下编写代码,并且也常常这么做。
但随着韶光的推移,我开始越来越多地用 LLM 来编写高等代码,尤其是在 Python 中,在 C 措辞中则较少。
在对 LLM 频繁利用的过程中,我逐渐知道了什么情形该利用它们、什么情形利用它们只会拖慢速率。

除此之外,我还理解到,LLM 实在有点像维基百科和 YouTube 上的各种视频课程:对付本身就故意愿、有能力和有纪律的人,有了 LLM 的帮助险些为虎傅翼;而对付那些本就不太上进、拖后腿的人,强大如 LLM 也帮不了他们。
因此我担心,至少就现阶段而言,LLM 只会让本就精良的人变得更精良。

但是,让我们一步一步来。

Redis 之父自曝用 AI 写代码锐评LLM 是博学的傻瓜有望取代 99 的轨范员

全知全能还是鹦鹉学舌?

在这波机器学习的新潮中,最令人担忧的征象之一是 AI 专家对付 LLM 的认知也较为有限。
伟人发明了神经网络,乃至还发明了自动优化神经网络参数的算法,而硬件能演习越来越大的模型,利用对要处理数据的统计知识(先验)以及大量试错来逼近最佳结果,人们创造了比其他方法更有效的架构。
但总体而言,神经网络仍旧相称不透明。

由于无法阐明 LLM 为何会涌现某些新功能,许多人推测科学家们会更加谨慎。
但另一方面,还有部分人严重低估 LLM,认为它们充其量只是略为前辈的马尔可夫链,最多只能重复在演习集中看到的极其有限的变革。
不过后来在面对证据时,这种“鹦鹉学舌”的说法险些被推翻。

与此同时,还有许多热心群众将现实中并不存在的超自然力量也归因于 LLM——而实际情形是,LLM 最多只能对自己在演习期间打仗过的数据表示空间中进行插值,这早已不是什么新鲜事。
其余值得一提的是,LLM 的插值能力也很有限,如果某个 LLM 能够在其打仗过的所有代码所限定的空间内连续插值,纵然它做不到真正的创新,也能够取代 99% 的程序员了。

好在实际情形并非如此。
LLM 确实能编写出自己从未见过的程序,并以一定频率将演习集中涌现的不同想法奥妙领悟,但这种能力的局限性也很大:每当须要奇妙的推理时,LLM 就会惨遭失落败。
不过话说回来,LLM 仍代表了 AI 出身至今的最大造诣,这没什么好否认的。

屈曲,但无所不知

有个事实我们须要明确:LLM 最多只能进行最基本的推理,且每每不准确,还常常夹杂着一些不存在事实的幻觉,但它们确实知识渊博。
在编程领域以及其他有高质量数据的领域,LLM 就像屈曲的天才,知道很多事情。

与这样的差错进行结对编程非常麻烦(对我而言,结对编程这件事本身就很麻烦):它们会有一些荒谬的想法,我们则必须不断地将自己的想法强加于它。
当然,如果这个博学的“傻瓜”可以为我们所用,回答我们向它提出的所有问题,那情形就大不相同了。
现有的 LLM 可能还无法超过知识的鸿沟,但如果我们想处理一个不太理解的主题,那 LLM 可以让我们从绝对无知的状态中解脱出来,让我们理解到足够的知识从而独立前行。

在编程领域,大概是二三十年前,人们对 LLM 的能力兴趣并不大。
那时,你必须节制几种编程措辞、经典算法和十个基本库。
剩下的就得靠自己了,靠自己的聪慧、专业知识和设计技能。
如果你具备了这些要素,你便是一个闇练的程序员,险些能做所有的事情。
随着韶光的推移,我们目睹了框架、编程措辞和各种库的爆炸式增长,虽然这种繁芜性的爆炸增长每每是完备不必要和不合理的,但事实便是事实。
在这种情形下,一个博学的“傻瓜”便是一位宝贵盟友。

我举个例子:我对机器学习的实验至少进行了一年,一贯在利用 Keras,后来出于各种缘故原由,我转到了 PyTorch。
我已经知道嵌入或残差网络是什么,但我不想一步一步地学习 PyTorch 文档(就像我学习 Keras 时那样,当时还没有 ChatGPT)。
而有了 LLM 后,编写利用 Torch 的 Python 代码就变得非常随意马虎了,我只需对我想要组合的模型有清晰的想法,并提出精确的问题即可。

举例解释

我不是在评论辩论像“嘿,X 类中实行 Y 的方法是什么?”这样的大略问题,这样我可能会赞许那些对 LLM 持疑惑态度的人的不雅观点。
事实证明,更繁芜的模型所能做的事情要风雅得多。
我可以见告 GPT4:看,这是我在 PyTorch 中实现的神经网络模型,这是我的批处理数据,我想调度张量的大小,使输出批次的函数与神经网络的输入相匹配,我想用这种分外的办法来表示事物。
你能给我展示进行重塑所需的代码吗?然后,GPT4 编写了代码,而我只须要在 Python CLI 中测试张量是否真的具有我须要的维度,以及数据布局是否精确。

还有一个例子。
前段韶光,我不得不为某些基于 ESP32 的设备实现一个 BLE 客户端。
经由研究后,我创造多平台蓝牙编程绑定或多或少都无法利用。
办理方案很大略,利用 MacOS 确当地 API 用 Objective C 编写代码。
于是,我不得不同时处理两个问题:学习 Objective C 繁琐的 BLE API,同时还要记起如何在 Objective C 中编程——我上一次用 Objective C 写程序是十年前,根本不记得事宜循环、内存管理等许多细节。

然而在 LLM 的帮助下,我用极短的韶光就写完了代码。
终极的代码是这样的,虽然不算都雅,但至少能完成任务:

https://github.com/antirez/freakwan/blob/main/osx-bte-cli/SerialBTE.m

代码紧张是通过在 ChatGPT 上剪切粘贴我想要做的事情来编写的,由于刚开始我不太理解如何做,最初天生的代码没法正常运行,但我可以让 LLM 向我阐明问题所在以及如何办理它。
如果没有 ChatGPT,我能做得到吗?当然可以,但这不仅摧残浪费蹂躏了我的韶光,我可能根本也不会去考试测验,由于这不值得:编写这样一个对我的项目来说次要的程序,其付出和收益之间的比例并不可不雅观。

末了还有一个例子,与代码编写无关,而是与数听说明有关。
当时,我想建立一个用我在网上找到的卷积神经网络的 Python 脚本,但文档相称缺少。
这个网络的上风在于它采取 ONNX 格式,因此我可以轻松提取输入和输出列表以及它们分配名称的列表。
我只知道这个卷积神经网络能检测图像中的某些特色,但输入图像的格式和大小及输出的繁芜度我都不太理解。

我首先将 ONNX 网络元数据的输出复制粘贴到 ChatGPT 中,并同步了我对该网络的一点理解。
然后,ChatGPT 假设输入的组织办法,输出可能是表示图像中与潜在毛病相对应部分的归一化方框等。
经由几分钟的来回谈论后,我得到了一个能进行网络推理的 Python 脚本以及将起始图像转换为适宜输入的张量所需的代码等等。

一次性程序

上述类似的例子还有很多,我在这里就不一一赘述了,基本上都是同样的情形和结果。
除此之外,我还常常碰着另一类情形:想迅速理解某些可以快速验证的东西。
在这种情形下,我就会用 LLM 来加快我对知识的需求。

不过,在不同的情形下,我也会让 LLM 编写所有代码。
例如,当我须要编写一个一次性的程序时,比如这个:

https://github.com/antirez/simple-language-model/blob/main/plot.py

我须要可视化一个小型神经网络学习过程中的丢失曲线。
我向 GPT4 展示了 PyTorch 程序在学习过程中天生的 CSV 文件格式,然后我哀求,如果我在命令行中指定了多个 CSV 文件,我就不再须要相同实验的演习和验证丢失曲线,而是要比较不同实验的验证丢失曲线。
以上结果便是 GPT4 天生的结果,统共耗时 30 秒。

同样,我须要一个程序来读取 AirBnB 的 CSV 报告,并按月份和年份进行分组。
然后,考虑清洁用度和每次预订的住宿天数,它将统计出一年中不同月份的均匀租金价格。
这个程序对我来说非常有用,但编写它也非常无聊:没有任何有趣的东西。
因此,我从 CSV 文件中截取了一小部分,并在 GPT4 上进行了剪切粘贴,然后给 LLM 写了要办理的问题,其天生的程序一次就成功了,以下,我将展示完全代码:

pythonimport pandas as pdpd.set_option('display.max_rows', None)df = pd.read_csv('listings.csv')reservations = df[df['Type'] == 'Reservation']reservations['Start Date'] = pd.to_datetime(reservations['Start Date'])reservations['Year'] = reservations['Start Date'].dt.yearreservations['Month'] = reservations['Start Date'].dt.monthreservations['Nightly Rate'] = (reservations['Amount'] - reservations['Cleaning Fee']) / reservations['Nights']all_listings = reservations['Listing'].unique()all_years = reservations['Year'].unique()all_months = range(1, 13)index = pd.MultiIndex.from_product([all_listings, all_years, all_months], names=['Listing', 'Year', 'Month'])all_data = pd.DataFrame(index=index).reset_index()merged_data = pd.merge(all_data, reservations, on=['Listing', 'Year', 'Month'], how='left')average_nightly_rates = merged_data.groupby(['Listing', 'Year', 'Month'])['Nightly Rate'].mean().fillna(0)print(average_nightly_rates)

要准确理解如何对数据进行分组,且这些数据本来就相称分散和无序,须要一些大略的推理:这不是一个 LLM 大略地重复一些它所见过的措辞可以办理的问题。
GPT4 在演习过程中可能打仗过类似程序,但与我所哀求的提示条件必定有所不同,但它依旧能写出符合的程序代码。
在我看来,这表明 LLM 能在一定程度上对演习集中各种程序描述的空间内进行插值。

在我看来,编写这种程序只会摧残浪费蹂躏我的韶光,而 LLM 可以为我代劳,这无疑直接加速了我编写代码的能力:我可以专注于真正主要的事情。

当 LLM 不尽如人意时:系统编程

只管我在利用 LLM 和编程方面取得了成功,但当我编写 C 措辞程序时,我险些总是把 LLM 仅用作一种更方便的文档形式。
我是系统编程专家,在这种情形下,只有当 LLM 能够进行繁芜推理时才会对我有用:然而在这种场景中,它们险些总是失落败的。

让我们从这个实验的提示开始:

概述一个俊秀、小巧但可行的 C 措辞实现的 Bloom 过滤器的哀求。
重点考虑哈希函数的主要方面,然后用高质量的 C 措辞编写出来。
同时考虑到你的示例实现应能存储 100,000 个元素,误报率不超过 5%,添加的元素因此空字符结尾的字符串。

以下是输出:

c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#define N 100000 // Number of elements#define P 0.05 // False positive probability#define M (int)(-(N log(P)) / (log(2) log(2))) // Size of bit array#define K (int)(M / N log(2)) // Number of hash functionsunsigned char bitArray[M / 8 + 1];void setBit(int n) { bitArray[n / 8] |= 1 << (n % 8);}int getBit(int n) { return bitArray[n / 8] & (1 << (n % 8));}// Basic hash functions (for demonstration purposes)int hash1(char str) { int hash = 5381; int c; while ((c = str++)) hash = ((hash << 5) + hash) + c; return abs(hash % M);}int hash2(char str) { unsigned long hash = 0; int c; while ((c = str++)) hash = c + (hash << 6) + (hash << 16) - hash; return abs(hash % M);}void add(char str) { setBit(hash1(str)); setBit(hash2(str)); // Add more hash functions if needed}int is_in(char str) { return getBit(hash1(str)) && getBit(hash2(str)); // Check more hash functions if used}int main() { char testStr = \公众testString\"大众; add(testStr); if (is_in(testStr)) { printf(\"大众%s is probably in the set.\n\公众, testStr); } else { printf(\"大众%s is definitely not in the set.\n\"大众, testStr); } return 0;}

从天生代码来看,GPT4 的表现不太出色。
Bloom 过滤器的运用相称广泛,不是一种太过奇异的数据构造。
不过要编写一个像样的 Bloom 过滤器,显然须要更强的抽象能力,例如找到一种有效方法,对同一字符串进行 N 次哈希处理,并确保各哈希值充分不干系。

然而,如果你明确哀求 GPT4 修正哈希函数,使其产生 N 个不干系的输出,它提出的办理方案要好得多:

cunsigned int hash(const char str, unsigned int hash_id) { unsigned int hash = 5381; int c; while ((c = str++)) { hash = ((hash << 5) + hash) + c + hash_id; } return hash % BF_SIZE;}

如果是 GPT4 自己提出了这个想法,它可能会以不同的办法编写 Bloom 过滤器,利用单个哈希函数一次设置 K 个 bits。

也便是说,GPT4 能独立完成编写一个得当且更通用的哈希函数的任务,但在编写 Bloom 过滤器这一更大的项目中,它却未能表现出足够的推理能力,而是输出了两个不同但相似的哈希函数——这与网络上一篇关于 Bloom 过滤器实现不佳的示例文章符合。

目前,LLM 的推理能力较弱,如果关于提问的信息来源稀缺,加上还掺杂着许多质量低劣的信息来源,输出结果就很随意马虎不尽如人意。
然而,这并非个案,我曾多次考试测验在算法或系统编程领域利用 LLM,结果都非常糟糕

与此同时,GPT4 能够反汇编它天生的函数(在单独的会话中),并准确理解其目的:

https://chat.openai.com/share/f54b64d7-d19a-4be4-8f10-08553aa812f1

因此,断言 LLM 在系统编程上没有用途肯定是不准确的。

一个有趣且基本在猜想之中的征象是,在这些情形下,较小模型和较大模型之间的差异确实很大。
下面让我们看看两个本地模型的表现。

例如,Mistral 的 MoE 模型 Mixtral 对同样的问题的回答如下:

cunsigned int hash(const char str, unsigned int hash_id) { unsigned int hash = 5381; int c; while ((c = str++)) { hash = ((hash << 5) + hash) + c; } return hash + hash_id;}

显然,仅在末了添加 hash_id 是一个极其糟糕的办理方案。
Mixtral 在很多方面都是一个很好的模型,但对付推理能力本就薄弱的 LLM 而言,目前的规则无疑是:越大越好。

这是我与本地 LLM deepseek 编码器的谈天,由于我没有足够的 RAM 以更高的精度利用该模型,以是量化到了 4 位。
然而,由于它有 340 亿个参数,因此在这个问题上的推理能力彷佛相称前辈:直说将 hash_id 添加到末端可能会导致分布不均,尤其是当 hash_id 过大或分布不均时,同时建议用位运算将 hash_id 稠浊进去。

cunsigned int hash(const char str, unsigned int hash_id) { unsigned int hash = 5381; int c; while ((c = str++)) { hash = ((hash << 5) + hash) ^ c + hash_id; // Using XOR to mix in the hash_id } return (hash ^ hash_id); // Mixing the hash_id one more time at the end}

这个结果,至少在我的 MacBook M1 Max 上运行得还不错,它还利用了异或来稠浊求和结果。
在这种情形下,我供应理解决问题的线索肯定对模型有所帮助,但是模型确定了问题的真正源头,并提出有效的办理方案——上述情形,是任何书本、文档或谷歌搜索都无法实现的。

不论这是一种插值的原始结果,还是从其他角度来看,不可否认模型确实进行了某种形式的推理,我们找到问题起源和解决方案也正得益于此。
以是,无论人们如何看待 LLM,断言它们对程序员没有帮助是一种极为草率的行为。

但与此同时,凭我在过去几个月的履历表明,对付系统编程而言,如果你已经是一名履历丰富的程序员,LLM 险些永久也供应不了有效的办理方案。
举个例子,我目前的项目是 ggufflib,涉及编写一个读写 GGUF 格式文件的库,这是 llama.cpp 加载量化模型的格式。
最初,为了理解量化编码是如何事情的,我考试测验用 ChatGPT,但后来我决定对 llama.cpp 的代码进行逆向工程:这样更快。

如果 LLM 能为系统程序员供应适当的帮助,那么看到数据编码“struct”声明和解码函数时,就该当能重修数据格式文档。
llama.cpp的函数很小,完备符合 GPT4 的哀求,但输出结果却完备没用。
在这种情形下,我们就只能像过去一样:取出纸和笔,阅读代码,看看解码器提取的 bits 在哪里注册。

透过外在看实质

我这么说可能很直接,但事实确实如此:当今的大多数编程事情,都因此略有不同的形式重复同样的内容——而这,并不须要高水平的推理能力。
只管 LLM 会受到高下文的严重限定,但它们在做这方面确实相称善于。

这该当引动身序员的思考:编写这类程序是否值得?当然,你会得到报酬,还可能是相称丰硕的报酬,但如果用一个 LLM 就可以完成个中一部分,那么大概五年或十年后,这份事情并不是你的最好归宿。

其次,LLM 到底是真的具备某种推理能力,还只是“鹦鹉学舌”?大概有时候它们看起来会推理,符合符号学家所说的“能指”观点,但实际上这是一种并不存在的意义。
那些长期与 LLM 打交道、并深知其限定的人们,对此该当深有感触:它们对以往打仗过的内容的领悟能力,远远超出了其随机输出单词的能力。
只管 LLM 的大部分演习紧张是在预演习期间进行的,但在预测下一个 token 时,大模型还是会根据目标创建某种形式的抽象模型。
这个模型可能很薄弱、零散且不完美,但通过实际不雅观察,我们会创造这种能力一定存在。
如果我们的数学定理令人疑惑,而最伟大的专家们常常持相反见地,那么对我们来说,“眼见为实”彷佛是一种明智的做法。

末了,我想说:事已至此,不该用 LLM 进行编程还有什么意义呢?向 LLM 提出精确的问题已是一项基本技能,这种技能练得越少,AI 对事情的帮助就越小。
此外,培养对问题的描述能力在与其他人交谈时也很有用,有时并非只有 LLM 不理解我们想说什么。
沟通不畅是一个很大的局限,很多程序员只管在自己的特定领域能力很强,但沟通能力却很差。

目前,谷歌搜索已经乱得不能用了:利用 LLM,哪怕只是把它作为一种压缩的文档形式,也是一个不错的选择。
就我个人而言,我将连续广泛利用 LLM,我从来都不喜好学习晦涩难懂的通信协议细节,也很讨厌那些想展示自己有多么精良的人编写的库的繁芜方法——对我来说,这些彷佛都是“知识垃圾”,感谢 LLM 每天都在把我从这统统中补救出来。

原文链接:http://antirez.com/news/140