Coding with LLMs in the summer of 2025 (an update)

Salvatore Sanfilippo

2025年夏天的LLM编程(更新版)

像 Gemini 2.5 PRO 这样的前沿 LLM,凭借其对众多主题的广博理解以及能在几秒钟内掌握数千行代码的能力,能够扩展和放大程序员的能力。如果你能以清晰的方式描述问题,并且能够接受与 LLM 协作所需的反复交流,你就能取得令人难以置信的成果,例如:

  1. 在你引入的 bug 接触到任何用户之前就将其消除:我在实现 Redis 的 Vector Sets 时就有过这种经历。我最终还是会消除所有 bug,但其中许多都被 Gemini / Claude 的代码审查立即清除了。
  2. 更快地探索某个想法如何可行:让 LLM 尽快编写用于测试的一次性代码,以验证某个方案是否真的性能更好、是否足够好等等。
  3. 参与结对设计活动,让你的直觉、经验和设计品味与 LLM 内部编码的博士级知识相结合。在这种活动中,LLM 有时会提出愚蠢的路径,有时又会提出极其聪明的想法:而你,作为人类,就在那里帮助跳出局部最优和错误,并利用你的数字朋友在某些方面比任何人类都懂得更多这一事实。
  4. 在明确的规格说明下让 LLM 编写部分代码,从而加速你的工作。
  5. 借助 LLM 使用那些远离你的专业领域但与你现有能力相邻的技术(例如:为 Amiga 演示程序编写 68000 汇编代码?),把 LLM 当作你大脑特定部分的延伸,弥补你所不具备的知识。
  6. 一年半前,我写过一篇题为《LLMs and programming in the first days of 2024》的博客文章。在那篇文章中,我认为 LLM 已经很有用了,而在这 1.5 年里,它们取得的进展彻底改变了游戏规则。然而,要发挥它们的能力,与 LLM 交互的人类必须具备某些素质并遵循某些实践。让我们来探讨一下。

    大多数时候拒绝 vibe coding

    在当前这个历史时刻,LLM 是优秀的放大器,却是糟糕的单人乐队式工作者。仍然存在一些小型一次性项目,让 LLM 编写全部代码是合理的,比如测试、几百行代码的小工具。虽然 LLM 可以在你的严格监督下(见后文)成功地编写部分代码库,并在开发中带来非常可观的提速(或者说,在以往相同的时间内开发出更多/更好的东西——这正是我所做的),但当它们独自面对非平凡的目标时,往往会产生脆弱的代码库:规模超出需要、复杂、充满局部最优的选择,在许多方面都不理想。此外,当手头的任务超过某个复杂度水平时,它们会完全失败。明天这一切也许都会改变,但在经历了每天用 LLM 写代码之后,我坚信最高质量的工作是通过“人类+LLM”的组合达成的。我相信人类和 LLM 一起比单纯的人类更有生产力,但这需要一个重要的“前提”:即这样的人必须具备出色的沟通能力和丰富的 LLM 使用经验:高效沟通的能力是使用 LLM 的关键因素。

    提供大量上下文

    当你的目标是与 LLM 一起推理如何实现或修复某段代码时,你需要向 LLM 提供大量的信息:论文、目标代码库的大部分内容(如果可能的话提供整个代码库,除非这会使上下文窗口过大以至于损害 LLM 的表现)。还要把你对应该做什么的全部理解进行一次“大脑倾倒”。这样的倾倒尤其应包含以下内容:

    • 关于那些看似不错实则糟糕的方案的提示,以及为什么它们可能是次优的。
    • 关于非常好的潜在解决方案的提示,即使人类尚未将其完全展开:LLM 往往可以借助这些提示找到正确的路径。
    • 明确的目标,说明应该做什么、我们要求的不变量是什么,甚至代码应有的风格。例如,LLM 倾向于编写充满不必要依赖项的 Python 代码,但通过提示词可以帮助减少这个问题。根据我的经验,C 代码的质量要好得多。

    在处理那些不太普及或不太显而易见的特定技术时,把相关文档也加入上下文窗口通常是个好主意。例如,在为 vector sets 编写测试时——这是 Redis 中一种如此新颖的数据类型,以至于 LLM 还不了解它——我会把 README 文件加入上下文:凭借这样一个简单的技巧,LLM 立刻就能以专家级的水平使用 vector sets。

    使用正确的 LLM

    最出名的 LLM 并不是最好的。编程活动主要应使用:

    • Gemini 2.5 PRO
    • Claude Opus 4

    根据我的经验,Gemini 2.5 PRO 在语义上更强大。它能发现更复杂的 bug,推理更复杂的问题。Claude Opus 有时可能更擅长编写新代码(有时则不然),其用户界面也更令人愉悦,而且总的来说,对于复杂问题,你至少需要两个 LLM 来进行一些来回交流,以便扩大你(作为人类)对设计空间的理解。如果只能选一个,那就选 Gemini 2.5 PRO。

    对所用 LLM 的基本要求是:不要使用 agent 或带有集成编码 agent 的编辑器之类的东西。你要做到:

    • 始终把内容展示给最有能力的模型,也就是前沿 LLM 本身。
    • 避免任何只向 LLM 展示部分代码/上下文的 RAG(检索增强生成)。这会摧毁 LLM 的表现。你必须掌控 LLM 在给出回复时能看到什么。
    • 始终留在循环之中,亲手把代码从你的终端移动到 LLM 的网页界面:这保证了你跟进每一个过程。你仍然是那个程序员,只是被增强了。

    结论

    尽管人们对能够独立编码的 agent 兴趣浓厚,但此刻,通过显式地使用 LLM 并保持在循环之中,你可以最大化自己作为软件开发者的影响力。这在未来不可避免地会改变,随着 AI 的进步,最终许多编码任务将由 AI 单独更好地完成:在那个未来,人类将决定做什么和怎么做,这依然至关重要。但我们还没有到那一步。在这个确切的时刻,掌控全局能让你利用 LLM 产出尽可能精炼的代码:在需要时保持极简,在必要时运用复杂的思想。

    你将能够完成那些原本处于你知识/专业边界之外的事情,同时在此过程中学到很多东西(是的,你可以从 LLM 身上学习,就像你可以从书籍或同事身上学习一样:这是一种新的教育形式)。而且,所有产出的东西都会遵循你对代码和产品的理念,具有高质量,不会因为 LLM 引入的错误和缺陷而随机失败。你还将对所有已编写的代码及其设计保持深刻的理解。

    时不时测试一下 agent 能做什么是有益的。但每当你觉得它们做得不如你时,就回到你的终端,在 AI 的帮助下编码(当你觉得它能提升你的产出时;有些时候你独自一人反而更好)。等到 agent 能出色完成工作的时候,我会第一个切换过去,而我仍会纯粹出于热爱继续自己写代码。但现在,让我们跳过炒作,以最佳方式使用 AI,那就是:保持掌控。然而还有另一种风险:出于某种意识形态上或心理上的抵触而回避 LLM,从而不断积累劣势(并且无法培养出一套难以描述的、与 LLM 协作所必需的技能)。也许这正是“中庸之道”(In medio stat virtus)的一个例证。