让 AI Agent 执行 TDD 有用吗?代码质量、测试质量与 Token 成本实测
本文通过实测对比 AI Agent 执行 TDD 与非 TDD 方案在代码质量、测试质量及 Token 成本上的差异。实验显示:Opus 评估下,TDD 方案未显现出质量优势,部分批次中非 TDD 方案反而排名更高;TDD 导致 Token 用量达非 TDD 的 2.96–8.50 倍;Agent 难以可靠执行红灯—绿灯循环,且其设计倾向受训练数据影响,更擅长整体规划而非小步迭代。
AI 辅助编程中的三种 TDD 用法
在 AI 辅助编程中,TDD(测试驱动开发)有几种用法:
- 人来写测试:由人用自然语言、BDD(行为驱动开发)风格或代码定义测试场景,再让 AI 编写实现,让测试通过。有时还要先把人描述的场景转成测试代码。
- 设置人工审核节点:AI 先写一个会失败的测试,人检查它是否验证了预期行为,再由 AI 编写实现。
- 完全放进 Agent 循环:要求 Agent 逐个编写会失败的测试,再编写实现,并确认刚才失败的测试已经通过。
目前,第三种用法远比前两种常见。但让 Agent 在自己的循环里完整执行 TDD,真的会带来差别吗?它究竟有价值,还是属于少数这样的情况:对人有益的做法,对编程 Agent 可能无关紧要,甚至适得其反?
我搭了一套探索性评测,想先摸一摸这个问题,看看会发现什么。这远称不上全面、系统的评测,但确实带来了一些值得思考的假设。如果你正在费力让 Agent 遵循 TDD,这些假设或许值得一看。
摘要: 按照 Opus 对产出质量的判断,采用 TDD 与否,并未带来清晰可辨的差异。相反,Opus 不止一次认为,未采用 TDD 的方案在设计和测试质量上略胜一筹。各方案的变异测试得分也没有明显差异。
实验设置
- 任务: 我让 Claude 帮忙设计了小型、中型和较大型三个任务,都是从零实现一段业务逻辑。我让它多提一些建议,特意要求逻辑足够独特、具体,以增加不同方案出现差异的可能性,避免只是复现训练数据里已有的大量常见模式。
- 指令: 每次运行都要求代码覆盖率至少达到 80%。
- 模型: 使用 Sonnet 4.6 生成方案。
- TDD 执行情况评判: 同样由 Sonnet 4.6 判断是否遵循了 TDD。
- 方案质量评判: Opus 4.8 在不知道方案生成方式的情况下,比较实现及其测试的质量。这是一次开放式探索,所以我没有详细规定什么才算质量好。以我的经验,标准列得越具体,模型就越可能过度关注这些标准。Opus 在代码质量判断上已经表现出了相当不错的能力。它在为方案排名时,现场生成了一套评分规则,再交给负责评估各方案的子 Agent 使用。

从这些结果中得出自己的结论时,需要考虑以下限制:
- 样本量显然很小,结果只能谨慎参考。
- “质量”的定义几乎完全交给了 Opus,我只对测试质量提了少量要求。
- 各次运行对 TDD 的执行都算不错,但没有一次完全遵循。
- 交给 Agent 的任务规模都相对较小,都是从零开发,且只涉及业务逻辑。
Agent 到底有多擅长 TDD?
正式开始前,我得先确认 Agent 真的执行了 TDD 指令。过去我的体验并不好:Agent 经常先写实现再生成测试,跳过确认测试失败的“红灯”步骤,或者提前实现太多功能,导致下一个测试直接通过,根本没有失败过。
最后选定的提示词在 Sonnet 上表现尚可,足以用于比较,尽管每次会话仍或多或少出现上述问题。每次 TDD 运行结束后,我都会让一个独立的 Agent 根据会话记录判断流程执行得如何,避免把实际上没有认真执行 TDD 的运行也纳入比较。
实验结果
我一共生成了 5 批方案,每批包含两个未采用 TDD 的方案和两个采用 TDD 的方案。其中一批还额外运行了两次,只要求先写测试,省去逐步“红灯—绿灯”的完整 TDD 约束。
小型任务的 1 批结果和中型任务的 3 批结果呈现出一点规律:Opus 通常把两个非 TDD 方案排在第 1、第 2,把两个 TDD 方案排在第 3、第 4。只有一次例外:我在提示词中更明确地加入重构和设计评审步骤后,一个 TDD 方案拿到了第 1。但同一批中,使用完全相同提示词的另一个 TDD 方案却排在最后……较大型任务中,两个 TDD 方案居中,两个非 TDD 方案则分别拿到了最好和最差的名次。
(详见附录。)
可能的解释
跨批次来看,TDD 和非 TDD 方案都拿过最好和最差的名次,TDD 整体表现略差。
接着,我让 Opus 查看会话轨迹,告诉它每个方案采用了哪种流程,请它解释可能的原因。它发现,非 TDD 组和“测试优先”组总是在写代码或测试之前,先完成整体设计,包括架构、数据类型、边界情况和契约。它们会整体考虑,而非一次只处理一条需求或一个测试。这似乎让它们在数据模型、跨功能边界情况的考虑和功能完整性上略占优势。
TDD 指令则会主动抑制这种预先设计。那些运行中的设计,是许多局部最小决策叠加的结果,之后很少重新审视,因此往往被第一个测试碰巧确定的结构锁住。凡是 Agent 没想到要写测试的行为,也就完全没有实现。
我和 Ivett Ördög[1] 聊起这个问题时,她提出了一个解释:“AI Agent 在训练中见过的是完整的函数,以及这些函数的描述。真正一步步执行 TDD 的例子,在训练数据中只占极小一部分。这意味着,大语言模型内部的代码表征,是从需求直接映射到代码的结果,而不是一步步形成这种表征的过程。”
TDD 的目标,在 Agent 循环里还能实现吗?
下面是我对在 Agent 循环中使用 TDD 的一些整体思考,依据也不限于这次实验。我会逐项回顾自己使用 TDD 时真正想达到的目标,重点放在 TDD 流程特有的收益上。至于测试本身,尤其是单元测试带来的收益,例如重构安全网、活文档和测试覆盖率,这里先略过。
先写测试 → 避免自证正确
先写测试,更容易让我对真正想要的输出编写断言,避免只是复述实现逻辑。一个测试如果沿用的恰恰是它要检查的那套逻辑,那么实现出错时,它也无法因此失败。只有把断言与具体实现路径分开,测试才能发现行为偏离了预期。
在 Agent 循环里还能实现吗?
实验中,有些 TDD 会话即使先写了测试,仍然出现这个问题。一个特别明显的例子是,测试重新运行同一段代码来生成“预期”答案,再拿它与实现的输出比较,相当于自己和自己比(见这份观察记录的第 4 项[2])。先写测试无法可靠地防止这种情况,也许能降低发生概率。对于大语言模型,我们能争取的本来也只是概率改善,但这份小样本数据不足以让我判断概率究竟有没有变化。
先写测试 → 提高可测试性
先写测试,能让代码从一开始就为可测试性而设计,避免事后补上的测试变得过分复杂、脆弱。
在 Agent 循环里还能实现吗?
结果没有给出明确支持或反对的信号。需要说明的是,我选的任务在规模和性质上,都不需要特别复杂的设计,因此未必能暴露这个问题。不过,可测试性在一定程度上也是测试驱动设计的附带结果,后文会谈到。
红灯—绿灯 → 确认测试有效
先看到测试失败,再看到它通过,也就是“红灯—绿灯”,可以证明它确实能捕捉回归问题。
在 Agent 循环里还能实现吗?
当人退出流程后,这一步还有多大意义?只有有人检查测试为什么失败,红灯才算得上证据。如果测试的编写和失败确认都由 Agent 完成,红灯只能说明它运行过测试、看到了失败,至于失败原因是否正确,仍然无法确认。实验中的 TDD 执行评估也反映了这一点:Agent 有时仍会跳过或假装完成红灯步骤,或者提前实现功能,让测试直接通过。
回归测试的有效性,可以通过变异测试来监测和改善,我此前写过这件事[3]。各方案的变异测试得分,没有显示 TDD 组明显优于非 TDD 组。只要有机制看清回归测试的质量,我并不特别在意它是通过什么流程实现的。
先写测试、红灯—绿灯—重构 → 推动更好的设计
先写测试,迫使我们先定义用法,再考虑实现,从而促成更好的接口和更模块化的代码。TDD 循环中的重构步骤,则进一步推动我们逐步改进设计。
在 Agent 循环里还能实现吗?
至少这次实验完全没有显示出 TDD 组在设计上的优势。按照 Opus 的评分,我甚至开始怀疑 TDD 会不会让设计变差:非 TDD 方案更多时候排名更高,而它指出的设计缺陷,在我看来也有道理。当然,数据集太小,无法得出确定结论。(如果有人愿意投入时间和 token,做一次更大规模的实验,那会很有意思!)
人先写测试时,会被迫先思考用法,再考虑实现。在还不知道怎么构建之前,我们必须花力气把行为和预期说清楚。Agent 没有这种体验,它可以在规划实现的同时写出测试。如果两者之间没有人工审核节点,先写测试究竟还剩下什么意义?
小步推进 → 只实现眼下需要的功能(YAGNI)
只编写足够让下一个测试通过的代码,强调的是克制:把开发范围限制在已有需求内,避免提前构建抽象,或处理尚无人提出的情况。
在 Agent 循环里还能实现吗?
这是一项非常以人为中心的收益。当 Agent 独自执行 TDD 时,它就消失了。我们失去了那种必须停下来、认真思考实现细节的过程。理论上,这些思考会前移到为 Agent 编写需求规格的时候,但在那里,我们缺少类似 TDD 的机制,帮助自己小步推敲规格。
那能否让 Agent 小步推进,发现某项内容可能多余时就来提问?按我平时的经验,它们在这方面并不擅长。实验中,“最小实现”指令同样未能可靠约束开发范围。Agent 经常超出当前测试的要求,因为它手里拿着完整需求。通常,我们也不会把规格一条条喂给它,那样效率太低。
小步推进 → 快速、局部的反馈
一次只迈一小步,意味着测试失败时,我几乎能立刻确定原因:从上一次全部通过到现在,唯一的变化就是刚写下的那一点代码。
在 Agent 循环里还能实现吗?
这套实验没有显示,采用 TDD 与否是否会影响 Agent 陷入调试困境的频率。但以我的日常经验,即便没有经过精心安排的小步骤,Agent 通常也比较擅长找出测试失败的原因。对于它们偶尔卡住的情况,TDD 的小步推进能否明显缓解,以及总体投入产出是否划算,我仍持怀疑态度。
小步推进 → 信心与学习
Kent Beck 在《测试驱动开发:实战与模式》的序言中,把 TDD 最重要的理由归结为“管理恐惧”。他说,面对难题时合理的恐惧,会让开发者犹豫、减少沟通,并回避反馈。有了 TDD,每个通过的测试都让我们看到进展,于是我们可以放松下来,因为已经取得的进展得到了保障。测试是一种心理机制,帮助我们继续前进。
在 Agent 循环里还能实现吗?
这显然是在管理人的恐惧,让人能够安心。当 Agent 在自己的循环里执行 TDD 时,这项收益无法直接迁移给我:它带来的掌控感和信任,与我亲自一步步完成时并不相同。
成本
至少 3 倍的 token 用量
详细数字见附录。
TDD 需要更多对话轮次和工具调用,自然会消耗更多 token。不过,其中很多会命中缓存,因此 3 倍或更高的 token 用量,不能直接等同于费用也增加了相同比例。(遗憾的是,实验中我没有单独跟踪缓存命中情况。)
提示词的维护与测试
TDD 似乎并非模型“天然擅长”的流程。让它执行 TDD,就像逆着训练数据的倾向往上爬,往往得反复调整提示词,才能让它在大多数时候遵循流程。比如,前几批实验后,我发现 Agent 在“红灯—绿灯—重构”循环里很少重构,于是修改提示词,强化这个对 TDD 至关重要的步骤。后来我让 Opus 检查这些会话,看看重构是否有所改善。它确实报告了更多重构步骤,但也指出:有些情况下,Agent 打算重构,却又认定现有设计已经足够好,而 Opus 认为设计明显存在问题。例如,所有实现都挤在一个大模块里,本来完全可以按职责拆开。
TDD 是一组相对复杂的指令,变量很多,Agent 对它的理解也会有许多变化。因此我预计,相较于简单指令,这类提示词在不同模型上的表现会更不稳定。要让它跨模型、跨版本持续有效,就得不断投入维护。

我的结论
目前,越来越多证据让我觉得,把模型应该怎样完成任务规定得过于具体,很难成为可持续的做法。与其细致规定过程,不如尽可能多地监测结果、提供反馈。能自动化的反馈就尽量自动化,同时认真考虑:在哪些环节,应由我们亲自判断结果是否正确、质量是否过关。
我知道这次小评测远不足以全面反映 TDD 的有效性,但它确实没有提供新的证据,让我相信这些投入值得。尤其是,如果我们能用其他方式获得 TDD 的大部分收益,就更是如此。
我个人已经停止要求编程 Agent 先写测试。至于让它完整执行 TDD,坦白说,我从来就没有这样要求过。除非之后出现能说服我的评测或其他有力论据,否则我会继续把精力放在 Agent 循环之外:思考自己使用 TDD 时真正获得了什么,并探索其他实现这些收益的方式。
怎样获得好的回归测试?
……让 Agent 和我都能在已有功能被破坏时收到信号。
我仍然重视扎实的回归测试。Agent 当然可能用错误方式修好失败的测试,但至少红灯能提供一个反馈信号,促使它重新检查可能遭到破坏的既有需求。与其给出繁复的 TDD 指令后期待好结果,不如借助变异测试监测和改进回归测试质量[3]。
怎样把定期重构放进流程?
……让代码库持续易于修改。
重构仍然至关重要,但传统 TDD 的小步方式,在 Agent 循环里似乎既不够高效,也不够有效。可以考虑这些重构触发方式:让 Agent 使用静态代码分析[4];定期评审结构和模块化程度[5];建立团队惯例,保持对代码库的理解,及早发现偏离;关注每次修改涉及的文件数量,以及每次修改的 token 用量[6]如何变化。
怎样建立信心?
……让我敢于把代码推到生产环境。
最难的问题依然是:怎样找回 TDD 曾给予我们的信心?怎样管理恐惧,保障已有进展?我还没有清晰答案,但有一种做法可能成为其中的基础。我最近试用了 Ivett Ördög 倡导的 Approved Scenarios(已确认场景)[7]。用我自己的话解释——这并非她的原话——它是一种半人工测试方式,由针对具体应用定制的测试运行器提供支持。运行器以便于理解的形式展示功能测试场景,等我充分确认后,就可以把预期,也就是场景或测试夹具,“冻结”在运行器中。此后,只要结果违背了这些冻结的预期,就必须由我重新确认。我的同事 Matteo Vaccari 在这个视频中很好地介绍了他的实践经验[8]。
未来,无论最终靠什么建立对软件的信任和信心,我都认为,我们熟悉的 TDD 所扮演的角色,会比生成式 AI 出现之前小得多。
附录:Opus 评审结果
完整结果见代码仓库[9]。
- NT = 未提供 TDD 指令。
- T = 提供了 TDD 指令。
- TF = 提供了先写测试的指令。
各批次 token 用量
按任务规模汇总如下:
| 任务 | NT 平均 token 数 | T 平均 token 数 | T / NT 倍数 |
|---|---|---|---|
| 小型 | 119,815 (n=2) | 1,018,245 (n=2) | 8.50x |
| 中型 | 736,486 (n=2) | 2,181,105 (n=6) | 2.96x |
| 大型 | 253,621 (n=2) | 1,239,408 (n=2) | 4.89x |
只有中型任务额外加入了“先写测试”这一组。
注意: 这些数字只是会话成本的粗略替代指标,无法衡量一个方案投入了多少代码编写或思考。记录 token 用量的程序调用了 pi-coding-agent[10] SDK 的 getSessionStats(),将会话中每轮助手回复的 input + output + cacheRead + cacheWrite 用量相加。这是整段对话的累计总量:每一轮都会重新读取累积上下文,而这些重复读取通常主要由缓存提供,又会再次计入该轮的 cacheRead。因此,“总 token 数”更接近于对话轮次数,再按当时的上下文长度加权。它把便宜的缓存读取 token 与昂贵的新 token 等同计数,因而很可能高估了 TDD 的实际金额成本。样本这么少,倍数只能看作方向性信号:TDD 的开销确实反复达到数倍,但具体是几倍会变化。
中型任务,第 1 轮
任务: 构建一条包含四个阶段的 Python 流水线(解析 → 聚合 → 格式化 → 校验),把原始的 ROW_ID:CATEGORY:VALUE:PERIOD 字符串转换成纯文本报告。
各项数据:
| ID |
|---|
JOTO 企业落地观察
- 企业部署 AI 编程 Agent 时,若将 TDD 设为强制流程,需警惕其与模型内在能力的错配。实验表明,Agent 更擅长整体架构设计而非小步迭代,强行嵌入 TDD 可能抑制其优势,反而增加 token 成本与提示词维护负担。企业应优先评估结果质量指标(如变异测试得分、覆盖率),而非预设过程规范。
- 这类系统在智能体工程中面临核心取舍:是追求人类开发范式的忠实复现,还是接受模型原生工作流并优化其输出。实验中非 TDD 方案在设计质量上偶有优势,提示企业可将资源转向强化结果验证机制(如自动化变异测试、人工关键路径审查),而非投入大量成本调教 TDD 行为。
- 对 RAG 知识工程而言,该实测揭示了一个关键约束:当前模型缺乏对‘红灯—绿灯’循环中失败原因的因果推理能力。当测试失败仅由 Agent 自动判定时,其诊断可信度存疑。企业若需高置信度回归保护,应将测试验证环节与人工判断或领域知识校验层耦合,而非依赖 Agent 单独闭环。
- AI 安全治理需关注此类流程性指令的隐性风险。TDD 指令虽意图提升质量,但实验显示其可能诱导 Agent 生成自我验证式测试(如用同一逻辑生成预期值),形成虚假安全感。企业应在部署前对测试生成逻辑做独立审计,尤其检查断言是否真正独立于实现路径。
立即咨询 JOTO
JOTO 提供覆盖企业智能体规划与搭建、AI 平台私有化部署、RAG 知识工程、AI 安全治理、FDE 驻场共创及持续运营优化的全周期 AI 落地服务,帮助企业把验证中的 AI 能力转化为安全、可控、可持续迭代的生产力。 联系 JOTO 获取 AI 落地咨询
想把这些做法用到你的业务里?
留下你的场景和痛点,我们帮你判断从哪一步开始。
联系我们

