和系统共舞:当 AI agent 走进软件这架活机器
副标题:Donella Meadows 风格——把 Harness Engineering 还给系统思考
一、先把一件事说清楚
我想先把一个边界讲清楚。Birgitta Böckeler 在 Martin Fowler 的网站上发表了一篇叫《Harness engineering for coding agent users》的文章。署名是 Böckeler,不是 Fowler 本人。她属于 Thoughtworks,那是 Fowler 待了一辈子的地方。所以我下面说”Fowler / Thoughtworks 这一脉”,其实是在说一种思想生态,而不是一个单独的人。
我喜欢这种边界。系统不是一个人。系统是一群人长期一起做事而留下来的痕迹——这恰好是接下来我想说的事的前提。
二、一只池塘和一座代码库
我家旁边有一片池塘。它看上去很安静,但里面发生着很多事情:水从溪流进来,又从溢流口出去;藻类生长,鱼吃藻类,鸟吃鱼;阳光、温度、降雨改变着所有这些速度。如果你只在某一个早上去看它,你会看见一只鸭子。如果你看一整年,你会看见一个系统。
代码库也是这样。你打开一个 commit,看见的是某个开发者今早改的几行代码。你打开过去十年的 git history,看见的是一个不断生长、衰老、被翻修、被遗忘、又被重新发现的活体系统。
我做了一辈子系统思考。当 AI coding agent 突然走进这片池塘,我并不觉得那是一个全新的时代到来,也不觉得软件工程被改写了。我觉得,池塘的水流变快了。而池塘原本就需要的那些东西——岸、深度、植物、循环——只是变得更不能被忽略而已。
Böckeler 文章里那个英文词”harness”,在我看来不是新词。它就是池塘的岸。是给水以形状的东西。
三、停下来,先看清楚系统由什么组成
每次有人激动地告诉我”我们要用 AI 改变软件开发”,我都会请他先停一停,回答三个最朴素的问题。
第一,**这架机器里有哪些存量(stocks)?**就是那些在某一刻可以被数清楚的东西。代码行数、模块数、依赖项、未解决的 bug、没写完的测试、没还清的技术债、团队成员的脑容量、文档的可信度——这些都是存量。
第二,**这些存量靠哪些流量(flows)流入流出?**新代码的提交、bug 的产生与修复、依赖的引入与下线、人员的来去、知识的吸收与遗忘、生产事故的发生与结束。每一个存量都被一两条进流和一两条出流维持着。
第三,**这些流量被哪些反馈环(loops)调节着?**比如,代码越多,理解越难,理解越难,bug 越多,bug 越多,又使新代码越难写——这是一个增强环(reinforcing loop),它会自己加速自己。又比如,bug 越多,团队越紧张,越紧张越要写测试,测试越多,bug 越快被发现,发现越快越容易被修,bug 少了团队又放松——这是一个调节环(balancing loop),它会自己稳定自己。
软件工程里那些被反复提倡的东西——持续集成、测试、重构、技术债治理、演进式架构——在我看来都不是”工程师的美德”。它们是某些循环里的关键节点。它们存在,是因为没有它们,循环会失衡。
AI agent 是什么?它是一个新的”流量增强器”。它不是新存量,也不是新循环。它只是把”代码生成”这一条流的阀门拧大了。
四、当一条流被拧大时会发生什么
让我说一个最简单的系统直觉:如果你只放大一条流,而其他流和环没有跟上,结果一定不是更好,而是振荡甚至崩溃。
这不是一个比喻。这是任何”装满—排空”系统的基础规律。一个浴缸,进水快了,排水没跟上,就会溢出。一片渔场,捕捞快了,繁殖没跟上,就会枯竭。一座城市,建房快了,下水道没跟上,就会内涝。
软件也一样。如果你只让”写代码的速度”提速十倍,而你的测试反馈速度、架构治理速度、依赖审计速度、部署回滚速度、生产监控反馈速度、人类理解速度都没跟上,你不会得到一支高产的团队。你会得到一个比以前更快地把系统推向不可维护状态的团队。
这就是为什么 Thoughtworks 那批人,在 Technology Radar 里反复说”要把 coding agent 拴上绳子”、”回到基础工程实践”。他们不是在说”保守”或”反 AI”。他们在描述一条系统规律:调节器的能力必须匹配被调节系统的复杂度。
控制论里有一条 Ashby 法则——只要你的控制器太弱,被控对象再聪明,也只是更聪明地失控。
五、harness 到底是什么:一组共同呼吸的反馈环
Böckeler 把 harness 解释为”agent 周围的工程环境”,包含上下文、规范、检查、工具、测试、信号。她还借用了控制论里”governor”(调速器)这个词,说 harness 是把代码库调向期望状态的调速器。
我想再走远一点。
一个真正有效的 harness,不是单一调速器,是一组同时呼吸的反馈环。它至少有这样几个圈:
一个圈是类型与编译反馈:你写错了一个名字,几秒之内你就知道。
一个圈是单元测试反馈:你改坏了一个分支,几秒到几十秒之内你就知道。
一个圈是集成与部署反馈:你破坏了某个组件之间的契约,几分钟到几十分钟之内 CI 告诉你。
一个圈是生产与用户反馈:你做的某个改动让真实用户更慢、更困惑、更不愿付费,几小时到几天之内监控、SLO、留存率告诉你。
一个圈是架构与债务反馈:依赖在过期、模块在膨胀、变更热点在某一处堆积、代码审查负担在上升——这是一个比较慢的圈,几周到几个月才显现。
还有一个圈,是组织学习反馈:某类失败反复出现,某条规则总是被绕过,某个团队总是在赶夜路——这是最慢的圈,几个月到几年。
这些圈各自有各自的延迟。延迟不一样,意味着它们调节的内容也不一样。你不能让架构治理用类型检查的速度去做,也不能让用户反馈替代单元测试。任何想把所有反馈压扁到同一种速度的人,都会被时间惩罚。
AI 时代真正的工程能力,不是写出新的反馈环,而是确保所有这些圈都是活的,都在转,都被人看到。
六、延迟这件事,会要命
我多次见过同一种系统失败。当反馈延迟过长,做决定的人就会过度反应。他们看到一个糟糕信号,加大干预;干预要好几周才显形,于是中间他们继续加大;等干预真的发挥作用时,已经过头了;他们又过度反向干预——系统就此进入振荡。
软件团队也一样。如果一次架构问题要半年才显现成”项目延期”,那时再追究,已经无人记得是哪一笔决定造成的;如果一种 agent 的偏差要等到上线才被发现,那这种偏差会被反复犯下数百次而无人纠正。
减少反馈延迟,不是工具的奢侈品,是系统能否被驾驭的前提。
Fowler 强调”十分钟构建”那种偏执,不是程序员的洁癖。那是系统思考者的本能:让信号比动作快,让动作比破坏小。否则你只是在系统失控之后做事后诸葛亮。
AI 把动作的速度急剧提升。它一次提交可以改三十个文件、写六十个新测试、引三个新依赖、动两条接口契约。如果你的反馈链条还停留在”明天 review、下周 release、下个月发现 bug”的节奏,agent 就是一台被装到拖拉机上的喷气发动机——动力越大,离地越快。
七、harnessability:有些池塘,本来就更容易拦水
Böckeler 在文章里提了一个词,叫 harnessability——有些代码库更容易被 harness 化,有些则不然。她的判断标准里有:是否有类型系统、是否有清晰的模块边界、是否使用带约束的框架、是否有可执行的结构。她还引用了 Ashby Law:要让调节器有效,被调节系统的变化空间必须可控。
这个判断我觉得非常正确,而且其实是 Fowler / Thoughtworks 一直以来工作的合理化解释。他们做的所有事——重构、领域驱动设计、契约测试、演进式架构、fitness function、CI、技术债治理——都是在让代码库更易于被驾驭。
这不是审美。这不是工程师的洁癖。这是一种系统改造:把系统的可能行为空间,收窄到调节器够得着的范围。
所以现实结论是这样:不是所有团队都能同等受益于 AI coding agent。拥有清晰边界、好测试、好 CI、好监控、好文档、有平台模板、能管技术债的团队,能更安全地放大 agent。缺乏这些基础的团队,AI 给他们的不是生产力,是混乱的加速度。
如果你今天问我”我应该怎么开始用 agent 写代码”,我大概率会反问你:”在你引入 agent 之前的那个池塘,岸长得清楚吗?”
八、十二级杠杆点:用在软件上
我自己写过一篇《Leverage Points: Places to Intervene in a System》,把干预系统的杠杆点分成十二级,从弱到强:参数、缓冲、存量结构、延迟、调节环、增强环、信息流、规则、自组织、目标、范式、超越范式。
很多年里,工程师们都喜欢在最弱的一两级动手——他们调参数。Sprint 速度、velocity、PR 数、上线频率、test coverage 百分比。这些都是最低杠杆的干预,值得做但远远不是最有力的。
我用我自己的杠杆点框架,把”AI 时代的软件工程”重新摆一摆。
最低层是参数。AI 让所有参数都可以被推得更极端:每天写多少代码、合多少 PR、跑多少个 agent。但你已经看出来了,参数被拉到极端,不会让系统更稳,往往让它更不稳。
往上是缓冲。预算、回滚窗口、异常容量、release calendar。AI 之后,缓冲变得更重要,因为变化更剧烈。
再往上是存量与流量结构。代码库本身的结构、模块边界、依赖图。这是 Fowler 长期工作的层级——他用重构改结构。
再往上是延迟。前面说过了。CI、构建、测试、生产监控的延迟,决定了一切干预的效率。
再往上是调节反馈环。测试、lint、type check、fitness function、code review、SLO 告警——它们都是调节环。AI 时代我们要新建一些(比如对 agent 的 mutation testing),更要保护那些已有但被忽略的(比如真正的人类 code review)。
再往上是增强反馈环。比如知识资产:每次失败被沉淀成文档、规则、模板、AGENTS.md、参考实现,下一次同类任务就更不容易出错——这是一个善意的增强环。也有恶意的增强环:每次为了赶进度跳过测试,下一次跳过测试更容易被允许。好的工程组织主动培育善意的增强环,并设置调节环来抑制恶意的增强环。
再往上是信息流的结构。谁能看到什么。谁知道某个模块出了问题?谁知道某个 agent 一直在偷偷绕过某条规则?谁知道某种 review comment 已经重复出现一百遍?把对的信息送给对的人,是高杠杆干预。Fowler 说过”构建状态要可见”。其实他是在说信息流。
再往上是系统规则。代码规范、合规要求、平台契约、AGENTS.md、合并策略、回滚策略。规则比参数有力得多,因为规则改变所有参数被解读的方式。
再往上是自组织能力。一个团队能不能自己识别问题、调整规则、发明新的反馈环。能自组织的团队,比被治理的团队稳得多。AI 时代尤其如此——你不可能用中央审批跑赢 agent 的速度。
再往上是目标。系统真正在追求什么?吞吐?速度?股价?最少事故?长期客户价值?最不疲惫的工程师?目标变了,所有参数、规则、循环的解读都变了。”用 AI 增加产出”和”用 AI 让团队不那么累”是两个完全不同的系统,长成的样子也完全不同。
最高层是范式。我们怎么理解”软件工程师的工作”。如果我们的范式还是”工程师就是把需求翻译成代码的人”,那么 AI 看上去就在替代我们;如果我们的范式是”工程师是把意图变成可演化系统的人”,那 AI 只是一个新的执行层。范式决定了我们怎么看见一切。
我之所以把这十二级排出来,是因为:99% 的关于 AI 写代码的争吵,都发生在最低两层。而真正决定系统命运的,是上面那几层。一个团队如果只在调”agent 一天写多少代码”这种参数,他们其实没在做工程治理。他们在做仪表盘。
九、目标层:你到底在调向哪里?
我要在”目标”这一层多停一会儿。因为它是最容易被忽略的高杠杆。
我见过很多组织,被 AI 一冲,目标就悄悄换了。原本他们的目标是:做一个被用户喜欢的产品;让团队成员能多年待在这里;不要在凌晨被告警吵醒;让代码库十年后仍然能被新人读懂。AI 来了之后,他们的目标变成了:增加 PR 数;缩短开发周期;在董事会的胶片上展示”AI 节省了多少工时”。
新的目标当然不是”错”的,但它和老的目标不一样。当一个系统目标偷偷被替换掉,它的整个反馈结构会被重新对齐。从此以后,组织里的每一个 incentive、每一次 review、每一份周报、每一个 OKR,都在为新目标服务。结果是:表面指标好看,但用户在流失,工程师在疲劳,技术债在膨胀,事故在翻倍。
这就是为什么我对 Thoughtworks Radar 那一段话特别认同。他们说,单纯的 coding throughput 指标会拉来大量低质量、低对齐代码;他们建议把 first-pass acceptance、iteration cycles、post-merge rework、failed builds、review burden 和 DORA 一起看。
但请注意,指标的选择本身就是目标的选择。换指标,是在动杠杆点第三级。这比动参数管用得多。
如果你现在正在为团队挑 AI 时代的指标,不要先想”哪个最容易测量”。先想”我们到底想长成什么样的系统”。
十、范式层:从”写代码的人”到”调系统的人”
再往上一级,是范式。
我相信,软件这个行业正在经历一次范式转换。不是”工程师消失”那种廉价末日叙事,而是更细的:工程师工作的杠杆点位,从存量层在向规则层、目标层、范式层迁移。
过去,工程师 80% 的时间在写代码。代码是存量。修代码是流量。我们大量精力花在第十层(存量结构)和第十二层(参数)上。
现在,AI 在很大程度上能动那一层。这不是说工程师没事干了。而是说:那些过去因为没人有时间做、所以一直被搁置的高杠杆工作,现在变成了我们的主业。
写出”agent 怎么和这套代码共处”的指南——这是规则层。
设计 fitness function、保护架构边界——这是规则层。
决定团队真正在追求什么、如何度量——这是目标层。
理解”软件不是被生产出来的,是长出来的”——这是范式层。
知道一个 review comment 重复出现意味着系统在告诉你某事——这是信息流层。
看到一个团队反复在某种事情上摔跤、不去骂人而去改环境——这是杠杆点的修养。
Böckeler 用了一个表述我特别喜欢:human in the loop 在变成 human on the loop。在圈外,监督圈本身。这不是退场,是升维。
十一、和系统共舞的几条手势
我曾经写过《Dancing With Systems》——一篇短文,写给那些不再相信”控制系统”的人。它的中心意思是:复杂系统不能被控制,只能被引导;不能被一次性解决,只能被持续调谐。
我把那几条建议翻译到”AI 时代的软件工程师”。
第一,先聆听,再行动。在你给 agent 加新规则、新指标、新流水线之前,先看你们的系统在自己说什么。事故复盘里反复出现的同一个根因。code review 里被反复指出的同一类问题。指标曲线里那个不大对的拐点。系统会先说话。听不见,是因为我们说得太多。
第二,把心智模型暴露在阳光下。你以为 AI agent 是”另一个工程师”。你的同事以为它是”一台代码机器”。你的产品经理以为它是”加速器”。你的财务以为它是”省人力”的方式。这些心智模型都不一样,而它们的不一样比代码 bug 更难发现。把模型摆出来,让它们互相照面。
第三,尊重直觉,但不让它独裁。资深工程师的直觉是宝贵的——他们能闻到代码味道,能看出架构走偏。但直觉容易被自尊污染。要让数据陪伴直觉,让直觉接受数据的反驳。
第四,对反馈保持谦卑。你可能为了让 agent 顺利工作,关掉了一些”挡路”的检查;你可能为了让指标好看,定义了一种宽松的 first-pass acceptance;你可能为了避免冲突,给某个团队网开一面。系统会把这些都记住,并在某个早晨把账单递给你。看到账单时,请别怪系统。
第五,扩大你的时间视野。AI 让”今天”无比兴奋。请去想三年。三年之后,谁还在维护今天写的代码?谁还在解释这一段是谁定的规则?三年之后,团队成员变了几轮,他们读到的代码库会是什么样?任何不能在三年时间尺度上回答的工程决定,都值得再问一次。
第六,庆祝复杂性。别再想”我要用 AI 把软件开发简化”。那是一个反系统的愿望。复杂性不会消失,它只会换地方。你简化代码,复杂性跑到提示词里;你简化提示词,复杂性跑到工具链里;你简化工具链,复杂性跑到组织流程里。好的设计不是消灭复杂性,是把它放在最容易管理的地方。
第七,把善意当成一种工程价值。这听上去好像和工程无关。但它是。系统不是抽象的。它由人组成。一个让工程师焦虑、让运营骂街、让用户失望的系统,再”先进”,也是失败的系统。AI 是一面放大镜——你善意做事,它把善意放大;你不善意做事,它也会把不善意放大。
十二、harness 也会失效
我必须在结束之前说一件不那么乐观的事。
Böckeler 自己在文章里也写了:你怎么知道你的 harness 是否真的有效?传感器没触发,是因为系统健康,还是因为传感器没覆盖到风险?这是一个开放问题。
我做了一辈子系统,可以告诉你:调节器自己也是系统的一部分,它也会衰老、生锈、漂移、被滥用、被绕过。测试可以变成走过场。lint 可以变成噪声而被关掉。架构规则可以变成过时教条。AI 评审可以看上去聪明却漏掉关键。指标可以驱动错误行为。AGENTS.md 可以越写越长直到没人看。
成熟的 harness engineering,必须包含一个”对 harness 自身的反馈环”。我们叫它 mutation testing 也好,叫事故复盘也好,叫架构审议也好,叫定期把所有 lint 规则拿出来 review 一次也好。它的本质是:让调节器接受被调节者的反馈。
没有这个环,再精致的 harness 都会变成一座装饰。
十三、一句结语,给从 Fowler 到 agent 的这条线
我想用一句话结束这篇文章。
软件工程过去几十年的所有重要工作——持续集成、测试金字塔、重构、技术债理论、演进式架构、Technology Radar——本质上都是在做一件事:让一个由人和代码组成的活系统,变得能被驾驭。
AI coding agent 没有改变这个事业。它放大了它。
如果你听见某个人说”AI 来了,软件工程的旧规则都过时了”,请不要紧张。系统会很快把账单递到他面前。如果你听见另一个人说”AI 改不了什么,按老一套就好”,也请保持警觉,因为流量已经被拧大了,岸的形状必须重新画。
真正属于 AI 时代的工程师,是那些既不被新工具迷住、也不被老经验封住,愿意一天又一天,谦卑地、耐心地,和系统一起共舞的人。
岸是用来引导水的,不是用来禁锢水的。