AI 编程之后,CI 成了新瓶颈

AI 编程把代码生成速度推上去后,Linear 发现真正拖慢交付的已不是写代码,而是等待构建、测试和合并。它重做 CI 的思路是:减少无效运行、提高并发、拆分慢任务,并把流水线健康度变成可观测数据。
AI 编程之后,CI 成了新瓶颈:Linear 如何重做持续集成系统
近日,Linear 分享了重做持续集成(CI)系统的过程。原因并不复杂:AI 编程工具让开发者和代码代理可以更快地产生更多变更,但原本为“人类偶尔提交代码”设计的 CI,开始承受远高于过去的提交、拉取请求和测试任务数量。
持续集成(CI)是指代码变更提交后,系统自动完成构建、测试和验证,以确认新代码能够安全合并。它原本是软件交付链路里的加速器,如今却可能变成 AI 编程时代最明显的等待环节。
Linear 的判断值得关注:AI 编程并没有削弱 CI 的价值,反而把 CI 从后台基础设施推到了交付效率的正中央。写代码的成本下降之后,团队会更频繁地提交、更快地打开 PR,也更愿意让代码代理反复修改同一个问题。只要每次验证仍然需要排队十几分钟,生产力提升就会在 CI 阶段被重新吃掉。

AI 编程改变的不是一条流水线,而是流水线的负载模型
AI 编程带来的核心变化,是代码变更数量和变更频率同时上升。
传统团队的 CI 往往默认几个前提:开发者提交代码的频率有限;一个 PR 会经历几轮修改;大多数构建任务在工作日均匀分布;测试失败通常意味着代码本身存在问题。但 AI coding agent 加入后,这些前提都不再稳定。
一个代理可能在几分钟内生成多个候选修复,连续推送多次提交;开发者也可能让多个代理并行处理不同任务。对代码仓库来说,这不是“多了几个开发者”,而是突然多出了一批持续制造变更的自动化客户端。
这会造成三个直接后果:
- CI 运行次数增加。 每一个候选修改都需要重新构建和测试,提交量增长会线性推高流水线运行量。
- 并发需求增加。 如果多个开发者和代理同时提交,单个构建任务变慢只是第一层问题,更大的问题是任务会在队列里等待。
- 失败噪声增加。 测试失败、基础设施故障、依赖下载失败和不稳定测试混在一起,工程师需要花更多时间判断到底是谁出了问题。
这也是为什么“把 runner 配得更大”通常不够。计算资源不足只是瓶颈的一种,缓存失效、测试拆分不合理、任务依赖过重、重复运行无效检查,同样会把 CI 变成排队系统。
从排队论角度看,CI 的体验取决于两个数字:单次任务的服务时间,以及任务进入系统的速度。当任务到达速度接近或超过系统处理能力时,队列等待时间会急剧上升。哪怕平均构建时间没有变化,开发者感知到的反馈速度也可能明显恶化。
Linear 的重做重点:不只是加机器,而是减少浪费
Linear 重做 CI 的关键思路,是把“每次变更都完整跑一遍”改成“只运行有必要的验证,并让必要的任务尽快完成”。
这听起来像常识,但落地时涉及流水线编排、依赖缓存、测试拆分、任务调度和失败诊断多个层面。真正有效的 CI 优化,不是简单地把一条 20 分钟流水线压到 18 分钟,而是同时降低无效运行比例和队列等待时间。
第一,优先处理排队,而不是只优化执行时间
CI 队列是 AI 编程时代最容易被低估的瓶颈。过去,工程师可能认为“这条测试 10 分钟跑完”就已经可以接受;但当同一时间有几十个变更进入系统,真正的反馈时间可能变成 10 分钟执行加 15 分钟排队。
Linear 的重做将并发能力放在重要位置。不同类型的工作负载需要不同的资源池,快速的静态检查不应该和重量级集成测试争用同一批执行资源。任务调度也不能只按照提交顺序排队,否则一个慢任务就可能阻塞大量更快、更重要的检查。
更合理的做法是把 CI 看成分层调度系统:
- 代码格式、类型检查和静态分析优先返回结果;
- 单元测试按模块拆开并行执行;
- 数据库、浏览器或外部服务相关的集成测试使用独立资源;
- 长时间运行的回归测试不阻塞最小合并检查;
- 合并队列根据变更优先级和资源情况动态安排任务。
这类设计的目标不是让所有任务都变快,而是先让最影响开发者决策的结果尽快出现。
第二,把测试并行化从“技巧”变成系统能力
测试并行化是指把一组测试拆成多个可以同时运行的任务,从而缩短总耗时。它是 CI 扩容最直接的手段,但前提是测试之间没有隐藏的共享状态和资源冲突。
许多团队的测试套件看起来可以拆分,实际却依赖同一个数据库、同一份临时文件或固定端口。结果是任务数量增加了,互相等待和重试也增加了,最终并没有获得预期收益。
Linear 的经验说明,并行化不能停留在“开更多 runner”这一层。系统需要知道每个测试文件过去的执行时长和失败情况,再按照历史数据尽量均匀地切分任务。否则,一个 shard 里塞满慢测试,其他 shard 提前结束,整体耗时仍然由最慢的那组决定。
可以用一个简单的例子理解这一点:假设 1,000 个测试总共需要 20 分钟。如果平均拆成 10 组,理论上可以降到约 2 分钟;但如果其中一组需要 8 分钟,其他组只需要 2 分钟,实际流水线仍然至少要等待 8 分钟。好的拆分系统要优化的是最长尾部,而不是简单平均数量。
第三,缓存必须覆盖真正昂贵的部分
缓存是指复用之前已经完成的构建或依赖结果,避免每次 CI 都从头下载和编译。它能显著减少重复工作,但缓存命中率比“是否配置了缓存”更重要。
AI 编程提高提交频率后,缓存失效的代价会被放大。一次提交可能只修改了一个前端组件,却因为锁文件、构建目录或缓存键设计不合理,触发整个依赖树重新安装,甚至重新编译所有包。
Linear 的做法强调缓存边界和缓存稳定性:依赖缓存、构建缓存和测试结果缓存应该分开处理;缓存键要与真正影响结果的输入相关,而不是把整个提交哈希粗暴地作为唯一键;同时还要防止不同任务并发写入同一份缓存导致污染。
缓存并不是越多越好。过期缓存会制造隐蔽错误,错误共享缓存可能让测试拿到不属于当前提交的产物。因此,缓存系统必须具备失效策略、版本隔离和可观测性。工程师需要知道某次构建为什么命中或未命中,而不是只能看到“缓存步骤执行成功”。
第四,减少不必要的 CI 运行
选择性测试是指根据代码变更范围,只运行可能受到影响的测试,而不是每次都执行整个测试集合。它是解决 AI 生成大量小变更的重要手段。
但选择性测试并不等于简单地按照文件路径匹配测试。一个共享工具包的修改,可能影响几十个服务;数据库 schema 的变化,可能影响从后端到前端的整条链路。要做得可靠,系统需要维护代码模块、依赖关系和测试范围之间的映射。
因此,选择性测试通常需要与全量测试结合:在每个 PR 上先运行快速、相关的检查,合并前或定期任务中运行更完整的回归测试。这样既能缩短日常反馈,又不会因为错误的影响范围判断而永久漏掉问题。
这也是 AI 编程时代 CI 设计的一个基本原则:减少重复验证,但不能减少关键验证。
CI 可观测性:从“红了”走向“为什么红”
CI 可观测性是指对流水线的耗时、排队、失败、重试、缓存和资源使用情况进行持续记录和分析。没有可观测性,团队只能看到某个任务失败,却不知道失败来自代码、测试、基础设施还是调度系统。
当 AI 代理连续提交多个修改时,失败诊断尤其重要。一个测试失败后,代理可能立即尝试修复并再次提交。如果失败原因其实是测试环境不稳定,代理就会围绕错误信号继续改代码,最终制造更多无效变更。
Linear 的重做把流水线健康度当成产品指标,而不是运维后台里的附属数据。至少需要持续观察以下指标:
| 指标 | 它回答的问题 | 对 AI 编程的意义 | |---|---|---| | P50/P95 构建耗时 | 大多数和最慢的任务需要多久 | 判断平均体验和长尾体验是否恶化 | | 队列等待时间 | 任务开始前等了多久 | 识别并发资源是否不足 | | 缓存命中率 | 有多少工作被重复执行 | 判断缓存设计是否有效 | | 测试重试率 | 失败后重跑是否能通过 | 识别不稳定测试和环境问题 | | 首次失败定位时间 | 工程师多久能找到根因 | 衡量诊断系统是否减少噪声 | | 每次变更的 CI 成本 | 一个 PR 消耗多少计算资源 | 控制 AI 生成代码带来的基础设施账单 |
其中,P95 比平均值更值得关注。平均流水线时间可能只有 6 分钟,但如果最慢的 5% 任务经常超过 30 分钟,开发者仍然会把 CI 视为不可预测的黑盒。
不稳定测试也需要单独管理。所谓不稳定测试,是指同一份代码在没有变化的情况下,测试结果仍然时而通过、时而失败。它会直接破坏 CI 的信任:当工程师习惯性点击“重新运行”,CI 就不再是质量门禁,而变成了概率游戏。
与传统 CI 优化相比,Linear 的方案好在哪里
传统 CI 优化通常围绕几个熟悉的动作展开:增加机器、启用依赖缓存、拆分测试、减少构建步骤。这些方法仍然有效,但 AI 编程把问题从“如何让一次构建更快”推进到了“如何管理高频、并发、可变的变更流”。
两者的差异可以概括如下:
| 对比维度 | 传统 CI 思路 | AI 编程时代的 CI 思路 | |---|---|---| | 主要压力 | 单次构建耗时过长 | 提交量、并发量和重复运行同时上升 | | 优化目标 | 缩短流水线执行时间 | 缩短端到端反馈时间 | | 资源策略 | 提供更多固定 runner | 按任务类型动态调度资源 | | 测试策略 | 每次尽量跑完整套件 | 相关测试优先,关键节点保留全量回归 | | 缓存策略 | 缓存依赖和构建产物 | 追踪命中率、失效原因和结果隔离 | | 故障处理 | 人工查看失败日志 | 区分代码失败、环境失败和测试不稳定 | | 评价指标 | 成功率和平均耗时 | P95 延迟、排队时间、重试率和单位变更成本 |
Linear 方案最值得借鉴的地方,是它没有把 CI 当成单纯的计算问题。CI 的价值不是“跑完所有脚本”,而是让工程师尽快获得可信反馈。一个耗时较长但结果稳定、原因清晰的流水线,可能比一个偶尔很快但经常误报的流水线更有用。
这套方法并不是没有代价
选择性测试、动态拆分和更复杂的调度会增加系统复杂度。团队需要维护依赖图、测试元数据、缓存策略和资源池,CI 配置也可能从几份 YAML 文件演变成一套内部平台。
因此,并不是所有团队都应该马上照搬 Linear 的完整方案。规模较小的团队,首先应该解决最明显的问题:让快速检查先返回、清理不稳定测试、给慢任务做历史耗时统计,并确认缓存确实命中。只有当提交量、并发量和仓库规模达到一定程度后,才值得投入更复杂的测试影响分析和自研调度系统。
另一个风险是过度依赖 AI 来判断哪些测试应该运行。测试选择器可以帮助降低成本,但它本身也可能漏掉跨模块影响。对核心支付、权限、数据迁移和安全逻辑,团队仍然需要保留明确的全量验证和人工审查。
AI 能够帮助生成更多代码,也能帮助生成测试、分析失败日志和修复流水线配置,但它不能自动保证验证体系是完整的。验证系统本身也需要被测试、被监控和被定期审计。
对开发团队的三个直接建议
第一,先测量端到端反馈时间,不要只看“单个 job 跑多久”。从提交到开发者拿到可信结果,中间包括排队、资源准备、依赖安装、测试执行和失败重试。真正需要优化的是这段完整时间。
第二,把 CI 失败拆成三类:代码失败、测试失败和基础设施失败。三者混在一起时,团队会错误地把基础设施问题归咎于开发者,也会让 AI 代理在错误方向上持续修改代码。
第三,为 AI 生成的变更设置与人工变更相同甚至更严格的验证门槛。代码生成速度越快,越不能用“先合并、出了问题再修”的方式弥补测试不足。CI 的职责不是阻止开发,而是让快速开发仍然有边界。
结语:下一场 AI 基础设施竞争,可能发生在 CI 层
AI 编程最先改变的是代码生产环节,但真正决定团队能否把这种生产力转化为软件交付能力的,是验证系统能不能同步扩容。
Linear 重做 CI 释放出的信号很明确:当代码生成不再是瓶颈,构建、测试、排队和故障诊断就会成为新的瓶颈。未来的 CI 不会只是几台 runner 加上一组脚本,而会更像一套面向变更流的调度系统——它要知道哪些任务最重要、哪些测试真正相关、哪些失败值得重试,以及什么时候必须阻止代码继续向生产环境前进。
对开发团队而言,最值得记住的一句话是:AI 让写代码变快了,但只有更快、更可靠、可解释的 CI,才能让软件交付真正变快。



