加拉帕戈斯群岛上的智能体编程笔记
摘要
Dan Luu 反思了他使用 AI 编程代理的经验,指出虽然 AI 可能会编造看似可信但实际错误的复现步骤,但在调试和测试等领域仍能带来生产力提升。他讨论了现代软件开发中信任、自动化和质量之间的平衡。
暂无内容
查看缓存全文
缓存时间: 2026/07/04 06:37
# 来自加拉帕戈斯群岛的智能体编码笔记
源地址:http://danluu.com/ai-coding/
我从去年十一月开始大量使用AI,整个过程相当有趣。一个智能体做的事,如果换成人类来做,你会立刻炒掉他。而我的反应自然是表现得好像这很棒,然后启动一千个智能体,让它们做更多这种事。
去年年中,我让GPT(可能是5.0或5.1版本)尝试找出一个bug的根源。自然,这段代码没有测试,`git bisect` 也不管用,这是一个UI交互bug,我甚至没资格为它写测试。所以我让Codex在日期X和Y之间进行二分查找,找出引入这个bug的提交。Codex立刻告诉我出问题的提交在这个日期范围之后(这绝对不可能)。当我告诉Codex这是错的,它又告诉我某个明显不是问题提交的提交,如此重复了一两次。当我指出那些也是错的,它又告诉我一个看起来挺合理的提交。当我要求它证明或反驳自己的理论时,它声称自己写了个测试,并确认那个所谓的提交就是导致问题的提交。
然后我要求它用视频展示,在正常的浏览器测试环境中,使用完整的开发者端到端栈。它声称自己没有权限这么做(这是谎话),但它可以用Playwright和相应的测试代码,录制该提交前后重现步骤的执行视频。视频很有说服力,显示该功能在提交前正常工作,提交后就失效了。这件事感觉不对劲,所以我手动在提交前后重现了这个问题,结果发现整个事件都是编造的。视频看起来像是Codex重现了bug,但那是一个旨在制造假重现的人工浏览器环境,根本不是真实环境。
如我所说,因为这次经历毫不讽刺地如此精彩,我立刻想:“我怎样才能得到更多这样的体验?”于是我开始越来越频繁地使用智能体,直到去年年中到年底,我大量地使用编码智能体。
由于本文涵盖的主题比较分散,这里有一个简要大纲。
- 测试背景 (http://danluu.com/ai-coding/#testing-background)
- 测试的一些细节 (http://danluu.com/ai-coding/#some-details-on-testing)
- 原始人模式 (http://danluu.com/ai-coding/#caveman-mode)
- LLM的方差 (http://danluu.com/ai-coding/#llm-variance)
- 杂项 (http://danluu.com/ai-coding/#misc)
- 智能体循环与本文写作 (http://danluu.com/ai-coding/#appendix-agentic-loops-and-writing-this-post)
- 人们为何各说各话 (http://danluu.com/ai-coding/#appendix-people-talking-past-each-other)
### 测试背景
LLM在测试方面杠杆效应极强。就投入的精力而言,现在比以往任何时候都更容易达到特定的质量标准,然而,软件的质量似乎比以往任何时候都低。十年前,我们查看了一周内我随机遇到的bug (http://danluu.com/everything-is-broken/)。当时bug就不少,现在我遇到的bug更多了,但我不认为情况非得如此。
一方面,bug发布后,现在比以往任何时候都更容易用数据驱动的方法来发现和修复它。举个例子,在工作中,我尝试创建一个从支持工单(聊天或邮件)到拉取请求(PR)的流水线。就我所见,这个方法效果不错。因为我为一家拥有传统工作流程的公司工作,所有这些修复都会经过人工审核,到目前为止,我们没有发现任何已知的误报。
从单位时间投入来看,进行更彻底的测试也成为可能。我个人认为,这可以足够有效,以至于我相当愿意通过“软件工厂 (https://factory.strongdm.ai/)”工作流来发布大量代码,因为我见过一个以测试为主、无需审核的工作流,其质量远高于我见过或听说过的任何依赖审核的工作流。
和所有人一样,我有自己的偏见,这些偏见源于我的经历。碰巧的是,我职业生涯的头十年是在一家公司度过的,该公司的测试流程在今天的LLM环境下运作得很好。我在Mastodon上提到过将模糊测试作为默认测试方法论 (https://mastodon.social/@danluu/116486547257066966),一位怀疑者尝试了一下,立刻发现了一些bug (https://mastodon.social/@[email protected]/116508702500087643):
> 所以我重读了那篇博客文章,开始是满脸“怀疑”,但没错,Claude的模糊测试找到了几类值得修复的bug
我与之交谈过的其他一些人也尝试采用了我们即将讨论的类似测试流程,他们都在自己工作的软件中立刻发现了bug,包括那些仅仅通过要求Codex或Claude审计代码找bug、找bug、“测试”、“更多测试”等所无法暴露的bug。例如,Dennis Snell提到,他和队友Jon Surrell不仅在他们的代码中发现了bug,而且在“上游依赖项中,包括HTML规范、三大浏览器以及其他开源项目”中也发现了bug,而且投入相当少。
总的来说,当我与软件从业者谈论测试时,我的出发点与他们如此不同,以至于他们立刻像看外星人一样看着我。所以,让我们谈谈我曾工作过的硬件公司Centaur的测试方式,这塑造了我对工作方式的偏好。我们在软件界做过的部分当时或现在依然非传统的事情包括:
1. 专职的QA/测试工程师,并将其作为一等职业路径
2. 默认不进行代码审查
3. 几乎没有手写测试
4. 通过程序员有时称为基于属性的测试、随机测试、模糊测试等方式进行持续测试,尽管我们只称那些为“测试”(手写测试被称为“手动测试”)。
5. 回归测试耗时过长(3个月),无法等待
6. 没有单元测试
为了让您了解大致结构,当我离开时(2013年),我们有大约1000台机器持续生成和运行测试,服务于大约20名逻辑设计师和20名测试工程师。这些机器是本地部署的,占据了我们所在大楼的半层楼面。
大致结构是,我们大约20%的机器运行回归测试,80%的机器生成和运行新测试。三个月的回归测试周期太长,无法作为提交的门禁,因此有一份更短的测试列表,运行大约需要10分钟,人们在提交前会运行这些测试。这些提交测试会在一个特殊设置上运行,以尽可能快的速度执行,包括使用金钱能买到的最快的超频机器,以及一个不同的模拟器设置。
新的失败会即时被发现并报告,有一到两名工程师的工作是分类这些失败并进行筛选(拒绝误报,修复导致生成误报的测试生成器中的问题等)。
就影响程度而言,除非您将文化视为一个单独的项目 (http://danluu.com/culture/),(1)可能是我们与典型软件公司之间最大的区别,但也是对这里的读者最无关紧要的,所以我将讨论放到脚注1中 (http://danluu.com/ai-coding/#fn:T),除了这句简短的评论:测试和其他技能一样;花更多时间练习会提高技能,而且,因为在大多数大型科技公司测试不是一等职业路径,所以软件公司的人员通常不具备像一些职业CPU测试工程师那样的测试技能水平。就像一个花了20年研究分布式系统或用户体验的工程师会比一个花5%时间在这些领域的同样有天赋的工程师做得好得多一样,一个花了20年从事测试工作的人也会比一个只花5%时间做测试的人做得好得多。
(2)是使我们在芯片公司使用的某些测试实践适合AI工作流程的原因之一。我们默认不审查代码,因为我们相信我们的测试实践足够好,以至于审查通常不会显著增加可靠性。我们每年发布少于一个用户可见的重大bug,审查是在需要时进行的,当有人希望别人对某个他们认为特别棘手的问题(footnote 2 (http://danluu.com/ai-coding/#fn:R))提供额外意见时才会进行。使用AI编码工作流,一个人生成的代码很容易超过任何一个人,甚至任何十个人手动审查的能力。人们对不经过审查发布代码的接受程度各不相同。就我个人而言,我非常乐意在没有人工审查的情况下发布代码,因为我见过这种做法应用在技术上比大多数软件公司的产品更具挑战性的产品上。
我经常看到人们说,“风险太大了;我们有数百万用户”,但凭经验,他们谈论的是一个以原始计数计算,人均错误率可能高出千倍的工作流,如果按严重性调整,这个比例会更高。如果一家公司主要依靠审查来捕获bug,而其bug发布率只有我们在Centaur时的百分之一,那么我可以理解他们的观点。但这不是典型软件公司的情况,在那里人们因为担心发布bug的风险而不愿放弃人工审查。
(3)和(4)是相辅相成的。我认识的几乎所有认真对待可靠性的软件团队(各种发布可靠数据库、分布式数据库等的团队)至少在方向上都做着同样的事情,尽管他们可能有更大比例的手写测试。出于同样的原因,依赖通过手动与软件交互并观察软件是否看起来正常工作来进行测试被认为是个坏主意,依赖直接输入测试输入和预期输出也是个坏主意。正如之前讨论过的 (http://danluu.com/testing/),手动编写测试效率极低。对于任何给定的可靠性水平,如果你倾向于随机化测试生成而不是手写测试,你会更快达到目标。
(5)源于大量测试发现了大量bug。一般来说,如果一个测试发现了一个我们后来修复的bug,我们会永远保留这个测试在我们的回归测试套件中。事实证明,如果你用好的测试发现了很多bug,你最终会得到一个庞大的测试套件。但撇开这一点不谈,仅从测试效率的角度来看,标准软件设置中,每次PR都在CI中运行同一套测试是非常低效的,如果你考虑一下什么更可能发现bug:是一天内运行同一个测试一千次,还是用同样的测试时间运行一千个不同的测试。
(6)也源于测试效率的考量,因为我们的团队比竞争对手小得多。这也是公司能够生存这么久的原因之一。当英特尔除了AMD之外正在消灭所有x86设计公司时,我们的运营成本足够低,使公司得以生存到2021年,之后以1.25亿美元被英特尔收购。鉴于公司团队规模极小,通过单元测试来获得合理的测试覆盖率是不可能的,而招聘足够多的人来做单元测试可能意味着公司会早一二十年走上Transmeta、Rise、Cyrix、TI、UMC、NEC、VM等公司的x86之路。从效率角度来看,单元测试表现很差。
总结一下,我们做了很多大多数软件人员告诉我是坏主意的事情(专职测试工程师、没有单元测试、没有代码审查等),但我们的质量比我工作过或用过的任何软件公司都要高得多。每当我谈到这一点时,人们会说这不适用于软件,因为CPU只有某些关注点,你不能用Y做同样的事情。当我第一次从CPU设计转向软件时,我也认为这可能是真的,但后来我把这种测试方法论应用到了每一种别人说行不通的Y上,结果都成功了,所以我不再觉得这个说法站得住脚(而且那些X通常包含对硬件开发实际样貌的错误假设 (https://www.hillelwayne.com/post/are-we-really-engineers/))。虽然硬件和软件之间存在真正的差异,但当我看到有人以此作为测试技术无法移植的理由时,通常是因为这个人依赖的是某种想象出来的因素,它之所以看似相关,只因为这个人对硬件开发了解不多。
一个显著的区别是测试与开发投入的努力比例,但模糊测试的固定成本相当低,所以这可以扩展到任何努力水平,而且效率提升依然存在。而且,由于测试效率的提升,努力的比例并没有软件工程师通常想象的那么大。我们大约有1:1的测试工程师与开发人员比例,然后大约花10%的时间处于“冻结”状态,目标是发现bug而不是发布新功能,所以这里的一个零阶估计是,我们将55%的努力花在测试上,45%花在开发上,或者如果我们把零努力花在测试上,我们可以将2.2倍的努力投入到开发中。如果你看一家软件公司,其发布重大bug的速度比我们快很多倍,然后你宣布紧急状态,让人们把55%的努力花在测试上,我不认为比率会变化太大。也许他们能将比率降低一半左右,但真正的差异并不在于努力水平本身。
如今,人们还会说,既然可以直接让LLM找bug,为什么还要费心做模糊测试?我现在已经多次尝试了这两种方法,我的经验是,模糊测试通常在发现bug的延迟上获胜,而且在发现更多bug和降低误报率方面占主导地位。LLM的方差相当高(稍后会详细说明),所以仅仅要求Codex或Claude找一个bug有时可以获胜,但平均而言,模糊测试赢了。
### 测试的一些细节
尽管我之前对LLM的测试能力说了非常积极的话,但LLM在测试方面似乎相当糟糕。更准确地说,是LLM让你比以前更容易地应用测试努力,而不是LLM擅长测试。
一个极端的例子是,所有我与之交谈过的、关心质量或测试的人,都认为LLM默认生成的测试,或者你告诉它们“写测试”、“写更多测试”等之后生成的测试,质量很差。人们倾向于将这些测试评为“毫无价值”到“略有用处”之间,具体取决于他们的标准。
例如,编译器工程师Em Chu说:
> 我目前正在使用的现有测试并不完美,但仍然高于LLM似乎瞄准的标准,我将其描述为“足够全面,足以让一个特性通过人工代码审查”。对于编译器(相比于例如UI),我猜编写平均水平的测试更容易,但最终产品通常期望更高的正确性标准,LLM在这方面就很差。它们在对抗性思维上糟透了,比如“现在,如果我这样做会怎样”或“我们来尝试所有组合的叉积”,这是人类用来编写能真正发现bug的测试的过程
与此同时,我也看到很多人对LLM在测试方面的能力赞不绝口,当告诉他们“写测试”、“写更多测试”等时。当我探究为什么人们说LLM擅长测试时,我发现通常这些人要么
相似文章
大规模生产代码库中的代理式编码:成功、失败模式与防护措施
来自数据库、iOS、前端、数据工程和后端领域的工程师讨论了AI代码生成如何将难点转移到验证和集成上,需要人类对细微风险和架构适配性做出判断。
代理式编程是一个陷阱
本文认为,代理式编程(即 AI 生成代码,人类充当编排者)是一个陷阱,原因包括系统复杂性增加、技能退化以及供应商锁定。文章强调了这种做法对开发者学习和批判性思维的负面影响,并将这一新的抽象层与历史上的编程范式转变进行了对比。
Agentic Code Review(15分钟阅读)
分析AI编码代理如何将瓶颈从编写代码转移到审查代码,数据显示代码变更量增加861%,缺陷率上升,使得代码审查成为软件工程中最具杠杆效应的技能。
与代理协作编程
与代理协作编程探讨了AI代理如何帮助开发者编写代码、自动化任务以及提高生产力。
2026年AI编程代理输出验证:查看差异、氛围检查再合并
关于当前AI编程代理输出验证实践的一点反思,指出开发者通常只是粗略查看差异就合并,而没有全面审计代理的会话活动,引发了对AI时代代码审查文化的担忧。