posts/cursor-builds-warm-agents.md
Cursor builds 快 3 倍,最值钱的是失败不生效
一个云端 Agent 还没读到 issue,先花了几分钟安装依赖。
克隆仓库、跑 pnpm install、拉 Docker 镜像、生成代码、编译几个本地包。模型一个 token 都没吐,机器已经忙成了工地。要是同一时间启动十个 Agent,十台机器再把这套仪式各演一遍。
这两天 Cursor 推出了 builds,把这些动作提前放到后台做。它会持续准备可直接启动的开发环境副本,新 Agent 不再从空机器起步。Cursor 给出的数字很抓眼,内部环境启动快了 10 倍,首个 token 最快提前 3 倍。
好家伙,冷启动终于有人认真治了。
但我看完整篇发布和 Builds 文档 后,最在意的不是 3 倍。真正值钱的是另一句,新 Build 如果失败,不会替换正在使用的环境,Agent 会继续从最近一次成功的 Build 启动。
让 Agent 起跑快,解决的是等待。让坏环境不能晋级,解决的才是交付。

首个 token 只是表面账
云 Agent 的等待时间很容易被低估。
大家平时盯模型延迟,首个 token 几秒出来,生成速度每秒多少 token。可工程任务开始前,还有一段不属于模型的灰色时间。机器要启动,仓库要克隆,依赖要下载,私有包要鉴权,代码生成器要跑完,测试数据库也得站起来。
这些动作单看都不神秘,叠在一起就很烦。更麻烦的是,它们会跟并发量一起复制。一个 Agent 冷启动两分钟,十个 Agent 不是大家一起等两分钟那么简单。它们可能同时挤包仓库、镜像仓库和构建缓存,把偶发网络抖动放大成一排失败任务。
Cursor 的做法并不玄学。Build 在后台克隆默认分支,执行安装命令,保存磁盘状态、环境版本和每个仓库对应的提交 SHA。成功后,它成为活动环境,平台保留一份预热副本。新 Agent 从正在运行的机器分叉,不必每次都从磁盘和网络重新拼一套世界。
官方还引用了 Faire 的使用数据。他们每周启动超过 2,000 次自动化 Agent 运行,复杂仓库已经能在几秒内启动。这个量级下,少等几十秒当然很香。可如果只把 builds 理解成更大的依赖缓存,还是看窄了。
缓存回答的是「能不能少做一遍」。生产系统还得回答「这份东西凭什么能用」。
失败不能晋级,比缓存更重要
一个依赖更新把安装脚本弄坏,新的 Dockerfile 少复制了一个配置,私有包凭证过期。传统的即时启动会把这些问题直接甩给下一次任务。Agent 接到修 bug 的活,结果半小时都耗在修自己的开发环境上。
更糟的是,不同任务可能撞到不同失败。有人命中旧缓存,有人拉到新依赖,有人恰好赶上包仓库超时。你看到三个 Agent 给出三个结果,第一反应也许是模型不稳定,实际是三块跑道根本不一样。
Cursor 给 Build 加了一条很朴素的发布规则。触发、准备、快照、激活。只有成功完成安装的快照,才会成为新的活动 Build。失败版本有日志,可以单独启动 Agent 去复现和修,但不会偷偷顶掉上一份可用环境。
厉害了,这已经不是启动优化,而是给开发环境补了一条 CI。
应用代码合并前要过测试,容器镜像发布前要过扫描,Agent 环境也该有自己的晋级门。它至少要证明仓库能克隆、依赖能装完、生成步骤能执行、关键服务能拉起。证明不了,就留在草稿区,不许当成整个团队的新地板。

这里还有个容易被忽略的细节。每次 Agent 运行都会记住自己用了哪一个 Build。Build 又记录环境版本和各仓库的确切提交 SHA。以后一个任务昨天能跑、今天跑不了,不必只盯 prompt 和模型版本,也能沿着环境版本往回查。
很多 Agent 平台的可观测性只记了模型、token、工具调用和最终答案。环境却像空气,出问题前没人觉得它需要版本号。等到 node-gyp、系统库、浏览器版本或者某个生成器变了,大家才发现那次成功根本复现不出来。
段错误。
Agent 的运行轨迹不只是一串消息,它还应该绑定一块可重放的地面。
安装和启动,得拆成两种命令
预构建环境最容易踩的坑,是把所有东西都塞进快照。
Cursor 在文档里把命令分成三类。install 在每次 Build 时执行,用来安装依赖、生成代码、编译产物和预热磁盘缓存。start 与 terminals 在每次 Agent 运行时执行,用来启动 Docker、数据库、隧道和共享终端里的应用进程。
这条边界很关键,因为 Build 只保存磁盘状态。正在运行的进程、shell 临时导出的变量和内存缓存,快照时都会停掉。把数据库启动塞进安装阶段,看着构建成功,Agent 真正醒来时只会得到一堆没有进程接手的文件。
我自己的判断是,迁移前先把环境动作按寿命拆开。
几小时甚至几天都不变的依赖下载、编译产物和工具安装,适合进 Build。每次会话都要重新确认的分支代码、临时端口、数据库进程和隧道,留在启动阶段。只对单个任务有效的访问令牌、工单编号和用户身份,更不能烤进共享快照。
这里顺手带出另一个硬要求,安装命令要幂等。也就是同一条命令多跑几遍,结果应该一致,不会因为目录已经存在就翻车,也不会重复写出一堆脏状态。Cursor 的 Builds 文档 明确要求 install 能重复运行,而且它可能基于已准备过的磁盘状态继续执行。
如果一条 setup.sh 只有在全新机器上才能成功,它不是自动化脚本,只是一段碰巧跑通过的回忆。
密钥别跟着快照一起旅行
环境预热越彻底,越容易有人想把凭证也提前塞进去。否则私有包拉不下来,内部 artifact 取不到,构建还是会卡住。
可共享快照一旦混进个人密钥,速度问题解决了,安全事故开始排队。
Cursor 的处理方式值得抄作业。Build 可以使用团队级和环境级密钥,满足私有注册表、artifact 存储和安装阶段的访问需求。用户密钥只在 Agent 启动时注入,不会出现在共享快照里。此前 Cursor 在 云 Agent 开发环境 里也给 Dockerfile 增加了构建密钥支持,密钥只作用于构建步骤,不会进入运行环境。
这不是产品细节,是环境合同的一部分。能被整个团队复用的凭证,才有资格参与构建。属于某个人、某个工单或某次会话的权限,只能在运行时短暂出现。
同一条思路还能延伸到网络出口。开发环境不该默认拥有整个公司的网络视野。Cursor 支持按环境限制出站域名,并把密钥作用域隔离在单个环境。一个只需要改前端文案的 Agent,没必要顺手拿到生产数据库和财务系统的入口。
说真的,让 Agent 快速拿到一把万能钥匙,确实也能快 3 倍。快进事故现场。
快照会过期,稳定不能变成陈旧
保留最近成功版本听着很稳,但它也有代价。
如果默认分支上午已经合了十个提交,Agent 下午还从昨天的 Build 起跑,它可能在一套过期代码上认真修一个已经不存在的 bug。稳定和新鲜度天然有拉扯,不能只选一个词写进宣传页。
Cursor 给默认分支 Build 配了过期阈值,默认是 24 小时。超过阈值后,Agent 启动时可以拉取最新代码。阈值设成 0,每次都会更新。功能分支则复用 Build 里的依赖和磁盘状态,再检出指定分支。如果分支改了依赖,Agent 仍要在测试前刷新环境。
这个设计有点子牛逼的地方,是它没假装快照能冻结整个软件世界。Build 固定的是一个可验证起点,不是宣布依赖和代码从此停止变化。
团队迁移时真正要定的是一份新鲜度预算。一天只改几次的后端服务,24 小时或许够用。每小时几十次合并的 monorepo,24 小时就像拿上周的地图开今天的路。依赖锁文件变更、基础镜像安全更新、环境密钥轮换,也都应该主动触发重建,别全等定时器来捞。
另外,失败回退不能静默太久。一直用最近成功版本确实不会中断任务,但如果连续三天构建都失败,团队其实已经欠下了一笔环境债。面板要告警,Build 年龄要进监控,任务结果也该把环境年龄带上。
能回退,不等于可以装作没坏。
上线前,先写一张环境合同
8 月 17 日起,Cursor 会为新旧环境默认启用 builds,而且不额外收费。开关变成默认值之前,我建议别急着看那条 3 倍曲线,先把自己的环境合同写出来。
它不需要很长,能回答这些字段就够了。
build:
source_commit: <每个仓库的提交 SHA>
environment_version: <环境版本>
install_command: <可重复执行的安装命令>
success_checks: <依赖、生成、编译与基础测试>
secret_scope: <仅团队级或环境级>
stale_after_hours: <允许的代码陈旧时间>
runtime:
start_command: <每次会话启动的服务>
user_secrets: <只在运行时注入>
network_allowlist: <任务真正需要的出口>
build_id: <本次任务绑定的 Build>
这不是 Cursor 官方模板,是一份可以直接改的最小验收单。配置放进 .cursor/environment.json 或团队自己的环境仓库都行,重点是它要能评审、能回滚、能跟任务结果关联。
指标也别只记首个 token。
环境准备时间能告诉你预热有没有生效,Build 成功率能暴露安装链路是否健康,活动 Build 年龄能提醒代码是否陈旧,任务首轮通过率与人工接管率才接近真正交付。再把失败按模型、工具、代码和环境分开,团队才不会把 npm install 超时算到模型头上。
可以用一个很粗但好用的式子看总账。
有效交付时间
= 排队时间
+ 环境准备时间
+ Agent 执行时间
+ 失败重试与人工接管时间
builds 主要砍掉第二项,也会通过稳定环境减少第四项。至于任务能不能完成,仍取决于模型、工具权限、测试质量和验收规则。预热环境不是魔法,只是终于把一块长期被忽略的工程地基补上了。
坦率讲,我喜欢这类更新胜过又一个榜单冠军。模型多涨两分,大家会刷屏一天。把环境做成有版本、能晋级、可回退的制品,没那么性感,却会在接下来几个月里少掉很多莫名其妙的失败。
开头那台忙着装依赖的机器,终于不用每次都从空地搭工棚了。
但更重要的是,坏掉的工棚不会被挂上「标准环境」的牌子。