复杂度棘轮 — AI Agent 时代为什么 90% 测试覆盖率是必须的
Garry Tan(YC CEO)2026 年 5 月 12 日发表的长推,是他”用 AI 构建软件”系列的第 7 篇。他同时是 GStack(93K GitHub Star、70 万行代码)和 GBrain(14K Star)两个开源项目的创始人,几乎全部代码由 Claude Code 和 Codex 编写,常态 15 个并行 Conductor 会话。
深思 SenseAI 做了中文翻译+评论版(微信公众号),本笔记以原文为主,深思版的独立评论在末尾单列。
速度和质量不再是二选一
过去 50 年的软件工程共识是”快就粗,好就慢”。Garry Tan 上周打破了这个共识:72 小时,一个人,14 个 PR,近 29,000 行代码,每次发布的测试覆盖率都比上一次高。
他说这靠的是一个机制:90% 测试覆盖率——而 AI agent 让达到这个覆盖率变得免费。50 年来,这种级别的验证成本太高,人类的意志力撑不住。现在 agent 在写代码的同时就把测试写了。
软件变”软”了(squishy)
不是变草率,是变有韧性。AI 编程 agent 现在能读代码、理解上下文、诊断错误、写修复。具体例子:
- 数据库迁移出错 → agent 读报错信息,理解 45 个版本的 schema 历史,写修复、写测试
- 文件同步在百万个符号链接上卡住 → agent 诊断出解析器超时,加 30 秒时限,带测试一起发布
- 信息提取管道有归因 bug → 跨模型评估发现问题,改提示词,在数据库层加规则
绝大多数代码级别的错误(逻辑 bug、解析失败、边界情况)agent 都能在下一轮诊断和修复。仍然是灾难性的错误只剩毁状态的那类:生产数据上的坏迁移、安全漏洞被利用、隐私泄露收不回来。但这些是少数。
棘轮机制
棘轮(ratchet)是只允许单向运动的机械装置,像套筒扳手拧螺栓——只能往前拧,不能往回转。
每次 AI 编程会话在代码库里留下三样东西:
- 测试 — 定义什么叫”正确”。改动破坏了什么,测试会报错
- 文档 — 记录的不只是代码做了什么,还有当时为什么这么决定、取舍是什么
- 评估结果(eval) — 给质量打分,让你能看出下一个版本是变好了还是退步了
下一个 agent 来处理这个代码库时,三样东西全在它的上下文里。它不能退化到测试套件以下(测试会失败),不能无视文档(就在眼前),不能把质量拉低到评估基线以下(分数记着)。质量地板每一轮都上升。单向前进。
实战:GBrain 认识论提取
GBrain 是 Garry Tan 在做的知识系统——给 AI agent 提供长期记忆,存储、索引和检索一个人的笔记、会议、对话和研究。
其中一个功能叫”认识论提取”(epistemological extraction):读取几千页内容,提取”谁相信什么、置信度多少、随时间怎么变”。例如:“Garry 认为比特币会涨到 30 万美元(置信度 0.45)”、“Jared 认为这家创业公司留存很强(置信度 0.80)”。横跨 28,000 页。
第一次跑提取,拉出了 100,720 条观点。用跨模型评估(GPT-5.5 和 Claude 各自独立评分)打分:总分 6.8/10。
最大的问题是 “持有者混淆”(holder confusion):一句”AI 将在 2027 年前取代 80% 的软件工程师”——这是谁的观点?写这句话的人说的?他们在引用别人?还是系统从播客文字稿里推断出来的?第一版在 35% 的情况下搞错了这个区分。
修复过程就是棘轮的一次转动:评估结果被记录 → 6 个失败模式被识别 → 第二版提示词针对性修复全部 6 个 → 置信度取整规则强制到数据库层(不再出现 0.74 这种假精确,0.75 才是诚实答案) → 17 条测试锁住这份契约。从此没有任何未来版本能在不通过这 17 条测试的情况下发布。
为什么 vibe coding 项目会死
Vibe coding(振动编程)是 Andrej Karpathy 发明的词——用自然语言描述你想要什么,让模型生成代码。Garry Tan 说,从 YC 申请材料和开源仓库来看,大多数跳过测试的 vibe coding 项目在到达中等复杂度后就开始瓦解——几千行代码、几个相互影响的功能。
原因很简单:他们漏掉了棘轮。没有测试,没有文档,没有评估。Agent 加入了复杂度,但没有什么阻止退化。每个新功能都有机会破坏旧的,没测试你不会知道,直到用户反馈。到 v0.5,代码库变成闹鬼的房子。然后开发者写一篇博客说 AI 写代码根本不管用。
Garry Tan 的判断:“AI coding works fine. They just didn’t build the ratchet.”
他也回应了一个潜在反驳——“写测试的人本来就是那种会写好架构的人”。他承认 fair,但棘轮机制跟人无关——重要的是下一轮会发生什么。新贡献者打开 PR、模型版本迭代了、你在凌晨两点判断力下降——测试无论如何都会抓住退化。棘轮就算人状态不好也照样运转。
测试即机构记忆
传统软件公司的机构记忆住在人脑里。知道为什么那个缓存层存在的资深工程师,记得那次差点毁掉数据库的迁移的架构师,能解释计费系统那个奇怪边界情况的技术负责人。人会离开——退休、被挖走、燃尽。每家公司都经历过:打开一个关键文件,注释写着
// DO NOT CHANGE THIS -- ask Dave,而 Dave
三年前就离职了。
Agent 的上下文窗口不会离职,不会被挖走,不会遗忘。当测试套件里写着”置信度取整必须用 0.05 步进”,文档解释”因为跨模型评估显示假精确会降低对分数的信任”——这份知识是持久的。任何 agent、任何模型、任何时候都能加载这个上下文。
对单人项目来说更关键:测试是你唯一拥有的机构记忆。
一切可观测的都可测试
棘轮不只对传统代码有效,对任何计算机能观察到的东西都有效。
操作系统给你进程树、文件系统状态、网络套接字、定时任务。终端给你每一次按键、每一行输出。浏览器给你渲染后的页面、按钮状态、导航事件。API 给你结构化响应。AI agent 给你可观察的行为——它说了什么、调用了什么工具、按什么顺序做事、行动前有没有先询问。
能接入测试框架(harnessable)→ 能观察 → 能断言 → 能棘轮。
最精彩的例子:GStack 有个”交互式方案审查”功能,让 AI 逐段走过你的架构方案、提问题、挑边界情况。问题是 Claude Code 有时会跳过整个交互部分——读完方案直接把所有发现一次性倒出来然后退出,不问用户一个问题。
怎么测试”AI 有没有对话”?Garry Tan 用 Bun 的 TTY 功能搭了一个测试框架(PR #1354),字面意思是把 Claude Code spawn 在一个伪终端里,喂给它一个特定场景,触发审查技能,实时监控终端输出。测试观察 agent 有没有在结束前发出一个交互式问题。没问就 fail。
这不是在测试代码,是在测试 AI agent 有没有遵守行为契约。在终端层面。通过字面上盯着它工作来实现。
棘轮的三层响应: 1. 技能指令里的强制停止门——明确写”你必须在进入下一节前问用户”,附带防合理化条款(anti-rationalization),点名说出失败模式让模型无法说服自己跳过 2. 反捷径条款——“方案文件是交互审查的输出结果,不是它的替代品”,一句话关上模型一直在钻的漏洞 3. 终端层面的门槛测试——实际把 Claude Code 在受控场景里运行,agent 没问至少一个问题就 fail
另一个例子:PR
#880,测试不只是检查代码能编译——它从源码构建插件、spawn 一个真实的
OpenClaw 实例(隔离 profile)、通过 CLI 安装插件、运行
plugins inspect 验证运行时加载、设置和验证配置、运行
plugins doctor 确认零诊断。359
行测试代码,完整的端到端往返。人类几乎不会手写这种测试,因为 setup
太繁琐。Claude 大约 5 分钟写完。
90% 覆盖率的数据基础
引用研究员 Capers Jones 对 10,000+ 个软件项目的研究,测量”缺陷移除效率”(DRE,Defect Removal Efficiency)——在 bug 到达用户之前被发现的百分比。数据是非线性曲线:
- 70% 以下覆盖率 → DRE 约 65-75%
- 85-95% 覆盖率 → DRE 跳到 92-97%
- 约 85% 处有一个拐点,缺陷逃逸率急剧下降
航空电子行业几十年前就搞清楚了。FAA 针对飞行关键软件的标准 DO-178C(飞行安全软件认证标准),要求 A 级系统(bug = 飞机坠毁)使用 MC/DC(Modified Condition/Decision Coverage,改进条件/判决覆盖),比行覆盖率更严格,实现 >99% DRE。强制要求不是因为官僚主义,是因为数据显示低覆盖率下关键缺陷的逃逸率跟”不出人命”不兼容。
工厂质量管理的类比:六西格玛。3 sigma 每百万次约 67,000 个缺陷;4 sigma 约 6,200 个;5 sigma 233 个。从 4 到 5 sigma 不是渐进改善,是相变。测试覆盖率遵循同样的曲线——从 70% 到 90% 不是提升 30%,是缺陷逃逸减少一个数量级。
AI 拆了那堵墙
为什么大多数团队停在 70-80%?因为最后 20% 需要付出不成比例的工作量。这个”努力之墙”50 年来一直成立。
AI agent 不感受”努力”。它不会厌烦地写第 14 个边界情况测试,不会在周五下午五点图省事,不会盯着一个复杂的集成测试想”以后再说”。让人类吃不消的那最后 20%,恰恰是 agent 最擅长的那类工作。
“Getting to 90% used to be a heroic effort. Now it’s a Tuesday. That’s the game change.”
棘轮不是关于覆盖率数字作为虚荣指标。它是关于编码行为契约的测试——持有者混淆测试、置信度取整测试、交互审查门。每条测试锁住一个具体教训。覆盖率只是代理指标,告诉你有多少系统行为处于契约之下。到 90%,几乎每一个行为变化都会触发测试信号。
已经发生了
GStack 现在 37 名贡献者,v1.30 单次发布合并了 21 个社区 PR。GBrain 25 名贡献者,v0.31.1.1 单次 PR 落了 22 个社区修复(认证流程、架构启动、同步、隐私问题)。
棘轮让外部贡献变得安全:每个 PR 必须通过现有测试套件。新贡献者不需要理解整个系统,只需要让测试通过。
上周 GBrain 发布记录: - v0.31.0:新增”当下记忆”表 + “梦境整合”阶段(把短期记忆升格为长期知识) - v0.31.1:修复 25 条 CLI 命令——它们一直在悄悄把请求路由到空的本地数据库而不是用户真实的”大脑” - v0.31.1.1:22 个社区反馈的修复 - v0.31.2:修复大型含符号链接仓库上无限挂起的代码同步,加 30 秒超时
每次发布都比上一次有更多测试。覆盖率不会滑落,因为维护它的”努力”不再是人类的负担。
新的复杂度天花板
软件的复杂度天花板刚升高了很多。以前受限于一个团队能同时在脑子里装多少东西。现在受限于一个人加上能把整个代码库、schema 历史、测试套件和文档全部加载进上下文的 agent。这个数字大得多,而且随着上下文窗口变大、模型推理代码能力提升还会继续增长。
Garry Tan 的结论很直接:每一家没有采纳”agent + 品味 + 只升不降的测试套件”模式的软件公司,已经在以比一个拥有这套工具的单独个人更慢的速度、更低的质量在发货了。
深思 SenseAI 翻译版的独立评论
深思版不只是翻译,加了几段自己的评论(标了”我读到这里…“),其中两个值得单独记:
1. 执行成本 vs 发现成本:Garry Tan 的逻辑是 agent 不累所以最后 20% 不是问题。深思指出这混淆了两件事——写测试的意愿和知道该测试什么的能力。最后 20% 之所以难,不只是因为人类懒,更是因为那些边界情况本身很难被识别。Agent 把执行成本降到接近零,但发现成本没跟着降。覆盖率数字到了 90%,但那 10% 里藏着什么可能比以前更难说清楚。
2. 退化问题 vs 方向问题:棘轮解决了退化问题,但没解决方向问题。只升不降的地板,前提是地板往正确的方向升。Garry Tan 把这个叫”品味”(taste),然后括号一笔带过了。深思认为括号里装的东西比文章讨论的其他一切都更难、更重要。
术语表
| 术语 | 解释 |
|---|---|
| Complexity Ratchet(复杂度棘轮) | Garry Tan 提出的概念:通过测试+文档+评估,让代码库质量只能上升不能下降的机制 |
| Ratchet(棘轮) | 只允许单向运动的机械装置,比如套筒扳手。这里比喻质量地板的单向上升 |
| DRE(Defect Removal Efficiency) | 缺陷移除效率——bug 到达用户之前被发现的百分比 |
| DO-178C | FAA 针对飞行关键软件的认证标准,要求 A 级系统使用 MC/DC 覆盖 |
| MC/DC(Modified Condition/Decision Coverage) | 改进条件/判决覆盖——比行覆盖率更严格的测试覆盖度量,航空电子行业标准 |
| Six Sigma(六西格玛) | 工厂质量管理方法论,用 sigma 等级衡量每百万次操作的缺陷数 |
| Vibe Coding(振动编程) | Andrej Karpathy 创的词——用自然语言描述需求让 AI 生成代码 |
| Epistemological Extraction(认识论提取) | GBrain 的功能:从大量文本中提取”谁相信什么、置信度多少” |
| Holder Confusion(持有者混淆) | 提取观点时搞错了”这句话是谁说的”——是作者?引用的人?还是系统推断的? |
| Cross-model Evaluation(跨模型评估) | 用多个不同的 AI 模型独立评分来衡量输出质量 |
| TTY(Teletypewriter) | 终端/伪终端,这里指用伪终端 spawn AI agent 并监控其行为的测试方法 |
| Harnessable(可接入测试框架的) | 能被测试工具挂钩和观测的系统行为 |
| GStack | Garry Tan 的开源编程 agent 框架(93K GitHub Star、70 万行代码、46 个 skill) |
| GBrain | Garry Tan 的开源知识系统——给 AI agent 提供长期记忆 |
| Conductor | GStack 的并行会话管理器,允许同时运行多个 agent 会话 |
| Anti-rationalization Clause(防合理化条款) | 在 agent 指令中点名说出具体失败模式,防止模型”说服自己”跳过规则 |
| Gate-tier Floor Test(门槛测试) | 在终端层面实际运行 agent 并检查其行为是否符合契约的测试 |
| Capers Jones | 软件工程研究员,研究了 10,000+ 个项目的缺陷数据,著有 Applied Software Measurement |
Discussion 补充(2026-05-14)
DRE 非线性曲线展开
缺陷移除效率(DRE)= 软件交付用户之前抓住了多少比例的 bug。Capers Jones 对 10,000+ 个项目的数据显示覆盖率和 DRE 之间不是线性关系,而是有明确拐点的 S 型曲线:
- 覆盖率 < 70%:DRE 约 65-75%。测的都是”容易测的路径”,真正藏 bug 的复杂分支还没碰到
- 覆盖率 70-85%:DRE 加速上升。这个区间开始碰到条件分支、错误处理、边界情况——bug 最爱藏的地方
- 覆盖率 ~85%:拐点出现。DRE 从约 80% 陡升到 92%+,不是渐进改善而是跳变
- 覆盖率 90-95%:DRE 达到 92-97%。缺陷逃逸从”每 100 个漏 25 个”变成”每 100 个漏 3-8 个”——差一个数量级
拐点出现的两个原因:
- Bug 分布不均匀:bug 集中在复杂条件分支、错误处理路径、边界情况。从 70% 覆盖到 85% 正好在扫这些”高密度区”,扫完后剩下的 15% 大多是简单的不太出 bug 的部分
- 交叉覆盖效应:测试之间形成网状相互约束——A 测试锁住函数 X 的输入范围,B 测试锁住函数 Y 的输出格式,两个约束加在一起间接覆盖了 X→Y 的调用链。覆盖率越高交叉约束越密,bug 能藏身的缝隙越少
Garry Tan 用三个领域的数据佐证这个非线性:
- 航空(DO-178C):FAA 对 A 级系统(bug = 飞机坠毁)要求 MC/DC 覆盖——不只是”这行代码跑过了”,而是”每个布尔条件的每种真/假组合都独立验证过”,实现 >99% DRE。强制要求不是官僚主义,是数据表明低覆盖率下关键缺陷的逃逸率跟”不出人命”不兼容
- 制造业(六西格玛):3 sigma = 67,000 缺陷/百万次;4 sigma = 6,200(好 10 倍);5 sigma = 233(又好 27 倍)。从 4 到 5 sigma 不是渐进改善,是相变
- Windows Vista 研究(Mockus、Nagappan、Dinh-Trong):覆盖率确实和更少的发布后缺陷相关,但达到 90%+ 的努力曲线急剧上升——最后 20% 需要的工作量远超前 70%
结论:数据说 85-90% 是魔法拐点,但 50 年来这个拐点对大多数团队”看得见够不着”——因为努力曲线太陡人类意志力撑不住。AI agent 不感受努力,那堵墙对它不存在,90% 覆盖率从”航空和医疗设备才负担得起的奢侈品”变成了”一个设置项”。