AI Agent 的复杂度棘轮效应:为什么 90% 的测试覆盖率至关重要

@garrytan
英语2个月前 · 2026年5月12日
237K
791
96
47
1.6K

TL;DR

Garry Tan 解释了复杂度棘轮效应,即 AI Agent 通过自动化测试和文档编写确保软件质量持续提升,使独立开发者也能轻松管理庞大的代码库。

过去一年我一直在用 AI 编码。不只是简单提示——而是构建真正的软件。我做了两个开源项目:GStack(让 AI 编程 Agent 更强大),以及 GBrain(把你阅读和书写的一切变成 AI 可用的可搜索知识库)。两个项目加起来,大约有 97 万行代码和 665 个测试文件。几乎所有代码都是由 Claude Code 和 Codex 在我的指导下编写的(大部分时间同时开着 15 个 Conductor 会话)。

上周,我在 72 小时内合并了十四个拉取请求。新增了近 29,000 行代码。每个版本的测试都比上一个版本更好。

这按理说是不可能的。速度和质量本该是此消彼长的。要么快速发布、不断折腾;要么缓慢前进、稳健交付。你必须二选一。

但现在你不需要选了。关键在于 90% 的测试覆盖率——而 AI Agent 让达到这个水平变得毫不费力。五十年来,这种程度的验证所需的人类意志力成本太高,难以持续。现在,Agent 会在编写代码的同时编写测试。结果就是我所说的“复杂度棘轮”:一个只会变得更好、永远不会变差的系统。

(这是关于 AI 构建系列文章的第七篇:1 2 3 4 5 6

软件曾经很脆弱

五十年来,整个软件工程学科都围绕着一个核心理念构建:防止错误,因为错误是灾难性的。

你必须一次就把代码写对。漏掉一个边界情况,就会在生产环境崩溃。发布一个有问题的数据库迁移,就会丢失客户数据。写了一个有微妙副作用的函数,当唯一理解它的人离职后,就没人知道它为什么能工作了。整个系统依赖于人类的谨慎,而人类并不谨慎。于是我们构建了繁琐的流程——代码审查、预发布环境、QA 团队、发布列车——所有这些都是为了在错误到达用户之前捕获它们。

这在一定程度上是有效的。但速度很慢。而且这意味着任何软件系统的复杂度都有一个硬性上限:一个团队能够同时记住的东西的数量。

现在软件变得“可塑性”强了

我不是说代码可以写得很潦草。我是说,软件现在拥有了以前不可能具备的韧性。

当我说“模型时代已经到来”时,我指的是 AI 编程 Agent——Claude、GPT、Codex 以及围绕它们发展的生态系统——现在能够阅读代码、理解上下文、诊断错误并编写修复代码。它们做得并不完美。但已经足以改变软件的错误模型。

迁移出问题了?Agent 读取错误信息,理解跨越 45 个版本的数据库模式历史,编写修复代码,编写测试。文件同步在百万个符号链接上挂住了?Agent 诊断出解析器超时,将其限制在 30 秒内,带着测试一起发布修复。提取管道出现了归属错误?跨模型评估捕获了它,提示词被迭代,数据库层增加了强制校验。

对于大多数代码级别的错误——逻辑错误、解析失败、边界情况出错——Agent 现在可以在下一轮交互中诊断并修复它们。这是真正的新能力。仍然具有灾难性的错误是那些破坏状态的错误:对生产数据的不良迁移、在被发现之前就被利用的安全漏洞、无法挽回的隐私泄露。棘轮在这里也有帮助(好的测试能在生产环境之前捕获大部分此类问题),但真正的转变在于,代码库中绝大多数错误都是可修复的类型。

这对于软件的构建方式来说是一个相变。但这只有在拥有棘轮的情况下才有效。

Agent 复杂度棘轮

棘轮是一种只允许单向运动的机制。套筒扳手能够顺时针转动螺栓,并阻止它逆时针回转。这就是比喻。

在由 Agent 编写的软件中,每次与 AI Agent 的编码会话都会向代码库添加三样东西:

  1. 测试,它编码了“正确”的定义——自动化的检查,每当有人更改代码时运行,并在更改破坏某些功能时大声报错。
  2. 文档,它记录下决策背后的原因——不仅仅是代码做了什么,还有其背后的推理和权衡。
  3. 评估结果,它建立了质量标准——对输出质量的结构化评估,附带评分,这样你就能知道下一个版本是更好还是更差了。

下一次 Agent 在这个代码库上工作时,它会将这三样东西全部加载到其上下文窗口(AI 可以查看和推理的文本)中。它不能低于测试套件的质量要求——测试会失败。它不能忽略文档——文档就在上下文中。它不能发布低于评估基准的质量——分数是有记录的。

质量下限随着每一轮交互而提高。单向运动。这就是棘轮。

在实践中是什么样子

我来具体说明。GBrain 是一个我正在构建的知识系统——它通过存储、索引和搜索一个人的笔记、会议、对话和研究,为 AI Agent 提供长期记忆。可以把它想象成你的 AI 助手能够实际读取的“第二大脑”。

它的一个功能是“认识论提取”:它通读数千页内容,提取出谁在什么时间、以何种置信度相信什么。“Garry 认为 Bitcoin 会涨到 30 万美元(置信度:0.45)”。“Jared 认为这家初创公司留存率很高(置信度:0.80)”。大概是这个样子,但要处理 28,000 页的内容。

第一次提取运行拉出了 100,720 条主张。我使用跨模型评估来评分质量——让 GPT-5.5 和 Claude 分别独立给输出打分。总分:6.8 分(满分 10 分)。

最大的问题是什么?我称之为“持有者混淆”。以“AI 将在 2027 年前取代 80% 的软件工程师”这条主张为例。谁持有这个观点?是写这句话的人吗?是他们在引用某人的话吗?还是系统的分析引擎从播客记录中推断出来的?版本 1 在 35% 的情况下会搞错这个归属问题。这很重要——如果你在构建一个追踪人们信念的系统,你需要知道“谁”相信它。

于是,评估结果被记录下来。确定了六个具体的失败模式。版本 2 的提示词解决了所有六个问题。权重舍入(置信度分数)在数据库层得到了强制——不再允许 0.74 这样的虚假精度,当 0.75 才是诚实的答案时。17 个测试锁定了这个契约。

现在,任何未来的提取版本都必须通过这 17 个测试才能发布。没有人需要记住为什么权重舍入很重要,或者什么是持有者混淆。测试会记住。

质量下限永久性地提高了。这就是棘轮转动了一圈。

为什么大多数“氛围编码”项目会失败

氛围编码”是 Andrej Karpathy 提出的术语,指通过用自然语言描述你想要的功能,然后让模型生成代码。它很强大,也是我的构建方式。但根据我在 YC 申请和开源仓库中观察到的情况,大多数跳过测试的“氛围编码”项目,一旦达到中等复杂度——几千行代码,几个相互交互的功能——就开始崩溃。

它们跳过了棘轮。没有测试,没有文档,没有评估。Agent 增加了复杂度,但没有任何东西能防止回归。每个新功能都有可能破坏旧功能,而没有测试,你只有在用户报告时才会发现。到版本 0.5 时,代码库就像一个鬼屋,每次改动都会破坏一些意想不到的东西。然后开发者写一篇博客文章,声称 AI 编码行不通。

AI 编码完全行得通。他们只是没有构建棘轮。

你可能会说,会写测试的人通常也是最初就能写出良好架构的人。有道理。但棘轮机制的关键不在于“人”——而在于下一轮交互会发生什么。当一个新的贡献者发起拉取请求,或者当模型版本发生变化,或者当你在凌晨 2 点编码、判断力下降时,测试会捕获回归,无论它们是谁写的。即使人类不在最佳状态,棘轮也能工作。这才是重点。

没有测试,改进就是一个充满噪音的过程——Agent 试图让事情变得更好,但由于没有回归信号,好的变化和坏的变化同样不可见。有了密集的测试套件,你就在被测试覆盖的表面上获得了一个棘轮:对于你已经编码的行为,质量只会上升。这覆盖了系统的大部分,但不是全部。但这足以维持高速前进。

测试作为机构记忆

在传统的软件公司里,机构记忆存在于人脑中。那位知道为什么存在那个缓存层的资深工程师。那位记得那次几乎摧毁数据库的迁移的架构师。那位能解释计费系统中奇怪边界情况的技术负责人。

人会离开。他们会退休、被挖走、或者筋疲力尽。当他们离开时,知识也随之而去。每家软件公司都有过这样的经历:打开一个关键文件,发现一行注释写着// 不要修改这个 —— 问 Dave,而 Dave 三年前就走了。

Agent 的上下文窗口不会离职。不会被挖走。不会遗忘。当测试套件编码了“权重舍入必须使用 0.05 的增量”,而文档解释了“因为跨模态评估显示虚假精度会降低对置信度分数的信任”时,这些知识就是持久的。任何 Agent、任何模型、任何时候都可以加载那个上下文并理解这个约束。

测试是能够经受住员工流动的机构记忆。对于一个单人项目来说,它们甚至更为关键——它们是你唯一的机构记忆。

一切可被驾驭的东西都是可测试的

棘轮不仅仅适用于传统代码。它适用于计算机能够观察到的任何事物。

想想现代系统的各个层面。操作系统提供了进程树、文件系统状态、网络套接字、cron 调度。终端提供了每一次击键、每一行输出、每一次交互式提示。浏览器提供了渲染后的页面、按钮状态、导航事件。API 提供了你可以解析和验证的结构化响应。而 AI Agent 提供了可观察的行为——它们说了什么、调用了什么工具、以什么顺序做事情、是否在行动前询问。

所有这些都是可以被“驾驭”的。如果你能驾驭它,你就能观察它。如果你能观察它,你就能对它进行断言。如果你能断言它,你就能给它装上棘轮。

这比传统的单元测试覆盖的表面要大得多。让我给你展示一下。

GStack 是我的开源编程 Agent 框架——拥有 93,000 个 GitHub 星标、701,000 行代码、46 项技能。其核心功能之一是“交互式计划审查”:你让 Agent 审查你的架构,它会逐部分地审视计划,提出问题,探究边界情况,挑战你的假设。就像有一个真正会读代码的工程经理。

问题是:Claude Code 有时会跳过整个交互部分。它会读取计划文件,一次性把所有发现结果丢出来,然后退出——没有向用户提出任何问题。审查的全部意义就在于来回的对话。跳过它就失去了意义。

你甚至怎么去测试这个?你不能用单元测试来测“AI 是否进行了对话”。没有传统的测试框架能覆盖这个。

所以我使用了 Bun 的 TTY 功能来构建一个测试工具(PR #1354),它字面意义上是在一个伪终端里启动 Claude Code,喂给它一个特定的仓库场景,触发审查技能,并实时监控终端输出。测试观察 Agent 在完成之前是否会触发一个交互式问题。如果它直接倒出所有发现结果并退出而不提问,测试就失败。

这不再是测试代码。这是在测试一个 AI Agent 是否遵守行为契约。在 TTY 层面。通过字面意义上观察它的工作过程。

棘轮的响应有三层:

  1. 技能指令中的 STOP 关卡——明确的规则,说“在进入下一部分之前,你‘必须’询问用户”,并带有反合理化条款,明确指出特定的失败模式,这样模型就不能说服自己跳过。
  2. 反捷径条款——“计划文件是‘交互式审查的输出结果’,而不是它的替代品。”一句话堵死了模型一直在利用的精确漏洞。
  3. 关卡级基础测试——TTY 工具测试,在受控场景中启动 Claude Code,如果 Agent 没有提出至少一个交互式问题就失败。

现在,当 Anthropic 发布新模型版本,或者我修改了技能提示词时,测试套件会捕获交互契约中的任何回归。Agent 不能悄悄地停止提问。测试会监控终端并进行检查。

再比如 PR #880,它发布了一个新的 OpenClaw 插件。测试不仅仅检查代码是否能编译。它会从源码构建插件,在一个隔离的配置文件中启动一个真实的 OpenClaw 实例,通过 CLI 安装插件,运行 plugins inspect 来验证运行时是否加载了它,设置配置槽,验证配置,然后运行 plugins doctor 来确认零诊断结果。一次跨越两个独立程序的完整端到端往返。359 行测试代码。这种测试人类几乎永远不会手动编写,因为设置过程太繁琐了。Claude 用了大约五分钟就写好了。这就是努力墙壁在实时消失。

这个原则可以推广。你可以在操作系统层面测试:迁移是否创建了正确的表、cron 作业是否触发了、进程是否还活着?在浏览器层面:页面是否渲染了、Agent 是否正确填好了表单。在 API 层面:模型是否返回了具有正确模式的合法 JSON。在行为层面:Agent 是否遵循了协议、是否在删除前询问、是否在被告知停止时停止了。

整个技术栈都是可测试的。棘轮适用于所有这一切。大多数人还没有意识到这一点,因为他们仍然认为测试覆盖率就是“我的函数是否返回了正确的数字”。真正的测试表面是计算机能看到的一切。

90% 这个数字

那么,90% 的测试覆盖率到底能给你带来什么?

Capers Jones 研究了超过 10,000 个软件项目,并测量了缺陷移除效率(DRE)——在上线前捕获的错误百分比。他在《Applied Software Measurement》中的数据显示了一个非线性曲线:低于 70% 的覆盖率时,DRE 大约在 65-75%。在 85-95% 的覆盖率时,DRE 跃升至 92-97%。这种关系不是线性的。曲线上大约在 85% 附近有一个拐点,缺陷逃逸率会急剧下降。

航空电子行业几十年前就明白了这一点。DO-178C 是 FAA(美国联邦航空管理局)针对飞行关键软件的标准,要求 A 级系统(故障意味着坠机的系统)实现修改条件/判定覆盖(MC/DC)。仅分支覆盖会遗漏 10-20% 的故障。MC/DC 比行覆盖率更严格,能实现 >99% 的 DRE。他们强制要求这个不是因为官僚喜欢文书工作。而是因为数据显示,低于某些覆盖率阈值时,关键缺陷的逃逸率之高,与不造成人员伤亡的目标不相容。

可靠性工程的平行类比也很清晰。工厂使用一个叫六西格玛的系统来衡量质量。其理念是:计算每百万单位产品中产生的缺陷数量,然后将其表示为“西格玛水平”——西格玛越高,缺陷越少。3 西格玛流程大约产生每百万 67,000 个缺陷(相当差)。4 西格玛流程大约产生 6,200 个(好十倍)。5 西格玛流程产生 233 个(又好了 27 倍)。从 4 西格玛到 5 西格玛的跳跃不是增量改进。它是一个相变。

测试覆盖率也遵循同样的曲线。从 70% 的覆盖率到 90%,不是好了 30%。而是缺陷逃逸减少了一个数量级。在 70% 覆盖率下溜走的缺陷,藏在那 30% 未测试的代码里。在 90% 时,藏身之处缩小到 10%,并且大多数危险的路径都被锁死了。

现在,我应该诚实地说明研究也揭示了什么。Mockus、Nagappan 和 Dinh-Trong 研究了 Windows Vista,发现虽然覆盖率与更少的发布后缺陷相关,但达到 90% 以上的努力急剧增加。最后 20% 的覆盖率所花的工作量远超前面 70%。几十年来一直如此。这就是为什么大多数团队止步于 70-80% 并认为已经够好了。

但有些事情变了:AI 编程 Agent 不会觉得辛苦。

它们不会因为编写第十四个边界情况测试而感到无聊。它们不会在周五下午 5 点偷工减料。它们不会看着一个棘手的集成测试然后想“我以后再回来处理”。那个在 70% 处让人类团队停滞的努力曲线,对 Agent 来说不适用。你可以让 Claude 为一个模块中的每个边界情况编写测试,它会愉快地、彻底地、在凌晨 2 点、毫无怨言地完成。那个让 90% 的覆盖率对人类团队来说不切实际的、残酷的最后 20%,正是 AI Agent 最擅长的工作。

这才是真正的解锁。不是 AI 让你写代码更快。很多人都注意到了这一点。而是 AI 让你能够以以前过于昂贵、无法维持的水平进行“验证”。数据表明神奇的 90% 阈值?它过去需要太多的人类意志力才能达到。现在它几乎是免费的。

这就是关键区别。棘轮不是关于把行覆盖率当作虚荣指标。而是关于那些编码了行为契约的测试——持有者混淆测试、权重舍入测试、交互式审查关卡测试。每个测试都锁定了一个特定的经验教训。覆盖率是一个代理指标,告诉你系统的行为有多少处于契约之下。在 90% 时,几乎每个行为改变都会触发一个测试信号。Agent 要么通过(可以安全发布),要么破坏一个测试(立即被捕获)。

剩下的 10% 是集成点、基础设施管道以及真正难以测试的边界情况。这没问题。正是这 90% 将混乱转变为棘轮。

达到 90% 曾经需要英雄般的努力。现在只是一个普通的星期二。这就是游戏规则的改变。

概念验证

两个项目都是我独自开始的。现在不再是单人项目了。

GStack 现在有 37 个贡献者。v1.30 在单个版本中合并了 21 个社区拉取请求。GBrain 有 25 个贡献者。v0.31.1.1 在一个拉取请求中落地了 22 个社区修复——涉及认证流程、模式引导、同步和隐私。

棘轮让这一切变得安全。每个外部拉取请求都必须通过现有的测试套件。新的贡献者不需要理解整个系统。他们只需要让测试通过。

上周的 GBrain 版本说明了这一点:

  • v0.31.0:一个新的实时记忆事实表,加上一个梦境整合阶段,将短期记忆提升为长期知识。
  • v0.31.1:修复了 25 个 CLI 命令,这些命令静默地路由到一个空的本地数据库,而不是用户的真实大脑。
  • v0.31.1.1:在一个 PR 中修复了 22 个社区报告的问题。
  • v0.31.2:修复了一个代码同步问题,该问题在大型仓库中存在符号链接时永远挂起,通过添加 30 秒超时解决。

每个版本发布时都带有比前一个版本更多的测试。Agent 在编写代码的同时编写测试。覆盖率不会下降,因为维持它的努力不再是一个人类负担。

新的复杂度上限

软件的复杂度上限刚刚被大幅提高了。

它曾经受限于一个团队能够将系统装进大脑的能力。现在,它受限于一个人加上能够将整个代码库、模式历史、测试套件和文档加载到上下文中的 Agent。

这是一个大得多的数字。并且随着上下文窗口变得更大、模型在推理代码方面变得更好,这个数字还在增长。

每一家不采用这种模式——Agent 加上品味加上一个只增不减的测试套件——的软件公司,已经在以比一个拥有这一切的人更慢的速度和更差的质量发布软件。

工具已经就绪。代码是开放的。测试就是棘轮。90% 的覆盖率,每一次拉取请求,没有例外。

五十年来,90% 的覆盖率是航空电子和医疗设备领域的奢侈品——这些团队有预算可以投入大量人力去攻克那个努力的高墙。AI Agent 推倒了那堵墙。使软件可靠的覆盖率阈值不再昂贵。它只是一个设置。问题不是你能不能负担得起 90%。而是你能不能承受不这样做。

棘轮、技能以及整个知识系统都是开源的,并且在 GitHub 上免费提供。去构建吧。

我采用 MIT 许可证的开源项目:

  • GStack —— 让 Claude Code 变得更强大。93K 星标。免费。
  • GBrain —— 你的 AI Agent 第二大脑。14K 星标。免费。

AI 解释器系列:

  1. 胖技能,胖代码,瘦工具 —— 架构
  2. 解析器 —— 智能路由表
  3. LOC 争议 —— 60 万行代码实际产出了什么
  4. 裸模型更笨 —— 模型是引擎,不是汽车
  5. 技能化宣言 —— 每个工作流都变成一个可测试的技能
  6. 元-元-提示 —— 复合技能产生涌现能力
  7. Agent 复杂度棘轮 —— 你现在所在的位置

https://x.com/garrytan/status/2054055071017538028

https://x.com/garrytan/status/2042925773300908103

https://x.com/garrytan/status/2044479509874020852

https://x.com/garrytan/status/2045404377226285538

https://x.com/garrytan/status/2045798603059548364

https://x.com/garrytan/status/2046876981711769720

https://x.com/garrytan/status/2053127519872614419

https://x.com/karpathy/status/1886192184808149383

一键保存

使用 YouMind AI 深度阅读爆款文章

保存原文、追问细节、总结观点,并在一个 AI 工作空间里把爆款文章沉淀成可复用笔记。

了解 YouMind
写给创作者

把你的 Markdown 变成干净的 𝕏 文章

图片上传、表格、代码块,往 𝕏 上手动重排太痛苦。YouMind 把整篇 Markdown 一键转成干净、可直接发布的 𝕏 文章草稿。

试试 Markdown 转 𝕏

更多可拆解样本

近期爆款文章

探索更多爆款文章