第一章 引言:代码的本质与 Linus 的“愤怒”
过去一两年,软件行业最耸动的统计数据,莫过于某些团队宣称“99% 的代码由 AI 生成”。乐观者据此宣告“编程已死”,焦虑者哀叹工程师即将失业,而一线工程师大多沉默——他们隐约觉得这个数字哪里不对,却说不出所以然。争论双方共享着一个未经审视的前提:“谁敲出了字符”是一个值得大惊小怪的问题。而计算机史告诉我们,这只是一个被一遍遍重演的老剧本。要拆穿它,得回到人类与机器之间还没有中间层的年代——纸带时代。
1. 抽象层级的跃升:从“纸带打孔”到自然语言
1949 年 5 月 6 日,剑桥大学数学实验室的 EDSAC 第一次运行程序:从纸带读入机器码,打印 0 到 99 的平方表。那卷五单位纸带上没有任何“语言”,每一横排的孔洞就是指令的机器码本身——程序不是被“存进”机器的,而是被手工刻在纸条上、送进机房的。在那个年代,“编程”的全部含义是:人类把自己结构化的思维,强行降维成纸纤维上的孔洞排列。
二十年后的日常质感更加粗粝。一卷 8 单位纸带上,每一横排 8 个数据孔加 1 个走带孔对应一个字节;潮气让纸带伸长,静电让纸屑粘在读带轮上,而打孔这个动作是不可逆的——你只能多打一个孔,无法让一个已经撕裂纤维的孔复原。打错了怎么办?可以剪下错行、用胶带接驳,但高速光读机经过接驳处时,厚度突变要么让光电管误读,要么直接撕带。于是工程实践冷峻而简单:打错一孔,从错处起整卷重打。
容错率是可以计算的。假设打孔的手误率为每行 0.1%,一卷 2000 行的程序纸带全程无错的概率约为 0.999 的 2000 次方,即约 13.5%——超过八成的纸带天生带着至少一处错误。更要命的是,介质本身不含任何冗余与纠错机制:纸带不会帮你发现错误,唯一的“校验和”是程序员自己的眼睛,就着台灯把孔洞与操作码表逐一比对。顺带一提,打孔卡片(Punch Card)的处境稍好:80 列一张,打错一张重打一张,代价以张计;而纸带是连续介质,错行之后的一切作废——这正是我们选纸带作为隐喻的原因:它是“零容错编程”最极致的形态。
软件史的第一次伟大反转,始于一个朴素的追问:凭什么人类要迁就机器,而不是机器迁就人类?1950 年代,汇编语言先在穿孔机上普及:ADD、MOV、JMP 取代了一串串操作码数字,符号标号取代了绝对地址;汇编器(Assembler)用两遍扫描建立符号表(Symbol Table),再解析引用、生成目标码。请注意这张“名字到地址”的对照表——它就是一切编译器的胚胎。紧接着,1957 年 John Backus 的团队在 IBM 704 上交付了第一个会优化的 Fortran 编译器:怀疑者曾断言机器生成的代码永远追不上手写汇编,几年之内,编译器在公共子表达式消除与寄存器分配上的斤斤计较就胜过了绝大多数人类——它从不遗忘,也从不手滑。而 C 语言(1972 年,Dennis Ritchie)把这场撤退推向深处:类型系统让编译器在翻译之余兼任意图的检查员,类型不匹配从运行时的“一声闷响”变成编译期的一行精确报错;可移植性把机器差异吸进编译器后端,同一份源码在 x86 与 ARM 上各自长出不同的机器码。后来的人们甚至不满足于此——CompCert 项目用 Coq 完成了对一个 C 编译器的形式化验证,把“编译不篡改程序语义”变成了可以证明的定理。
至此,一条主线清晰可见:人类的意图不断“退后”,抽象层级不断升维。Andrej Karpathy 后来为这条撤退路线绘制了坐标系:Software 1.0 是人类显式书写代码(Python、C++);Software 2.0 是人类定义目标函数与数据分布,由梯度下降“写”出神经网络的权重——程序从文本坍缩成参数空间中的一个点;Software 3.0 则以自然语言为程序、以 LLM 为运行时,意图的表达彻底脱离形式化语法。三个时代的执行介质迥异,方向却一致:意图的载体持续升维,实现的细节持续下放。

对应关系可以更正式地落成一张表:
| 时期 | 意图的表达载体 | 当年的“编译器” | 翻译的性质 | 犯错的代价 |
|---|---|---|---|---|
| 1940s–1950s | 纸带孔洞、接插板 | 打孔员的手工与读带机的光电管 | 物理映射:一排孔即一条指令,逐位对应 | 打错一孔,错处之后整卷重打 |
| 1950s–1960s | 汇编助记符(MOV/ADD/JMP) | Assembler:两遍扫描、符号表解析 | 符号同构:助记符与机器码几乎一一对应 | 错一处,人工逐行排查 |
| 1960s–2020s | 高级语言源码(Fortran / C) | gcc/clang:词法→语法→AST→IR→优化→目标码 | 确定性符号变换:形式文法 + 重写规则 | 语法错误编译期拦截,逻辑错误靠人肉 |
| 2020s– | Prompt / Spec | LLM Agent:高维语义空间的采样器 | 概率性语义变换:意图分布 → 代码样本 | 语法正确、语义跑偏,且无任何编译器兜底 |
从纸带打孔到 C 语言,再到 Agent Prompt,人类从未改变计算机的物理本质,我们只是在不断后退——退到抽象层级更高、更接近意图的地方。
历史讲到这里,一个疑问浮出水面:如果每一次“机器接管实现细节”都被证明是工程学的胜利,为什么唯独这一次,当 AI 接管代码生成时,舆论的反应是恐慌?Linus Torvalds 替我们把这个问题问得很难听。
2. Linus Torvalds 的反问与高阶语义编译器
2026 年 Open Source Summit North America 的主题演讲对谈中,Linus Torvalds 罕见地对“AI 编写代码”的炒作发了火。据 The New Stack 报道,原话是:
“When I see people saying 99% of our code is written by AI, I literally get angry. Because those same people, I can pretty much guarantee, 100% of their code is written by compilers. But they never say that.”
—— Linus Torvalds, Open Source Summit NA Keynote, 2026(The New Stack 报道)
“当我看到有人说‘我们 99% 的代码都是 AI 写的’时,我是真的生气。因为我敢打包票,这群人 100% 的代码都是编译器写的——但他们从来不这么说。”
这通火气的靶心不是 AI 工具本身——同场访谈中,他并不否认自己也在用 AI 处理样板代码。他愤怒的是一种精心维持的选择性失明:同一批工程师,对“编译器把源码逐行改写成他们认不出的机器码”习以为常,视之为理所当然的基础设施;对“AI 把意图改写成代码”却大惊失色,称之为取代。这两个过程在结构上是同构的——都是人类意图经过一层自动化变换后抵达硬件——只是新旧不同,待遇却天差地别。
“99%”这个数字本身就是语义空心化的口号,它把“谁敲出了字符”偷换成了“谁贡献了工程价值”。按字节口径,编译器产出的机器码体量远超人类敲下的源码;按心智口径,AI 生成的每一行代码,其意图、边界条件与取舍仍然来自下达任务的人。不先声明“哪一层算作者”,任何百分比的争论都只是话术。换言之,抱怨“代码都是 AI 写的”,就像抱怨“家具都是木工工具造的”一样空洞——决定家具品质的从来不是刨子和凿子,而是设计图纸与测量规。
顺着这个比喻,可以给 AI Agent 一个精确的工程定位:AI 绝非替代人类思考的神迹,它在本质上是一个基于概率与自然语言的高阶自适应“语义编译器”。gcc 编译的是语法——它把符合上下文无关文法(CFG)的符号串,经词法、语法分析、符号表与类型检查,用确定性的重写规则变换成目标码;LLM 编译的是语义——它把一段意图的自然语言描述,在一个高维参数化的语义空间里,采样出一段行为等价的代码。编译的对象从“形式”升格为“意义”,这是抽象层级的又一次常规跃升,而不是历史的断裂。
但两台“编译器”的底层机理截然不同:
| 维度 | gcc / clang(传统编译器) | LLM Agent(高阶语义编译器) |
|---|---|---|
| 输入 | 形式化语言(CFG 文法约束的符号串) | 自然语言 / Spec(无形式文法) |
| 变换机制 | 确定性符号变换:词法→AST→IR→目标码 | 概率性语义采样:token 分布 + Temperature |
| 同输入同输出 | 是:同源码、同参数,产物可逐字节复现 | 否:同一 Prompt 每次长出不同的代码 |
| 错误形态 | 编译错误:精确到行列,必现,可静态拦截 | 幻觉:语义层面的跑偏,偶发,且能通过全部语法检查 |
| 正确性保证 | 类型系统与形式语义;CompCert 甚至给出全编译器的机器验证 | 无形式化保证,语义等价性只是统计意义上的近似 |
这张表右下角的空白,是整篇文章真正的起点:如果正确性不再来自编译器内部,它就必须来自编译器外部。这正是后文要回答的核心问题,此处先按下不表。
3. 引出主题:从“显式控制”到“控制论治理”
先确立一个事实:软件史上每一次抽象层级的跃升,消灭的都只是工种,而不是工程。Fortran 消灭的是“人肉汇编员”,却催生了现代软件工程——需求分析、测试、版本管理,这些围绕高阶意图的新学科。同理,AI 成为高阶语义编译器之后,软件工程也不会消亡;它面临的是一场范式转移:从“显式控制(Explicit Control)”转向“控制论治理(Cybernetic Governance)”。
显式控制的含义是:工程师逐行拥有并审查代码,工具只负责加速“写”与“查”——更快的编译器、更强的调试器、更顺手的 IDE,都不曾改变“人对每一行代码负全责”这一控制结构。而面对一台概率性的语义编译器,显式控制失去了着力点:你不可能逐行审查一台机器在采样空间里的每一次掷骰子——正如没人逐条审查 gcc -O2 之后的三地址码,但彼时的编译器好歹正确性可证,这一次连这块地基也松动了。控制的重心被迫从代码内部撤出,退到代码之外:去定义精准的 Goal、搭建严密的 Harness、驾驭收敛的 Loop。这三个词此刻只需记住——第二章将从控制论中为它们找到严格的数学与物理对应物。
而要把这场范式转移讲透,需要先为全文立下一个命题:
代码从来不是软件工程的目的,它只是人类大脑因无法直连硬件而被迫做出的工程妥协。
纸带孔洞是意图在 1950 年代的中间产物——寄存器、指令周期这些偶然复杂度无处下放,只好由人肉承担;C 源码是意图在 1970 年代的中间产物——编译器吸收了机器差异,源码便升维到算法与数据结构的抽象面上;今天的源码正在成为意图在 2020 年代的中间产物——样板代码与胶水逻辑被语义编译器吸收,剩下的交给人类。代码的形态从来不由代码自身决定,而由“这个时代把哪些复杂度判定为偶然”决定。至于 AI 消不掉的那些复杂度——《人月神话》的作者 Brooks 称之为本质复杂度(Essential Complexity)——以及它们为何恰恰是人类价值的锚点,是后文的话题,此处只埋一个记号。
至此,全文的问题正式抛出:当代码的生成被交给这台高效却充满不确定性的“自适应编译器”,人类工程师的终极价值究竟回归何处?答案的方向已经隐约可见——不是与编译器比拼打字速度,而是站在编译器之外,成为那套保证系统不出轨的机制的设计者。用控制论的语言说:这套机制的名字叫作设定值(Goal)、传感器与约束架(Harness)、负反馈回路(Loop)。这场从纸带打孔开始的控制论转向如何发生、又如何落地,是接下来六章要展开的全部内容。
第二章 理论跃迁:从“开环编程”到“闭环控制”
过去七十年,软件开发的主流心智模型从未真正改变:开发者在头脑中构思逻辑,通过键盘将逻辑逐行转译为确定性的代码,再由编译器与运行时将其固化执行。我们把这套动作称为“编程”,却很少追问一个更底层的问题——在这个过程中,信息沿着怎样的拓扑结构流动?当系统的实际行为偏离预期时,是谁在测量偏差,是谁在计算修正量,又是谁在执行修正?
将这一过程置于控制论(Cybernetics)的显微镜下,传统软件工程的控制结构暴露出根本性的拓扑缺陷:它是开环的。 Agent 驱动的 Vibe Coding 之所以构成范式革命,不在于“AI 会写代码”——机器码的自动生成从编译器诞生之日起就是行业常态——而在于它第一次改写了软件生成的控制拓扑:软件工程正在从低效的“开环控制”,走向自适应的“闭环控制”。 这是一次迟到了两百年的理论归位。
1. 传统开发的局限:被动且脆弱的“开环系统”
在经典控制理论中,开环控制系统(Open-Loop Control System)的输出仅由输入与系统自身的传递函数决定:输出端不被测量,偏差不被回传,控制动作也不会依据结果做任何自我调整。扰动作用于被控对象时,系统浑然不觉——这是开环结构与生俱来的盲区,与执行者的技艺高低无关。哪怕是最优秀工程师交付的系统,只要控制拓扑是开环的,它对环境漂移与需求变更依然双目失明。

在这个拓扑中,角色分配一一对应:
- 人类大脑同时扮演控制器(Controller)与执行器(Actuator):它读取需求文档(输入),在颅内完成控制律的计算,再以键盘为终端,把控制信号——源代码——注入系统;
- 代码是控制信号,软件系统是被控对象(Plant):行为在提交那一刻起,便不再受任何主动调节;
- 需求落成代码的瞬间,“编程”这个动作即告结束,系统自身对逻辑缺陷与环境漂移不具备任何感知与修正能力。
这段结构在一切顺利时被刻意掩盖,却在第一个错误出现时原形毕露。当编译报错的红字刷满终端,当 CI 面板上单元测试断言失败的红灯亮起,当生产日志里突然滚出 Segmentation Fault——系统的反应惊人地一致:原地瘫痪,等待人类这个“外置闭环”的介入。 传统软件没有自愈功能,因为测量装置从一开始就不在回路之内。
更深的代价埋在人类的认知经济学里。为了补全那条断裂的反馈链路,开发者被迫身兼三职:充当人肉传感器,逐行阅读 Traceback,在记忆中重建崩溃现场的调用栈;充当分析器,在假设与验证之间往复推演,为故障寻找一个配得上直觉的解释;再充当执行器,手工修改代码、重新编译、再次运行。认知科学的研究反复证实,人类从中断恢复到先前的深度工作状态需要数十分钟——一段本可在五分钟内修复的断言失败,往往让整个下午的心流支离破碎。而这条以血肉铺就的反馈通路,正是开环系统真正的带宽瓶颈:回路中串联的最慢元件,决定整个系统的带宽。 反馈一旦必须流经人脑,系统的迭代周期便只能以小时乃至天计,错误的消化速率被一个碳基传感器的吞吐上限牢牢锁死。
耐人寻味的是,即便到了 DevOps 时代,自动化测试也没有改变这一拓扑。CI 流水线可以不知疲倦地运行测试,但它能做的只是把红灯“通知”给人类——而通知的收件箱,依然是那个人类带宽的瓶颈。测量被自动化了,修正依旧开环:系统看得见自己的伤口,却把缝合的手术刀递给了不在场的人。
2. Agent 驱动的范式革新:内化于系统的“自适应闭环”
要丈量这次跃迁的分量,得先回到工业革命的原点。1788 年,瓦特(James Watt)为蒸汽机装上了离心调速器(centrifugal governor,又称 flyball governor):两只金属重球铰接在由主轴带动的立轴顶端,转速升高,离心力使重球张开,经机械连杆关小蒸汽节流阀;转速回落,重球下垂,阀门再度开大。没有电子元件,没有计算单元,仅凭一套连杆机构,蒸汽机第一次实现了转速的自动恒定——负载突变、煤质波动、管网压力变化,都被这条物理回路持续测量、持续抵消。在此之前,纽科门式蒸汽机需要司炉工一刻不离地手动调节;调速器的出现,让机器第一次把“观察—比较—修正”的循环内化到了自身。离心调速器甚至深刻影响了后来的控制理论:麦克斯韦(James Clerk Maxwell)1868 年发表的《论调速器》(On Governors),正是以它为对象建立了反馈系统的第一批数学方程。
闭环反馈因此并不是什么信息时代的新概念,而是工程世界运行了两百多年的古老智慧。软件工程之所以迟到,原因值得深思:其一,代码是一种不可见的材料,缺陷在被观测之前无声无息,而观测工具——测试框架、静态分析、沙箱——自身的成熟也不过是近二十年的事;其二,也是更根本的,闭环要求廉价且可重复的修正动作:蒸汽机的节流阀扳动一次,成本趋近于零,而人类开发者每修正一次错误,代价是动辄数小时的上下文重建。当执行器如此昂贵,闭环在经济学上就不成立,整个行业于是只剩下“一次写对”的执念。Agent 的出现恰好同时解开了两端——它既是能够自主“观察—定向—决策—行动”(OODA)的控制器,也是边际成本趋近于零的执行器。

于是,软件构建从“一次成型的创作”变成了“动态逼近的过程”:
- 注入设定值(Setpoint):人类不再下发微观指令,而是注入高维度的期望状态——Goal;
- 执行与测量:Agent 生成代码变更并推入测试与沙箱环境,环境立刻产出测量值——编译结果、测试报告、运行日志;
- 负反馈消化偏差(Negative Feedback):实测状态一旦偏离 Goal,报错无需惊动人类,直接作为误差信号(Error Signal)回传控制器;
- 迭代收敛:Agent 依据误差自主修正,驱动下一次 Loop,直至误差收敛为零——测试全绿。
在开环开发时代,程序员是系统反馈回路里最疲惫的电线;在闭环 Agent 时代,系统第一次学会了消化自己的痛楚。
这里需要为“负反馈”做一次正名:它不是悲观主义,而是把“偏差”转译为“方向”的机制。每一次编译报错,都是系统对自身状态的一次重新定位;每一次断言失败,都是收敛曲线上一次必要的采样。偏差不再以中断与恐慌的形式降临到人类头上,而是被系统安静地消化在回路内部。演化的引擎,第一次被装进了系统自己的身体里。
3. 软件工程概念的“控制论”映射
为了把这次范式跃迁从口号变成可推演、可度量的对象,下表将 Agentic 架构下的核心开发概念,逐项映射回经典控制理论的框架。这不是修辞层面的比喻,而是结构层面的同构——两组系统共享“参考输入—误差计算—控制律—执行—测量”的同一套差分骨架。
| 控制论概念 | 软件工程映射(Vibe / Agentic Coding) | 深度工程哲学解读 |
|---|---|---|
| 设定值(Setpoint / Reference) | Goal(目标 / SDD 规格说明) | 系统收敛方向的唯一锚点。设定值含混一分,稳态误差便大一分;它必须具备近乎绝对的刚性与无歧义性。(详见第三章) |
| 控制器(Controller) | AI Agent(LLM + 推理/规划引擎) | 以误差信号为输入、以消除误差为目标的自适应调节单元。其概率本质决定了它永远无法“一次写对”,必须依赖误差持续校准自身。 |
| 执行机构(Actuator) | 工具链(IDE / Shell / 编译器 / 包管理器) | 把高维决策落实为确定性文件变更的管道。执行的廉价化与可重复化,是闭环得以高频运转的隐藏前提——昂贵的执行器会杀死整个回路。 |
| 被控对象(Plant) | 软件系统及其运行时 | 被塑造的“物质”。其全部行为空间由代码与配置决定,因此可以被执行器完全重写;但也意味着任何未被约束的行为都属于系统合法行为的一部分。 |
| 传感器(Sensors) | Harness(测试套件 / 静态分析 / 类型系统 / 沙箱) | 把不可见的运行行为转译为可比较的测量值。测量不到的量便无法被控制——测量精度就是控制精度的天花板。(详见第四章) |
| 误差信号(Error Signal) | Loop 日志(编译错误 / 测试失败 / Traceback) | 期望状态与实测状态的差值 Δ。闭环中它不再是需要掩盖的耻辱,而是驱动系统演化的负熵能量;没有误差的系统并非完美,而是失聪。 |
| 扰动(Disturbance) | 需求变更 / 依赖升级 / 环境漂移 | 外部世界对系统的持续作用。开环系统对扰动无感,直至输出崩溃的那一刻;闭环系统以负反馈持续抵消扰动,维持输出对设定值的跟踪。 |
由这张表可以析出两条控制论的硬核结论。其一,闭环的控制精度永远受制于传感器的测量精度——测量不到的行为便无法被控制,这条铁律将在第四章引出 Harness 的全部设计哲学。其二,系统的抗扰动能力来自负反馈回路的增益,而非来自对扰动的预测:没有人能预知下一次依赖升级或需求变更何时降临,但足够刚性的测量,能让系统在扰动发生后的第一个 Loop 内就把它消化为一条普通的误差信号。至于这条回路自身的动力学——误差的消化节奏、收敛的速度与稳定性——则是第五章的主题。
4. 控制权退后:人类角色的升维
控制拓扑的改写,必然引起人类角色的重新定价。
开环时代,工程师是微观执行者:盯指针是否越界、括号是否匹配、内存是否泄漏,如同早期车间里用双手搬运每个零件的工人,双手的灵巧程度就是产出的天花板。闭环时代,人类退到了回路之外,升维为控制论专家与系统架构师:调校设定值的精确度,设计并维护高强度的传感器网络(Harness),评估系统在给定约束下的收敛速度——而不是 Agent 在第三次 Loop 里写错的那个变量名。
耐人寻味的是,人类并未因此退出回路,而是发生了回路位置的迁移:从回路中带宽最窄的那根导线,变成回路之外一切偏差的最终参考源。控制理论告诉我们,设定值的微小漂移,会沿回路被忠实放大为输出行为的系统性偏差(稳态误差);人类对系统的控制权没有减少,只是控制的作用点从“事后修正”前移到“事先定义”。
控制论奠基人诺伯特·维纳(Norbert Wiener)将这门学科定义为“关于动物与机器中控制与通信的科学”,他写道:“信息的本质,是我们在适应外部世界以及将这种适应转化为外部世界可感知到的过程中,同外部世界进行交换的内容。” 软件工程从来就是这样一种交换——意图在需求文档、人脑、源代码、机器码之间的层层转译中持续损耗。沿香农(Claude Shannon)的信息论视角看得更清楚:每一层转译都是一次有损编码,开环系统被迫在发送端一次性完成全部编码,于是需求文档里任何一处含糊,都被原样固化进系统;而闭环回路本质上是一条高带宽的纠错信道——开环开发像 UDP,把意图打包发出后便不再追问是否抵达;闭环开发像 TCP,每一次丢包都被确认、重传,直到接收端的状态与发送端的意图逐比特吻合。 意图不再需要一次讲对,纠错的成本被系统自己承担了下来。
当然,闭环不会凭空成立。一个反馈控制系统要稳定运行,必须同时满足两个刚性前提:其一,设定值必须足够精确——模糊的 Goal 会让系统在多重可行解之间来回震荡,意图如何被固化为无歧义的规格说明,是第三章的主题;其二,测量必须足够刚性——传感器一旦被概率模型污染,闭环即刻退化为开环,这正是 Harness 设计与“负向空间”的全部要义,留待第四章。而当设定值与测量两端都被锁死,误差信号自身的消化节奏——Loop 的工程学——便成为这场范式革命跳动的动态心脏,我们将在第五章展开它的每一次搏动。
第三章 意图的收敛:Goal(目标)与 SDD 的硬核落地
在第二章中,我们建立了整篇文章的工程哲学骨架:软件工程正从“开环控制”走向“闭环控制”,AI Agent 成为控制器,Harness 成为传感器网络,Loop 成为负反馈通道。但这套闭环系统要成立,还缺少一个被我们默认了太久的环节——设定值(Setpoint)。
任何一个控制系统的第一性问题都不是“控制器有多聪明”,而是“参考值有多精确”。再灵敏的自适应控制器,如果围绕一个漂移的、含噪的、甚至错误的目标收敛,其输出只会以极高的效率偏离真理。本章要解决的正是这个前提性命题:在 Agent 时代,人类意图如何被转译为一个不漂移、可编译、可验证的 Setpoint。答案是 SDD(Spec-Driven Development,规范驱动开发)——它不是“把需求写清楚”这种老掉牙的劝告,而是一套将意图编译成确定性约束的工程基础设施。
1. 设定值失真:Prompt 漂移与“Vibe Slop”灾难
先看一个每个用过 AI 编程工具的人都经历过的实验。
用同一句看似明确的 Prompt——“给订单服务写一个创建订单的 REST 接口”——分别生成三次。你会得到三种接口签名:第一次是 POST /api/orders 配 { product_id, quantity };第二次是 POST /api/v1/order/create 配 { productId, count };第三次干脆是 PUT /orders/:id 并内嵌了一个 userId 字段,理由写得头头是道。三次输出在各自语境下都“说得通”,但没有任何两次能共享同一个客户端。
从控制论看,这不是模型的能力缺陷,这是设定值信道本身的物理属性问题。自然语言是一条高带宽、低保真的信道:它承载语义的吞吐量极大,但每一次“采样”都伴随着可观的方差。LLM 本质上是概率采样器,面对一句语义有几十个自由度的 Prompt,它不会在“唯一正确解”上收敛,而是在“合理解分布”上随机取点。风格漂移、字段命名漂移(snake_case 还是 camelCase)、错误码约定的隐性丢失、分页参数的有无——每一次生成都像掷一次骰子,而每一颗骰子都落在契约的空白地带。
如果失真只是三次采样不一致,问题还不大;真正的灾难在于失真的累积性。第一次生成的接口被后续代码引用,第二次的命名风格被新代码模仿,第三次的隐性约定被当成既有事实写进了文档。每一份“Vibe Slop”——那些看似能跑、契约松垮、边界模糊的 AI 生成物——都是一次未被记录的系统状态变更。它们不会立刻崩溃,而是像热力学中的微扰一样持续注入架构熵:耦合度缓慢上升、契约语义缓慢模糊、术语表缓慢分裂。半年后,没有人知道“这个字段到底是可选还是必填”,因为最初的设定值从未被锚定在任何地方。
香农(Claude Shannon)的信息论在这里给出了冷静的判词:意图经过多层转译必然发生信息丢失,而未经编码的自然语言是丢失率最高的信道之一。从产品经理脑中的业务规则,到需求文档,到 Prompt,到 LLM 采样,到生成代码中的 if/else 与散落的校验逻辑——意图被粉碎成低维碎片,散落在整个代码库里,且没有任何一处碎片能还原全貌。企业级软件的 Setpoint 要求的是比特级的一致性:同一个字段名、同一种错误语义、同一条命名规则。仅凭自然语言 Prompt,不可能承载这种精度——它不是错的工具,而是被用在了错误的精度等级上。
一个漂移的 Setpoint,对闭环系统意味着两种死法:要么系统在多个合理解之间持续震荡、永不收敛;要么高效地收敛到一个错误答案上。前者浪费 Loop,后者浪费架构。
值得强调的是,Prompt 漂移对闭环系统而言是结构性中毒而非一次性噪声。一次采样错误尚可被 Code Review 拦截,但 Agentic 工作流的特点恰恰是高速迭代:一个含噪的 Setpoint 会在数十次 Loop 中被反复引用、被下游产物反复固化。控制理论对此早有术语——参考值含噪(noisy reference)的系统,其稳态误差永远不会归零,控制器越灵敏,输出围绕错误锚点的振荡幅度反而越大。这正是“Vibe Slop”灾难的控制论精确表述:不是 AI 写错了某一行代码,而是整个闭环被一个不可信的参考信号劫持了。
2. SDD 作为工程解毒剂:Spec 即 Setpoint
SDD 的核心命题可以用一句话说尽:用结构化、无歧义、机器可读的规范工件(Spec)锁定人类意图,让 Spec 本身成为系统的“设定值寄存器”。 Thoughtworks 技术雷达在讨论 Spec-Driven Development 时将其定位为一种从“面向人阅读的文档”到“面向机器消费的接口”的范式转换——同一句话,在控制论语境下读,就是在说:Setpoint 必须从模拟信号升级为数字寄存器。
这句话的分量,需要逐类落到具体的规范工件上才能看清。SDD 的硬核之处不在于“要写文档”,而在于每一份 Spec 都是一份可编译的源代码,它经由确定性的工具链产出确定的工程产物。这不是比喻,下面逐一展开“工件 → 编译产物”的具体机制。
OpenAPI 契约:接口层的宪法。 一份 openapi.yaml 用形式化语法声明每一个端点的路径、方法、请求体、响应体、错误码与媒体类型。围绕它存在一整条成熟工具链:openapi-generator 可以从契约直接生成服务端 stub 与多语言客户端 SDK,让实现者与消费者共用同一个类型源头;Prism 之类的 mock server 能在一行真实实现都不存在的情况下对外提供符合契约的假端点,让前端与测试先行;契约测试框架校验真实实现的响应是否真的匹配声明。以 Pact 为代表的消费者驱动契约测试更进一步:它不验证实现是否“符合文档”,而是验证生产者与消费者之间真实的交互期望是否匹配——契约从纸面条文升级为双方系统的联合断言。最关键的是,OpenAPI 描述的每一个字段约束——必填与否、格式、枚举取值——都在代码库之外形成了一个独立可校验的真值。接口签名的“三次生成三种结果”问题在此被结构性消灭:因为签名的源头不再是采样的结果,而是契约的条文。
JSON Schema:数据层的类型定理。 如果说 OpenAPI 约束的是系统边界,JSON Schema 约束的就是流经系统的每一个数据载荷。它的编译产物同样是多重的:其一,运行时校验——ajv 等校验器在数据进入系统边界时执行断言,非法载荷在第一道防线被拦截,校验逻辑不再散落在业务代码的 if/else 深处;其二,多语言类型代码生成——从一份 Schema 生成 TypeScript 类型、Python pydantic 模型、Go struct,让跨语言系统共享同一份数据结构定义,消灭了序列化层最常见的“字段漂移”类 Bug;其三,模糊测试的种子空间——Schema 定义了合法输入的完整包络,这恰好是 fuzzing 工具构造变异输入的地图:在包络边缘注入畸形数据,恰好是探测系统鲁棒性的最有效方式。一份 Schema 同时是校验器、类型生成器的输入和模糊测试的作战图——这正是“可编译意图”的含义。
Mermaid 与架构意图图:结构层的施工图。 一份 Mermaid 的组件图或依赖声明,把“服务 A 不允许直接访问数据库,必须经由服务 B”这类架构决策从口头约定升级为图形化工件。它此刻还是一份静态意图声明——注意,这是本章埋给第四章的一条暗线:当这类结构意图被 ArchUnit 之类的工具编译成可执行的架构断言(“依赖方向违反即构建失败”),它们就从图纸变成了 Harness 的一部分。此处只需记住:结构约束的合法性源头是这张图。
这些工件共同完成了 Brooks 在《没有银弹》中那场著名区分的工程显式化:AI 消灭的是“写代码”这一偶然复杂度——语法、样板、脚手架——但它无法消灭业务规则本身的本质复杂度。而传统做法恰恰是把本质复杂度伪装成偶然复杂度:一条退款规则,被碾碎成二十个文件里的条件分支,没有人能指着任何一处说“这就是规则本身”。SDD 的深层价值在于反其道而行:本质复杂度第一次以未被降维的形态——作为工件、作为契约、作为系统第一公民——驻留在工程之中。意图不再藏身于代码的分布表示里,它有了自己独立的、可 diff、可评审、可版本化的实体。
这正是高维意图的保留。过去,一份 API 契约的信息同时编码在控制器代码、序列化层、测试断言和 wiki 文档里,四处拷贝、四处漂移;现在,它只在 Spec 中存在一次,所有产物都是它的确定性函数。引用信息论的说法:Spec 是意图的高保真编码,而代码、测试、类型、文档都只是这个编码的一次无损解码——解码可以任意重复,编码只有一个。
“在传统开发中,规范(Spec)是写给人类看的过期文档;在 Agent 时代,规范(Spec)是直接编译出代码与测试的高维基因。”
3. SDD 的双向驱动逻辑
Spec 成为 Setpoint 之后,它在控制系统中同时向两个方向输送约束力。理解这两个方向,就理解了 SDD 为什么是闭环架构的中枢而不是一份静态附件。
向下:Spec 作为 Goal 驱动 Agent 生成代码。 在 Agentic 工作流中,Spec 不再是生成之后的评审标准,而是生成之前下发的输入。当 Agent 拿到的不是一个模糊的句子,而是完整的 OpenAPI 契约、JSON Schema 与目录结构约定时,它的每一次采样都被约束在契约包络之内:字段名已被钉死,错误码已被枚举,边界条件已被声明。生成从“在解空间中随机游走”变为“在包络内插值”。这并没有削弱模型的创造力——它排除了的是采样噪声,保留的是包络内的合理多样性。Setpoint 越精确,控制器的有效增益反而越高,因为误差信号不再被“哪个解释是对的”这类伪偏差污染。用 Ashby 的必要多样性定律(Law of Requisite Variety)反过来看:Harness 与 Spec 所提供的约束多样性,恰好是用来压制 LLM 采样不确定性的那一半控制器状态。
向旁:同一份 Spec 派生测试套件与类型约束——即 Harness 的原材料。 这是 SDD 最容易被低估的一向。契约测试、由 Schema 生成的边界用例、由类型定义传导出的编译期检查——这些不是开发完成后的“补充测试”,而是 Spec 的直接编译产物,与实现代码并行生成,先于实现存在。换句话说,Harness 不是为某个具体实现量身定做的验收单,而是 Setpoint 向测量维度投下的影子。Harness 的完整理论——为什么它是守恒的边界、如何以负向空间定义自由——是第四章的主题,此处只把管线接通。
由此可以收束出本章的“Spec 编译管线”全景:
| 规范工件 (Spec) | 编译工具链 | 生成产物(向下/向旁) |
|---|---|---|
| OpenAPI 接口契约 | openapi-generator / Prism / 契约测试框架 | 服务端 stub、多语言客户端、mock server、请求/响应校验 |
| JSON Schema 数据契约 | ajv / 类型生成器 / fuzzing 引擎 | 运行时校验器、TypeScript 类型、pydantic 模型、模糊测试输入空间 |
| Mermaid 架构意图图 | 静态渲染(本阶段)→ ArchUnit(第四章) | 结构声明;未来编译为可执行架构断言 |
| 目录/命名/约定规范 | Lint 规则、模板脚手架 | 一致的项目骨架、可静态检查的约定约束 |
这张表揭示了 SDD 的根本性颠倒:传统流程中,文档是代码的滞后副本——代码一改,文档沦为谎言;而在 Spec 编译管线下,代码成了 Spec 的瞬时展开。谎言的结构被反转了:现在如果实现偏离契约,偏离会被立即测量出来,因为测量基准(契约测试、校验器)与实现共享同一个源头。
于是本章的论证链条闭合了。自然语言 Prompt 是一条高带宽低保真的意图信道,撑不起企业级软件所需的 Setpoint 精度;SDD 用机器可读的规范工件把意图编译成确定性约束,使 Setpoint 第一次获得了寄存器级的刚性;这份刚性的 Spec 向下约束 Agent 的采样空间,向旁编译出 Harness 的原材料,在控制拓扑中占据了“目标源点”的位置。
但请注意,精确的 Setpoint 只回答了控制系统的一半问题:往哪收敛。 一个围绕正确目标工作的 Agent,仍然可能在收敛途中越界——写出能跑但破坏架构的代码、通过测试但污染边界的实现。收敛过程不越界靠什么?答案在系统的另一组组件里:测量与约束的网络,即 Harness。那是第四章的内容。
第四章 守恒的边界:Harness(约束架)与负向空间设计
第三章回答了“设定值”的问题:Goal 与 SDD 把人类意图压缩成足够精确的参考输入。但任何一个接触过控制论的人都清楚,精确的设定值只构成闭环的一半。闭环的另一半是一个朴素得近乎粗暴的事实——你无法控制你无法测量的东西。
而本章要测量的对象,恰恰是一台以概率为燃料的机器。
标题里的“守恒”是一个物理学词汇。守恒律的残酷之处在于,它宣布某些量既不能被创造,也不能被消灭,只能被转移、被约束、被圈定在边界之内。软件工程里守恒的那个量,是不确定性。LLM 带来的生成多样性是真金白银,但它附带的幻觉、随机与漂移不会因为我们满怀期待而消失。工程上唯一可行的路只有一条:用 100% 确定性的结构,为这份不确定性划定边界——把“绝不允许”的空间钉死,把其余的空间留给概率。在第二章的控制论账簿上,承担这项工作的装置叫做传感器;在软件工程里,它的名字叫做 Harness(约束架)。
1. 没有传感器,闭环就不成立
闭环控制的第一公理是:没有测量,反馈就无从谈起。一个系统能控制什么,取决于它能看见什么;反馈回路的精度上限,由传感器的精度决定。这条公理对 Agent 体系提出的要求非常具体:测量装置必须与生成装置统计无关。你不能让被控对象自己给自己读数,就像你不能让考生兼任阅卷老师——误差与答案若出自同一分布,测量就是一场自欺。
不幸的是,LLM 恰恰天然不适合充当测量者。它是高方差的执行器,而不是高精度的传感器:
- 幻觉(Hallucination) 最危险的地方不在于它错,而在于它错得文法正确、风格优雅、信誓旦旦。一段编造出来的 API 调用,读起来与人类专家手写的代码别无二致——这正是肉眼审读最难拦截的失败形态。
- 采样随机性:同一个 Prompt 在 temperature > 0 下重复采样,得到的不是同一个答案,而是一簇分布。两次运行产出两份不同代码,对生成任务这是多样性,对测量任务这是噪声。
- 上下文漂移:随着 Loop 轮次堆积,Agent 对最初约束的记忆被上下文窗口稀释。约束被遗忘不是故障,而是长上下文的物理性质。
指望模型“自我检查”在此显得荒谬:让生成器评审自己的产出,误差与产出自相关,测量从原理上就失效了。必须有某种外生的、确定性的、与生成过程零相关的装置来完成读数。这就是 Harness 存在的控制论理由。
从状态空间的角度看,全部可能代码构成的相空间是天文数字级的,其中“能正确工作的代码”只占极小一块。Harness 的作用,是在这片相空间里切割出可验证的“可存活区域”,像一片刚性重力场:它不改变概率云的内在涨落,却决定云团只能沿可验证的轨道沉降。概率允许 Agent 写出任何东西,但唯有穿过测量装置的代码才被允许成为制品。
这条思想并非 Agent 时代的发明,它有清晰的谱系。2002 年 Kent Beck 在《测试驱动开发》中确立的 red-green-refactor 循环,本质上就是一台微型闭环控制器:先把期望状态写成一条注定失败的断言(设定值),再驱动实现收敛到绿色(误差归零)。但在过去的二十余年里,这条闭环的“执行点”始终是人类自己的意志力——它是自律,而自律出了名的不可靠:交付压力之下,红灯可以被人为忽略,测试可以在截止日期的前夜被成批注释掉。Agent 时代完成了这次升维:LLM 没有自律可言,它只有概率分布;于是闭环的执行点从“人的克制”外移为“机器的跑道”。TDD 没有过时,它只是从人类的品德课,变成了 AI 的基础设施——跑道不需要执行者自觉,跑道只需要存在。
2. 负向空间设计:以约束定义自由
Harness 的设计哲学,可以借雕塑来理解。米开朗基罗说,雕像本来就在石头里,他只是凿去了多余的部分;中国版画讲“计白当黑”,负形不是空无,而是被同等精确地设计过的形状。把这套美学移植到软件工程,就得到一个精确命题:Harness 只定义“什么绝不允许存在”,从不教导“应该怎么写”。 前者是负向空间,用确定性工具穷举;后者是正向空间,整片留给生成式概率。这恰好完成了一次关键的切割:我们需要 LLM 的多样性,于是把“怎么写”还给概率;我们惧怕 LLM 的方差,于是把“不许怎样”收归机器。
负向空间不是一句口号,它有一条由具体工具筑成的谱系。每一层工具都有自己的工作原理、自己的红线类型、自己的反馈形式。
第一层:行为红线——单元测试与属性测试。 手工编写的单元测试(JUnit、Pytest)把行为钉在一个个具体样本上,是负向空间的最小单元;但它的盲区同样明显:样本只能覆盖你想到的输入。属性测试(property-based testing)在此完成了质变:开发者不再列举输入-输出对,而是书写不变量(invariant)——reverse(reverse(xs)) == xs,decode(encode(x)) == x,排序结果必须有序且是原序列的重排。以 QuickCheck(Haskell)与 Hypothesis(Python)为代表的引擎用随机生成器构造成百上千个合法输入,持续轰击这些全称命题;一旦发现违反者,shrinker(收缩器)会把反例系统性地削减到最小形态——从一个 500 元素的列表收缩到 [0, 0]——把“某个输入失败了”翻译成“这就是事故现场的最小罪证”。人类负责书写 ∀,机器负责搜索 ∃。 测试断言由此从“样本抽查”升格为“全称判决”。
第二层:红线的反身性检验——变异测试。 测试本身会不会失明?变异测试(mutation testing,PIT、Stryker、mutmut)把审判席转向了测试:工具向被测代码注入大量“变异体”——把 > 改成 >=、取反一个条件、删除一条语句——每只变异体都是对实现的一次微小篡改。如果测试套件不能让某只变异体变红,说明现有红线对这类篡改恰好失明:测试全部通过,但测试并没有在测量。这一层对 Agent 时代格外尖锐——LLM 生成的测试常与 LLM 生成的实现共享同一个概率盲点,形式完备而实质共谋;存活下来的变异体,就是这场共谋的呈堂证供。
第三层:语法与风格红线——AST 级 Lint。 ESLint、Clippy、Ruff 之所以比正则表达式可靠,在于它们先把源码解析为抽象语法树(AST),再在结构层面执行规则:typescript-eslint 的 no-floating-promises 识别“创建了 Promise 却未 await”的结构性危险,Clippy 的 unwrap_used 在 Rust 代码里通缉每一个可能 panic 的裸 unwrap,Ruff 以接近零的延迟在 Python 代码上跑完数百条规则。每条规则都是一条机器可读红线,以配置文件的形式提交进仓库——从此人类评审与 Agent 生成共用同一份“不许做什么”的清单,反馈延迟以毫秒计,早于一切执行。
第四层:编译期红线——类型系统。 TypeScript 的 strict 模式打开 strictNullChecks 之后,undefined 不再是埋进代码深处、等待凌晨两点引爆的哑弹,而是编译期必须显式处理的类型;Rust 走得更远,所有权与借用检查(borrow checker)在编译期消除整类内存错误——use-after-free、double free、数据竞争——且不付出运行时代价。在 Curry–Howard 同构的朴素表述里,类型是待证明的命题,程序是证明本身;编译器因此是最便宜的 Harness:作者不必为它编写任何一条测试,它却在每次保存时全量运行,把反馈压进毫秒级。在 Agent 体系里,每一个生成片段的第一道关口不是测试,而是类型检查——最便宜的闸门最先关上。
第五层:架构红线——ArchUnit,第三章的下半集。 第三章把架构意图收敛为 Mermaid 图与契约;ArchUnit 负责把这张图编译成可执行断言。下面两条规则每天都在无数 CI 流水线上巡逻:
// 控制器不许绕过 Service 层直插 Repository——依赖方向是架构的承重墙
classes().that().resideInAPackage("..controller..")
.should().notDependOnAnyClass()
.that().resideInAPackage("..repository..");
// 模块间不允许出现依赖环——成环之日,增量编译与独立测试的全部承诺作废
slices().matching("..(*)..").should().beFreeOfCycles();
过去,架构腐化只能靠 code review 中人类日渐衰退的记忆拦截——人会疲惫、会遗忘、会被“就这一次”说服;CI 不会。架构图一旦变成断言,就从“会过期的文档”升格为“常开的探照灯”。
第六层:红线的强制执行点——CI/CD 钩子。 红线若没有强制执行点,就只是一份建议书;没有法庭的法律,只是文学。pre-commit 钩子把 Lint 与格式化红线推到提交动作发生之前——最便宜的拦截发生在离错误最近的时刻;merge gate 借助分支保护赋予红线否决权:CI 不绿,任何人、任何 Agent 都不许合入,人类评审从“逐项盯防”中解放出来,机器接管“一票否决”;覆盖率阈值(例如行覆盖不低于 80%、diff 覆盖 100%)则把覆盖率从“事后的报告”改造为“事前的闸门”。
第七层:物理边界——沙箱。 以上六层约束的都是符号;沙箱约束的是物理动作。容器、microVM、默认拒绝的网络出口、只读挂载的文件系统,把 Agent 的 shell 权限关进一次性围栏:即便所有语义测量全部失效,爆炸半径也被限制在环境之内。负向空间的定义由此完成从“这段代码不许错”到“这个行为者不许越界”的延伸——红线的最后一圈,画在执行器身上。

七层约束可以汇总为一张负向约束清单:
| 红线类型 | 代表工具 | 违反时的反馈形式 |
|---|---|---|
| 行为红线(样本级) | 单元测试(JUnit / Pytest) | 断言失败,红色堆栈 |
| 行为红线(全称级) | QuickCheck / Hypothesis | 最小化反例(falsifying example) |
| 红线反身性检验 | PIT / Stryker / mutmut | 存活变异体清单 |
| 语法与风格红线 | ESLint / Clippy / Ruff | 毫秒级静态诊断 |
| 编译期红线 | TypeScript strict / Rust 借用检查 | 编译错误,零运行时成本 |
| 架构红线 | ArchUnit / ArchUnitNET | JVM 测试失败,指认违规依赖 |
| 强制执行点 | pre-commit / merge gate / 覆盖率阈值 | 拒绝提交、拒绝合入 |
| 物理边界 | 容器 / microVM / seccomp | 权限拒绝,爆炸半径受限 |
现在可以点明这张清单背后的工程守恒律了:表中每一件工具都是 100% 确定性的程序——同样的输入必然给出同样的判决,没有 temperature,没有心情。用 100% 确定性的代码工具,包裹 80% 概率性的 LLM 决策——这不是经验之谈,而是闭环系统得以成立的工程守恒律。 我们没有(也不必)让模型本身变得更确定;我们构造的是一个不依赖模型自觉的确定性外壳:概率云可以涨落,但任何一行代码只有在穿过全部闸门之后才被允许成为制品。不确定性并未被消灭——守恒律禁止这种幻想——它只是被逐层过滤、就地放逐。而所有没被 Harness 拦截的不确定性,终将在生产环境的凌晨两点连本带利地回来。
3. 控制权转移:谁掌握传感器,谁掌握系统
负向空间一旦建成,它就不仅是一套工具,而是一条关于系统能力的定律。W. Ross Ashby 在《大脑设计》(Design for a Brain, 1952)中提出、并在《控制论导论》中系统阐述的必要多样性定律(Law of Requisite Variety)指出:控制系统的内部状态多样性必须不小于被控对象所呈现的多样性——只有多样性才能吸收多样性。翻译成工程语言:扰动的种类如果多于传感器的种类,未被测量的扰动就只能在系统中自由演化,稳定便无从谈起。此时系统的震荡不是运气差,而是数学必然——按下葫芦浮起瓢的回归拉锯,本质就是约束多样性对需求多样性的欠账。
落到 Agent 工程,这条定律可以写成一条不等式:
约束多样性(Harness)+ 生成多样性(Agent) ≥ 需求空间的不确定性。
Agent 一侧的生成多样性取之不尽,这正是我们雇佣它的原因;但无约束多样性与之配对的生成多样性,只是未经测量的方差。每一种不确定性都必须有与之配对的传感器:
| 不确定性的类型 | 与之配对的传感器 |
|---|---|
| 边界条件与路径组合 | 属性测试(随机生成 + 反例收缩) |
| 并发时序 | TSan / 确定性调度与回放 |
| 服务间契约漂移 | 契约测试(Pact) |
| 架构依赖走向 | ArchUnit 架构断言 |
| 测试本身的失明 | 变异测试 |
| Agent 的物理越权 | 沙箱(容器 / 网络隔离) |
没有配对传感器的不确定性,就是控制系统的盲区;在盲区里,LLM 的方差如入无人之境。Harness 的覆盖面,就是控制的边界——这不是修辞,而是 Ashby 不等式取等号的位置。
由此,控制权完成了它的最终转移。模型在商品化,Agent 框架在换代,上下文窗口的数字年年翻新;而测试套件、规则集、架构断言与闸门逻辑——这些 Harness 资产——不随任何一次模型发布而折旧。测量者定义了“成功”的语言:每一代新模型、每一个新 Agent,都必须穿过同一道闸门、在同一张红线上留下零违规记录,才获准进入代码库;红线的编写者由此规定了所有未来执行者可活动的相空间。谁掌握 Harness 的设计权与测试编写权,谁就掌握了 AI 的终极控制权。 一家把“AI 开发”理解为几条 Prompt 模板的组织,并不真正拥有什么;一家把 AI 开发沉淀为硬化 Harness 的组织,拥有的是约束一切未来模型的边界——Agent 可以替换,模型可以换代,唯有 Harness 是组织真正沉淀下来的控制资产。
但传感器的故事到此只能讲一半。测量值本身不会修改任何一行代码——误差信号必须被送回控制器,经过反馈回路的消化,才能转化为下一轮的修正动作。传感器只回答“差多少”,“怎么补”属于回路。这正是下一章的主题:Loop。
第五章 动态的熵减:Loop(循环)与负反馈自愈
第二章完成了控制论的概念映射,第三章把 Goal 锻造成了精确的设定值,第四章铺设了 Harness 的传感器网络——但至此为止,这一切仍是静态结构。一套再精密的传感器阵列本身不会飞行,一副再刚性的约束架本身也不会演化。让系统真正“活”起来的,是时间维度上那个周而复始的过程:Loop(循环)。如果说 Goal 决定了系统收敛的方向,Harness 决定了系统测量的精度,那么 Loop 决定了系统逼近真理的速度与稳定性。本章要回答三个层层递进的问题:误差信号如何在 Agent 的回路中被生成、传输与消化?Bug 在闭环哲学中究竟意味着什么?以及——当 Loop 真正自转起来之后,人类应该站在哪里?
1. 误差信号的生成与消化
一次典型的 Agent 闭环迭代,其内部并不是“生成代码→祈祷→瞄一眼结果”的模糊过程,而是一条逐级滤波的信号流水线:

每一个阶段的产物,都是同一个物理量的不同截面——误差信号(Error Signal),即期望状态与现实状态的 Δ(Delta)。编译器报出的 error[E0308]: expected String, found &str 是类型维度上的 Δ;pytest 打印的 FAILED tests/test_refund.py::test_partial - assert 400 == 200 是行为维度上的 Δ;CI 面板上的 coverage: 87.3% → 84.1% (-3.2%) 与 benchmark: p95 latency +12% vs baseline 则是质量维度上的 Δ。它们形式各异,控制论意义上却是同一个东西:现实输出与设定值之间的差值电压。
误差信号生成之后,必须被传输到控制器才能发挥作用。在 Agent 架构中,这条传输通道有一个非常具体的名字——上下文窗口(Context Window)。Traceback、失败列表与 diff 被压缩为文本,回注进 Agent 的上下文,构成下一轮决策的输入。这带来三条硬核的工程推论:
- 信号必须完整。 被截断的 Traceback 等同于传感器信号被削波(Clipping):控制器拿到的是一个失真的误差,据此输出的修正必然带有系统性偏差。Harness 的设计纪律之一,就是让报错完整、可读、附带文件路径与行号——因为它不是供人翻阅的“事故报告”,而是直接喂给控制器的“输入电压”。
- 信号必须分层。 成熟流水线的执行顺序是类型检查 → Lint → 快速单测 → 集成测试 → 性能基准。这不是工程洁癖,而是滤波器设计:毫秒级即可暴露的类型错误若拖到集成测试阶段才现身,误差信号就会淹没在数十条下游噪声里。先廉价后昂贵、先局部后全局,本质是反馈信道上的带宽分配。
- 信号必须可消化。 若一轮 Loop 的失败列表长达数千行、超出上下文的物理预算,误差信号便宣告过载。对策同样是控制论的:压缩单次改动面、对失败用例做聚合归类,让每轮进入控制器的信号保持在一个可处理的幅度内——这恰好引出下一节的增益调校。
还有两个经常被忽视的硬件级事实。其一,不稳定测试(Flaky Test)是传感器噪声:时通时断的用例向控制器注入虚假误差,Agent 会被噪声驱动着对不存在的偏差做随机游走,工程上必须对其实施隔离与重试滤波,否则控制器终日在修理一件没有坏的设备。其二,回路的控制带宽被链路上最慢的传感器锁死:若集成测试需要三十分钟,Loop 的采样周期就是三十分钟,任何高频震荡都来不及被纠正——反馈的时效性就是控制的时效性,把最慢的测试留在最外层,不是偷懒,是在保护系统的带宽。
必须扭转一个根深蒂固的直觉:报错信息不是“失败通知”,而是控制系统的输入电压;Log 不是程序排出的代谢废物,而是负反馈回路的神经脉冲。 没有脉冲传入大脑,四肢就会在黑暗中瘫痪;没有报错回注 Agent,Loop 就退化回了第二章批判过的开环系统。
2. Bug 哲学观的重塑:错误即负熵流
传统软件文化对 Bug 持有一套隐性的羞辱叙事:Bug 是开发者的失误,是评审中被红框标出的丢脸证据,是考核表上被计数的负面事件。在这种叙事之下,组织会演化出掩盖误差信号的本能——把测试写弱一点,把断言写松一点,让红色尽量不出现在面板上。这是典型的指标劫持:当组织惩罚误差信号,系统就会自动调低传感器的灵敏度。
闭环工程哲学对此有完全不同的读法,而这个读法有坚实的物理学根脉。1944 年,薛定谔在《生命是什么》(What is Life?)中指出:生命有机体之所以能长期维持自身高度有序的低熵状态,是因为它们持续从环境中摄取“负熵”(negentropy),并把熵排泄给外部环境——有机体以负熵为食。
把这个论断原样搬进软件工程,会得到一个略显残酷却极为精确的结论:
闭环系统以报错为食。
一个代码库要维持低熵——意图清晰、行为可预测、改动可被精确定位——就必须持续吞入“现实与期望之差”的信息,并把不确定性排出体外。每一条 Compiler Error、每一个 Test Failure,都是系统吞吐的一份负熵原料:它精确指出了“这个世界在哪个坐标上与你的期望不符”。修复的过程,就是从代码中排出一份不确定性的过程。红→绿(Red→Green)的每一次翻转,都不是对一次失败的掩埋,而是可能性空间的一次坍缩——系统排除了“此处存在一种错误”的假设,不确定性的余额减少了一格。
维纳在《控制论》中把信息锚定为熵的减少,香农的信息论则从数学上给出了度量:信息量 = 被消除的不确定性。 以此观之,一条详尽、精确、带完整堆栈的报错是极高信息量的信号——它把“哪里错了”的不确定性压缩到了几个字符之内;而一个静默通过的绿构建,如果其测试不过是些恒真断言(assertTrue(true)),其信息量严格为零。我们过去把测试全绿当作系统在“正常运转”,现在应当改口:测试全绿只意味着系统“没有报告新信息”——它可能处于稳态,也可能只是传感器已经断线,两者的面板读数一模一样。
由此得到一个反直觉的判别准则:一个从未报错的 Agent 迭代不是完美,而是失明。 概率模型天然倾向生成“看起来合理”的代码,它对自己的幻觉具有高度的自我一致性。若一次漫长的迭代从头到尾零报错,更可能的解释不是 Agent 天赋异禀,而是:测试根本没跑、断言从未生效、或者 Harness 压根没有被接入回路——第四章所述的传感器失明在此显形。静默的失败远比响亮的报错危险:响亮的报错至少还在消耗不确定性,静默的失败却在悄无声息地增加它。
在控制论哲学中,Bug 从不是致命的故障,而是系统逼近真理时所释放的负熵能量。
3. 控制论的火候:Loop 的工程调校
闭环系统的性能不只取决于“有没有反馈”,更取决于反馈的调校。控制理论中第一个关键参数是增益(Gain)——控制器对误差信号的响应强度。映射到 Agent Loop 上,增益有一个非常具体的化身:单次 Loop 的改动面。
增益过高的症状,每个实战过的人都见过:一个 diff 触及 40 个文件,Harness 一次性吐回 30 条失败用例与交叉依赖错误,Agent 试图在下一轮一举修复全部——结果修 A 坏 B,报错列表换个组合重新出现;下一轮再修,再换一批。这不是 Agent 不够聪明,而是教科书式的控制论失稳:增益过高 → 超调(Overshoot)→ 震荡(Ringing)→ 发散(Divergence)。每一次“全面重构式”的修正,都在把系统推向相位翻转的边缘。

阻尼(Damping)设计由此而来:小步提交(Small Commits)、窄反馈面(每轮只运行与改动相关的测试子集),本质是给高频振荡加装机械阻尼,让每一轮 Loop 的误差信号保持在小幅度、可定位、可独立消化的区间。反过来,响应过慢同样失败:单轮只改一行的“蠕动模式”会让收敛速度慢到上下文与预算双双耗尽。火候的精髓,是让改动面与误差幅度成比例。
实战中最直观的增益仪表是三个数字:单轮 diff 触及的文件数、单轮新增报错的条数、以及相邻两轮报错集合的重叠率——重叠率持续趋近于 1,就是震荡逼近的预警信号。此时正确的操作不是催促 Agent 再加一把劲,而是回退 diff、收窄改动面、人为把增益拧小一档。
更精细的调校语言可以借自 PID 控制器——但请先看清它的边界:
| 控制项 | 经典含义 | Agent Loop 中的对应物 | 典型工程风险 |
|---|---|---|---|
| P(比例) | 修正量 ∝ 当前误差 | 按当前报错清单的幅度决定本轮 diff 的修正力度 | 见报错就大面积重写 → 高增益震荡 |
| I(积分) | 修正量 ∝ 误差的时间累积 | 跨 Loop 持久化的记忆:Spec、架构约束、ADR、累积的 TODO 清单 | 积分饱和(Integral Windup):在错误路线上越走越深的惯性 |
| D(微分) | 修正量 ∝ 误差变化率 | 对回归趋势的预判:冒烟测试、金丝雀发布、benchmark 斜率告警 | 把噪声当趋势,过度刹车拖慢收敛 |
必须坦白这张表的局限:P/I/D 是连续线性系统的近似语言,而真实的 Agent 回路是离散、非线性、事件驱动的。 它更接近 bang-bang 控制(开关控制)——像恒温器一样全速运转到越过阈值再急停,而不是沿着一条可微的误差曲线平滑逼近。Agent 的误差函数既不可微也不连续:测试要么通过要么失败,不存在“0.7 个通过”。把 PID 读作严格的数学等价会走火入魔,把它读作调校直觉的脚手架,则相当好用。
其中 I 项的积分饱和值得单独点破:当 Agent 携带的累积上下文(此前的尝试、此前的报错、此前的决定)越来越厚,错误假设会产生自我强化的惯性——“既然前三轮都朝这个方向改,那就应该继续”。工程上的泄压阀,是在必要时重置积分器:清空上下文、回退到上一个绿构建、把失败路径写成显式的 Spec 条目,让系统从错误的积分历史中清零重启。
现在可以精确回答“OODA 循环的系统内化”究竟意味着什么——它不是一句“要快速迭代”的口号,而是 Agent 单轮 Loop 内部四个可逐一指认的步骤:
- Observe(观察): 读取上一轮 Harness 回注的 Traceback、失败列表与覆盖率 Δ,完成传感器数据的采集。
- Orient(判断): 在上下文中定位——错误模式是什么、涉及哪些文件、与 Spec 的哪条约束冲突。这是 LLM 概率推理的主战场,也是整个 OODA 中最昂贵的一环。
- Decide(决策): 选择下一个动作——改哪个文件、跑哪条测试、先读代码还是直接动手、抑或判断误差已收敛应当停手。
- Act(执行): 经由工具链(Edit / Shell / Test Runner)落地动作,产出新的 diff,进入下一个采样周期。
关键在于分界线的移动:人类不再介入 Loop 中途的任何一次失败。 中途的每一次红(Red)都是系统内部的工作过程——正如你不会在洗衣机运转中途打开舱门,去纠正每一次水流的转向。人类被保留的权限只在两个位置:为 Loop 设定预算与保险丝(最大迭代轮数、超时、成本上限——控制工程里的看门狗定时器 Watchdog),以及在 Loop 连续 n 轮发散时接管决策(安全阀)。至于中途某个变量名写错引发的第五轮失败?那是控制器的工作,不是调度员的工作。
4. 人类的旁观位置
于是,当 Loop 自转起来之后,人类工程师的位置被彻底重置。从“修理工”到“巡航调度员”,凝视的对象发生了根本迁移:
| 维度 | 修理工时代(开环) | 巡航调度员时代(闭环) |
|---|---|---|
| 注意力单元 | 单个 Bug、单条报错 | 收敛曲线、Loop 节奏 |
| 核心仪表 | 编辑器里的红色波浪线 | 绿建比、回归频率、误差衰减斜率 |
| 介入时机 | 每一次编译失败 | 发散、传感器失灵、设定值漂移 |
| 交付判据 | “我改完了” | “系统收敛了,且收敛速度在预算之内” |
调度员不追逐每一次报错,是因为单次报错的信息价值已经交由 Loop 去消费;他守护的是系统层面的不变量:误差是否随轮次单调衰减、绿建比是否稳定、回归是否集中爆发、单轮时延与算力成本是否劣化。他处理的是“系统不收敛”这类元问题,以及前三章各自留下的隐患——设定值漂移(第三章)与传感器失灵(第四章)。
完美的 Agent 迭代不是没有报错发生,而是在人类察觉报错之前,误差信号就已经在 Loop 内部完成了自我收敛。
这句话的反面同样成立:当一次迭代静得可疑——没有报错、没有挣扎、一遍通过——调度员的第一反应不应是欣慰,而应是检查 Harness 是否真的接通了回路。喧嚣的 Loop 是活着的系统,死寂的绿是失明的系统。
至此,这台机器的四个部件全部就位:精确的 Goal 给出了设定值,刚性的 Harness 给出了传感器,调校得当的 Loop 给出了负反馈自愈的能力。控制回路已经封闭,系统已经可以稳定地自我收敛。那么——当机器自己会跑、会修、会收敛之后,握着方向盘的人类这一侧,剩下的体验究竟是什么?那是一种解放,还是一种更隐蔽的责任?这正是第六章要拆解的张力:Vibe 与 Agentic 的辩证统一。
第六章 张力与融通:Vibe Coding 与 Agentic Coding 的辩证统一
过去两年,描述 AI 辅助开发的话语场被两个词反复撕扯:一边是 Vibe Coding——强调流畅、直觉、“想到即得到”的极客体验;另一边是 Agentic Coding——强调自主代理、工具编排与工程治理的硬核范式。技术社区为此争论不休:Vibe 派嘲讽 Agentic 是“给编程套上官僚流程”,Agentic 派则反击 Vibe 是“拿生产环境做赌注的即兴表演”。
这场争论从一开始便建立在错误的前提上。本章的任务是拆掉这个前提:Vibe 与 Agentic 并非同一抽象层上的两个竞争者,而是同一个控制论系统在两个观察位置上的两个名字。 理解这一点,前面五章铺陈的 Goal、SDD、Harness、Loop 才能最终合龙为完整的工程哲学闭环。
1. 两个名字,两个视角:体验(Vibe)与机制(Agentic)
“Vibe Coding” 一词由 Andrej Karpathy 在 2025 年初提出。他在一条广为流传的推文中描述了一种全新的开发状态:完全沉浸于“氛围”(fully give in to the vibes),拥抱指数级的试错,甚至“忘记代码的存在”(forget that the code even exists)。值得注意的是这句话的语境:它不是方法论宣言,而是一位资深工程师的体验报告——Karpathy 用它来标记自己与 LLM 结对时感知到的那种交互形态的质变。
要理解这个质变的坐标位置,需要放回 Karpathy 本人勾勒的软件演化谱系。Software 1.0 是以 C++/Python 手写代码的时代,代码即软件本身,意图被逐行粉碎在 if/else 与循环结构里;Software 2.0 是神经网络权重的时代,“代码”变成梯度下降产出的浮点矩阵,人类只书写损失函数与数据管线;Software 3.0 则是自然语言成为一等编程介质的今天——Prompt 即程序,LLM 即运行时,人类在意图层直接对系统下指令。
在这个坐标系里,Vibe Coding 的准确含义立刻清晰起来:它不是“乱说一气也能出代码”的投机取巧,而是 3.0 阶段人类意图表达方式的自然形态。它的交互形态由三个具体特征构成:
- 自然语言指令:意图不必再被翻译为某种形式语法,“给用户加一个两步验证”本身就是合法的程序;
- 低摩擦修改:一次需求调整不再需要穿越编辑、编译、调试的长链条,一句话即可触发一轮精确修订;
- 意图直给:人类陈述的是“要什么”,而非“怎么要”——实现路径被整体让渡给系统的控制器。
当自然语言本身成了最高效的编程介质,流畅地表达意图便不再是纪律的松弛,而是抽象层级跃升后的正当权利。正如第一章与第二章所论证的,人类从纸带打孔一路退后,退到今日,退到了距离硬件最远、距离意图最近的位置——Vibe 体验正是站在这个位置上所看到的风景。
一个具体的事件足以说明两种视角的分裂。面对“把登录页改成深色模式”这样一句指令:座舱内的人只经历了一次说话与一次确认,全程十秒;而机房视角下,同一句指令触发的是一次完整的目标解析、设计 token 重构、样式回归测试的再生成、可访问性对比度校验与受控发布。同一个系统事件,在体验层被记作“一句话”,在治理层被记作“一次受控的闭环执行”。Vibe 与 Agentic 的争执,不过是这两份记录被人误读成了对两个不同系统的描述。
而 Agentic Coding 描述的是同一系统的另一副面孔。它不关心“用起来是什么感觉”,只关心“底下如何运转”:自主代理(Autonomous Agent)如何拆解任务、编排工具链(Tool Orchestration)、在权限边界(Permission Boundary)之内行动,以及支撑这一切的 Loop 与 Harness 基础设施。如果说 Vibe 是驾驶舱里的体感,Agentic 就是底盘里的工程。
用控制论的语言说:Vibe 是 phenomenology(现象体验),Agentic 是 governance(治理机制)。

两个词的对照可以更精确地展开为一张表:
| 维度 | Vibe 侧(体验视角) | Agentic 侧(治理视角) |
|---|---|---|
| 观察单元 | 一次交互回合(Prompt → 结果)的体感 | 一次完整闭环(Goal → Loop → 收敛)的治理结构 |
| 交互介质 | 自然语言、意图直给、低摩擦修改 | 结构化任务、工具调用、权限与契约 |
| 成功判据 | 意图完成度、表达顺畅度、“像对话一样写软件” | 收敛率、边界内自治度、可审计性、可回滚性 |
| 失败形态 | 幻觉累积、失控漂移、Vibe Slop(回指第三章) | 权限越界、债务失控、Loop 死循环空转 |
| 回答的问题 | “人机协作是什么感觉?” | “这个系统凭什么可信?” |
看清这张表,就能发现所谓“两种编程方式之争”是多么荒谬:拿 Vibe 的体验去反对 Agentic 的机制,等于拿“驾驶快感”去反对“底盘工程”——它们根本不在同一个问题上作答。
2. 矛盾的假象:没有 Harness 的 Vibe 是裸奔
那么,Vibe 与 Agentic 的对立感从何而来?它来自一个真实存在的现象:同样打着 Vibe 旗号的实践,工程后果天差地别。 而把这两种后果归因于“Vibe 本身”,则是哲学上典型的范畴错误(category mistake)——把本应属于不同抽象层的谓词,摆到同一根坐标轴上当作可比较、可取舍的两个端点。
Karpathy 描述的那种“忘记代码存在”的状态,是他个人在深厚工程直觉托底下的体验报告。而当这种交互形态被剥离全部治理结构、原样搬进严肃生产环境时,灾难几乎必然降临:LLM 的概率性输出不再被任何传感器约束,幻觉与熵在代码库中不受控地累积——这正是第三章命名的 Vibe Slop。于是舆论场出现了滑稽的错位:批评者举出的所有“Vibe Coding 失败案例”,其失败的根因都不在“凭感觉交互”这一层,而在于感觉之下空无一物。
没有 Harness 的 Vibe Coding 只是在技术债务的悬崖边裸奔;而拥有严密 Harness 的 Vibe Coding,才是软件工程向自适应控制迈进的终极形态。
从技术结构上看,这几乎是一个平凡的判断。闭环控制的成立前提是传感器先于执行器存在:没有测试与静态分析,就没有误差信号;没有误差信号,Loop 根本无法启动;Loop 无法启动,Agent 的每一次输出都是一次无反馈的开环射击。第四章的论断在此显示出全部重量——没有传感器,闭环就不成立。所谓“裸奔的 Vibe”,本质上是把第二章批判过的开环系统重新请回了王座,只是这一次,充当“人肉闭环”的人换成了对结果一无所察的监督者。
Demo 的轻盈与生产的沉重之间的落差,是最直观的证据。一个两分钟的演示视频里,创始人对着麦克风说出需求,屏幕上的代码自动生长,测试一片翠绿——这套体验完全真实,没有造假。但演示之所以轻盈,是因为它系统地隐去了所有让生产沉重的部件:精确的 Goal 定义、覆盖边界的 Harness、消化中间态失败的 Loop。演示与生产系统之间的差值,恰好等于 Goal + Harness + Loop 的总质量。 这不是 Vibe 体验的虚假宣传,而是观察者站错了位置得出的错觉——只看到了座舱,没看到底盘。
赛车运动把这个隐喻演绎到了极致。民用量产性能车上,防抱死系统(ABS)与牵引力控制(TCS)是刚性控制力的化身:ABS 以每秒十余次的频率点刹、防止车轮抱死,TCS 在驱动轮打滑的瞬间切断动力。驾驶者感受到的“这车听话、敢给油、过弯有信心”,恰恰是这些刚性系统在背后持续纠偏所涌现出的体感。更有意思的是,F1 为了保留“纯驾驶”的原教旨体验,干脆通过规则禁用了 ABS 与牵引力控制——但这并没有让 F1 变成裸奔:刚性的管辖权被移交到了别处。单体壳生存舱(Monocoque Survival Cell)、HALO 头部保护结构、由工程团队以毫米级公差锁死的悬挂几何与空动套件——车手在座舱里只管方向、刹车点与节奏,悬挂如何与路面耦合,他既不知道也不需要知道。
车手“感受到的自由”,从来不是无约束的自然状态,而是刚性系统精密守恒之后的涌现属性。 用控制论的语言说:负反馈的刚度并不消灭系统的自由度,而是把自由度从“全部可能构型”压缩到一条“安全且高性能的子流形”上——约束越刚性,可放心探索的动作空间反而越宽阔。
3. 融通:“Harness 越确定,Vibe 越自由”
于是,体验与机制的关系终于露出真容:它不是折中(trade-off),不是“既要又要”的和稀泥,而是乘积关系。

任何一个因子趋近于零,乘积就整体崩塌:Goal 含糊,系统朝错误方向高速收敛;Harness 缺失,收敛无从测量,Loop 沦为空转;Loop 不自转,中间态的失败全部砸回人类视野,体验立刻退化为“盯着 AI 改八遍括号”。Vibe 的上限,由 Harness 的刚度决定——这不是修辞,而是第二章控制论映射的严格推论:传感器的测量精度,决定了控制器能把系统推到多接近稳定边界的极限位置。
当然,刚度并非越大越好——这是对融通关系的最后一点澄清。控制系统里,阻尼过小,系统会在设定值附近震荡发散,对应工程上“无限返工、反复推翻重来”的体验灾难;阻尼过大,系统迟滞笨拙,对应流程官僚化、每处修改都要穿越层层审批的另一极灾难。Harness 的调校因此是一门手艺:刚在关键不变量上,松在允许探索的局部——真正高明的约束架,让 Agent 在该自由的地方一点不觉得被束缚,在该停下的地方一毫米也越不过去。
前面三章在此合龙。第三章给出精确的 Goal:SDD 规格把高维意图锚定下来,让系统知道“收敛到何处”;第四章搭起刚性的 Harness 与负向空间:它只定义“不能踩的红线”,用百分之百确定性的工具锁死百分之八十概率性的模型;第五章让 Loop 自转:误差信号在人类察觉之前被消化,中间态的失败被隔离在人类视野之外。三者齐备的时刻,一件历史性的事情发生了——人类第一次获得了“只管意图”的体验权利。 管方向的人不必再管轮子,这正是 Vibe Coding 真正值得捍卫的内核。
由此可以给出本章的判词:
自由并非毫无束缚,而是系统在严密守恒定律下的安全涌现。Harness 越确定,Vibe 越自由。
值得强调的是,这句判词翻转了传统软件工程对“约束”的整个情感结构。在过去,规范、测试、静态分析被体验为创造力的镣铐,是写代码这件正事之外的额外负担;而在控制论视角下,它们是自由的基础设施——正如乐手的自由来自制琴师锁死的弦距、品丝与琴颈钢筋,车手的自由来自工程师锁死的悬挂与空动。人从来不是因为摆脱约束而获得自由的;人是站在足够刚性的约束之上,才敢把身体的全部重量交出去。
至此,全文的逻辑链条闭合了:从纸带打孔到高阶语义编译器,从开环系统到自适应闭环,从 Prompt 漂移、负向空间、负熵消化一路走到这里——Goal、Loop、Harness 三者共同支撑起人类意图的最新居所。软件工程的重心从未离开人类之手,它只是从“编写”迁移到了“治理”。
但一个最后的问题随之浮现:能够把这套控制论系统当作创作乐器来演奏的人,需要一副怎样的能力结构?当“写代码”不再是主业,工程师究竟凭什么立身?这正是下一章——工程师的终极画像——要回答的问题。
第七章 结语:工程师的终极形态——“控制论架构师”
从纸带上的孔洞,到编译器,再到今天由 Goal、Loop 与 Harness 构成的自适应闭环,我们已经沿着软件工程的抽象阶梯完成了一次完整的巡礼。现在,那个从一开始就悬在背景里的问题必须被正面回答:当代码的生成被移交给一台概率机器,工程师还剩下什么?本章不发安慰剂,只做一次收束——因为答案早已写在前六章的每一条回路里。
1. 软件工程没有消亡,而是完成了维度收敛
每一次抽象层级的跃升,都会伴随一次“工程师已死”的讣告。高级语言诞生时,手写汇编的工匠预言行业的终结;编译器优化成熟、内存管理自动化时,又有人宣布软件不再是一门手艺。历史一次次证明:被消灭的从来不是工程师,而是工程师与机器之间那些不得不由人肉承担的“偶然复杂度”(Accidental Complexity)。
Brooks 在《没有银弹》中留下的二分法,至今仍是解剖 AI 编程最有力的手术刀。写代码——语法的背诵、样板代码的誊写、指针与内存的手工管理——从来只是软件工程中“偶然”的那一部分,是意图在通往硬件的路上被迫穿上的粗糙外衣。AI 消除的正是这部分偶然复杂度。而业务权衡中的取舍、架构演进中的张力、系统边界处的定义——“本质复杂度”(Essential Complexity)——从未因工具的换代而减少分毫。它不会消失,只会换形态:过去它隐藏在 if/else 的分支深处,如今它浮出代码的水面,凝结在 Goal 的措辞里、Harness 的红线里、Loop 的节奏里。
所以,第一章里 Linus 的反问应当在此刻得到完整的回答。抱怨“代码 99% 都是 AI 写的”,与抱怨“家具都是工具做的一样”犯了同一个范畴错误:锯子和刨子从未决定过一只柜子的品质,决定品质的是图纸与测量尺。图纸没有因为电锯的出现而变得无关紧要——恰恰相反,电锯越锋利,图纸上的每一笔越致命,因为错误也会以同样的速度被放大。AI 正是那台新换的锋利机床,而图纸与测量尺,第一次如此完全地回到了工程师的手中。
这就是“维度收敛”的确切含义。我们没有失去对代码的掌控,我们只是退后到了更宽广的视野:Code Review 的 diff 在工程师的责任版图里收缩成越来越小的一块,而契约的措辞、传感器的密度、回路的收敛速度扩张成新的疆域。工程师的工作从微观的“代码实现学”,升维为宏观的“系统治理学”。维度收敛不是能力的降格,而是控制面的扩张——瓦特调速器没有让工程师离开蒸汽机,它只是把工程师从飞轮旁边请回了反馈机构的设计桌前。
值得辨明的是,这场哀悼真正悼念的对象是什么。人们怀念的并非软件工程本身,而是开环时代工程师那种不可替代的体感:逐行敲定逻辑的掌控感、通宵调试的参与感。然而第二章已经指出,那种体感里掺着大量水分——在开环系统中,人类被迫充当反馈回路里最疲惫的电线:亲自阅读 Traceback、亲自计算误差、亲自下发修正。AI 接管的正是这根电线的工作。电线被更换,不等于房间里的设计者被解雇;恰恰相反,当系统第一次学会消化自己的痛楚,工程师才有余裕退回到真正的本职——那张从未有人代劳的图纸面前。
2. 未来顶尖工程师的三维画像
未来的顶级程序员不是手写语法最快的人,而是那些精通意图建模(Goal)、擅长刚性防御(Harness)并能精准引导系统收敛(Loop)的控制论架构师。
这三维不是三张孤立的标签,而是同一条控制回路上三个不可省略的环节:没有 Goal,回路失去方向;没有 Harness,回路失去测量;没有 Loop 的调校,回路失去速度。三者缺一,闭环即告解体。
把这三维放回第二章的控制论映射中,其对应关系一目了然:意图建模者守护设定值的刚性,边界防守者守护传感器的精度,收敛引导者守护回路的动力学。一套闭环系统的稳定性,从来不是由控制器——那个概率驱动的 Agent——单独决定的,而是由设定值、传感器与回路节奏三者的品质共同决定。Agent 本身正在迅速商品化,而这三个环节的专业纵深,恰恰是工程师不可让渡的领土。
精确的意图建模者(精通 Goal 与 SDD)。 他不再逐行推敲 if/else 的分支细节,而是专注于把模糊的业务语言炼成机器可读的契约:撰写与评审 OpenAPI 规范、JSON Schema、类型签名与验收标准(Acceptance Criteria);为一个字段的取值范围反复辩论,因为他知道一处含糊的措辞会在 Loop 中被放大成一千行偏离意图的代码;他清楚区分意图中刚性的部分(不可协商的约束)与可协商的部分(实现自由度),并把这种区分写进 Spec 的结构,而非写进会议纪要。设定值(Setpoint)的精度决定收敛的终点——第三章的判据,在此刻变成了一门手艺。
严密的边界防守者(精通 Harness 搭建)。 他不再靠人肉 Code Review 逐行盯防每一个 PR,而是把架构红线编译成可执行的断言:设计测试金字塔的分层与覆盖策略,让单元测试守住函数、契约测试守住接口、端到端测试守住用户旅程;用 ArchUnit 把“上层不得依赖下层”的架构纪律写成每次构建都会强制执行的规则;在 CI 流水线上设置闸门,让 Lint、静态分析与权限检查成为不可绕过的物理事实;用沙箱圈定 Agent 所能触碰的文件系统与网络边界。他深谙负向空间的逻辑:不教 AI 怎么写,只划定它不能踩的红线——红线之内,皆是自由。
高效的收敛引导者(精通 Loop 节奏)。 他不再逐条阅读 Agent 的中间产物,而是调校反馈回路本身的动力学:设计 Loop 的步长,决定一次迭代该验证一个函数还是一整条链路;拓宽或收窄反馈面,决定每一轮报错携带多少定位信息——太薄的报错让误差信号沦为噪声,太厚的日志又让上下文被淹没;他精通上下文工程,懂得什么信息该进入 Agent 的上下文窗口、什么必须被裁剪,因为上下文的质量就是控制信号的质量;他读得懂收敛曲线,能从偏差衰减的速度判断系统是在稳步逼近 Setpoint,还是陷入了在局部最优之间震荡的死循环。增益调校是他的手感:何时收紧约束让系统快速收敛,何时放宽边界让系统保有探索的余量。
| 开环时代的旧手艺 | 闭环时代的新形态 |
|---|---|
| 指针运算与括号配对 | 契约设计与不变量思维(OpenAPI / JSON Schema / 类型系统) |
| 人肉调试与逐行阅读 Traceback | 传感器网络设计:报错信号的可定位性、可观测性、测试分层 |
| 逐行实现与语法背诵 | 收敛曲线阅读与 Loop 节奏、上下文工程的调校 |
| Code Review 人肉盯防 | 架构红线编译为 ArchUnit 断言与 CI 闸门 |
| 写完即过期的需求文档 | 作为第一公民的 Spec:同时编译出代码与测试的高维基因 |
这张映射表里没有一行写着“学习 AI 工具”,原因很直白:为 AI 焦虑的工程师,其手艺往往被偶然复杂度整个占据;而完成升维的工程师会发现,自己多年来在需求澄清、测试设计与架构评审上的全部肌肉记忆,在闭环时代不是作废,而是第一次被放大成了系统的主控权。本质复杂度从来都是这份工作的本体——只是过去它被埋没在打字声里,如今它浮出了水面。
3. 终局:走进控制室
我们放下了打孔的纸带,离开了拥挤的代码执行车间;我们走进了那间只需设定航向、监控仪表盘并确保轨道安全的控制室。
这句话里的三个动作,恰好对应三维画像:设定航向,是意图建模者的工作;监控仪表盘,是收敛引导者的判读;确保轨道安全,是边界防守者的红线。而控制室不是休息室。仪表盘上的每一次报警仍然需要人来取舍:错报与漏报的权衡、收敛速度与探索空间的权衡、刚性约束与迭代速度的权衡——这些权衡没有一项能被外包给回路本身,因为它们正是本质复杂度的栖身之处。
同时,控制室里的安静重新定义了“失败”的语义。第五章已经阐明:在闭环哲学中,Bug 不是故障,而是系统逼近目标时释放的负熵能量;编译报错与测试失败在 Loop 内部被消化,OODA 在 Agent 体内自主完成,人类无需干预中途的每一次跌倒。这意味着控制室监控的从来不是“有没有报错”——报错恰恰是系统在工作的证据——而是偏差是否随时间单调衰减。工程师的目光从“消灭红色”转向“判读曲线”,这是五章的 Bug 哲学在终局处的职业投影。
控制室里的从容也从来不是免费的。第六章的赛车已经说明:极速驾驶的爽快(Vibe),建立在极其刚性的防抱死底盘与牵引力控制系统(Harness)之上;控制室里的镇定亦然——仪表盘之所以值得信任,是因为每一条传感器都经过人工标定;轨道之所以安全,是因为每一条红线都经过人工辩论。负熵不会凭空流入系统:报错仍会被制造、被消费、被消化,而决定熵从哪条通道排出系统的人,依旧是工程师。控制论的每一代实践者都明白同一个道理:自动化的终点从不是人的退场,而是人的判断被安置在唯一不可替代的位置上。
于是,全文可以在它开始的地方收束。Linus 的反问曾把 AI 从神龛上请回工具架;而现在,我们可以替他补上后半句:我们的代码从来都是由别的东西“写”出来的——先是由纸带上的孔洞,后来由编译器,今天由一台基于概率的语义编译器。变化的是翻译意图的机器,不变的是图纸与测量尺。纸带上的孔洞曾是我们与机器之间唯一的语言,那时的编程是人类思维被迫进行的降维;如今我们不再打孔,但从未停止表达意图——只是这一次,表达意图与守护意图之间的距离,终于近到了可以闭环的程度。这篇文章从纸带开始,以控制室作结,而它自身的结构,也完成了它所论述的那件事:一次干净的闭环收敛。
