《测试全绿之后,AI 代码还留下了 1 万个状态》
五个 Coding Agent 接到同一个“入账通知处理”需求,交付的代码全部跑通了公开测试套件。
为了验证测试本身的区分力,我们故意保留了一段存在并发缺陷的原始代码跑同一组测试,结果同样全绿——这说明既有测试集本身缺乏足够的边界区分度。随后,我们在测试中补齐了重试、同订单并发、跨订单并发以及异常数据类型等边界用例,五个实现的业务逻辑均顺利通过;期间甚至有两个实现自带的自测脚本写错了异步 mock 与断言顺序。
然而,当测试场景推进到 10,000 个不同订单的长跑模拟时,差异暴露了。四个实现各自在进程内留下了整整 10,000 个临时协调锁,未被释放与回收;只有一个实现的状态计数在任务结束后平稳回落到了 0。
绿色测试只能证明已覆盖的行为仍然成立,不能证明实现没有多余状态,更不能证明状态会在异常与长跑中被妥善清理。

功能正确不等于状态可控
单次请求级别的单元测试天然存在盲区。当 Agent 遇到并发冲突或幂等要求时,最直接的解法往往是引入辅助结构。它可以是以订单号为键的内存锁、防重哈希表,或带重试计数的状态上下文。
在生命周期只有几毫秒的单测中,状态的创建与使用路径被充分验证,断言随即通过。但在真实运行中,创建与清理往往是不对称的。一旦请求在某个分支提前返回、抛出未捕获异常,或者单纯缺少显式的删除机制,这些为了协调并发而创建的状态就会滞留在内存中。短测试只看“结果是否返回”,看不到“现场是否还原”;它能确认一次请求拿到正确数据,却无法证明一万次请求后系统内部是否堆积了多余的痕迹。
这种状态残留就像租客退房时带走了垃圾,却留下了换掉的门锁。门确实关上了,但整栋楼的钥匙串正在无限膨胀。
少写代码的实质是压缩状态暴露面
GitHub Trending 上的开源项目 Ponytail 尝试将“确认是否真正需要这段代码”置于 Agent 执行路径的前置阶段。根据该项目在其基准页自报的数据,在 12 个真实任务基准中,该方案平均减少了约 54% 代码量、约 22% 的 token 与约 20% 的调用成本。
这类探索给代码评审带来的核心启发不在于行数指标,而在于控制系统的状态面。Agent 倾向于用局部加法解决局部冲突,遇到并发就加锁,遇到慢调用就加缓存,遇到失败就加重试队列。少写代码的工程价值不是行数竞赛,而是减少需要持续证明其生命周期的状态。 每一个新增的 Map、锁对象、上下文变量与中间状态,都意味着一道必须被严密证明的清理责任。

将状态生命周期纳入代码评审
在评估 AI 生成的业务逻辑时,必须将状态生命周期的完整性作为独立的验收标准。
- 显式追踪新增状态的生命周期。审查代码时,要求 Agent 明确标出每个新增状态的拥有者、存活时段与销毁时机。
- 构建长跑与异常退出测试。除了功能断言,在测试用例中加入大样本迭代、中断重试以及错误分支退出,并在用例尾部断言状态容器的容量。
- 将“状态归零或收敛至明确上限”设为合并门禁。业务返回码正确不代表流程结束,协调状态回到基线才是任务完成的必要条件。
在下一次审查 AI 交付的代码时,可以直接向它提出四个问题。
- 这段实现里新增了哪些全局或进程级状态?
- 每个状态由哪个模块创建,又在哪个具体分支中被彻底移除?
- 如果下游在状态持有期间超时或抛出异常,清理逻辑是否必定执行?
- 连续处理一万个不同标识的请求后,该状态集合的大小能否回归初始边界?
