AI 会写程序之后,软件工程真正变贵的是什么
本文转载自 William Yeh,并进行简体中文化。原文链接:https://william-yeh.net/post/2026/03/genai-se-level-up/原文采用 CC BY-NC-SA 4.0 授权协议,本文亦遵循相同协议进行分享。
很多人很容易把这一轮 AI 写程序的进展,诠释成模型正在取代软件工程师,甚至「模型正在取代软件工程」。
这个说法只碰到了表面,却没有碰到核心。 软件工程没有消失,重心正在上移。 过去 SDLC 昂贵的部分,多半落在编写代码、处理低阶细节、人工重构; 现在,既然模型能迅速产生候选实现,昂贵的环节也跟着换了位置。 就像高德拉特的 Theory of Constraints 所说,瓶颈会转移。
问题是,转移到哪里? 相对于以前,新的瓶颈比较容易处理,还是比较困难?
软件工程的典范确实在变。 变化的重点,是抽象层的提升、验证负担的转移,以及治理形式的重组; 工程纪律本身并没有因此终结。

一、LLM 不是编译器
软件工程史上反复出现的一个主题,是抽象层不断上升。
早期编程高度依赖机器码与汇编语言,人类必须直接处理硬件细节、寄存器配置与控制流程。 高阶语言与编译器出现后,指令优化能力强,甚至在大多数情况下强过人类,工程师的注意力才逐步从「这些指令怎么排列」转向「这个逻辑怎么表达」。 写法变方便,人机分工更是被彻底重构。
从这个角度看,今天的 LLM 编程确实像是另一轮抽象层提升。 人类不再只写语法层面的指令,更常以自然语言、规格、测试与约束来描述意图,再由模型生成候选实现。 意图导向、规格导向的开发方式,之所以现在重新变得可行,不是因为理念突然变新,而是因为技术与工具终于开始撑得住。
但这个历史模拟只能用来说明方向,还不足以替后面的结论背书。 很多人看到这里,下一步就想说:既然高阶语言取代了低阶语言,今天 LLM 也会像编译器一样,成为新的工程基础设施。 这个推论太快了。 编译器之所以能成为工程基底,关键不在于它很强,而在于它可预期:同样的合法输入,在同样条件下,应该得到语意一致的输出。
模拟的作用,主要是帮你看清抽象层又上升了一层。 一旦把它延伸成「LLM 已经等同于编译器」,这个类比就走得太远了。 真正需要记住的差异很简单:编译器可以默认信任,LLM 不能。
二、语意层的不确定性
一个常见说法是,现代系统本来就充满不确定性:缓存未命中、垃圾回收时机、JIT 优化、多线程交错,哪一个不是非决定性的? 既然工程师早就习惯和这些东西共处,那么 LLM 的不稳定似乎也只是另一种可管理的系统特性。
这种说法最大的问题,是没有分清楚不确定性发生在哪一层。
传统系统的非决定性(nondeterminism),大多发生在执行路径、资源调度与性能表现层面; 在设计得当的前提下,系统的语意正确性仍可通过类型系统、同步模型、测试与形式方法加以分析与约束。 LLM 的不稳定则更常直接出现在语意建构本身:同样一个提示,可能对应不同的实现策略、不同的边界条件假设、不同的错误处理方式,甚至引入安全弱点、违反隐含限制,或偏离原始需求。[1][2]
这不单纯只是「跑法有点抖」而已,而是「你得到的东西本身可能已经换了意思」。
但把话说到这里,也不能滑向另一个极端,好像 LLM 完全不可工程化。 那也不对。 在任务范围受限、提示结构清楚、工具接口稳定、测试充分的条件下,的确可以明显收敛模型输出。 Anthropic 对 workflow 与 agent 的区分,本身就说明了一件事:工程上真正重要的,是你到底授予了多少自主性,又用什么外部机制把这种自主性给框限起来。 [3]
更准确的理解方式,是把 LLM 看成候选实现产生器,并且用规格、测试、权限与审计把它包起来。 它可以很强,但不能裸奔。[4][5]
要理解 AI 为什么能在某些问题上表现惊人,最好的科普其实不是写程序,而是下棋。
2016 年,AlphaGo 赢了顶尖棋士李世乭固然很了不起,更深远的意义是,它让很多人第一次亲眼看到:只要规则固定、目标清楚、胜负可判定,而且系统可以大量自我对弈,AI 就能在封闭问题里快速逼近甚至超过人类。 围棋虽然复杂,但它仍然是一个封闭世界:棋盘有限,合法动作明确,输赢标准预先给定。 这种问题的难,主要是搜索空间巨大,不是目标函数模糊。 AlphaGo 与后续 AlphaGo Zero 的关键,就是把策略学习、价值评估与搜索结合起来,并通过大量自我对弈持续优化。[6][7]
几年后,AlphaDev 把同一种逻辑用在程序世界。 它把「寻找更好的小型排序程序」表述成一个可搜索的问题:每一步都是组合更好的指令序列,目标函数则相对明确,例如正确性与性能。 也正因为目标清楚、评估稳定、搜索空间可封装,AlphaDev 才能在某些小型排序问题上找到优于既有人类基准的方案。[8]
这里最值得讲清楚的一点是:AlphaGo 和 AlphaDev 的胜利,主要来自 AI 在规则封闭、反馈明确、可大量试错的任务里,对搜索的高效率利用。
这也是为什么它们不能被直接外推到一般企业软件工程。 企业工程面对的通常不是单一且干净的目标函数,而是一组彼此抵触的要求:可维护性、模块边界、合规、事故可追溯性、部署风险、团队交接成本、长期总持有成本。 这些维度很难被压成一个简单分数。 局部性能最优,往往不等于系统治理最优。
不同层级的问题,适合不同程度的自动化。 AI 未必能接管所有工程决策。
四、审查重心转移
代理式工作流的真正冲击,在于它暴露了一个现实问题:当模型生成候选实现的速度远快于人工阅读速度,传统以逐行diff为核心的审查方式,开始难以扩展。
近年来,部分开发者与团队开始尝试一种更激进的工作流:人类主要提供需求、规格与目标,模型或代理则负责编写代码、执行测试、修复错误,甚至在一定范围内自动迭代。 如果用更通俗的话来说,人的角色开始有点像导演,而不再只是亲自下场逐镜头剪片的剪辑师。
这类工作流中,OpenClaw 作者 Peter Steinberger 最具代表性。 他让模型在一个带有工具、上下文与回合控制的环境里,自己跑完一段工作流。 这时候,人类审查的焦点就可能从逐行阅读代码,转向评估需求表述是否清楚、系统意图是否被正确理解、代理执行路径是否合理、测试结果是否可信,以及最终行为是否真的满足目标。[9]
这里最容易产生的误解是,以为「不 review code」等于「不再审查」。 其实更准确的理解是:审查没有消失,改变的是审查的对象。 当 AI 能在短时间内产生大量候选实现时,人类不可能再用老的方式逐行追踪每一段程序; 于是,较合理的做法是:把更多信任建立在规格、测试、静态分析、语意差异辨识与执行证据之上,而不是只建立在肉眼阅读程序文字之上。
不过,我们不要把 OpenClaw 或 Steinberger 当成普遍结论。 它们比较像 F1 赛车:不代表所有人明天都要照那样开车,但它会提前暴露未来工程可能面对的结构性问题。 这些案例的价值,不在于证明「未来所有工程团队都会这样工作」,而在于它们把某些本来还不明显的压力,提早推到了台面上。
更值得注意的,其实不是某一个 demo 跑得多炫,而是不同团队在实现代理式流程时,最后都会收敛到一个很务实的原则:先把能确定、能验证、能回退的部分做好,再去谈更高程度的自治。 Anthropic 在与多个团队合作构建 agent 的经验中,也反复看到这个倾向。 真正比较稳的系统,往往不是一开始就追求「让模型自己决定一切」,而是先把任务切清楚,把工具接口缩小,把失败后的回收方式设计好,然后再视情况逐步放宽模型可自行决定的范围。[3]
这个观察的意义不只是「先从简单开始」这种老生常谈,而是它揭露了代理式工程的成本函数:自主性不是免费的。 每多给模型一层循环控制、多一个外部工具、多一次可自行决策的机会,就同步提高观测、验证、审计与回溯的要求。 所谓成熟,不是把 agent 权限一次拉满,而是知道哪一些判断值得交给模型,哪一些边界必须牢牢握在人类手上。
这才是代理式软件工程真正有趣、也真正让人不安的地方。 工程师没有突然失业,但未来高价值的审查能力,未必是看得出每一行 code 怎么写,而更可能是看得出这套系统的规格是否清楚、证据是否充分、风险是否被控制、责任是否能被追溯。
五、规格开始卡住
如果开发越来越依赖对话、提示与逐步澄清,那么上下文管理就不再只是使用技巧,而会成为真正的工程问题。
原因很简单。 多轮代理式互动,不是把同一句话反复说,而是不断增加限制、修正假设、引用先前输出、放弃失败路径。 系统不只要记住内容,还要知道哪些前提已经失效,哪些推论应该撤回,哪些局部探索不应污染全局。[10]
模型并不是因为对话变长才变笨,而是:模型在多轮互动里,常常不擅长处理自己先前留下来的推论痕迹。 一旦早期对问题的理解有偏差,后面的回合就很容易不是重新定义问题,而是在错的前提上继续修修补补。 Laban 等人的研究可被理解为对这个现象的系统化描述:对话越长,真正危险的往往不是记不住信息,而是舍不得放掉先前已经形成的错误解释。[10]
也因此,后续像Context Branching这类做法才有意义。 它的重点不是把 prompt 包装得更花俏,而是把「探索不同解法」这件事,从一条连续对话改成可分支、可切换、可舍弃的工作流。[11] 这其实是在把版本控制的观念搬进规格管理:不是所有尝试都值得留在主线,也不是每一次失败都应该污染后续推理。
请记住,LLM 的限制不只出现在单次生成的正确率,也出现在规格如何随着回合演化、修正与隔离。 未来越重要的能力,可能越不是「问得更长」,而是「把探索过程切得更干净」。
六、测试开始立法
如果 LLM 与代理式系统开始承担更多实现、重构与局部迭代工作,那么测试策略就不能只是沿用旧习惯,而必须重新回答一个问题:测试的作用,到底只是查错,还是同时负责规定 AI 可以怎么改、不能怎么改。
要谈这个问题,先得把经典的两个测试流派讲清楚。
所谓 Detroit school,也常被称为 Chicago school 或 classicist TDD,核心想法是:测试应尽量从系统的外部行为与状态变化来验证,而不是过度关注对象之间的互动细节。 这一派通常偏好经过真实组合的对象,较少使用 mock; 如果某个功能完成后,系统状态正确、输出正确、公开接口行为正确,那么内部到底是怎么协作的,不一定需要在测试里写死。 这种思路的好处,是测试通常比较耐重构; 只要外部契约没变,内部怎么调整,测试不必跟着大改。[12]
相对地,London school,也就是常说的 mockist TDD,更强调从对象协作与互动设计出发。 这一派常采取 outside-in 的开发方式:先从外部需求开始,逐层往内设计对象之间如何分工,并在过程中大量使用 mock 来验证「谁应该调用谁、何时调用、带什么参数」。 这种做法的优点,是它把设计问题提早暴露出来。 当你在写测试时就必须明确定义各个组件如何互动,很多模糊的责任分配会被迫提前理清。 因此,London school 的支持者常认为,测试不只是验证工具,也是设计工具。[13]
把两者压缩成一句话,可以这样理解。 Detroit / Chicago school 关心的是:最后系统有没有做对事。 London school 关心的是:系统是不是用我预期的协作方式做对事。
这里没有谁对谁错。 它们对应的是两种不同的风险感知。
如果你最担心的是重构成本、测试脆弱性、内部设计被过早绑死,那只会更偏向 Detroit。 因为它保留了较大的内部实现自由,只要外部结果没变,系统就能持续演化。 如果你最担心的是依赖边界不清、责任分工混乱、组件互动失控,那只会更偏向 London。 因为它要求你把协作契约提前讲清楚,借由 mock 让设计更早成形。
问题在于,到了 AI 参与开发的场景,这两派的权重会变。
在代理式重构或生成场景中,模型很可能会调整控制流程、替换内部实现、重新切分模块,甚至用一种人类原本没想到的方式达成同样的外部行为。 如果这时候测试过度绑定方法调用次序、参数传递路径与对象互动细节,那么大量本来有效、甚至更好的重构,都可能被测试判定为失败。 换句话说,过度 London 化的测试,在 AI 场景里特别容易把「设计选择」误写成「功能规格」。
这正是 AI 时代需要重新审视这场旧争论的原因。 问题已经不只是「哪一派更优雅」,而是「哪一种测试更能区分:什么是系统真正不能变的东西,什么只是暂时的实现路径。」
第一层,对于 AI 需要自由探索、自由重构的区域,测试应更接近 Detroit school 的精神。 也就是尽量用公开API、可观察状态、整体行为与高阶不变量来定义正确性,而不要过早把内部协作方式写死。 这一层的目的,是替模型保留足够的搜索空间,让它能在不破坏外部契约的前提下,自主改进实现。
第二层,对于那些真的不能乱动的区域,例如对外协议、错误处理流程、安全检查、高成本依赖调用、金流与审计事件,London school的精神仍然有价值。 因为在这些地方,我们在意的本来就不只是结果对不对,也在意它是否以正确、可追溯、可受控的方式发生。 这时互动测试不是多余,而是在保护关键边界。
第三层,则是传统TDD争论较少正面处理、但在AI场景中特别重要的一件事:测试不只要检查答案,还要提供足够抽象的验证标准。 只靠单一输入对单一输出的例子,对人类手写程序有时还勉强够用; 对生成式系统来说,这种验证往往太窄,容易让模型学会的是「迎合测试」,不是「满足规格」。 也因此,property-based testing 这类方法会变得更重要,因为它验证的不是个别样本,而是程序在一整类情境下是否维持某些不变条件。[14]
所以,比起问「Detroit 还是 London 哪个对」,更值得问的是:哪些测试是在保护真正的外部契约? 哪些测试其实只是把历史实现偶然性误写成规格? 哪些互动细节真的是安全或合规要求? 哪些地方其实应该交给模型自由重构?
AI 时代比较合理的方向,不是在 Detroit 和 London 之间二选一,而是把不同测试放回它们各自最适合的层级。 对可自由重构的内部逻辑,应优先保护外部结果与高阶不变量; 对不能出错的依赖互动、权限流向与副作用,再用更严格的互动验证去守边界; 至于生成式系统特有的风险,则要再往上补一层,利用 property-based 或 differential testing 去检查「不同实现是否其实破坏了同一个规格」。[15]
测试不再只是查错工具,更像是一套治理语言:一方面给模型留出探索空间,另一方面清楚告诉它,哪里可以动,哪里绝对不能动。
七、Clean Code 变了
关于「干净代码」(clean code),过去最常见的说法是:它能降低人类工程师的理解成本,让维护、交接与重构变得比较容易。 这个说法当然没有错。 但到了 LLM 参与开发的时代,这套论述还得再往前走一步。 今天的问题已经不只是「人看不看得懂」而已,更是:模型能不能稳定理解你给它的程序。
对人类来说,命名差一点、函式大一点,也许还能硬读; 对模型来说,这些东西会直接改变它如何切分问题、辨认模式、推测哪里是主干、哪里只是噪声。
这里最容易被低估的一点是,对模型来说,代码不是单纯的执行对象,也是上下文材料,要根据这些材料去推断命名意图、模块边界、控制流程与可重用模式。 程序越杂乱,模型越难分辨什么是核心结构,什么只是历史残留; 越容易把偶然写法误判成必要约束,把局部噪音误当成系统规律。 于是,所谓 clean code 在 AI 时代的意义就变了:它不只是让人比较好维护,也是在替模型降低语意负担。
Clean code 真的可能有帮助吗?
Jain 等人的研究,把这件事变成了一个可以测量的假设 [16] :如果不急着增加数据量,而是先改善代码本身的可读性与结构性,模型会不会学得更稳? 他们不是去改善算法本身,而是改善模型接触这段程序时所看到的认知表面。 整体方向是:先让程序的命名更有语意、让结构更容易分段理解、让高阶步骤更容易被看见。
而结果也很清楚:在程序生成任务上,数据整理得更好,确实能带来可观提升; 甚至在某些设定下,少量但较干净的数据,会比大量但混乱的数据更有价值。 这个结论对工程实务非常重要,因为它说明了一件常被忽略的事:在 AI 时代,很多时候真正拉开差距的,不是你喂了模型多少东西,而是你喂进去的材料到底有多容易被正确理解。
这个发现替 clean code 提供了一个新的经验支持,也改变了我们对工程价值的理解。 过去谈工程纪律,常常像是在谈一种类似「童子军规则 (The Boy Scout Rule)」的道德心:今天命名清楚、模块分明,未来团队比较好维护。 这当然成立。 但在 AI 时代,这些做法不只服务未来的人,也立刻服务当下的模型。 你把程序整理得越清楚,模型越容易在较小的语意空间里工作; 上下文噪音越少,生成就越稳定; 结构越清楚,幻觉风险和误解成本就越低。 也就是说,传统工程纪律没有因 AI 而过时,反而第一次在「机器可理解性」上得到了很强的操作性理由。
在LLM时代,干净代码正在从人类维护性的美德,变成模型可生成性的基础设施。 对我们这些有品质执念的资深程序员来说,真是个好消息。
下一次再谈 clean code,不要只问「这样别人看不看得懂」。 还要多问一句:这样的结构,模型能不能稳定理解、稳定延续、稳定验证。 这不是审美问题。 这是生成条件问题。
八、可治理的代码
一旦接受前面的判断,工程问题就会改写成另一句话:不是能不能生成 code,而是能不能生成可被安全吸收、可被验证、可被审计的 code。
这至少包含三层要求。
第一层是执行隔离。 未经验证的 AI 输出,不应直接跑在高权限、真实数据或可对外互动的环境中。 候选实现的执行,本身就是安全决策,而不是普通的开发便利功能。[17]
第二层是语意审查与变更理解。 当产出速度远超过人工阅读速度,人类不可能只靠文字 diff 理解变更影响。 未来的审查机制势必更依赖语意差异分析、结构化重构辨识、静态检查与契约违反提示,协助人类把注意力集中在真正改变业务逻辑、权限流向与风险边界的地方。[18]
第三层是高保证验证。 对多数一般系统来说,单元测试、整合测试与模拟环境已足够吸收大部分风险; 但在安全关键、金流、基础设施与高合规场景,这些往往不够。 这时更形式化的状态建模、模型检查与规格验证方法,就可能成为必备品。[19]
这一切都指向同一个事实:生成加速了,但验证不会因此自动变简单。 很多时候,它只会变得更重要。
九、乐观主义的边界
坊间流传很多乐观派说法。 像「AI 明天就会取代工程师」这种口号不必认真对待,真正需要认真回应的,是它的强化版本:真实软件工程benchmark确实在快速进步,代理式 coding 正在逼近大规模可用门槛。
的确,以 Copilot 的实验来看,生成式工具已经能在受控任务中带来明显的速度提升。[20] 而从 SWE-bench 这类更贴近真实 issue resolution 的 benchmark 来看,代理式 coding 也确实已经跨过了早期那种「只能做玩具题」的阶段。[21]
但也正因为能力上升得够快,benchmark 本身开始暴露出另一层问题。 OpenAI 在 2026 年不再把 SWE-bench Verified 视为前沿能力的好指标,并不是因为它不重要了,而是因为模型越接近高分,测试设计缺陷、数据污染与任务定义模糊,就越会主导最后的评估结果。[22]
所以,这不是一份单纯的捷报,更像是一份压力测试报告:当模型还不够强,大家关心它会不会做; 一旦模型开始会做,大家才突然发现,真正决定结果能否信任的,是测试到底有没有设计好、规格到底有没有写清楚、验证到底有没有跟上。
别再说「工程快要不重要了」,应该要说「当模型更强时,规格、测试与 benchmark 设计反而变得更重要」。 一旦能力上来,先暴露出来的不是工程不再需要,而是验证与治理的缺口被照得更亮。 这恰恰回到本文的中心命题:能力提升,没有让治理退场,反而把治理的必要性放大了。
你的治理能力,有跟着提升上来吗? 这才是值得担心的。
结论
历史是良师。 当年从汇编语言过渡到C语言,人类并没有完全放手,而是在更高的抽象层级上重新建立了约束体系:结构化编程、模块化、类型系统。 这些约束不是为了限制编译器,而是为了确保人类仍然能在必要时理解和控制系统。
LLM 时代的转折也很类似。 「把边界限缩到可掌握的颗粒度」这个原则没有消失,只是往上迁移到更高的抽象层级:从「人类要看懂每一行代码」,迁移到「人类要看懂每一个模块的意图与契约」,再到「人类要看懂系统的架构决策与约束框架」。
想把这一轮变化看清楚,要先问对问题。 不要再问「AI 会不会取代编程」——那是一个太粗、太浅、也太容易把讨论带偏的问题; 真正值得问的是:谁在定义规格? 谁在验证结果? 谁在控制权限? 谁在承担后果?
这四件事没有被设计好,模型越强,风险只会越大。 这四件事被设计好了,模型越强,工程收益才可能真正放大。
至于将来是否会出现像 AlphaGo 那样彻底超越人类认知框架的时刻? 也许会。 但在那之前,我们需要的不是盲目的信任,或盲目的不信任,而是像编译器时代一样,在新的抽象层级上,重新建立一套人类能够理解和掌控的约束体系。 只是这次,那套约束体系的名字可能叫做 harness、validation loop、architectural guardrails,而不是 structured programming 和 SOLID。
-
1. Liu, Fang, et al. “Exploring and Evaluating Hallucinations in LLM-Powered Code Generation.” 2024. -
2. Zhang, Ziyao, et al. “LLM Hallucinations in Practical Code Generation: Phenomena, Mechanism, and Mitigation.” 2024. -
3. Anthropic. “Building Effective AI Agents.” 2024/2025. -
4. Shavit, Yonadav, et al. Practices for Governing Agentic AI Systems. OpenAI, 2023. -
5. Google DeepMind. Frontier Safety Framework 2.0, 2025. -
6. Silver, David, et al. “Mastering the game of Go with deep neural networks and tree search.” Nature 529 (2016): 484–489. -
7. Silver, David, et al. “Mastering the game of Go without human knowledge.” Nature 550 (2017): 354–359. -
8. Mankowitz, Daniel J., et al. “Faster Sorting Algorithms Discovered Using Deep Reinforcement Learning.” Nature 618 (2023): 257–263. -
9. Steinberger, Peter. “Shipping at Inference-Speed.” 2025. -
10. Laban, Philippe, C.-S. Wu, et al. “LLMs Get Lost In Multi-Turn Conversation.” 2025. -
11. Nanjundappa, Bhargav Chickmagalur, and Spandan Maaheshwari. “Context Branching for LLM Conversations: A Version Control Approach to Exploratory Programming.” 2025. -
12. Fowler, Martin. “Mocks Aren’t Stubs.” 2007. -
13. Freeman, Steve, and Nat Pryce. Growing Object-Oriented Software, Guided by Tests. Addison-Wesley, 2009. -
14. He, Lehan, et al. “Use Property-Based Testing to Bridge LLM Code Generation and Validation.” 2025. -
15. “Differential Testing with LLMs using Natural Language Specifications and Code Artifacts.” 2025. -
16. Jain, Naman, et al. “LLM-Assisted Code Cleaning For Training Accurate Code Generators.” 2023 / ICLR 2024. -
17. Perrone, Giuseppe, et al. “WebAssembly and Security: A Review.” 2024. -
18. Tsantalis, Nikolaos, Ameya Ketkar, and Danny Dig. “RefactoringMiner 2.0.” IEEE Transactions on Software Engineering 48, no. 3 (2022): 930–950. -
19. Lamport, Leslie. Specifying Systems: The TLA+ Language and Tools for Hardware and Software Engineers. Addison-Wesley, 2003. -
20. Peng, Sida, et al. “The Impact of AI on Developer Productivity: Evidence from GitHub Copilot.” 2023. -
21. SWE-bench. Official Leaderboards. -
22. OpenAI. “Why SWE-bench Verified no longer measures frontier coding capabilities.” 2026.
夜雨聆风