2025年夏,与大语言模型编程(更新版)

作者:antirez  |  2025年6月4日

像 Gemini 2.5 PRO 这样的前沿大语言模型,凭借其对众多主题的广泛理解,以及几秒钟内掌握成千上万行代码的能力,已经能够拓展和增强程序员的能力。如果你能清晰地描述问题,并且能够接受与 LLM 来回交流的过程,你可以实现一些令人惊叹的成果,比如:

  1. 在代码发布前就消灭你引入的 Bug:我在 Redis 的 Vector Sets 实现中就体验到了这一点。虽然最终我总能消灭所有的 bug,但很多 bug 在 Gemini / Claude 的代码审查中就被直接去除了。
  2. 更快速地验证某个想法是否可行:让 LLM 编写“试验代码”,以尽快验证某个方案是否更高效、是否足够好等。
  3. 进行“协作设计”:将你的直觉、经验、设计品味,与 LLM 所具备的博士级知识结合在一起。在这种合作中,LLM 有时会给出愚蠢的建议,但也会带来惊艳的创意。你的角色是避免陷入局部最优或犯错,并充分利用你的“数字搭档”所掌握的、远超人类的知识广度。
  4. 按照你的明确规范来加速编写部分代码。
  5. 在非你专长但相邻领域开展工作:比如用 68000 汇编为 Amiga 平台写一个 demo?LLM 可以作为你思维的扩展,帮助你填补知识空白。

大约一年半前,我写过一篇文章叫《2024年初的大语言模型与编程》。那时我就发现 LLM 已经非常有用。而在接下来的这 1.5 年里,它们的进步已经彻底改变了游戏规则。然而,要真正发挥它们的能力,人类与 LLM 的交互方式必须具备某些素质并遵循一定实践。我们来探讨一下。


大多数时候,请避免“感觉编程”(vibe coding)

在这个历史节点上,LLM 更擅长“增强”,而不是“独立完成”。有些小型一次性项目,比如测试、几百行的小工具,让 LLM 全权编写确实没问题。但 LLM 能成功编写代码库的一部分(在你严格监管下,后文会讲),也确实可以大幅加快开发速度(或者说,用同样的时间产出更多或更好,这正是我现在的做法)。

但当面对非平凡的目标时,LLM 单独工作往往会产出脆弱、臃肿、复杂、充满局部最优选择且整体表现不佳的代码。而且,一旦任务复杂度超过某个阈值,LLM 往往会完全失败。

也许明天情况就会变,但就目前我每天与 LLM 编程的经验来看,我坚信最高质量的产出来源于人类+LLM的协作。我认为人类与 LLM 的结合比单靠人类更具生产力,但前提是这些人类具备优秀的沟通能力和丰富的使用 LLM 的经验。与 LLM 高效沟通,是能否真正用好它们的关键。


提供大上下文

当你想与 LLM 讨论某段代码的实现或修复时,你必须向它提供尽可能多的信息:论文、目标代码库的大段代码(最好是全部,除非这会导致上下文窗口过大,从而影响性能)。还要倾倒你对任务的全部理解。这份“脑内转储”尤其要包括:

当涉及较小众或不常见的技术时,最好也把相关文档放入上下文窗口。例如,在为 Redis 的 vector sets(一种尚不被 LLM 熟知的新数据类型)编写测试时,我把它的 README 文件也提供给 LLM:这个简单的技巧让 LLM 立刻能以专家级水平使用它。


使用合适的 LLM

最知名的 LLM 并不等于最适合编程。我建议主要使用:

在我看来,Gemini 2.5 PRO 的语义理解力更强,能发现更复杂的 bug,处理更复杂的推理任务。Claude Opus 有时在写新代码方面表现更好(但不总是),UI 也更友好。通常,使用两个 LLM 来回推敲复杂问题,有助于扩展你对设计空间的理解。如果只能选一个,请选 Gemini 2.5 PRO。

使用 LLM 编程的核心要求是:


总结

尽管现在有很多“自动编程代理”项目,但目前最大化开发者生产力的方式是:显式使用 LLM,保持人在 loop 中。将来这可能会变,AI 进步之后,很多编码任务可能确实由 AI 完成更好。那时人类的角色将转向决定做什么与怎么做。但我们尚未到那一步。

此刻,保留控制权才能让 LLM 发挥最大潜力:在需要时写出极简代码,在必要时运用复杂思路。

你将能够完成本不属于你知识边界内的任务,同时在这个过程中学到很多(是的,你可以从 LLM 中学习,就像从书本或同事那里学一样——这是一种新的学习方式)。而所有成果都将遵循你的代码风格与产品愿景,质量高且不因 LLM 的疏漏随机失败。你也将保有对代码和设计的深刻理解。

偶尔尝试一下自动代理当然没坏处。但每当你发现自己做得比它更好时,请回到终端,继续用 AI 作为辅助工具来编程(当你觉得它能提升你的输出时;有时你独立完成可能更好)。如果哪天代理真的能胜任,我会第一个切换过去,到那时我会纯粹出于爱好继续手写代码。

但现在,让我们抛开炒作,在“保留控制权”的前提下,充分利用 AI 的力量。

当然,也存在另一个风险:出于某种意识形态或心理上的抗拒而拒绝使用 LLM,最终导致落后,并错失一整套“与 LLM 协作所需的复杂技能”(这些技能很难明确定义)。也许这真是“中庸之道”的一个例子。


2024年初, 大语言模型与编程

作者:antirez  |  2023年

我想先说明,这篇文章并不是一篇关于大语言模型(LLM)的回顾总结。很显然,2023 年是人工智能领域极为特殊的一年,这一点无需赘述。本文更像是一个程序员的亲身记录。自从 ChatGPT 出现以来,以及之后我开始使用本地运行的 LLM,我广泛地采用了这项新技术。目标当然是加快我的编程效率,但这并不是唯一目的。还有一个重要目标是:避免将我的精力浪费在那些不值得花力气的编程事务上。

无数小时浪费在为一些琐碎、缺乏思维挑战的细节查找文档上;耗费心力去学习某些过度复杂却没有正当理由的 API;为一次性用几小时后就丢掉的小程序编写代码……这些都是我不想再干的事情。尤其是在今天的 Google 变成一片信息垃圾海洋之后,想从中捞出有用信息变得愈发困难。

与此同时,我显然不是编程新手。我完全可以不用任何辅助工具写代码,并且事实上我也经常这么做。随着时间推移,我越来越多地使用 LLM 来编写高级代码,尤其是 Python,而 C 语言则较少使用。让我感到惊讶的是:我已经非常清楚什么时候该用 LLM,什么时候它只会拖慢进度。

我也意识到,LLM 有点像维基百科或 YouTube 上的各种课程:它们对有动力、有能力、有自律的人非常有用,但对于已经掉队的人来说帮助不大。至少在目前阶段,它们只会让强者更强。

但我们慢慢来看。


万能还是鹦鹉?

当前机器学习发展浪潮中最令人担忧的现象之一是:很多 AI 专家不愿承认他们的认知局限。 是人类发明了神经网络,更重要的是,还发明了用于自动优化神经网络参数的算法。硬件能力不断增强,能够训练越来越大的模型。基于大量关于输入数据的统计特性(先验知识),通过反复试错的近似法,研究人员发现了一些表现更优的网络架构。但总体而言,神经网络仍然相当不透明。

面对 LLM 出现的某些“涌现能力”我们无法解释的事实,本该看到更多科学家持谨慎态度。但现实是,很多人对 LLM 的能力严重低估,甚至断言这些模型不过是“高级版的马尔可夫链”,最多也只能复述它们训练时见过的内容的微小变体。后来,“鹦鹉模型”这一说法在事实面前几乎被全面推翻。

与此同时,大众的热情也走向另一个极端:赋予 LLM 超自然的能力,而这些并不真实存在。 事实上,LLM 最多只能在训练数据所定义的空间内进行“插值”运算——而即便如此,这已经是巨大成就了。 但现实是,它们的插值能力也是有限的(尽管令人惊叹且出乎意料)。如果今天最大的 LLM 真能在它们所见的代码空间中连续、流畅地插值,那它们已经可以取代 99% 的程序员了。

但现实更谦逊,就像大多数时候一样。LLM 确实能写出它从未见过的程序形式,能将训练集中出现的不同概念融合成新代码。但它们的这种能力目前存在明显的边界,一旦涉及微妙的推理,它们就会彻底失败。 然而,它们依然是迄今为止 AI 的最伟大成就,这是毫无疑问的。


愚蠢却无所不知

的确,LLM 最多只能进行初级的、常常不准确、甚至夹杂“幻想”的推理。但它们的知识面极其广泛。在编程领域(和其他高质量数据充分的领域)中,LLM 就像“博学的笨蛋”:知道很多,却常常胡说八道。

如果你跟这样的“搭档”做结对编程会很痛苦(对我而言,结对编程本身就很糟糕):它不断提出莫名其妙的想法,而你需要不断地推翻它。但如果这个博学的傻子只是你手边的工具、只负责回答你的问题,那就完全不一样了。

当前的 LLM 无法带你走出认知边界,但它们可以把你从完全无知提升到“能动手”的程度。

放在 20、30 年前,也许它们的能力毫无意义——那时候,一个程序员只需掌握几门语言、经典算法和十来个标准库。剩下靠的就是自己的能力与经验。只要你具备这些,你就可以胜任绝大多数工作。

但现在我们迎来了编程复杂度的大爆炸:各种框架、语言、库层出不穷,许多复杂性完全没有必要,也无法正当化。 在这种环境下,有个“知道一切的傻子”反而变得弥足珍贵。


实例时间

我不是在说那些简单的问题,比如“类 X 中的方法 Y 是什么”。如果只是这样,那 LLM 确实价值不大。

真正强大的 LLM 可以完成非常复杂的任务。 几年前,这种能力会被认为是“魔法”。

我可以告诉 GPT-4:
“这是我在 PyTorch 中实现的神经网络模型,这是我的 batch。我要调整 tensor 的形状,使 batch 输出能兼容网络的输入,我想用这种方式表示。”
GPT-4 写出了代码。我所要做的只是用 Python CLI 检查 tensor 的维度是否正确、数据布局是否符合预期。

另一个例子:
我曾需要为基于 ESP32 的设备实现一个 BLE 客户端。经过研究我发现,多平台蓝牙编程接口几乎都不可用。最终的解决方案是:用 macOS 原生 API 编写 Objective-C 代码。
问题是,我同时需要重新学习两个东西:
1. 繁杂且设计糟糕的 BLE API;
2. 十年前我最后一次写 Objective-C,现在我对事件循环、内存管理等完全不记得了。

最终代码在此(功能可用,但不算优雅):
https://github.com/antirez/freakwan/blob/main/osx-bte-cli/SerialBTE.m

这个项目很大一部分代码是我在 ChatGPT 上不断粘贴意图,然后让它告诉我错在哪里、怎么修。我自己当然可以搞定,但老实说:如果没有 ChatGPT,我根本就不会尝试做这个项目,因为性价比太低。


即弃型程序

上面这些例子我可以列出几十个,但大同小异。本质是:我有问题、我能验证 LLM 的回答是否靠谱,因此用它加快了学习速度。

但也有一些项目我直接让 LLM 写全套代码,比如下面这个简单可视化脚本:
https://github.com/antirez/simple-language-model/blob/main/plot.py

我展示给 GPT4 一段训练过程产生的 CSV 文件,让它生成展示 loss 曲线的代码,并要求在输入多个 CSV 时比较不同实验的验证 loss,而非训练 vs 验证 loss。它 30 秒就生成了完全可用的结果。

类似地,我还用它写了一个统计 AirBnB 数据的脚本,从 CSV 中按月归类房源、扣除清洁费、统计不同月份的平均租金。这程序很有用,但写它毫无乐趣。所以我复制了一段 CSV 让 GPT4 处理,它一次就生成了可用程序。

这种数据处理需求,虽然需要一些简单推理,但并非 LLM 从训练中“记住”的内容。它必须具备一定的泛化能力,才能把训练集中的类似案例延伸到我给的任务上。


系统编程:LLM 的边界

尽管我使用 LLM 很成功,但一旦我用 C 语言写系统程序,我基本只把 LLM 当文档搜索工具。

比如我让它实现一个可用的 Bloom Filter,要求支持 10 万个元素,误判率不超过 5%。结果它输出的代码非常普通,两个哈希函数质量也不行。

即使我再进一步引导它改善哈希函数,比如使用参数扰动或者 XOR 混合,它也做不出优雅泛化版本。

即便如此,GPT4 能理解它自己生成的代码,并对其功能进行反向分析(这点本身值得肯定)。

我还尝试用 LLM 去理解 llama.cpp 中关于 GGUF 文件格式的量化细节,比如 block_q6_K 结构和 dequantize_row_q6_K 函数,结果 LLM 无法还原出结构逻辑,也不能生成解释或等效重构函数。

这就表明,目前 LLM 还不能胜任高级系统开发者的角色,尤其是涉及位运算、存储格式逆向、内存布局等场景。


总结:该思考的时候了

我遗憾地说:今天的大部分编程,其实就是在重复相似的东西。

LLM 甚至能完成其中一大部分。虽然它们受限于上下文长度,但我们程序员真的该思考:继续写这些代码,值得吗?

LLM 是否真的能推理?
很多人以为它只是会“摆出像是有意义的句子”,实际上并没有真正理解。但大量实践告诉我们:它的行为不仅仅是“复读”。它确实形成了某种弱、破碎但真实存在的内部模型。

如果 AI 专家都分歧巨大,不如相信你亲眼所见。


用与不用:那是你的选择

今天不用 LLM 编程,是不理智的。提出正确的问题,是一项关键能力,不仅对 AI 有用,对人类协作也一样。

LLM 不是万能的,但能帮你规避“垃圾知识”:那些晦涩的协议细节、拗口的第三方库接口……我以前就讨厌学这些,现在 LLM 替我挡掉了一大部分。

我会继续大量使用它们。

原文

原文

相关链接

2025夏天
2024春天