AI 创作声明:本文由作者提供原始素材、核心观点和最终判断,AI 参与结构整理、表达润色和发布格式化。文章发布前由作者审核确认。

前言:代码早就写完了,Issue 怎么还没结束?

最近两天,我盯着 Vestigra 的开发流程,反复冒出一个很奇怪的感觉:

AI 的开发效率好像很低。

这句话听着有点反直觉。AI 不需要休息,找代码、改文件、跑命令都很快,一个 Issue 的实现有时没多久就能写完。

但真实画面通常是这样的:代码改完了,后面还要完整编译、部署到虚拟机、启动产品、跑自动化测试。测试一旦失败,还得先判断是实现错了、脚本错了、虚拟机状态不对,还是单纯的环境抖动。判断完再修,再编译,再部署,再跑一次。

一轮性能测试就可能要五六分钟,长一点甚至超过十分钟。只要重复两三轮,实际写代码的时间反而成了整个 Issue 里最短的一段。

这就很尴尬了。

第三篇开发日记里,我还在想“什么才算真正完成”。到了第四篇,问题变成了另一面:如果每次都要把整个产品重新证明一遍,一个 Issue 到底什么时候才能结束?

一、第一次觉得 AI 慢,确实是产品把它拖慢了

这不是我第一次觉得 AI 开发效率低。

前一次的原因比较直接:Vestigra 当时有严重的 Runtime 性能问题。产品运行时间越长,各种执行事件越慢,文件读写也越来越慢。

AI 的开发活动并不是飘在空中的。它同样要读文件、搜代码、写 diff、调用编译器和执行测试。底层环境开始卡以后,它的每一步都会跟着卡:

  • 搜索代码变慢;
  • 读取和修改文件变慢;
  • 编译、部署变慢;
  • 测试结果也迟迟回不来。

当时我把问题归到产品性能瓶颈上,这个判断并没有错。无论操作电脑的是人还是 Agent,只要文件系统和执行环境越来越慢,开发都不可能快。

后来这一轮性能问题处理掉了,我原本以为开发速度会立刻恢复。

结果并没有。

文件能正常读了,命令也不再慢吞吞,但一个 Issue 从开始到真正结束,还是要花很久。

这次拖住它的已经不是产品性能,而是验证。

二、真正耗时的,开始从“写代码”转移到“证明代码”

Vestigra 现在已经积累了一套覆盖面不小的测试:

  • Smoke 测试;
  • 基础功能测试;
  • 真正启动产品、验证实际行为的功能测试;
  • Ring0 测试;
  • 性能测试;
  • 回归测试;
  • 针对历史 Bug 留下来的自动化脚本。

这些测试单独拿出来都很有价值。它们能防止我只证明“代码可以编译”,却没有证明产品在真实 Runtime 里还能工作;也能防止前面辛苦修过的问题,过两轮开发又偷偷回来。

但我最开始犯了一个很朴素的错误:

既然这些测试都有价值,那就每完成一个 Issue 全跑一遍。

于是开发闭环逐渐长成了这样:

1
2
3
4
5
6
7
8
实现 Issue
→ 完整编译
→ 部署到虚拟机
→ 启动产品
→ 执行自动化测试
→ 分析失败原因
→ 修复或调整
→ 重新编译、部署和测试

自动化测试只要报错,AI 就不能简单地说“失败了”。它还得继续查:

  • 当前实现是不是真的有问题;
  • 测试脚本是不是写错了;
  • 虚拟机是不是残留了上一轮状态;
  • 产品有没有正确启动;
  • 这次性能波动是不是偶发噪声。

有时候查到最后,代码根本不需要改,只是环境要重置,再跑一次。

有时候确实是代码问题,那就得把整条编译、部署、启动和测试链路再走一遍。

所以“代码写完”和“Issue 结束”完全是两回事。AI 写得再快,也不能跳过后面那段昂贵的证明过程。

三、测试越完整,我反而越容易把每个 Issue 困住

以前我会下意识地把测试覆盖率和质量画上等号。覆盖得越多,心里当然越踏实。

但真实跑起来以后,我发现自己混淆了两件事:

1
测试覆盖率 ≠ 测试执行频率

一套测试应该保留,不代表它必须在每一个开发节点都执行。

尤其是性能测试。它本身就要跑五六分钟,有时超过十分钟,而且对机器状态、采样窗口和 Runtime 环境都比较敏感。一次失败消耗的不只是十分钟,还包括读日志、判断原因、调整环境和再次执行。

两三轮下来,一个很小的 Issue 也能被拖成一场持久战。

于是我做了一个一开始听上去很危险的决定:

把大多数自动化测试从单个 Issue 的默认开发链路里拿出去。

这里的“拿出去”不是删除,更不是以后不测了。

我仍然要求开发阶段完成必要编译、部署,并把产品真正启动起来。当前 Issue 的关键逻辑也必须在 Runtime 里跑通,不能退化成“编译成功就算交差”。

我拿掉的,是每次局部修改之后都重复执行整套性能、回归和广覆盖测试的要求。

测试没有变少,只是被放到了不同的节点。

四、AI 不下班以后,Nightly 这个天然窗口消失了

以前人写代码时,长测试有一个很自然的去处:Nightly。

白天开发,下班后让 CI 跑性能测试和完整回归。第二天人回来,再看报告、修问题。人的工作时间结束以后,机器正好接管耗时验证。

AI 没有这个节奏。

一个 Agent 做完当前 Issue,可以立刻做下一个。开发过程不会因为晚上到了就自然停止。如果完整测试还在等待“下班以后再跑”,那它可能永远等不到一个明确窗口。

可如果每个 Issue 后面都跑,AI 就会被测试链路反复堵住。

这不是简单地选择“要效率”还是“要质量”。真正要重新设计的,是完整验证到底跟着什么触发:

  • 跟着每一次代码修改?太重;
  • 跟着每一个 Issue?还是太频繁;
  • 跟着人的作息?AI 又不下班;
  • 跟着一个明确的阶段性交付?目前看更合理。

所以我开始把“开发完成”“Issue 验收完成”和“阶段性交付完成”彻底拆开。

五、我现在把验证拆成三个层次

现在这套流程,大致被我分成了三层。

第一层:Issue 开发

负责实现的 Agent 完成当前 Issue,并做必要的编译、部署和核心运行态验证。

这一层追求快速反馈,但不等于只做静态检查。产品必须真的启动,当前改动影响的关键链路必须真的执行。

这里不再默认运行全套性能测试、回归测试和历史 Bug 脚本。

第二层:单个 Issue 的独立验收

实现完成以后,交给独立验收者,只回答一个具体问题:

这个 Issue 是否满足自己的验收标准,并且在干净环境里真的能工作?

它关注的是局部正确性,不负责顺手证明整个 Vestigra 在所有维度上仍然正确。

第三层:Sprint、里程碑或阶段性目标的完整验收

只有一个阶段里的所有 Issue 都完成开发,并且逐个通过独立验收以后,才统一执行完整自动化测试。

这一层才会跑:

  • Ring0 测试;
  • 广覆盖产品功能测试;
  • 性能测试;
  • 回归测试;
  • 针对历史 Bug 保留下来的自动化脚本。

如果这里发现问题,就创建新的 Issue,重新进入开发和独立验收,而不是假装前面的局部验收没有价值。

现在三个“完成”的关系变成了:

1
2
3
开发完成
≠ Issue 验收完成
≠ 阶段性交付完成

它们不是重复做同一件事,而是在证明不同范围的正确性。

阶段 主要回答的问题 验证范围
Issue 开发 当前实现是否基本可用 必要编译、部署、核心运行态验证、当前 Issue 直接相关测试
Issue 独立验收 当前 Issue 是否满足自己的验收标准 干净环境中的定向功能验证
Sprint / 里程碑验收 这一批变更有没有破坏整体产品 Ring0、广覆盖功能、性能、回归和历史 Bug 测试

六、AI 还把我的意思理解错了一次

我第一次把这套流程讲给 AI 时,它给出的方案看上去很接近:开发阶段不跑完整测试,等验收完一个 Feature,再跑一次完整自动化。

我看完以后发现,还是不对。

它只是把完整测试从“每个 Issue 开发完成后”,挪到了“每个 Feature 验收完成后”。名字换了,频率并没有真正降下来,原来的效率问题还在。

我真正想要的是:

  • 验收单个 Issue 时,只验证这个 Issue 本身;
  • 一个阶段里的所有 Issue 都验收完成以后,再统一执行广覆盖测试;
  • 完整测试服务于阶段性交付,不服务于每一个局部变更。

这次误解反而帮我把验证粒度想得更清楚了。

以后我不能只对 Agent 说“开发和验收分开”,因为这句话太容易被形式化执行。真正需要写进流程的是:每一层验收拥有什么范围、由什么条件触发、失败以后回流到哪里。

否则 AI 会非常认真地执行一套看起来分层、实际上仍然很重的流程。

七、两套虚拟机,分别证明“从零开始”和“长期活着”

Vestigra 的开发和验证现在还涉及两套不同环境。

第一套是干净虚拟机。

每个 Issue 完成以后,产品要部署到这套环境里。它不保留上一轮安装和开发留下来的状态,主要回答:

当前实现能不能在一个全新的环境里安装、启动和运行?

第二套是持续运行的虚拟机。

它不会在每个 Issue 后重置。产品持续运行,状态持续积累,等到新的里程碑版本形成后,再部署进去做阶段性验证。

这套环境主要观察另一类问题:

  • 长期运行以后会不会逐渐退化;
  • 多轮升级以后旧状态会不会污染新版本;
  • Runtime、队列和数据是否会随时间积累出问题;
  • 干净环境里看不出来的连续性问题会不会再次出现。

一套验证“从零开始”,一套验证“长期活着”。

两套环境都需要,但没有必要让每一个 Issue 同时承担它们的全部成本。

八、走向多 Agent 之前,我得先看清时间花到哪里了

目前我还没有真正开始多 Agent 并发开发。

单 Agent 慢的时候,我多少还能靠感觉发现:它是不是在某一步停了太久,某个测试是不是重复失败,编译和部署是不是明显不正常。

多 Agent 就不一样了。

多个任务一起跑,Issue 在变化,日志不断刷,编译和测试到处发生。整个系统看起来会非常忙,但“很忙”不等于“很快”。某些 Agent 可能已经困在失败重试里,只是被并发制造出来的热闹遮住了。

所以在扩大并发以前,我还需要给 AI 开发系统补一层最基本的可观测性:

指标 我想回答的问题
编译耗时 时间是不是主要卡在构建和工具链
Issue / Feature 开发耗时 实际实现到底花了多久
单个 Issue 验收耗时 局部证明的成本有多高
完整测试耗时 阶段性交付的整体证明有多重
失败分析与重试耗时 多少时间消耗在无效循环里
不同环境的部署耗时 干净环境和持续运行环境分别带来多少成本

这套效率追踪现在还没有真正做完。我只是已经确认,不能等到多 Agent 全部跑起来以后,再靠肉眼猜哪里慢。

代码系统需要 observability,AI 开发系统同样需要。

目前的结论:写得快,不等于交付得快

回头看,这两次“AI 怎么这么慢”,其实是两个完全不同的问题。

第一次是环境瓶颈。Vestigra 自己的性能退化,把读写、编译和执行全部拖慢了。

第二次是验证瓶颈。产品逐渐成熟,测试越来越完整,证明一个改动可靠的成本开始超过写出这个改动的成本。

我现在做的不是减少质量保障,而是重新安排质量保障发生的时机:

  • 单个 Issue 尽快获得真实运行反馈;
  • 独立验收只证明当前 Issue;
  • 完整测试留给 Sprint、里程碑或阶段性交付;
  • 干净环境负责可重复性;
  • 持续运行环境负责连续性;
  • 最终再用数据看清开发、验证和重试到底各自花了多久。

AI 不会疲劳,也不会主动下班,但编译、部署、启动、性能测试和失败重试的成本不会因此消失。

当写代码越来越便宜以后,真正昂贵的已经不只是设计“什么才算完成”,还包括设计“要在什么时候、用多大成本,证明它真的完成了”。

这是我目前给 Vestigra 开发流程划下的新边界。

等效率追踪和多 Agent 并发真正跑起来以后,这套边界大概还会再被现实推翻一次。