EDITOR’S SELECTION

为什么软件工厂会失败

Dex Horthy 分析无人值守的 AI 软件工厂为何会持续损害代码库的可维护性、现有基准为何无法衡量设计质量,以及人工评审为什么仍不可替代。

图片

原文:Why Software Factories Fail — Dex Horthy

或者说:光有 harness 还不够

更新:这篇文章的演讲版已经上线 YouTube:https://www.youtube.com/watch?v=Ib5GBkD555M

这是系列文章的第一部分。第二部分在这里:https://x.com/dexhorthy/status/2081058573556306030

看来我们现在都在搞循环了

所有人都在争先恐后地把 AI 编码投入生产。关于循环工程(loop engineering)已经有过很多讨论,而主流观点似乎是:我们大概应该写更多循环。

图片

StrongDM 介绍过他们的无人值守软件工厂:没有人读代码,也没有人写代码。

这套叙事大致是这样的:

  1. 你才是瓶颈。
  2. 模型已经足够好了。
  3. 代码是免费的。
  4. 只管发布更多东西。

OpenAI 的 Ryan Lopopolo 在二月写过这件事,并在四月做了一场演讲,介绍 OpenAI 的软件工厂 Symphony。

这些人都非常聪明,我也十分尊敬他们。但如果用最愤世嫉俗的方式来解读,这不过是又一个把更多风险投资砸进“垃圾内容大炮”的借口。

呃……进展还算“顺利”

我们的朋友 Mario 在 AI Engineer Europe 上台,恳求大家慢一点——因为一些本不该因编码 Agent 操作失误而宕机的公司,确实正在因为编码 Agent 的失误而宕机

正如 Matt Pocock 所说,代码库正在以前所未有的速度分崩离析

我一直没能找到 StrongDM 那座“黑灯工厂”后来究竟运行得怎么样的确切数据或结论。他们的 weather report 在今年二月至六月之间只有几次零散更新。编辑补充——7 月 23 日,团队成员在 Hacker News 上参与了一些讨论,听起来我们或许很快就能看到一份更正式的更新。

Faros AI 的团队 发布了一份报告:自从我们2在一、二月份开始使用这些 AI 编码工具后,Pull Request 的评审质量显著下降。

  • 评论更多了、评论更长了,而且大量 PR 在完全没有评审的情况下就被合并。
  • 事故大幅增加。
  • 每位开发者产生的缺陷数量大幅增加。

图片

这份报告更像是一个相关性信号,而不是可以验证的确凿证据(是的,我是故意选这个词的,别让我开始吐槽 Claude 式文风)。而且这篇文章的重点本来就是要警惕垃圾数据,但就我所看到的情况而言,它在方向上是可信的。

“是你拿错了方式”(其实不是)

很多人会告诉你,这是一个技能问题——如果你得不到好结果,那是你自己的错。

但无论你选择怎样……呃……“拿着它”,我都敢保证,总会有人告诉你:如果把 token 拉满还没有用,那就是你的技能有问题。你只需要花更多 token,别再读代码。假如你刚开始走这条路,我保证这就是过程的一部分。去年夏天我也这么想

不幸的是,为了打击我的自尊,我以前讲过一些关于“怎样拿得更好”的蠢话,后来被录了下来,如今在 YouTube 上累计大约有一百万次观看。我不是在炫耀;我说这些,只是为了说明:我已经深入研究如何更好地使用编码 Agent 很长时间了,而且确实发现了一些被很多人认为真正有用的方法。

总之,我们被迫听了这么久“只要更用力地烧 token”之类的网络鼓噪,它所承诺的结果可以简洁地概括为:只要做足 harness 工程,我们就能两全其美:

  • 速度提高 10 到 100 倍;
  • 质量依然很高;
  • 再也没人需要做那件所有人都讨厌的事——代码评审。

我们只需配置更多 Linter,再给足够多的 PR 评审机器人撒上一些“对抗性评审”之类的魔法词语,软件就会开心地自我构建,而且永远不会出事故。

这不是技能问题

我想尝试说服你:无论做多少 harness 工程,或者把循环堆到多么极端,都解决不了一个本质上属于模型训练的问题。

为了真正理解它,我不得不研究编码模型究竟是如何训练和评估的——既包括 RLVR,也包括各种基准测试。

这篇文章会依次讨论:

  1. 软件工厂的历史可以追溯到 1968 年;它后来如何演变,AI 又怎样改变了它;
  2. 为什么模型可以在轻松拿下基准测试(甚至全新的“前沿”基准)的同时,生成堆积如山的垃圾代码;
  3. 尽管如此,你仍然可以快速前进,而不用点燃自己的代码库。

我会尽量穿过每天都会冒出来的新 Skills 插件炒作,以及那场 AI 精神错乱式的“token 拉满”建议瘟疫,用一般性的语言讨论真正有效的方法类型,而不引用任何特定 Skill 或框架。

**视频版本:**本文基于我在 AI Engineer World’s Fair 2026 的主题演讲,并在其基础上做了扩展。

感谢 @addyosmani@CyrusNewDay@HamelHusain@zeeg@dillon_mulroy@nayshins@jeffreyhuber 对本文提出的反馈。

题外话:这和 vibe coding 无关

Addy Osmani 理清了一个值得特别指出的问题:

一个开发者用 vibe coding 做一个可能只有十几个人会运行的业余项目,和一个团队为了再撑一个季度而维护一套十年历史的企业系统,两者几乎没有任何值得一提的共同约束;而流传中的大多数建议,其实只是其中一类人在告诉另一类人该怎样生活。

如果你喜欢 vibe coding,请继续尽情 vibe。我自己仍会用 vibe coding 做很多东西,只不过我也维护着大量生产软件(并通过 HumanLayer 帮助另外数千名工程师做同样的事),所以接下来的内容面向的是那些在复杂代码库中解决困难问题的人。

我经常听人用 **brownfield(棕地项目)**来描述这种差异。过去它通常指某个有十年历史的 Java 项目,但按照我们现在的发布速度,一个由 Agent 构建的代码库可能只要 三到六个月就会开始举步维艰——你会逐渐慢下来,而增加新功能的方式也必须随之改变。

软件工厂简史

我的整个职业生涯都在构建和研究软件工厂,但直到最近我才知道:“软件工厂”这个词最早可以追溯到 1968 年的一次 NATO 会议——也正是那次会议带来了“软件工程”这个说法。

此后我唯一觉得格外有趣的事情,是美国国防部曾写过一份 31 页的 PDF,大意似乎是国防部需要开始更好地使用 Jenkins

2022 年的软件工厂

让我们把“软件工厂”的定义固定在 2022 年,也就是 AI 大规模进入开发流程之前。在一个典型的软件工厂中:

  • 人决定构建什么——工程师、产品经理和管理层共同推动愿景;
  • 需求进入跟踪系统——Linear、Jira 或其他工具:它们是描述工作下一步状态的状态机;
  • 有人领取工单并完成开发——过程中可能会做一些手动或自动测试;
  • 提交 Pull Request——自动检查、人工代码评审,也许还会有人拉到本地测试;
  • 发现问题?返回“有人完成开发”这一步继续循环
  • 发布到生产环境——产品开始真正接触用户;
  • 增加监控——整个行业都在研究怎样在系统出故障时,于凌晨三点呼叫一名工程师;
  • 用户抱怨——提出需求、发现缺陷、提交功能请求,然后团队再把它们放回跟踪系统。

就这样不断循环。我们甚至还没谈到 AI,图中就已经存在好几个循环了。

把共识前置

几十年前,团队就意识到一件事:开发需要几小时甚至几天,评审也同样如此。

图片

因此,我们把工作前置——规划、架构提案、Sprint 计划——让团队共同参与。这意味着:

  • 减少返工,因为在任何人写代码前,大家已经达成共识;
  • 减少逐行评审所需的时间。如果你读过一个很长但完成得很好的 PR,就知道当它已经接近完美时,评审可以有多快。

图片

后面我们还会回到这一点。现在先看看把 Agent 式编程带进流程后会发生什么。

Agent 式软件工厂

现在,几乎每家公司——

都花了今年的大部分时间解释他们怎样构建了一座 Agent 工厂,能够产出大约 75% 的代码

Agent 式工厂基本上就是把 “有人完成开发”替换成“Agent 完成开发”——里面当然还有编排、harness、沙箱、模型、计算机操作等东西。关于这些细节我不会深入,因为坦白说,我已经读腻了,而且我相信你也一样。

图片

当 Agent 负责开发时:

  • 构建时间从几小时或几天降到几分钟或几小时;
  • 评审仍然需要几小时或几天。人类仍需阅读代码并测试改动,因此评审现在成了瓶颈。

图片

于是,你也加速评审:

  • 用 Agent 进行代码评审,检查风格、缺陷和安全问题;
  • 用 Agent 做回归测试,通过浏览器、计算机操作等方式从外部测试产品,也许完成后还会发给你一段可爱的小视频。

图片

评审现在变快了,但它很可能依然是瓶颈。不过,我们可以增加更多循环。

下一步,你可能会把事故直接接入工厂。工程师不再于凌晨三点被叫醒;早晨醒来时,面前可能已经有一个修复问题的 PR。

图片

我们还可以把用户反馈接入工厂。用户提出需求,然后系统自动把它构建出来。

图片

到这里,工作就只剩两个问题:你能往队列里塞多少东西,以及你能以多快的速度评审和测试产出?

图片

这就把我们带到了无人值守的软件工厂。

无人值守的软件工厂

Dan Shapiro 创造了这个说法Simon Willison 则介绍过 StrongDM 对它的实现——在这座工厂里,我们不再阅读代码。

你看着自己那座美丽的软件工厂,发现它被那个烦人的代码评审步骤毁掉了,于是你说:让人类阅读每一次改动?算了吧。

图片

所以你去掉了它,把精力投到其他地方:

  • 投资测试,让 Agent 测试自己的工作;
  • 投资沙箱和编排;
  • 投资自动评审;
  • 投资监控;
  • 投资发布流程;
  • 投资收集用户反馈信号。

图片

现在,工作真的只剩一个问题:我们能让 Agent 构建多少东西?我们想把多大的一片海烧开

这一切一定会很顺利(并不会)

图片

我要提出一个可能有争议的观点:无人值守的软件工厂行不通。

下面来谈谈软件工厂为什么会失败。

我们试过了

2025 年 7 月,我们彻底进入无人值守模式:只读规格和工单,让后台 Agent 处理所有小型和中型任务,整套流程全部自动运行。

如果你真的这样做过几个月,就已经知道它会怎样收场。你终究会遇到至少一个棘手到 Agent 无法解决的问题——即使你已经使用了最先进的提示词和工作流。

  • 你会做深入、理解上下文的研究,把所有正确的信息汇集到模型最擅长处理的区域;
  • 你会让 Agent 用十种不同方式尝试复现问题。

最终,你还是得咬牙钻进那个已经三个月没认真读过的代码库,试图搞清楚究竟哪里坏了。

与此同时:

  • 你的网站宕机了;
  • 用户非常愤怒;
  • 如果你和我差不多,你自己也痛苦不堪——不得不阅读那些被你放进系统的垃圾代码。

第一次发生这种事时,我把它甩在了脑后。尽管我刚刚花了差不多两周,在 Claude 制造的意大利面式代码里艰难穿行,我仍然觉得“速度带来的收益值得承担下行风险”。到了十一月,大约第三次发生时,我们决定从头重写可能更容易;我的联合创始人整整花了两个星期待在 VS Code 里(甚至不是 Cursor),亲手把所有模式重新搭了一遍。

模型会随着时间推移降低代码库质量

我真正想说的是:模型存在一个缺陷。没有相当程度的人类引导,它们无法随着时间推移维持并改善代码库质量。4

我所说的可维护性,指的是这样一种具体情况:修改代码库的一部分而不破坏另一部分,会变得越来越困难。这就是 Martin Fowler 所说的“霰弹式修改”(shotgun surgery)

关于可维护性我不打算再展开。已经有很多书可以读:

那么,为什么模型做不好软件可维护性?

“但模型从那以后肯定变强了吧”

读到这里,你可能已经迫不及待地想说:Dex,模型从去年七月以后肯定已经强了很多吧?

确实如此——某些方面强了很多,另一些方面则差不多。

  • 解决一次性问题,或者用 vibe coding 做一个新的营销网站?是的,强多了。
  • 随时间推移改善代码库质量?在我看来,没有好多少。

图片

我无法证明这一点,你也无法证明。我们没有任何优秀的基准,可以衡量模型维持代码库质量的能力。(稍后会谈到这个方向正在发生什么。)

没有优秀的基准,可以衡量模型维持代码库质量的能力。

但如果你已经和编码 Agent 共事了一段时间——而且很多人正在公开谈论同样的问题——你大概已经有这种感觉:随着时间推移,它们往往会让事情变得更糟,让代码库越来越难以维护。

为了理解为什么会这样,我想把视角拉远一点,看看第一个真正伟大的编码 Agent。

Claude Code 赢在 harness 内的强化学习

Claude Code 在不到一年里,收入从零增长到约 40 亿美元——现在似乎已经接近 90 亿美元。

图片

这有点不可思议,因为当时已经存在很优秀的命令行 Agent。aiderclinecodebuff 都早于 Claude Code 出现,都有真正优秀的上下文工程,也拥有你可能归功于 Claude Code 的同一组工具:读取、写入、编辑、搜索、Bash。我都用过,它们很好。但工具调用有时就是会……失败——你会眼看着它连续三次在同一个编辑操作上挣扎,最后只好重新打开编辑器,自己完成。

2024 年的 SWE-Agent 论文 说明了:工具形态上的微小变化会产生明显差异。例如,在 ReadFile 的结果中加入行号,或者把 Edit 工具从查找/替换改成按行范围编辑。

图片

随后 Claude Code 上线,并迅速垂直增长。你可以把它简单归因于分发能力,但广泛接受的解释是:Claude Code 获胜是因为它更好;而它之所以更好,是因为 Anthropic 在 harness 内部对模型做了强化学习——这是第一次有实验室针对自己即将发布的那套确切工具来训练模型。于是,它变得极其擅长在 Agent 循环中调用这些工具。

不断调整工具定义和评估,直到找到模型最喜欢的形态,是一回事——我曾为不同场景在这上面耗费数周。拥有模型权重,并且可以修改模型本身,让它更善于使用一组特定工具,则完全是另一种游戏。

OpenAI 团队在十一月的一场演讲中把这一点讲得很清楚:如果你构建了 harness,却不拥有模型权重,也无法在其中对模型做强化学习,那么和同时拥有两者的团队相比,你永远处于劣势。

60 秒理解编码 Agent 的强化学习

为了弄懂这个主题,我做了很多研究,也制作了不少可视化来解释其中重要的部分。但后来我发现,Calvin French-Owen(Codex 团队 MTS、Segment 创始人)在 AI Council 的演讲中讲得更好、更清楚,所以我直接放上这段受他幻灯片启发的动画:

为了让模型更擅长编码,你会:

  1. 生成一些用于解决问题的编码 Agent 轨迹(例如“修好我的测试”);
  2. 根据某些标准对这些轨迹评分(验证器);
  3. 更新模型权重,让好的轨迹更有可能出现,让坏的轨迹更少出现。

然后在数周或数月里,把这个过程重复数百万次。

但这类系统中的“评分”部分,往往异想天开地只有一个维度。

糟糕设计不会受到惩罚

SWE-bench Multilingual 为例。它的任务规模很小——每项大约十五分钟——来自 Redis、jq、Django 等开源仓库。奖励只有 0 或 1,依据是:

  • FAIL_TO_PASS——你是否修复了被要求解决的问题?
  • PASS_TO_PASS——你是否在不破坏其他东西的情况下完成修复?

这里有一个真实任务 fastlane__fastlane-19304,来自 Ruby 项目 fastlane。它的 zip action 读取两个可选参数,然后立刻对它们调用 .empty?;所以只要没有填写 include 和 exclude,它就会崩溃:

图片

最终关闭这个 Issue 的人工修复只有两行(把默认的 nil 转换为空数组):

图片

在评估过程中,模型:

  1. 从一个基础提交开始——仓库被检出到这个修复落地前的一刻;
  2. 获得缺陷报告——在这个例子里是:zip_command: undefined method empty? for nil:NilClass。

Agent 会根据 Issue 自行编写代码。它看不到标准答案补丁,也看不到作为评分器的测试补丁

图片

然后:

  1. 保留它生成的补丁;
  2. 丢弃它对测试文件做出的所有修改(我们见过模型悄悄注释掉失败测试,或者塞入一个让测试失去意义的 Mock);
  3. 在补丁上应用基准提供的测试补丁;
  4. 运行完整测试套件:既包括现有的 zip 测试(PASS_TO_PASS),也包括新增测试(FAIL_TO_PASS),确认两者都能通过。

图片

题外话——基准测试不是验证器;事实上,它们必须彼此留出独立样本(不要在测试集上训练,诸如此类)。我主要想表达的是“判断一条编码 Agent 轨迹质量”的基本形态,以及它的局限。

模型怎样得到正确答案并不重要。只要测试通过,我们就赢了;但侵蚀代码库可维护性不会受到任何惩罚

侵蚀代码库可维护性不会受到任何惩罚。

于是你就会得到无处不在的 try/catch:

图片

验证质量比“测试是否通过”难几个数量级

运行测试只需几秒,就能得到明确的通过或失败结果。这正是强化学习可以运行数百万次循环、优化每一代模型的原因。

但糟糕架构的成本函数,要以数周、数月,甚至数年来衡量。它会在某个人为了修改一行代码而第一次打开那个文件,却发现根本不可能只改一行时显现出来——有人当初 vibe 得太用力了,现在我们必须在十一个地方做同样的修改,还要祈祷隔着三个文件的某处不会悄悄坏掉。

图片

测试能在几秒内给出反馈,但糟糕架构的成本函数,要以数周、数月,甚至数年来衡量。

糟糕设计恰恰是今天的基准无法评估的东西。我知道,强化学习不等于基准测试;但如果这个问题已经在强化学习中解决,我相信它多少也会开始体现在基准的设计方式上。

无论如何,我个人不会把当今基准上的任何提升,视为模型突然变得善于保护代码库质量的证明。

前沿在进步,只是很慢

当然,很多聪明人都在解决这个问题。我的观点不是它永远做不到,而是炒作的速度已经超过了纪律建设

下面这些工作,我认为方向是正确的:

  • SWE-Marathon(Abundant AI):约 400 小时的任务,例如“克隆完整的 Excel,包括每一个功能”;奖励渠道是复合的,而不再只有一个通过/失败位;
  • DeepSWE(Datacurve):在开源仓库中设置现实世界从未真正实现过的大型任务,因此它们按定义不可能已经出现在训练集中(解决了污染问题,但没有解决质量问题);
  • Frontier Code(Cognition):包含跨多个 PR 的任务,并采用一种很聪明的确定性质量评估方式——如果模型写出的测试在应用补丁之前不会失败,就对模型进行惩罚(如果你没听说过变异测试,接下来会很有意思5)。它还会让一个评审模型检查 diff 是否符合代码质量规则

图片

但让模型判断质量,能力终究有限。

事实上,不难想象:如果一个模型能够可靠区分好代码和坏代码,它一开始也许就会直接写出好的版本。强化学习需要一个快速而可靠的预言机,但我们还没有能判断可维护性的这种工具。

如果模型能够可靠地区分好代码和坏代码,它一开始也许就会直接写出好的版本;但可维护性不存在快速的预言机,因此我们无法在强化学习中为它提供奖励。

当然,增加评审 Agent 和 token 确实有帮助——它们可以提高下限,捕获那些愚蠢的错误。

但它们无法抬高上限,因为上限取决于我们在强化学习中成功教给模型的东西,而优秀设计正是我们仍不知道如何教给模型的能力。

所以,我仍然不会拿自己的代码库押注在这些方法上。但这是我第一次看到有评估真正尝试给可维护性打分,而不是止步于通过或失败。

题外话:也许未来的某个模型会彻底理解这一切,我们就可以停手。如果你想一直 yolo 提示词,等 GPT-7 发布后看看结果,请自便——但先别管什么苦涩的教训,我们现在就有问题需要解决,而接下来我会说明我们怎样处理它们。

重新把灯打开

今天我才知道,Twitter Articles 有一个“媒体数量限制”。因此剩余内容会放进第二部分——敬请期待。

COMMUNITY NOTES · 讨论

讨论与补充

评论将在接近此处时加载。