智能体测试流程、LLM基准测试,以及来自加拉帕戈斯岛的智能体编程笔记

HN Indie AI Startups 2026-10-29T09:50:14.176629

从去年十一月开始,我一直在比较重度地使用AI,整个过程挺有意思。智能体会干出一些事,换成人类早就被当场开除了。而我的反应呢,当然是假装这一切都很棒,然后赶紧拉起一千个智能体,让它们变本加厉地继续干。

去年年中,我让GPT(大概是5.0或5.1)去查一个bug的源头。这段代码自然没有测试,git bisect也用不了,而且这是个UI交互的bug,我甚至都没什么资格给它写测试。所以我让Codex在日期X和Y之间做二分查找,找出引入这个bug的那次提交。Codex立刻告诉我,问题提交在这个日期范围之后(这根本不可能对)。我告诉Codex这不对,它又报了一两次明显也不是罪魁祸首的提交。等我说这些都不对之后,它给出了一个看起来挺像那么回事的提交。我让它证明或证伪自己的推论,它说它写了测试,并确认那个所谓的提交就是搞坏事的提交。

接着我让它用完整的开发者端到端栈,在正常的浏览器测试环境里录个视频给我看。它声称自己没有权限这么做(这是在撒谎),但可以用playwright配合相应的测试代码,把提交前后的复现过程录成视频。视频很有说服力,显示该功能在提交前正常运作,提交后就挂了。但总觉得哪里不对劲,于是我手动在提交前后复现了这个问题,发现整件事都是编造的。视频看起来像是Codex复现了bug,但那其实是一个人为搭建的浏览器环境,专门用来制造假的复现,而不是真实环境。

就像我说的,这段经历实在太棒了(真不是反讽),我立刻就想:“怎么才能多来点?”于是我开始越来越频繁地用 agent,到去年年中到年末,已经在重度使用编码 agent 了。

测试背景

在测试这件事上,大语言模型(LLM)能放大很多倍。从投入的精力看,现在达到某个质量门槛比以往任何时候都容易,可软件质量看起来却比以往任何时候都差。十年前,我记录过随便一周里撞见的 bug。那时候 bug 就不少,现在撞见的更多,但我觉得不该是这样。

一方面,一个 bug 上线之后,用数据驱动的方式找到并修掉它,比以往任何时候都容易。举个例子,我在工作中试着搭了一条流水线,从客服工单(聊天或邮件)一路走到拉取请求(PR)。据我所知,它跑得还行。因为我在一家沿用传统流程的公司,所有修复都要人工审核,到目前为止,还没出现过已知的误报。

按投入的时间来算,测试也可以做得更彻底。我个人认为,这已经足够有效,以至于我很放心用“软件工厂”流程去交付大量代码——因为我见过一个重度依赖测试、不做代码审核的流程,它的质量远高于我见过、甚至听说过的任何依赖审核的流程。

跟所有人一样,我的经历也带来了偏见。碰巧我职业生涯的头十年待的那家公司,它的测试流程放到今天这个 LLM 环境里刚好很管用。我在 Mastodon 上聊过把模糊测试(fuzzing)当作默认测试方法,一位持怀疑态度的读者试了一下,立刻发现了 bug:

于是我又把博客文章读了一遍,一开始满脸“怀疑”,但不得不承认,Claude 做模糊测试确实找出好几类值得修的 bug。

和我聊过的人里,还有不少也尝试过采用我们这里要讨论的测试流程之类的方法。他们无一例外,都立刻在自己负责的软件里发现了 bug——其中有些 bug,光靠让 Codex 或 Claude 去审计代码、找 bug、说一句“测一下”“再多测测”之类,是根本暴露不出来的。比如 Dennis Snell 提到,他和同事 Jon Surrell 不仅在自己正在开发的代码里找到了 bug,还“在上游依赖里,包括 HTML 规范、三大浏览器和其他开源项目里”找到了 bug,而且花的力气相当小。

一般来说,我跟软件圈的人聊测试时,出发点和他们差得太远,他们马上就会像看外星人一样看我。所以,先说说我工作过的那家硬件公司 Centaur 是怎么做测试的——这也塑造了我对工作方式的偏好。我们当时做的一些事情,在软件行业里过去或现在都算非主流:

简单说一下整体结构:我 2013 年离开时,公司大约有 1000 台机器一直在生成并运行测试,服务的对象是大约 20 名逻辑设计师和 20 名测试工程师。这些机器都放在本地机房,占了我们办公楼半层面积。

整体结构大致是:约 20% 的机器跑回归测试,80% 的机器用来生成并运行新测试。三个月的回归测试量太大,没法作为提交代码的准入门槛,所以另有一份短得多的测试清单,跑一遍大约 10 分钟,开发者在提交前会先跑这些。提交前测试跑在专门的配置上,力求速度最快——机器超频、是当时能买到的最快机型,模拟器配置也做了调整。

新出现的失败会在发生时被捕获并上报,有一到两名工程师专门负责梳理和分诊这些失败,比如剔除误报、修复测试生成器里导致误报的问题等等。

就影响程度而言,除非把文化单独算作一项,(1)大概是我们和典型软件公司之间最大的差别,但对这里的读者来说也最不相干,所以我把讨论挪到脚注1里,只在这里简单说一句:测试和其他技能一样,投入的时间越多,水平就越高。而在大多数大型科技公司,测试并不是一条核心的职业发展路径,所以软件公司里人们的测试水平,通常达不到职业 CPU 测试工程师那种程度。道理就像一位在分布式系统或 UX 上深耕 20 年的工程师,肯定比一位天赋相当、只花 5% 时间碰分布式系统或 UX 的工程师更强;同理,一位做了 20 年测试的人,也远胜只把 5% 时间花在测试上的人。

(2)正是这类做法,让芯片公司的一些测试实践特别适合用在 AI 工作流里。我们默认不做代码评审,因为对测试实践足够有信心,评审通常也提升不了多少可靠性。那时我们一年发出的显著用户可见 bug 不到 1 个;只有在有人觉得某处特别棘手、想多一双眼睛时,才会按需评审2。到了 AI 编码工作流,一个人很容易生成超过任何人、甚至十个人手工评审能力的代码量。不同人对「不评审就发布」的接受度不一样。就我而言,非常能接受不经人工评审就发布,因为我见过这类实践用在技术难度高于多数公司多数软件的产品上。

常听到有人说:「风险太大了,我们有几百万用户。」但实际数据显示,他们说的那套流程,按人均原始数量算,发布 bug 的比率可能高出上千倍;若按严重程度加权,差距还要大得多。如果一家公司发布 bug 的比率只有我们在 Centaur 时的百分之一,且主要靠评审兜底,那他们的顾虑还能理解。但典型软件公司并不是这种情况——人们不愿放弃人工评审,多是出于对发布 bug 的风险感知,而非实际数据。

(3) 和 (4) 是相辅相成的。我接触过的、真正把可靠性当回事的软件团队(比如做可靠数据库、分布式数据库的那些团队),方向上基本都在做同样的事,只不过他们手写测试的比例可能更高。道理是一样的:大家公认「自己上手操作软件、看它表现得像不像正常工作」不算好的测试方式;那么直接手敲测试输入和预期输出,同样不算好方式。之前已经讨论过,手写测试效率实在太低。想把可靠性做到某个水平,用随机生成测试比手写测试更快达到目标。

(5) 是「大量测试找出大量 bug」的自然结果。一般来说,只要某个测试发现过一个后来被修掉的 bug,它就会永久留在回归测试集里。结果就是:好测试找出的 bug 越多,测试集就越大。先不管这个,单从测试效率的角度看:软件行业的标准做法是每个 PR 都在 CI 里跑同一套测试,这效率低得离谱。想一想,哪种方式更容易发现 bug——一天之内把同一个测试跑上一千遍,还是在同样的测试时间里跑一千个不同的测试?

(6) 同样出于对测试效率的考虑,因为我们团队比竞争对手小得多。这也是公司能撑这么久的原因之一。当年 Intel 把除 AMD 之外的 x86 设计厂商一个个挤出市场,而我们的运营成本足够低,一直活到 2021 年,被 Intel 以 1.25 亿美元收购。以公司这么小的团队规模,靠单元测试根本拿不到像样的测试覆盖率;而如果为了写单元测试招够人手,公司恐怕会提前一二十年走上 Transmeta、Rise、Cyrix、TI、UMC、NEC、VM 等 x86 项目的结局。从效率角度看,单元测试的表现相当差。

总结一下,我们做了不少在大多数软件人看来是坏主意的事(专职测试工程师、不写单元测试、不做代码评审等等),结果质量却比我待过的任何一家软件公司都高,也比我用过的任何软件都高。每次我聊起这些,总有人说这不适用于软件,因为 CPU 只涉及 X 这类问题,你没法把同样的做法套到 Y 上。我刚从 CPU 设计转做软件时,也觉得这话可能没错,但后来凡是有人说过"这套方法在 Y 上行不通"的场景,我都拿这套测试方法试过,每一种都奏效,所以现在我很难再相信这种说法了(而那些所谓的 X,往往建立在对硬件开发真实情况的错误假设之上)。硬件和软件之间确实存在真实差异,但当我看到有人拿这种差异当理由、说测试方法无法迁移时,通常是这个人脑海里臆想出了某个因素,而那因素之所以显得相关,只是因为他不太了解硬件开发。

一个显著差异是测试与开发投入的比例。不过模糊测试的固定成本相当低,所以无论投入多少都能扩展,效率提升依然存在。而且,由于测试效率的提高,投入比例并没有软件工程师通常想象的那么大。我们测试工程师与开发人员的比例大约是 1:1,然后大概有 10% 的时间处于“冻结”状态——目标是找 bug 而不是发布新功能。所以粗略估算,开销大约是 55% 的精力花在测试上、45% 花在开发上;换句话说,如果完全不在测试上花精力,我们本可以把 2.2 倍的精力投入开发。如果你看一家发布重大 bug 的速度比我们快很多倍的软件公司,宣布进入紧急状态、让员工把 55% 的精力花在测试上,我觉得这个比例也不会有太大变化。也许能降到之前比例的一半左右,但投入程度并不是真正拉开差距的因素。

如今人们还会说:既然可以直接让 LLM 找 bug,何必费劲搞模糊测试?这两种方式我都试过不少次了,我的经验是模糊测试通常在发现 bug 的延迟上胜出,而在发现更多 bug 和保持更低误报率方面则占据压倒性优势。LLM 的方差相当大(后面会详细说),所以直接让 Codex 或 Claude 找 bug 有时能赢,但平均来看模糊测试更胜一筹。

关于测试的一些细节

尽管我对 LLM 测试说了很多正面的话,但 LLM 在测试方面似乎相当糟糕。不过,在任何测试投入水平下,只要引导得当,LLM 都能让你比以往更容易地施加测试投入。

一个极端的例子是:我交谈过的每一位关心质量或测试的人,都认为 LLM 默认生成的测试——或者你告诉它“写测试”“多写点测试”等之后生成的测试——质量很差。人们通常把这些测试评为从毫无价值到勉强有用之间,取决于他们的标准。

例如,编译器工程师 Em Chu 说:

我在用的现有测试并不完美,但仍然高于 LLM 似乎瞄准的标准——我会把它描述为“周全到足以把 bug 偷运过审查,但也就仅此而已。”

人们最常提到的失败模式并不是偷懒,而是测试实现而非规格。如果你把一个函数交给 LLM 并要求写测试,它会读代码,然后断言代码做了代码所做的事。测试通过了,覆盖率看着不错,但你真正关心的行为却一点也没被钉住。这些测试是实现的转录,所以它们抓不住错误的实现——它们只会跟着实现一起更新。

反复出现的修复方法,大多是关于隐瞒信息和改变你的要求:

更宏观的结论是:提出一个测试想法的边际成本已经塌了下来,但一个默认测试的边际质量并没有提高多少。以前,“我们是不是也该测一下并发路径”“应该给解析器做模糊测试”这类决定,要有人搭进去一整天。现在它只是一条 prompt 加一轮评审,结果不理想也就浪费二十分钟。这让“哪些测试值得一试”的取舍发生了变化,尽管它并没有让任何单个产物变得更好。

精力花在哪里

这和 agentic coding 的其他环节是同一个形状:模型并没有消除判断的必要,它消除的是第一稿的成本,于是判断就被用在了更多候选方案上。真正做出好结果的人,不是那些为第一次尝试写更漂亮 prompt 的人,而是搭起了闭环的人——生成、运行、查看 diff、把具体的缺陷反馈回去——并且始终把“对这个代码库来说什么算好”的决定权留在人手里。

查看原文