深度剖析将 Claude 视为编译器的常见误区,建立对 LLM 能力和限制的理性认知。161 points、163 讨论高热度,是 Claude 用户的必读内容。
2025 年初,我写了《Claude 是编译器吗?》。当时我的回答是:我不知道。
现在我已相当确定答案是"不是,这是一个范畴错误,它比编译器更强大"。但这需要一些解释。
计算机程序出了名的复杂且脆弱。程序运行在极高的精度级别上。没有"挥挥手"这样的 CPU 指令。而高层目标往往是严重不确定的。
在一个高度风格化的世界观中,软件分层构建,每一层都增加了规范性并隐藏了"不必要的"细节。愿景变成战略,产品计划变成编码计划,代码变成二进制。每一步由不同的角色处理:高管、副总裁、产品经理、架构师、工程师、编译器。
关键是,每一步都涉及大量决策。这正是增加规范化程度的含义。(这也是我招聘工程师时两个关键指标之一是判断力的原因。另一个是和睦相处。)
最底层,从源代码到二进制,就是编译器做的事。编译器做很多决策!内联优化、寄存器分配、是否发出警告或直接拒绝程序。这些决策很重要:它们影响性能、系统稳定性、可预测性和失败模式。编译器工程师的工作就是安排编译器做出一致的好决策。
一个好的、可信赖的编译器让软件工程师不用做这些决策。大多数工程师几乎不知道编译器如何工作;要有效工作也不需要知道。
在 2025 年,我们处在一个用 LLM 生成小块代码的世界。在这个心智模型中,编码 agent 可能作为一个新层插入,位于软件工程师和传统编译器之间。它"编译"自然语言为代码,做决策以减轻工程师的负担。它的价值与其可靠性和能做出的决策规模成正比。
问题在于,这个高度风格化的世界观是假的。抽象会泄漏,层会相互摩擦。即使它们不相摩擦,我们也会主动戳破它们。
跨越层次工作极其有价值;机械同感很重要。
帝国大厦在一年内、预算内完工(!!)的部分原因,是系统地跨越不同层次工作。比如,在决定外部铬镍钢包层时:
建筑师、承包商和分包商都觉得没有充分咨询是无法胜任这个复杂的施工技术问题的。因此,在充分的初步讨论后,召开了一个全面会议,出席者包括业主代表、建筑师和承包商、卷压材料的分包商、金属工人和安装人员,以及在各个准备阶段检测所有板材的检验人员。
当你说出来时,这听起来真的很明显。
但我们在实践中系统性地失败了。我只能想象那些金属工人得到机会指导设计走向不是缓慢而痛苦的方向时的喜悦。
我们失败的部分原因是不知道什么值得问。最好的高管有深厚的行业知识是有原因的。我也怀疑,部分原因是不屑一顾("一个金属工人能告诉我什么?")。但很大一部分也是沟通和组织开销。层的存在是有原因的——信息隐藏使组织可扩展。
Claude 比编译器更强大,因为它可以垂直跨越整个堆栈工作。LLM 现在可以讨论战略、产品、架构、代码和机器代码。它(还)不能像经验丰富、专注的人类那样做好大多数单个任务,但它可以做所有这些,无需安排会议或请求许可。
这是一个具体的例子。
exe.dev VM 有漂亮的域名:vm-name.exe.xyz。当我们启动一个新 VM 时,我们添加一个或三个 CNAME 条目。很容易,对吧?
但我们的 VM 启动速度很快,快到即使我们在创建 VM 之前创建了 DNS 条目,用户仍然需要等待 DNS 传播,偶尔需要等待几分钟而不是几秒。
我们做了显而易见的事情:我们写了自己的 DNS 服务器,这样 DNS 总是立即与真实来源匹配。生活很美好。
但延迟很重要,所以我们添加了区域。就这样,DNS 再次成为关键瓶颈,因为所有 DNS 都从俄勒冈州提供。此外,部署导致微小的 DNS 中断。要解决这个问题,我们现在只需要一个地理分布但完全一致的 DNS 服务器。
我们做了一个明智的工程师在面对困难问题时会做的事:作弊。我们用直觉工程了一个分布式 DNS 服务器,针对我们的特定需求调优。
目标很清楚:降低距离俄勒冈州远的用户的延迟,提高正常运行时间的可靠性。但其余的就不清楚了。我们必须从我们想要的确切行为(特别是在各种故障条件下)、它如何适应我们的整体公司计划、最能实现这些目标的架构,一直到精细的实现细节,搞清楚一切。
我们亲自讨论了最高层的战略和架构决策。我们会制作一个相当通用的 DNS 服务器,并加上我们特定的行为调整、使用中心辐射模型、使用仅追加复制策略,并在边缘有持久化。
剩下的就是实际构建它。
我让 LLM 研究分布式 DNS 系统的标准设计、教我 DNS 的内部机制和怪癖、指出历史安全失败、探索替代实现策略(AXFR/IXFR?不用谢)、研究开源产品、推演故障模式、规划测试策略。
一旦我有了一个看起来有希望的初始设计草图,我提示多个并发 agent 循环来构建整个东西,包括测试和对抗代码审查。他们提出了很多问题——从重大结构方法到逐行代码关切,每个细节级别都有。当我回答他们(或撤销产生遗憾的答案)时,我慢慢地将我学到的东西转化为非常简洁的书面指导,编纂了被证明很重要的决策。
然后我要求新的 agent 比较完成的实现,寻找有趣的偏差。agent 做出的许多重要决策——并且做法不同——从未被问及,这令人震惊。
这是一个例子。复制使用相当明显的方法:通过请求自上次已知条目以来的所有内容来追赶,然后长轮询新条目。有一个丑陋的转折:数据库回滚。罕见,但确实会发生,它打破了"仅追加"契约。
agent 注意到了这一点,他们用极其不同的方式解决了它。我最终选择的设计是给每一行一个"时间线"字段,如"你生活在哪个时间线中?"。这些是随机生成的,每个"获取自行 N 以来的条目"的同步请求都包括边缘服务器对行 N 的时间线值。如果有时间线不匹配,我们知道历史已被改变,回退到完整的干净重新同步。
不同 agent 构建的系统之间也有明显的风格差异。Claude 和 Codex 都同意 Claude 创建了更优雅的系统,但 Codex 更彻底。
我逐个处理了已确定的主要偏差列表,进行了实验,然后添加了更多书面指导。
然后我重复了整个差异规范分析过程,两次。我知道我的格言。
计划扔掉一个;你会的,反正。
如果你计划扔掉一个,你会扔掉两个。
到我准备构建最终版本时,我已经积累了一份伤疤组织文档,这份文档在经验上足以引导 agent 做出大多数重要决策,在每一层,从高层目标到架构,再到偶尔的低层细节,比如负载承载并发缓存的数据类型的确切形状。
最终的系统包括单元测试、端到端测试、用于降低生产推出风险的影子模式,以及由 agent 编写和针对 agent 的简洁文档套件。
这累计花费了我大约一周的注意力。我读的实际代码少得可怜。
在那之后,我向团队展示了解决方案。我计划启动服务器,然后去度假。当同事们问我问题时——"X 如何工作?在 Y 条件下会发生什么?"——我发现我可以自信地回答所有问题。(我确实去了度假。一个月后的 DNS 事件数:0。)
Claude 在这里不只是一个编译器。我从未交付任务并让 agent 做出一堆决策以将其投入实践。那是直觉编码。
相反,Claude 是一个垂直集成的资源,一个多编译器。它跨堆栈工作的能力加快并增强了我在不同级别做出一堆决策的能力,包括关于哪些决策很重要的决策。(大多数单个代码行不符合这个标准。)那是直觉工程。
我会说,在所有重要的方面,我理解这些代码。当然,如果我现在必须手工编辑它,会有一条陡峭的学习曲线。但我不用。更重要的是,我可以推理关于这个系统,与同事分享观点,并引导 agent 做未来的工作。还有一个长久的产物,它体现了设计的中心、有意的方面,这些方面重要到足以被记录,跨越所有层,因此应该在错误修复和代码变更中幸存下来。
这个时代的一个问题是:软件工程师需要理解关于他们工作系统的什么?
精心选择的层提供理解。物理基本定律看起来无所不包,但对于解释为什么在事故中坐在公共汽车里比坐在汽车里更好,它们不如经典力学。
一些软件层正在消亡,因为它们提供便利,但没有额外的洞察。(对不起,Tailwind。我爱你。)但是允许我们以可理解的方式表达重要决策的软件层?那些会留下来。
我们把更多的注意力转向了堆栈的上层,但没有完全放弃更低的层。Agent 不是逃避理解系统更深层的免费通行证。Go 标准库的大部分是用 Go 写的,但一些关键例程是用汇编写的。你不能依赖编译器。
软件工程师被拉扯着。这既令人兴奋又令人疲惫。但变得越来越清楚的是,在不久的将来,直觉工程就是……工程。