Anthropic 工程团队指出 AI Agent 显著增加了 CI 负载,加速流水线反而治标不治本;提出应从架构层面重新思考 CI 瓶颈问题。
九月有三篇帖子值得工程负责人放在一起读。
Anthropic 的工程团队写道,他们的持续集成(CI)任务量在六个月内增长了 25 倍。他们的工程师现在每个季度提交的代码量是 2021 年到 2025 年期间的约 8 倍。他们推出的解决方案是测试影响分析:只运行可能受变更影响的测试。
一周后,Linear 发表了一篇帖子,标题是《AI 编程让 CI 成了瓶颈》。他们的测试套件自一月以来几乎翻了两番,而且代理现在写掉了大部分测试。他们对流水线进行了端到端的重构以跟上需求。
然后 Depot 的 CEO 写道,CI 正在发生变化,未来的方向是"给代理一种验证代码并在其工作过程中维持信任的方式"。
Anthropic 和 Linear 都不卖 CI 工具。他们汇报的是自家流水线上发生的事,这正是值得引起重视的原因。以下是我的解读:三篇帖子对问题的判断都是对的,但其中两篇在修错误的层级。
二十年来,CI 的规模一直是按人类输出量来设计的。一个开发者每周开几个 PR,流水线在每次 PR 之后运行一次。如果花了 20 分钟,没人在意,因为开发者已经在做下一个任务了。
代理从两个方面打破了这个算术。第一是量。当一个工程师并行运行多个代理时,PR 数量是按倍数增长的,而不是百分比。Anthropic 的 25 倍数字并不是个例。销售 CI 运行器的 Blacksmith 表示,他们运行的 CI 任务数量每周增长 5% 到 10%。
代理很快,但围绕它的循环很慢。
第二是位置。CI 在 PR 存在之后才运行。一个代理写完代码、开了 PR、然后等 20 分钟看红色检查结果,在这期间它已经丢失了工作上下文。每一次失败都要走完一整个往返。代理很快,但围绕它的循环很慢。
所以业界做了显而易见的事:让 CI 更快。更快的运行器、更智能的测试选择、更大的缓存、代理可以在提交前调用的流水线。所有这些都有帮助,也都是必要的。但所有这些都没有触动一个前提:你正在验证的是一个代码仓库。
对于一个独立应用,代码仓库就是系统。跑完测试,你就知道了你需要知道的大部分东西。
对于云原生系统,代码仓库只是四十个服务中的一个。该仓库里的测试只测试那个服务,其他一切都用 mock。一个变更可以通过每一个单元测试、以创纪录的速度通过 CI、通过从该分支构建的沙盒,但仍然在第一个跨越服务边界的真实请求上挂掉。
在分布式系统中,真正造成伤害的失败发生在接缝处。响应里改了个字段名,但下游消费者还在读旧名字。一个服务里收紧了超时设置,级联到别处引发重试。Schema 变更在测试 fixture 下能工作但在预发布环境锁住了表。新端点在测试工具调用时行为正确,但在依赖它的服务调用时行为错误。
CI 流水线里没有任何东西——快的还是慢的——能看到这些。它做不到,因为它只看一个仓库。
这就是为什么我认为九月的那些帖子是症状,而不是诊断。CI 变慢是因为验证从人工关卡变成了自动关卡,但没有人问过这个自动关卡检查的是什么。把关卡加快并不会改变它检查的内容。
代码更快了,验证还是老样子,破坏却更多了。这就是那个 gap。
DevOps Research and Assessment(DORA)发现了一个应该让你担心的事实:AI 采用率越高,软件交付吞吐量和软件交付不稳定性都在增加。代码更快了,验证还是老样子,破坏却更多了。这就是那个 gap。
Cursor 在二月提了一个观点,现在正变得越来越重要。他们的代理运行在云沙盒里,每个沙盒都有自己的虚拟机,现在 Cursor 合并的 PR 中有超过 30% 来自以这种方式工作的代理。他们明确给出的理由是:"如果无法使用自己正在创建的软件,代理就会触到天花板。"
这是正确的直觉。代理必须运行代码,而不只是写代码。每一个严肃的编程代理现在都在做某种版本的这件事。GitHub 的 Copilot 云代理在由 GitHub Actions 驱动的临时环境中运行测试。Codex 运行一个 setup 脚本并恢复缓存的容器。Devin 从环境蓝图启动。Greptile 的 TREX 运行分支并将日志和截图附加到 PR 上。
但看看这些沙盒各自包含什么:仓库、分支,以及 setup 脚本能安装的东西。没有任何一个包含其他 39 个服务、真实的消息队列,或者有生产形态数据的数据库。
所以循环闭合了,但它闭合在错误的东西上。
所以循环闭合了,但它闭合在错误的东西上。代理针对自己代码的副本验证它的变更。然后变更进入 CI,后者针对同样的副本验证它,只是更快。然后它合并到预发布环境,而那才是第一次有东西检查它是否与系统的其他部分配合工作。
对于分布式系统,PR 之前的验证必须针对系统,而不是仓库。这是那个转变。这不是在同一个问题上给出更快的反馈,而是一个不同的问题,只是问得更早了。
本能的反对意见是成本。如果每个代理都需要整个系统来验证,而一个工程师在运行五个代理,你就需要每个工程师配五个预发布环境。没有人负担得起,也没有人应该尝试。
答案和二十年前业界应对计算资源的方式一样。你不是给每个工作负载自己的机器,而是做复用。
一个 Kubernetes 集群可以运行每个服务的一个共享稳定版本,并在其上托管数千个轻量级测试环境。每个测试环境只部署变更的服务。标记为该环境的请求会经过修改过的服务,而其他每一跳都解析到共享的稳定版本。修改过的服务连接真实的依赖项,而那些依赖项完全感知不到任何变化。
一个测试环境的成本大约相当于一个 pod 的价格,而且它在几秒内就能启动。50 个并行工作的代理共享一个稳定环境,而不是把它克隆 50 份。这才使得在代理循环内进行系统级验证变得负担得起。
又便宜又快的环境不是全部答案。代理还需要一种结构化的方式来使用它们:发这个请求、捕获那个日志、断言这个契约成立了、报告结果。如果放任自流,每个代理都会发明自己的检查方式,没有两次运行是可比的。
有效的模式是:平台团队把这些步骤写一次,作为一系列批准的操作,对活跃系统执行变更并记录发生了什么。代理通过 Claude Code、Cursor 及类似工具已经支持的 skills 和 hooks 来调用它们,这样验证就作为循环的一部分运行,而不是循环之后才运行。治理和步骤本身一样重要,因为平台团队需要知道一个代理在共享集群里无法做不安全的事。
输出也很重要。一条记录显示发出了哪些请求、触及了哪些服务、哪些契约成立了——这是下一层可以读取的产物。审查工具和合并关卡可以看到一个变更在人工查看之前已经在真实服务上执行过了,CI 变成了一个确认步骤,而不是跨服务破坏第一次出现的地方。
我预计 CI 厂商会继续让 CI 更快,我也预计编程代理会继续变得更擅长在沙盒中运行代码。两者对所有人都有好处,但两者都没有消除仓库和系统之间的那个 gap。那些最终胜出的团队不会再问流水线能以多快的速度确认一个仓库仍然通过自己的测试,而是会问一个代理能在多早的时候证明一个变更与周围的一切配合工作。这个问题的答案只有一个地方:在代理的循环内部,针对真实系统,在 PR 之前。我们构建 Signadot 就是为了让这种检查变得足够便宜,可以在每次变更上运行,并且是有治理保障的。