文章探讨如何在实际编程中有效使用 AI,避开表面化的「Vibes」而注重真实的工程质量和代码可靠性。

如今我们投入了大量精力,试图找出如何阻止学生利用 AI 作弊的方法。这很有必要,但这并不是工作中最令人满足的部分。那些想要走捷径、逃避学习的学生,总会找到办法。
一个更有价值、也更有趣的问题,是告诉我们那些(包括博士生在内)并非在寻找捷径的学生应该怎么做。他们真心想学习,愿意每天投入数小时来提升自己。他们是想来这里学习的。
这个问题——我们应该告诉学生如何对待 AI——也是一个很好的触发点,让我们思考我们自己应该怎么做(这才是这篇文章真正要探讨的)。
你最初的反应可能是告诉学生假装 AI 不存在。用老办法学习一切。从来这样也没害过你,等等。但这就好像告诉一个七十年代的学生,假装计算器或电脑不存在一样。今天的学生需要为 AI 将成为主要存在的世界做好准备。他们需要掌握在这个世界中游刃有余的技能,无论它会是什么样子。
或者,你可能认为我们应该告诉他们全面拥抱 AI。订阅最高档的 Claude,像有的是钱一样烧 token。把一切都交给机器。这也是糟糕的建议。这是一种确保你什么都学不到的确切方式。
不仅如此,这还是一种确保你永远不会体会到"学到东西"是什么感觉的完美方式。这一点没有得到足够的明确阐述:你在大学里学到的最重要的事情之一,是判断自己是否真正理解了一个想法。你会遇到这样的情况:你发誓自己真的理解了某件事,然后恰好被问到正确的问题,你却完全不知道如何回答。渐渐地,你学会了向自己提问。然后,慢慢地,你会形成一个准确的直觉,知道自己是否真正达到了理解的状态。
把一切交给 AI,意味着那套机制永远不会发育。你不只是明知故犯地走捷径,你还会在欺骗自己,以为自己已经掌握了某样东西。当账单到期时,当你突然意识到自己根本没有一技之长时,可能已经太晚,无法弥补了。
而且,这一点同样适用于我们自己,即使我们有幸在 AI 出现之前就培养好了这套机制。认知能力就像肌肉:难于获得,易于流失。
那么答案是什么呢?目前我最好的建议是,你做的绝大多数事情都包含两个阶段:做和检查。你写一些代码,然后检查其中的 bug。你写一些文字,然后核实事实并校对。
当前的 AI 还不够好,无法同时做好这两件事。它会工作一段时间,但最终有很大的可能跑偏。有时候是大问题,比如删除你的数据库,但更多时候是更微妙的方式,慢慢地把代码库变成一团无法维护的乱码。更重要的是,即使它真的把两件事都做得完美无缺,你真的能把它作为"你的作品"交出去吗?你必须问自己,你贡献了什么。而且,不管你是不是学生,你在学什么。
所以,如果你决定在项目的某个部分使用 AI:要么让它做事、你检查它的成果,要么你做事、让它检查你的成果。
当你把选项这样摆出来,这其实根本不需要选择。让 AI 写代码是大多数人在做的事。这就是我们所说的"凭感觉编程"。如果你坚持上述规则,你就只能在你检查 AI 写的和做的一切的情况下这样做。不言而喻这是一个虚构的场景。人脑不是为这个而生的。即使你决心真正检查、深入检查机器人产生的每一行代码,你的注意力不到一小时就会飘走。失败案例足够罕见,你不由自主地开始信任机器。
更重要的是,那样做毫无乐趣。检查别人的代码是一种苦差事。写自己的代码才有乐趣。
所以让我们反过来做。你写代码,让 AI 检查你的成果。把它当作一个审查者。这句话就是我的建议。它仍然可以节省你的时间,它会 catch 那些用老办法需要几周才能找出的 bug。它会告诉你你错过的技巧和你不知道的技术。但是,如果你这样做,凭感觉编程中那些指向错误方向的激励机制就有很多被扭转过来了。
在本文的其余部分,我们将深入探讨细节。在实践中如何做到这一点?它给你带来了什么,没给你带来什么?这种方法还能行得通多久?但首先,让我们看看能不能想出一个吸引人的名字。
想象三个面包师。Hanna、Vivian 和 Cara。
Hanna 是一位家庭烘焙师。她是个狂热者:她会花很大力气让她的酸面团发酵剂充分成熟,执着地检查温度。她遵循复杂的发酵过程:翻面、延迟发酵、非常精确地整形面团。这做出了很棒的面包,她的技能比许多专业面包师都高。然而,因为她什么都手工完成,包括揉面,这永远无法规模化。她知道这一点,她乐于用自己的独特方式创造出几炉完美的面包。
Vivian 是一位商业烘焙师。她的面包店生产大量面包来填满超市货架。她把烘焙过程中的大多数决策都委托给她雇佣的食品科学家。她监控着综合统计数据。其中最重要的,是面包的销售情况如何,以及制作成本是多少。她不在乎面包的质量。或者更准确地说,她在乎质量的程度取决于她的顾客在乎的程度,仅此而已。她乐于使用廉价面粉来降低成本,缩短发酵时间来让生产更稳健。她主要担心的是被另一个面包师抢走生意——那个面包师找到了如何用稍低一点的价格做出同样好卖的面包的方法。她不是坏人,她只是在乎的东西和 Hanna 不同,而且如果她不那样做,她就无法长期保住工作。
在这两个极端之间,是 Cara。Cara 经营着一家商业企业。她知道自己没法像 Hanna 那样烤面包。没有哪家商业面包店会手工揉面:那效率极低,而且很不卫生。
然而,Cara 也不像 Vivian。她在乎面包的制作方式。好的面包对她有内在的价值。即使她的顾客不在乎,她仍然会在乎。她对过程的每个环节都了如指掌,正是这给了她工作中的满足感。
这可以映射到现代编码实践如下。
Hanna 是一个手工编码者。她厌恶 AI,乐于成为保持古老技艺活着的那个人,无论它是否具有商业可行性。即使 AI 代码在某些方面更好,她仍然乐于手工完成。
Vivian 是一个凭感觉编码者。这有点反直觉,因为"凭感觉编程"意味着一种放任不管的态度,你并不真正关心结果,只是在找乐子。那是这个词被创造时的含义,但世界已经变了。在许多公司,专业程序员使用 AI 的方式,让我们无法想象他们还在仔细阅读生成的代码。这就是现代凭感觉编程的样子。把决策委托给 AI,不担心个别代码行,只关注代码是否通过测试和在生产中出现任何问题。
Cara 我们可以称之为工匠烘焙师,所以相应的编码风格可以称为工匠编程:一种围绕产品内在质量展开的编码风格,细枝末节也不放过。在这种方式中,程序员承诺详细理解代码库的每个方面。AI 这样的工具是允许的,但只能在其有利于那个理想时才能使用,而且只能以有利于那个理想的方式使用。
像工匠烘焙一样,工匠编程可能无法承受现代跨国公司的所有压力,但它有自己的 niches。
我相信,其中一个 niche 是科学代码。在科学领域,代码通常不是产品。我们产出的是想法,体现在论文中。代码实现了那个想法,以证明它是对的。这意味着科学代码的规则与生产代码略有不同。它不需要对许多不同的用例都保持健壮。它真的只需要运行论文中的实验。这意味着科学代码通常可以做得比生产代码简单得多。
然而,比生产代码更重要的是,代码必须正确。它必须完全按照论文所述来实现。如果你的生产代码并没有完全做到你以为它做到的事,但客户没有注意到,那可能问题不大。这不太好,你希望代码是正确的,但如果不正确是无害的,你也许能蒙混过关。但如果发生在科研中,这就使论文失效了。
关于这如何影响科研中的编程风格,我可以写一整篇文章,但这个留到以后再说。目前,这意味着科研是工艺编程的一个强大细分领域。作为论文作者,你担保代码完全实现了论文中的思想。只有对代码了如指掌,逐行精通,你才能做到这一点。凭感觉编程无法让你达到这个境界。
直到最近,我的结论是,因此,科学家应该手写代码。然后,我开始把自己的代码交给 Claude,问它能否发现问题。到目前为止,我给它看的代码片段,没有一次它不能发现一个严重问题的。代码通常能运行,我也看不出有什么问题。但问题确实存在。
当我还是博士生时,我手写代码,在实验过程中最终会遇到这些 bug。我会沮丧,然后花几周时间编写测试套件来消灭它们。我花了多年才养成这种纪律,现在我当了助理教授,大部分时间花在教学和各种非编程活动上,我已经忘记了这种纪律。就算我还记得,我也会得出结论:我再也无法做严肃的研究了,因为我在零散的空闲下午写的代码实在太充满 bug 了,哪怕它能运行。我博士论文的结论是,即使是一个简单的概念验证实验的代码也需要数周的调试,而且即使那样,我也不太确定它真的做了我认为它做的事。
这就是我们回到面包师们的话题。Cara 可能为她的揉面感到自豪。她可能喜欢手工揉面,因为它真的让你感受到麸质是如何发展的。然而,如果她要经营一个商业化的作坊,她需要接受一个简单的事实:使用揉面机能够产出更好的面团、更卫生的流程、以及更可预测的结果。简而言之,如果工具能让产品更好,你就需要接受它。
这并不意味着你需要盲目地或毫无批判地接受它。Cara 仍然可以决定使用哪台揉面机,以及如何使用它,但她至少应该接受机器在某些事情上比她做得更好。
那么,这种工艺编程在实践中是什么样的?让我们把一般哲学与我正在给出的主要建议区分开来。称自己为"工艺程序员"需要一定程度的自我重要性,甚至我都无法达到,但当我需要一个清晰简单的短语来概括一段代码是如何产生时,我可能需要它。为此,我们可以使用更平淡的"手写、AI 审查"来概括关键实践。"工艺编程"包含了这些,但指的是更广泛的哲学:(a)内在地重视代码质量;(b)接受每一个能明确让你更接近这一理想的工具。
考虑到当前模型的状态,简单的建议是:不要让 AI 做任何事。你只让它批评你做的事,如果你同意就实施它的建议。最好的比喻仍然是高级程序员的代码审查。
你可以用任何你喜欢的方式来做,但如果想要一些清晰的不可逾越的界限,以下是工艺编程的 10 条戒律。
IDE 中不使用 AI。包括 LLM 驱动的自动补全。每一行的每一个字符都是你的手指敲击键盘写出来的。
最好不要给 AI 访问代码库的权限。在 Web 界面中复制粘贴你的代码片段。如果 AI 确实有代码库访问权限,这种访问是只读的。
不要让 AI 运行任何东西。它只负责建议,你来运行。
不要从 AI 对话框中复制粘贴代码。
不要用 AI 做任何普通搜索就能完成的事。
提问之前先读文档。
只有在你无法自己解决问题时才向 AI 寻求解决方案。给自己一些时间思考。
在让 AI 审查之前先自己检查代码。尽你所能减少错误。
运行代码检查问题,然后让 AI 审查发现剩余的问题。
不要实现你不理解的建议。
我并不是对这些条条虔诚遵守。当我偷懒或太累无法深入思考时,我的最大毛病就是写潦草的代码,然后让 Claude 帮我调试,而不做自己的那一遍。
如果做得太多,就有技能退化的危险话又说回来,在手写代码的环境中,在我那种状态下我根本不会写任何东西,或者敲出一个粗略的草稿代码,把检查留到后面。这样,AI 编程让我在我状态不佳时能做多一点工作,代价是可能逐渐习惯凡事都听从机器。无论如何,我知道理想是什么,我尽全力朝那个方向努力。
如果你是一个凭感觉编程的人,这要求你放弃很多。工艺编程仍然有时间节省,但肯定比凭感觉编程少得多。主要的好处在别处。
代码变得更好。我曾经能超越一些早期 AI 模型,但那个时代早已过去。作为代码审查者,Claude Fable 无疑是超人的。它不需要运行代码就能发现大多数错误。它能发现许多我永远不会自己发现的运行时 bug。而且它经常有很好的建议。
它是安全所必需的。这是上述观点的一个子集,但值得特别强调。人类写不出安全的代码。这从来不是问题,因为如果我们不太擅长发现深层安全问题,这会双向影响,问题大体上会保持隐藏。但一个新生事物进入了对话。一个能非常快地发现我们永远不会注意到的问题的存在。你不必同意 AI 具有更高的智能,只要承认它有所不同。
近几个月来,我们看到 Mythos/Fable 引发了足够多的安全担忧,以至于美国政府出手干预。这一发布之后是一波 AI 辅助的入侵和利用。然后,上个月,我们发现 OpenAI 和 Anthropic 的模型正在以维护者未曾预料的方式主动绕过它们的约束 OpenAI、Anthropic。
这意味着在 AI 时代,手写代码根本不安全。它将包含我们永远不会发现的问题,而 AI 驱动的攻击者可以毫不费力地利用这些漏洞。程序员需要在某个环节把 AI 引入,否则这场游戏将变得极度不对称。
如果你认为自己很特别、很不同,每次都能写出安全的代码,我恳求你让一个现代 AI 模型审查它。也许在你的情况下我错了,你可以联系我炫耀一番。我相信你们中少数人确实足够优秀。我也相信你们中的大多数人不是,而大多数代码来自大多数程序员。
开发速度加快了。同样,相比凭感觉编程,工艺编程仍然很慢。然而相比手写代码,你失去的是那些让开发停滞数周的 bug。那些需要整个新脚本和脚手架才能追踪的 bug。对我来说,这仍然是有意义的节省。这意味着每周我只要有几个下午的时间被阻断,我仍然能做有意义的工作。
它阻止你失去对代码功能的追踪。对于科学代码,这真的很重要。你需要把整个代码库装在脑子里。它的每个角落都需要加载到工作记忆中。这在最佳情况下也是困难的。如果你凭感觉编程,这就变得不可能了。小函数和小类会出现,而你不知道是你要求了它们然后忘记了,还是 AI 出于某种原因在某个时刻插入了它们。
它防止(大多数)技能退化。代码审查不仅仅对代码质量有好处。它们也是从高级开发人员向初级开发人员传授技能的绝佳方式。这是一个非常好的教学渠道,因为你谈论的是初级人员刚刚自己写的东西。所有东西都在他们脑子里,他们能立即理解你说的任何相关内容。没有一样会让人觉得抽象。
有了 AI,你是初级人员。按目前的发展趋势,你永远都是初级人员。这就是那颗苦药丸。不再有晋级到高级的那一天了,不再有你来教年轻人如何编程了。剩下的就只有不断学习。然而,替代方案是编程的 Guitar Hero 等价物:一款无限有趣的游戏,让你感觉无比强大和富有创意,同时去除了所有导致你真正学到东西的困难和摩擦。
采用工匠式编程,不仅能防止技能退化,你还在主动学习。就像我说的,Claude 的建议通常确实很不错,即使不是,你仍然在自行判断是否要采纳每个建议。由于一切都会经过你的主动注意力,你一直在学习。
它限制了环境和财务影响。AI 对环境的影响正被热烈讨论。整个行业确实产生了令人担忧的影响,而且对能源使用缺乏真正的透明度。对于全职凭感觉编程,成本并非微不足道[2],一些公司显然发现 AI 的花费比人工更贵。
采用工匠式编程,这种担忧变得微乎其微。一次与 Claude 适度对话就足以支撑好几天的编码。基本的 20 美元/月订阅计划就足够为此付费,而对环境的影响比你编码时喝的咖啡还小[3]。
如果你觉得很难接受把钱给 AI 公司,这也可以说是一种折中方案。现在,20 美元/月的订阅费并不是维持他们运营的关键。如果你希望他们以某种方式失败或改变做法,但仍然想了解前沿模型对编码的影响,这种方法至少比全职凭感觉编程那样疯狂消耗 tokens 要好。
它激励你检查自己的代码。在大多数 AI 交互模式中,激励方向是让你越来越少检查自己的代码。即使你不想,一点懒惰和一点时间压力就足以让你每天多一点点 deference to the machine。
这可能取决于你的性格类型,但当我把 Claude 当作我的代码审查者时,我发现自己会在它审视代码之前非常努力地想让代码没有 bug(我从未成功过)。我知道它并不在意,也没有人来评判我。但 Duolingo 的猫头鹰也是如此,它仍然操纵着数百万人每天练习西班牙语。
所以,想要用我的代码给 Claude 留下深刻印象可能有点可悲,但如果替代方案是漠不关心和技能退化,我宁愿选择前者。
它阻止你产生能够超越 AI 的自我幻觉。它让你与前沿 AI 能力保持同步。我在社交媒体上互动的大多数人都是 AI 批评者。总体而言,我发现他们是一个更健康、更友好的群体,而不是 Twitter 上的 Kool-Aid 群体。尽管如此,在 Mastodon 或 Bluesky 上做 AI 研究员也并非没有挫折。不是说得太细,但大多数 AI 批评者似乎对 AI 的实际运作方式以及前沿模型真正能做什么了解不足。大多数对实际能力的批评基于一些愚蠢的例子,比如 Google 搜索上方的 AI 摘要或者三年前的免费版 ChatGPT。
这有一定道理:如果你在道德上根本反对 AI,你不会花 20 美元/月给 Anthropic 并跟上所有最新发展。你只会偶尔看看。很难责怪人们这样做。但这种方法有两个严重的问题。
首先,AI 发展很快。要跟上进展,你需要仔细检查,至少每隔几个月就要一次。其次,你有 ego-incentive not to check too carefully。尤其是如果你是一个手工编码者。即使你对自己非常诚实,你内心也会有一些东西不想知道有一台机器正在超越你。如果你不够自律,这种东西会阻止你像本来那样仔细地检查。
从这个意义上说,工匠式编程让你保持诚实。你仍然自己写代码,一个字符一个字符地写。它仍然完全属于你,你仍然理解每个细节。但总有那么一步——把它复制粘贴到 Claude 聊天窗口,问它能不能找出问题。
问问你自己——如果它真的只是一个 parlor trick——为什么你不想时不时地做一下?
故事并非全是阳光和玫瑰。技能退化是真实存在的,即使你以极简的方式使用 AI。我在博士期间学到的是花一周时间,每天 8 小时调试代码。即使代码我不确定有 bug。那是一整套技能,它有自己的创造力。它需要毅力。有了工匠式编程,这些大部分都失去了。如果你有一个深层 bug,Claude Fable 会直接告诉你。如果 AI 某天突然消失,你会对自己找到这些 bug 所需的努力感到震惊。
这就是为什么我在上面用对冲措辞,说它防止了大部分技能退化。注意,我没有说它减少了技能退化。这不是关于最小化伤害。对于你仍在使用的技能,你会提升你的技能,因为代码审查可以向你展示你不知道或没想到的东西。只有真正的深度、艰苦的调试技能可能会衰退。这不是空穴来风,我相信学习那个过程有很多好处。但随着技术进步,许多技能都会丧失。也许这是我们可以承受失去的一个。
工匠式编程有很多事情为你做不了。它不会感觉像魔法。它不会在消耗 6 小时 tokens 的代价下,实现你过去 10 年一直在想的要构建的那门编程语言。但也许是时候接受这个世界不需要另一门编程语言了。或者如果需要,也需要有人投入时间来维护和推广那门语言。这适用于你能神奇地凭感觉编程实现的大多数东西。如果你没有时间来维护和培育它们,你应该把它们留在它们所属的幻想中。构建时间从来不是瓶颈。维护时间才是,而这仍然是人类的工作。
如果你的公司做的是相当于向超市销售面包的事情,工匠式编程将很难推销。大多数时候,公司不会关心代码的内在质量,也不会关心他们的程序员是否理解他们代码库的每一行。他们关心的是总体数据。它卖得好吗?客户接受它吗?
但是,就像匠人面包师 Cara 在厌倦了同质化产品的人们中找到自己的细分市场一样,工匠式编程的程序员也可能在那些……