速度和质量不必二选一
Garry Tan(Y Combinator CEO)过去一年用 AI 编码构建了约 97 万行代码、665 个测试文件的两个开源项目。上周单周发布近 2.9 万行新代码,每个版本比前一个测试更充分。
这按理说不可能。速度和质量应该 trade off。快速发布、打破东西;慢速发布、做对东西。二选一。
现在不用选了。解锁点是 90% 测试覆盖——而 AI Agent 让达到这个水平变得免费。
五十年来的工程假设
五十年来,软件工程的整个学科围绕一个理念组织:防止错误,因为错误是灾难性的。
你必须第一次就把代码写对。漏掉一个边界情况,生产环境崩溃。发一个坏的数据库迁移,丢失客户数据。写了一个微妙的函数,等唯一懂它的人离职后,没人知道它为什么工作。整个系统依赖人类小心,而人类并不小心。于是我们建立了精心设计的流程——代码审查、预发布环境、QA 团队、发布火车——所有设计都是为了在错误到达用户之前抓住它们。
这某种程度上有效。但很慢。而且意味着任何软件系统的复杂度都有硬天花板:一个团队能同时在脑中容纳的东西数量。
错误模型已经改变
当我说"模型已经来了",我指的是 AI 编码 Agent——Claude、GPT、Codex 以及围绕它们生长的生态——现在可以阅读代码、理解上下文、诊断错误、编写修复。不完美,但足够好,以至于软件的错误模型已经改变。
迁移坏了?Agent 读取错误信息,理解跨 45 个版本的数据库 schema 历史,写修复,写测试。文件同步在百万符号链接上挂起?Agent 诊断解析器超时,设 30 秒边界,发修复带测试。提取管道有归因 bug?跨模型评估抓住它,prompt 迭代,在数据库层加约束。
对于大多数代码级错误——逻辑 bug、解析失败、边界情况损坏——Agent 现在可以在下一轮诊断和修复。这是真正的新事物。剩下的灾难性错误是破坏状态的那些:生产数据上的坏迁移、检测前被利用的安全漏洞、无法撤销的隐私泄露。棘轮在这里也有帮助(好的测试在投产前抓住大部分),但真正的转变是代码库中绝大多数错误是可修复的那种。
什么是复杂度棘轮
棘轮是一种只允许单向运动的机制。套筒扳手向前转螺栓,防止它转回去。这就是隐喻。
在 Agent 编码的软件中,每次与 AI Agent 的编码会话给代码库添加三样东西:
1. 测试
编码"正确"意味着什么——每次有人改代码时自动运行,如果变更破坏东西就大声失败的自动化检查。
2. 文档
记录为什么做这些决定——不只是代码做什么,而是背后的推理和权衡。
3. 评估结果
建立质量阈值——对输出质量的结构化评估和分数,让你知道下一个版本更好还是更差。
下次 Agent 在代码库上工作时,它把这三样都加载进上下文窗口。它不能低于测试套件——测试会失败。它不能忽略文档——就在上下文里。它不能发低于评估基线的质量——分数被记录了。
质量底线每轮都上升。只进不退。这就是棘轮。
实例:GBrain 的提取质量
GBrain 是 Garry 正在构建的知识系统——通过存储、索引和搜索一个人的笔记、会议、对话和研究,给 AI Agent 长期记忆。把它想象成你的 AI 助手真正能读的第二大脑。
其中一个功能是认识论提取:阅读数千页内容,提取谁相信什么、信心多少、随时间如何变化。第一次提取运行拉出 100,720 条声明。用跨模型评估评分质量——GPT-5.5 和 Claude 独立评分输出。总体:6.8/10。
最大问题?Garry 称之为"持有者混淆"。比如声明"AI 将在 2027 年前取代 80% 的软件工程师"。谁持有这个信念?是写它的人?是他们在引用的人?还是系统的分析引擎从播客转录中推断出来的?版本 1 有 35% 的时间把这个区分搞错。这很重要——如果你在构建追踪人们相信什么的系统,你需要知道谁相信它。
评估结果被文档化。六个具体失败模式被识别。版本 2 的 prompt 解决了全部六个。权重舍入(信心分数)在数据库层强制执行——不再有 0.74 这样的虚假精度,当 0.75 才是诚实的答案时。17 个测试锁定了契约。
现在未来任何版本的提取都不能在不通过这 17 个测试的情况下发布。没人需要记住为什么权重舍入重要、什么是持有者混淆。测试记住了。
质量底线永久上升。这就是棘轮的一转。
VibeCoding 的陷阱
"VibeCoding"是 Andrej Karpathy 的术语:用自然语言描述你想要什么,让模型生成代码。它很强大,也是 Garry 的构建方式。但从 Garry 在 YC 申请和开源仓库中看到的,大多数跳过测试的 vibecoded 项目在达到中等复杂度时就开始崩溃——几千行代码、几个交互功能。
它们跳过了棘轮。没有测试、没有文档、没有评估。Agent 增加复杂度但没有任何东西防止回归。每个新功能都有机会破坏旧的,没有测试你就直到用户报告才发现。到 0.5 版本时,代码库成了一个鬼屋,每次变更都破坏意想不到的东西。然后开发者写一篇博客说 AI 编码不行。
AI 编码没问题。他们只是没建棘轮。
测试即制度记忆
在传统软件公司,制度记忆活在人身上。知道为什么那个缓存层存在的高级工程师。记得几乎摧毁数据库的迁移的架构师。能解释计费系统中奇怪边界情况的技术负责人。
人类离开。退休、被挖走、 burnout。他们离开时,知识跟着走。每个软件公司都有过这种经历:打开一个关键文件,发现注释写着"// 不要改这个——问 Dave",而 Dave 三年前就离职了。
Agent 的上下文窗口不会辞职。不会被挖走。不会忘记。当测试套件编码"权重舍入必须使用 0.05 增量",文档解释"因为跨模型评估显示虚假精度会降低对信心分数的信任",这个知识是持久的。任何 Agent、任何模型、任何时间都可以加载那个上下文并理解约束。
测试是熬过员工流失的制度记忆。对单人项目来说更关键——它们是你唯一的制度记忆。
超越传统单元测试
棘轮不只适用于传统代码。它适用于任何计算机能观察的东西。
想想现代系统的层次。操作系统给你进程树、文件系统状态、网络 socket、cron 调度。终端给你每次按键、每行输出、每个交互提示。浏览器给你渲染的页面、按钮状态、导航事件。API 给你可以解析和验证的结构化响应。AI Agent 给你可观察的行为——它们说什么、调用什么工具、做事顺序、是否在行动前询问。
所有这些都可以被利用。如果你能利用它,你就能观察它。如果你能观察它,你就能断言它。如果你能断言它,你就能棘轮它。
这比传统单元测试的表面大得多。
TTY 级行为测试
Conductor 是 Garry 的开源编码 Agent 框架。其核心功能之一是交互式计划审查:你让它审查架构,它逐节遍历计划,问问题、探测边界情况、挑战假设。像有一个真正读代码的工程经理。
问题:Claude Code 有时会跳过整个交互部分。它读计划文件,一次性 dump 所有发现,然后退出——不问用户一个问题。审查的全部意义是对话。跳过它就失去了目的。
怎么测试这个?你不能单元测试"AI 是否进行了对话"。没有传统测试框架覆盖这个。
所以 Garry 用 Bun 的 TTY 功能写了一个测试,字面意义上 spawn Claude Code 在伪终端里,喂它特定仓库场景,触发审查 skill,实时观察终端输出。测试观察 Agent 是否在完成前触发交互问题。如果它 dump 发现然后退出不问任何事,测试失败。
这不是测试代码。这是测试 AI Agent 是否遵守行为契约。在 TTY 级别。通过字面意义上观察它工作。
棘轮响应是三层:
- STOP 门:skill 指令中的显式规则——"在继续下一节之前你必须问用户",带反合理化条款,命名具体失败模式,让模型不能说服自己跳过
- 反捷径条款:"计划文件是交互审查的输出,不是替代品。"一句话关闭模型一直在利用的确切漏洞
- 门级底线测试:TTY harness 测试在控制场景中 spawn Claude Code,如果 Agent 不问至少一个交互问题就失败
现在当 Anthropic 发布新模型版本,或 Garry 改 skill prompt 时,测试套件抓住交互契约中的任何回归。Agent 不能悄悄停止问问题。测试看着终端并检查。
端到端测试的新高度
另一个例子:Conductor 发布了一个新 OpenClaw 插件。测试不只要检查代码编译。它从源码构建插件,在隔离 profile 中 spawn 真实 OpenClaw 实例,通过 CLI 安装插件,运行 plugins inspect 验证运行时加载了它,设置配置槽,验证配置,运行 plugins doctor 确认零诊断。两个独立程序之间的完整端到端往返。359 行测试代码。人类几乎永远不会手写的测试,因为设置太繁琐。Claude 大约五分钟写的。这就是努力墙实时消失。
原则可以推广。你可以在操作系统级别测试:迁移是否创建了正确的表、cron 作业是否触发、进程是否还活着。在浏览器级别:页面是否渲染、Agent 是否正确填写表单。在 API 级别:模型是否返回带正确 schema 的有效 JSON。在行为级别:Agent 是否遵守协议、是否在删除前询问、是否在被告知停止时停止。
整个栈都是可测试的。棘轮适用于全部。大多数人还没意识到这一点,因为他们仍然把测试覆盖想成"我的函数是否返回了正确的数字"。真正的测试表面是计算机能看到的一切。
90% 覆盖率的魔法
Capers Jones 研究了超过 10,000 个软件项目,测量缺陷移除效率(DRE)——在用户之前抓到的 bug 百分比。数据显示非线性曲线:70% 覆盖率以下,DRE 约 65-75%。85-95% 覆盖率时,DRE 跳到 92-97%。关系不是线性的。在 85% 左右有个拐点,缺陷逃逸率急剧下降。
航空业几十年前就发现了这一点。DO-178C,飞行关键软件的 FAA 标准,要求 A 级系统(bug 意味着坠机)使用 MC/DC 覆盖——比行覆盖更严格。仅分支覆盖会漏掉 10-20% 的故障。MC/DC 实现 >99% DRE。他们强制要求不是因为官僚喜欢 paperwork,而是因为数据显示低于某些覆盖阈值时,关键缺陷以与不死人不兼容的速率逃逸。
可靠性工程的类比很干净。工厂使用六西格玛系统测量质量。计算每百万单位生产的缺陷数,表达为"西格玛水平"——越高西格玛意味着越少缺陷。3 西格玛过程每百万约 67,000 缺陷(相当差)。4 西格玛约 6,200(好十倍)。5 西格玛 233(再好 27 倍)。从 4 到 5 西格玛的跳跃不是渐进改善。是相变。
测试覆盖遵循同样的曲线。从 70% 到 90% 覆盖不是好 30%。是数量级更少的逃逸。70% 时溜走的缺陷藏在 30% 未测试代码里。90% 时藏身之处缩到 10%,大多数危险路径被锁定。
AI Agent 抹平了努力墙
现在,Garry 也诚实地说研究还显示了什么。
Nagappan 等人研究了 Windows Vista,发现虽然覆盖与更少发布后缺陷相关,达到 90%+ 的努力急剧上升。最后 20% 的覆盖 disproportionately 比前 70% 花更多工作。这几十年来一直如此。这就是为什么大多数团队在 70-80% 停下来,说"够好了"。
但有些东西变了:AI 编码 Agent 不经历努力。
它们写第十四个边界情况测试时不会无聊。周五下午 5 点不会抄近路。不会看着棘手的集成测试想"我晚点再回来做这个"。阻止人类团队到达 70% 的努力曲线不适用于 Agent。你可以让 Claude 为一个模块的每个边界情况写测试,它会愉快、彻底、在凌晨 2 点、不抱怨地完成。对人类团队来说使 90% 覆盖不现实的残酷最后 20%,正是 AI Agent 最擅长的工作。
这是真正的解锁。不是 AI 让你写代码更快。很多人已经注意到了。而是 AI 让你能以以前太贵而无法维持的水平验证。数据说神奇的 90% 阈值?过去花太多人类意志力才能到达。现在免费了。
这就是关键区别。棘轮不是把行覆盖当虚荣指标。而是把测试当作编码行为契约——持有者混淆测试、权重舍入测试、交互审查门。每个测试锁定一个学到的具体教训。覆盖是告诉你多少系统行为在契约下的代理。90% 时,几乎每个行为变更都触发测试信号。Agent 要么通过(安全发布)要么破坏测试(立即抓住)。
剩下的 10% 是集成点、基础设施管道和真正难测试的边界情况。没关系。90% 就是把混沌变成棘轮的东西。
到达 90% 过去是英雄般的努力。现在只是一个周二。这就是游戏规则改变。
开源社区与棘轮
Garry 的两个项目都从单人开始。现在不是了。
Conductor 有 37 个贡献者。v1.30 单版本合并了 21 个社区 PR。
GBrain 有 25 个贡献者。v0.31.1.1 一个 PR 落地了 22 个社区修复——认证流程、schema 引导、同步、隐私。
棘轮让这变得安全。每个外部 PR 必须通过现有测试套件。新贡献者不需要理解整个系统。他们需要让测试通过。
上周的 GBrain 发布讲述了这个故事:
- v0.31.0:新 facts 表用于实时记忆,加上 dream 整合阶段把短期记忆提升为长期知识
- v0.31.1:修复了 25 个静默路由到空本地数据库而不是用户实际大脑的 CLI 命令
- v0.31.1.1:一个 PR 中 22 个社区报告修复
- v0.31.2:通过在大型符号链接仓库上加 30 秒超时,修复了永远挂起的代码同步
每个版本发布的测试都比上一个多。Agent alongside 代码写测试。覆盖不会滑,因为维持它的努力不再是人类负担。
结语
软件复杂度天花板刚刚变得高得多。
过去它被一个团队能在脑中容纳系统的能力所限制。现在它被一个人加上能把完整代码库、schema 历史、测试套件和文档加载进上下文的 Agent 所限制。
这是一个大得多的数字。而且随着上下文窗口变大、模型更擅长推理代码,它持续增长。
每个不采用这个模式的软件公司——Agent 加品味加一个只上升的测试套件——已经在比一个拥有这些的人发货更慢、质量更低。
工具在这里。代码是开放的。测试就是棘轮。90% 覆盖,每个 PR,没有例外。
五十年来,90% 覆盖是航空和医疗设备团队的奢侈品——有预算把人类时间扔向努力墙的团队。AI Agent 拆毁了那堵墙。使软件可靠的覆盖阈值不再昂贵。它只是一个设置。问题不是你是否负担得起 90%。而是你是否负担得起不达到 90%。