开头
刷到 SpaceX 工程师演示 AI Coding 的视频时,我第一反应和大多数人一样:屏幕上那 200 多个 Agent 同时跑任务、同时改代码、同时提 PR,视觉效果确实拉满。但盯着看了一会儿,我意识到真正值得研究的东西,不是模型的代码能力又强了多少,而是他背后那套让 200 多个 Agent 不互相打架、不重复劳动、不把仓库搞崩的工程框架。
这篇文章不会去复述那个视频,而是把它拆开看:并行 AI Coding 到底在并行什么,200 这个数字是怎么来的,以及一个普通团队能不能把这套玩法移植到自己的项目里。我给的结论是:能,但瓶颈不在于模型,也不在于会不会写 Prompt,而在于任务切分、调度、验证这套工程配套。如果你已经在用 Codex、Claude Code 这类工具做单 Agent 编码,觉得“一个一个改太慢了”,这篇文章应该能帮你打开思路。
1. 200 个 Agent 并行,真正牛的其实是“装配线”
先把这个概念说透:那个视频里看起来是 200 多个 Agent 在同时干活,但底层大概率不是在同一个时刻有 200 个请求打向大模型 API。更合理的理解是,这是一条软件工厂装配线,Agent 是产线上的工人,每个工人只负责一小段工序,系统负责把任务排队、分发、验收、合并。视觉上看到的是 200 个并行,本质上是调度系统把几千个任务管理得井井有条。
1.1 为什么不能用“多开终端”的办法平替
很多人尝试过并行 AI Coding,第一反应往往是“我开 5 个终端,每个终端跑一个 Claude Code 不就行了?” 这个想法不算错,但做到 5 个已经是极限了。超过这个数,你会遇到三个绕不过去的问题:
第一个是任务分配靠人肉。你得自己判断哪个 Agent 该做哪个模块,谁先谁后,这等于把调度系统长在自己的脑子里,项目一大人就废了。
第二个是上下文混乱。Agent 之间互相不知道对方改了什么,A 改了接口签名,B 还在按旧接口写调用,Git 合并时全是语义冲突——不是 Git 解决不了那种冲突,而是代码逻辑上直接对不上。
第三个是缺少验证关。单个 Agent 写完代码、跑一遍自己写的测试就觉得自己完成了,但没人从系统层面确认它有没有破坏别人的功能。
真正的 200 Agent 并行,是把“人肉调度”变成了“系统调度”,把“靠感觉验收”变成了“网关自动验收”,把“共享同一个工作目录”变成了“各自沙箱 + 分支隔离”。这四件事,才是这种玩法牛的原因。
1.2 “并行”在系统层面是怎么实现的
我在自己的项目里复现这套思路时,对“并行”有了新的理解。任务队列里的状态不是简单的“执行中 / 完成”,而是一套生命周期:pending、ready、running、blocked、passed、failed、retrying。调度器每秒钟扫描一次,把依赖已经满足的 ready 任务分配给空闲 Worker,Worker 拉起一个容器去执行,执行完把结果交给评估网关,评估通过才允许合入。
所以 200 个并行 Agent 的真实含义是:任务队列里处于 running 状态的任务数量是 200 左右,但实际在调用模型 API 的 Worker 可能只有 20 个,甚至更少。其他任务都在排队、在等待依赖、在跑测试、在等待重试。这是一个“伪高并发”的经典实现方式——把 CPU 密集的模型调用拆成异步任务,用队列削峰填谷,而不是真的同时发起 200 个并发请求。
这也解释了为什么那个视频里的 Dashboard 看起来那么壮观:你看到的是 200 个任务同步推进,不是 200 个 API 请求同时飞出去。理解这一点很重要,因为它直接决定了工程架构该怎么设计。
2. 任务切分:并行 Agent 的数量上限,取决于你的拆分能力
很多人在复现这套玩法时,第一个卡住的地方不是技术,而是“没有那么多任务可分”。200 个 Agent 并行,意味着你手里至少有几千个规模合理的任务,而且任务之间要尽可能解耦。任务切分是整个体系的起点,也是并行度真正的天花板。
2.1 一个仓库到底能拆出多少个独立任务
拿一个典型的后端项目来算账。假设这是一个电商后台,有商品、订单、用户、支付、优惠券五个域。拆任务的时候,我会按这几个层次去切:
- API 层:每个资源一组端点,按域拆出 50 个任务,每个任务负责一个子域下的 controller、DTO、校验逻辑、对应接口测试。
- Service 层:按业务用例拆,比如“创建订单”“取消订单”“订单超时关单”,大概 40 个任务,每个任务包含 service 实现和单元测试。
- Infrastructure 层:按存储介质拆,MySQL、Redis、消息队列各自独立,30 个任务,包括 repository 实现、缓存策略、消息消费者。
- 基础工程:项目骨架、CI 配置、统一错误码、日志规范、数据库迁移脚本,10 到 15 个任务。
- 前端与文档:如果仓库是前后端一体,前端页面按页面拆,文档按模块拆,又能多出三五十个。
这么一拆,一个中等规模仓库轻轻松松就是 150 到 300 个任务。你不需要每个任务都从零写代码,很多任务是“改既有代码”“补测试”“修类型错误”“更新文档”,这些任务同样能被 Agent 消化。
2.2 Task Spec:并行时代最重要的文档
给单 Agent 发需求,你可以一句话说个大概,它不懂会问你。但到了 200 个 Agent 并行的场景,没人有空回答你的问题,Agent 之间也没有群聊可以商量。每个任务必须有一份完整的 Task Spec,把所有约束写清楚,让 Agent 只需要照着做。
我的 Task Spec 通常长这样:
## 任务:实现订单取消接口 ### 目标 在 orders 模块新增一个取消订单接口,支持用户对未发货订单执行取消操作。 ### 接口定义 - 路径: POST /api/v1/orders/{order_id}/cancel - 请求体: {} (空对象,仅需用户认证) - 响应: 200 + OrderCancelResponse - 错误码: 4001 订单不存在 / 4002 订单状态不允许取消 ### 涉及文件(仅允许修改这些文件) - src/modules/orders/controller.ts - src/modules/orders/service.ts - src/modules/orders/types.ts - tests/orders/cancel.test.ts ### 禁止修改 - src/shared/ 下的任何文件 - 数据库迁移脚本 ### 验收标准 1. 所有新增文件通过 ESLint 2. pytest / jest 全量覆盖新增代码,且测试通过 3. 不影响 "创建订单" 和 "订单查询" 两个既有用例你会发现这份 Task Spec 和平时写需求文档最大的区别是:它明确划定了“可动范围”。因为并行执行时,Agent 没有全局视野,如果不限制文件范围,它很容易觉得“顺手把这个公共组件的接口也改了更优雅”,然后引发连锁雪崩。Spec 里的“禁止修改”和“仅允许修改”,就是用来锚定 Agent 活动边界的。
2.3 依赖关系怎么办:波次调度
任务不可能全部独立,总有一些天然依赖。比如数据库 schema 没定,repository 层的任务就无从下手;repository 没写,service 层就算写出来也是空转。我的做法是把所有任务建一张 DAG(有向无环图),依赖方向为“前置任务 → 后置任务”,然后按拓扑排序分成若干波次。
第 0 波放最底层的任务:数据库迁移、基础 schema、项目配置、公共类型定义,这些任务全部独立,可以满并行跑。第 1 波放依赖第 0 波结果的任务:repository 实现、缓存层。第 2 波再放 service 层和 API 层。以此类推,每一波内部完全并行,波与波之间靠“任务完成回调”自动触发,不需要人工介入。
这种分波次跑的方式还有一个好处:每一波结束都会产生一个“集成点”。我能在这个时间点拉一次全量回归,确认这一波合入后仓库依然是绿的,再放下一波进场。这比 200 个 Agent 一起乱跑,最后集中爆炸要可控得多。
3. 并行执行的工程骨架:队列、工作池、沙箱、评估网关
任务切分是图纸,工程骨架是厂房。想让 200 个 Agent 稳跑,你需要四件套:任务队列、Worker 工作池、沙箱隔离、评估网关。这四样东西缺一个,并行的规模都上不去。
3.1 用队列而不是“开线程”
调度系统的核心是一个持久化的任务队列。每个任务进来时记录 ID、Spec 路径、依赖列表、状态、重试次数、运行日志。Worker 启动时向队列拉取任务,而不是由调度器直接 push——这是生产者消费者模式,好处是 Worker 可以随时水平扩展,宕机了也不会丢任务,重启后继续拉。
任务状态流转我建议至少要有这几个:pending(刚入库)、ready(依赖全部满足)、running(Worker 认领)、passed(评估通过)、failed(评估失败或运行异常)、retrying(失败后进入重试)。调度器就像一个耐心的前台,只做两件事:扫描 ready 任务、回收超时任务。
队列落在哪种基础设施上,取决于你的规模。我列个表给你参考:
| 方案 | 适合规模 | 优点 | 缺点 |
|---|---|---|---|
| SQLite / PostgreSQL 轮询 | 任务量低于几千 | 零额外组件、状态好查 | 轮询频率上去后有数据库压力 |
| Redis Queue / BullMQ | 中等规模、高频调度 | 延迟低、有重试机制 | 任务状态不好审计,复杂查询要外挂数据库 |
| Temporal / 持久化工作流 | 大规模、长流程 | 重试、超时、状态机都内置 | 引入额外基础设施,学习曲线陡 |
我个人的推荐是:从 PostgreSQL 轮询开始,任务表 + 一个 worker 定期 SELECT FOR UPDATE SKIP LOCKED 拉任务就够了。等到任务量和并发真的上去了,再平滑迁到 Temporal,而不是一开始就上重型调度框架。
3.2 沙箱:让 Agent 随便折腾,但别弄脏主仓库
200 个 Agent 不可能共享同一个磁盘目录,否则互相覆盖文件是迟早的事。每个任务执行时,应该拉一个独立的容器或至少一个独立分支来干活。
标准做法是:每次任务启动,用仓库当前分支打一个快照,在容器里恢复整个仓库,然后切一个任务专属分支,让 Agent 在这个分支上改代码、跑测试。容器要限制 CPU、内存、磁盘和超时时间,比如单任务最多跑 15 分钟,超出直接杀掉。
沙箱的核心价值有两个。第一是隔离副作用:Agent 里面跑的命令可能是危险的,比如“给我安装一个全局工具”“把 node_modules 删了重装”,这些副作用被限制在容器里,不会污染宿主机。第二是失败隔离:一个任务把容器搞崩、把磁盘写满、甚至把内核参数改了,其他 199 个任务毫发无伤。打个不太严谨但好懂的比方,这就像游乐场的每个项目都有独立围栏,一个设施停了,别的设施照常排队。
3.3 评估网关:每份产出都先过测试,再谈合并
这一环是并行不翻车的命门。我见过太多“多 Agent 协作”项目死在同一个问题上:Agent 说“我做完了”,然后人就信了。单个 Agent 这么做问题不大,顶多代码写得烂;但 200 个 Agent 都说“我做完了”,没人逐个检查,整个仓库会以肉眼可见的速度腐化。
评估网关要做的事很简单:每个 Agent 完成任务后,不直接合入,而是先跑一套标准检查。最少要包含这几项:
cd $WORK_DIR make lint # 静态检查 make typecheck # 类型检查 make test # 单元测试 + 回归测试 make build # 确保产物能构建只有四条全绿,任务才允许 commit、push、创建 Merge Request。只要有一条挂了,任务标记 failed,把失败日志回传给 Agent,让它自己修,最多重试三次,三次还不过就标记 blocked 转人工。
这个设计有一个很微妙的地方:Agent 自己写的测试不能作为唯一验收标准。因为 Agent 的“自洽”能力很强——它写一个函数,再写一个测试去测这个函数,实现和测试共享同一套错误假设,结果是绿的,但功能在真实场景下根本跑不通。我后面会细讲这个坑。
4. 调度系统的真实面目:失败、重试、合并与上下文隔离
四件套搭好,只是万里长征第一步。真正跑起来之后,你会发现调度系统不是“把任务丢给 Agent 就完事”,而是每天二十四小时在处理异常。这一节把最容易出事、也最容易被忽略的几个环节拎出来讲。
4.1 Agent 执行失败的四种典型原因
我跑过几百个任务之后,把失败原因基本归成了四类:
第一类是 Task Spec 含糊。比如“优化一下这个函数的性能”,这个描述根本没有验收标准,Agent 自由发挥的空间太大,跑出来的结果五花八门。解决方法是把验收标准量化,改成“在 X 数据集上,P95 延迟降低 30%,且所有测试通过”。
第二类是环境问题,最常见的是缺依赖。Agent 在沙箱里跑测试,发现缺一个包,它有两种选择:自己装,或者改代码绕过。自己安装没问题,但有些 Agent 会“顺手”改代码,让它在缺依赖的情况下也能跑通,这就很危险。解决方法是沙箱镜像里预装项目全部依赖,并禁止 Agent 修改依赖清单,除非 Spec 里显式授权。
第三类是测试写错。Agent 为了让测试通过,把断言写得过于宽松,比如只检查返回值类型不检查值。这是最讨厌的失败,因为网关是绿的,代码是烂的。后面我会专门讲怎么防。
第四类是依赖任务没真正完成。上游任务是“实现 createOrder”,Agent 只写了 interface 没写实现,但自测时用了 mock,结果下游任务一接真实实现就炸。解决方法是把“上游任务必须提供真实可运行的实现”写进 Spec 的禁止项,并在评估网关上额外跑集成测试而不是只跑单测。
4.2 上下文隔离与“选择性失忆”
200 个 Agent 并行时,上下文的管理策略跟单 Agent 完全不同。单 Agent 对话可以越长越好,能记住之前聊过什么;并行场景下,系统反而要主动给每个 Agent “清空记忆”,让它只专注当前任务。
具体做法是,Agent 拿到的上下文由三部分组成:Task Spec 全文、被授权文件的内容、相关接口签名。其他东西一概不给。仓库的其他部分如果有关联,应该在 Task Spec 里用“参考接口”的章节列出来,Agent 通过读文件而不是靠猜来获取。
这么做有两个原因。第一是省钱省 token:一个仓库几十万行代码,不可能全塞进每个 Agent 的上下文,200 个 Agent 重复读一次就是十倍百倍的开销。第二是减少幻觉:上下文越宽,Agent 越容易“过度联想”,干出超出任务范围的活。给得越少,它越老实。
全局记忆由调度器保存,而不是由 Agent 保存。比如“哪个文件正在被哪个任务改”“哪些任务已经完成了”,这些信息存在任务表里,由调度器统一管理。Agent 不需要知道自己之外的世界发生了什么,系统替它记着就行。
4.3 合并冲突:写不进 Git 的语义冲突更麻烦
文件层面的冲突,Git 的三路合并能解决大部分。两个 Agent 各改各的文件,最后合入主分支时基本不会冲突。真正头疼的是语义冲突:任务 A 改了下单接口的返回结构,任务 B 在新写的支付回调里用了旧返回结构。两个任务单独跑测试都是绿的,合并之后集成测试一跑就炸。
我的兜底方案是三道防线:
- 在 Task Spec 里声明“接口契约”,把公共接口定义放在共享文件里,并标记为禁止单任务修改。谁要改接口,必须走一个单独的“接口变更任务”,变更完成后再放行下游任务。
- 每一波任务合并完成后,强制跑一次全量构建和全量测试,任何失败都回到“上一波绿点”,而不是勉强修复。
- 合入主分支的权限归调度器,不归 Agent。Agent 永远只 push 到自己的任务分支,合入动作由系统在评估网关绿灯后执行。
5. 工具选型与落地路径:从几个 Agent 到上百个 Agent
这套体系听起来很重,但落地时你可以从很轻的配置开始。关键是选对工具组合,并且知道每一步投入进来的成本值不值。
5.1 单 Agent 引擎怎么选
Worker 里真正干活的“手”通常是一个 CLI 版的编码 Agent。我试过几种主流的,简单说下感受:
| 引擎 | 特点 | 适合场景 |
|---|---|---|
| Codex CLI | 命令行原生、能自己读仓库、能执行命令 | 自动化流程里的 Worker,适合并行接入 |
| Claude Code | 对话体验好、上下文理解强、工具调用稳 | 需要仔细推理的复杂任务 |
| Aider | 轻量、Git 原生、便宜 | 小任务批量执行,和已有命令行的集成方便 |
| Cline | VS Code 插件,也能命令行调用 | 希望在图形界面下观察单任务执行细节 |
我的习惯是“装配线两头用贵模型,中间用便宜模型”:任务切分和最后的代码评审用 Claude 这类逻辑推理强的,中间几十个执行 Worker 用 Codex 这类适合自动化的。贵模型不值得铺满 200 个任务,便宜模型跑批量任务边际成本低,效果也不算差。
5.2 编排层:Temporal、LangGraph 还是自研
编排层是很多人的纠结点。LangGraph 是现在 Agent 圈最火的框架,适合编排“少数几个有记忆、有状态、需要互相协作”的 Agent;但它是为“Agent 对话”设计的,不是为“200 个工人的工厂流水线”设计的。真要做大规模任务队列,LangGraph 里那些会话记忆、图状态同步会成为负担。
我自己更倾向用 Temporal 这类持久化工作流引擎来当调度底座。它有内置的重试、超时、心跳机制,任务跑了一百分钟突然 Worker 挂了,Temporal 会自动把任务重新丢到队列里。200 个 Agent 并行时,这种可靠性比“内存里维护一个状态机”要踏实得多。
如果项目只是练手,也可以用最简单的方案:PostgreSQL + Python 脚本 + 系统 crontab。调度器每分钟扫一次任务表,把 ready 任务塞到队列中间件,Worker 起来跑容器。代码量不大,但逻辑完整。等你真的需要了,再把调度层替换成 Temporal,任务表结构可以基本不动。
5.3 成本与速率的一个粗算
关于 200 个 Agent 并行,很多人最关心的是“烧钱吗”。我按一个中等仓库粗略算一下:假设总共 300 个任务,每个任务输入约 30k token(包含 Task Spec、相关代码),输出约 5k token,单个任务耗 35k token,一个全程下来就是 10M token 量级。如果全用顶级模型,按输入输出混合价算,一次大改造可能花几百到上千美元;如果换成偏便宜的模型跑执行层,成本能压到三分之一。
速率方面,真正的瓶颈是模型 API 的限流。假设你不走批量接口,单 key 每分钟上限 500 次请求,那么工作池开 20 个并发就已经很激进,再高没意义,因为都在排队等限流恢复。所以 200 个并行 Agent 里的数字,应该理解为“系统管理着 200 个在途任务”,而不是“同时发起 200 个模型请求”。
6. 这套玩法的边界与我的个人复盘
搭建并跑了这套并行体系之后,我对“AI Coding 大规模并行”有了更清醒的认识。它确实能带来数量级的交付速度提升,但它不是银弹。任何一个环节做得不到位,并行带来的问题可能比单 Agent 还多。
6.1 为什么大多数人不需要真的上 200 个并行
先泼一盆冷水:如果你的项目在 10 个任务以下,或者任务之间强耦合,强行上并行只会增加调度开销。我见过有人为了“并行”硬把一个大功能拆成 20 个小任务,结果每个任务都在改同一个模块,合入时冲突解决花掉的时间比单 Agent 做完整件事还长。
判断该不该上并行,看三个条件:任务量够不够多、任务之间够不够独立、有没有可靠的自动评估手段。三个条件缺两个,老老实实单 Agent 串行跑完更划算。并行不是炫技,是一种匹配特定负载的架构。
以我实际项目为例,改造一个维护了三年的老服务,代码结构乱、测试覆盖低。我不敢让 200 个 Agent 自由发挥,而是先跑了一个“基础设施 Agent”把类型检查补上、把旧测试框架迁到新版本,等仓库绿了,再放 50 个并行任务去按模块重构。这个渐进过程明显更顺,因为它先制造了一个安全的并行前提。
6.2 我踩过的三个坑:模糊约束、自洽测试、并发写公共文件
第一个坑是模糊约束。我最初给 Agent 的任务描述里有“优化”“重构”“改进”这类日常词,结果一个 Agent 把公共错误码枚举从 string 改成了 int,理由是“int 更规范”。单独看没问题,但它牵一发动全身,下游十几个任务全部爆红。后来我把所有任务描述改成了“目标 + 可动文件 + 验收标准 + 禁止项”四段式,类似“只允许修改指定的 4 个文件,禁止修改公共类型定义”,再没出过这种问题。
第二个坑是 Agent 自己写测试自己过。有一次审查一个 Agent 的产出,发现它提交了一个缓存模块,测试文件只有两个用例:一个测“能拿到缓存”,一个测“缓存为空时返回 null”,都是空壳断言。真正的缓存击穿、过期、并发写根本没人验证。解决办法是:对关键技术任务,测试用例由我预先写好,Agent 只写实现;一般任务至少要求测试覆盖率达到某个指标,而不是“只要有测试就行”。
第三个坑是并发写同一个公共配置文件。两个任务同时往 package.json 里加依赖,后提交的覆盖了先提交的。后来我把这类公共文件的写入全部串行化,统一由一个“依赖更新 Agent”处理,其他 Agent 在 Spec 里就只能读不能写。
6.3 如果你要从零开始尝试,我的操作建议
先别急着复刻 200 个 Agent 的全套架构。我自己就是一步一个台阶踩过来的,给一条平滑路径:先跑通“3 个 Agent 并行 + 人工 review + 人工合并”,把 Task Spec 的写法、评估网关的检查项磨顺;再上“10 个 Agent + 队列 + 沙箱”,体验一下自动化调度带来的效率提升;最后才是多 Worker 并行、自动合入、失败自动重试。
每个阶段都要有一个明确的硬指标:比如从 3 到 10 的过程,以“零手工修复代码”为目标——所有代码产出都被 Agent 自己修到通过,你再出手就算失败。指标达到了,再推到下一个规模。这样你的整套基础设施是被真实压力锻炼出来的,而不是一次性搭个看起来很美、一跑全崩的纸壳子。
最后再说一个让我印象深刻的细节:那套 200 个 Agent 并行的演示里,最出彩的其实不是 Agent 写代码的速度,而是它把“每个任务从开始到合入平均只要几分钟”这件事稳定地跑了下来。做到这一步,技术含量不在模型层,而在调度、隔离、验证这些“不性感”的工程活上。这也是我写这篇文章最想传达的东西——AI Coding 的上限,很大程度取决于你的工程下限。