☰
双Agent协作实践:用OpenRig编排Claude Code与Codex高效组队
2026/10/13 14:19:28 网站建设 项目流程

最近我在折腾一个有点“邪修”味道的工作流:把 Claude Code 和 Codex CLI 同时挂到一个项目里,让它们像两个不同工种的开发一样组队干活,我本人只负责写需求卡片、看结果、偶尔骂两句“这里不对”。这个玩法圈内叫 vibecoding,核心思想很简单——代码写得好不好不再是最重要的事,能不能把 AI 的产出快速组装成可用产品才是。为了不让这两个 Agent 互相踩脚,我找了个叫 OpenRig 的调度工具,把整个过程理成了可复用的配置。这篇就当是踩坑记录加配置笔记,写给那些已经烦透了“单 Agent 上下文越滚越长、改到后面连自己都忘了前面”的人。

我自己试了一个礼拜,结论是:双 Agent 协作不是噱头,是真的能把以前两小时的活压到二十分钟,前提是任务边界画得够清楚。下面我会把环境搭建、核心配置、任务拆法、交接机制和踩过的坑全部拆开讲,照做就行。

1. 为什么我不再只开一个 Agent,而是让两个 Agent 组队

先说说动机。之前我一直用单 Agent 跑完整需求,比如“给我做一个带后端的记账页面”。它确实能干,但干到一半问题就开始冒出来:上下文窗口撑不住,前端样式还没完,后端接口的设计已经被挤出了记忆;改完前端改后端,今天的 Agent 把昨天自己写的接口签名给忘了,然后一脸自信地生成一套完全不匹配的代码。这个过程特别像让一个全能型选手同时负责方案设计、代码实现、测试验收,最后所有人都知道他精力分散了。

后来我把 Claude Code 和 Codex 分开跑,一个终端管一个,效果稍微好点,但很快又崩了:两个终端之间完全没有信息同步,A 改了接口,B 还在按旧签名写调用,git 一合并全是冲突。我自己要来回切窗口、搬上下文,这不叫协作,叫传话筒。

OpenRig 就是来解决这个问题的。它的思路特别朴素:不要试图把整个仓库塞给一个大模型,而是把这个仓库切成几个“工位”,每个工位由一个 Agent 独立负责,工位之间通过任务卡片、文件所有权和 git 分支来同步。Claude Code 和 Codex 各自有各自的优势场景,有的擅长类型推导和重构类的后端逻辑,有的在 UI 和状态管理上更顺手,组队之后就能各干各的活,互不干扰。

如果你也遇到单 Agent 项目一复杂就“前面写得挺好,后面开始胡说八道”的情况,或者你手里有两个 API key 却不知道怎么用出效率,这个玩法值得一试。它不要求你有多深的工程能力,但要求你愿意把需求拆成小块——这恰恰是 vibecoding 最核心的动作。

2. OpenRig 的定位:编排层、任务卡与所有权地图

OpenRig 不是模型,也不太像传统的 CI/CD 工具。我更喜欢把它理解成一个“Agent 工头”:它自己不写代码,只负责把人(两个模型)安排到正确的工位上,给他们发任务卡,检查他们有没有越界,然后在合适的时机让他们交接。

2.1 三个核心设计:调度器、任务卡、所有权地图

第一个是调度器。它读一个 YAML 配置文件,里面定义了每个 Agent 用哪个引擎、在哪个目录干活、拥有哪些文件、最多迭代多少轮。启动的时候执行openrig run --task "...",调度器会把任务翻译成每个工位的子任务,然后按顺序或并行发起。

第二个是任务卡。每个工位工作时,都会在.rig/tasks/目录下维护一个 markdown 文件,里面写清楚目标、当前状态、已完成的工作、下一步建议。这看起来很像现在流行的“AI 规范文件”,但区别在于它是动态更新的:Agent 每做完一步就把状态推进一格,另一个 Agent 在下一次开工前会先读最新的卡片。

第三个是所有权地图。这玩意儿是防止冲突的关键。配置里每条 worker 都有ownership字段,比如src/api归 Claude Code,src/pages归 Codex。调度器会在启动时生成一把锁,任何 Agent 要修改不属于自己所有权范围内的文件,都会被 OpenRig 拦下来并提示“越界操作”。这从根本上解决了两个 Agent 同时改同一个文件的问题。

2.2 为什么不推荐直接开两个终端各跑各的

很多人会问,我自己开两个终端,手动分配活,不也一样?我试过,差别非常大。手动模式的问题在于没有任何强制边界,Agent A 不知道 Agent B 改了什么,更不知道哪些文件不能碰。你靠嘴来协调,最后你成了瓶颈。OpenRig 解决问题的角度不是“让 Agent 更聪明”,而是“让傻 Agent 也不至于互相伤害”。它通过文件锁、任务卡、分支隔离,把协作这件事从“靠模型自律”变成了“靠机制约束”。对于目前的大模型能力来说,机制约束比自律靠谱得多。

下面这张表是我自己体感上的对比,方便你快速判断要不要入坑:

对比维度单 Agent 直接干手动双开终端OpenRig 编排双 Agent
上下文压力全仓一个上下文,后期必乱各自独立,但没有同步各自独立,且通过任务卡同步
冲突风险无冲突,但有逻辑不自洽极高,合并时头大低,所有权地图硬性兜底
角色分工一个模型干所有活靠人肉分配配置里明确分工
适合的项目小脚本、一次性任务中大型但容忍乱需要持续迭代的仓库
心智负担低高,你是协调者中,前期配好后面省心

3. 环境准备与最小配置:半小时把两个 Agent 拉起来干活

配置并没有你想象中那么玄学。整个环境准备加最小配置,半小时内就能跑通。我假设你已经装好了 Node.js 18+、Python 3.10+ 和 git,并且电脑上已经能分别使用 Claude Code 和 Codex CLI 这两个命令行工具。如果你还没装,先把它们各自的官方 CLI 搞定,能单独跑通一个“修复这个 typo”的任务再回来。

3.1 安装 OpenRig 与密钥配置

我自己是直接用源码跑的,因为 CLI 工具还处于快速迭代期,用 npm 安装也能用,但更新跟不上。建议这样:

git clone https://example.com/openrig openrig cd openrig npm install npm link

这个npm link会把openrig命令挂到全局,之后你就能在任何项目目录里调用了。密钥方面,不要在配置文件里写 API key。OpenRig 会从环境变量里读:

export ANTHROPIC_API_KEY="你的key" export OPENAI_API_KEY="你的key"

用环境变量的好处是配置文件可以安全地提交到 git 里,别人 clone 下来只需要配自己的 key。千万别犯我犯过的错——第一次我图省事,把 key 直接写进rig.config.yaml,后来差点把仓库推到公共平台,吓出一身汗。

3.2 初始化项目与最小配置

进入你的项目目录,执行:

openrig init

它会生成一个rig.config.yaml模板。我第一次看这个文件的时候以为是在写 K8s 配置,后来发现没那么复杂。一个能跑通的最小配置长这样:

version: 1 team: - name: claude-worker engine: "claude" cwd: "./src" ownership: ["src/api", "src/domain", "src/lib"] role: "后端接口、数据模型与核心逻辑" max_iterations: 30 exit_when: "任务卡中所有 todo 项均为 done" - name: codex-worker engine: "codex" cwd: "./ui" ownership: ["src/pages", "src/components", "src/store"] role: "前端页面、状态管理与交互逻辑" max_iterations: 30 exit_when: "任务卡中所有 todo 项均为 done"

每个字段都有实际意义,别照抄就完事。cwd决定了 Agent 的默认工作目录,ownership决定了它能改哪些文件,role会作为系统提示词的一部分注入,告诉 Agent 它在这个团队里是什么角色。exit_when是 Agent 判断自己什么时候该收工的条件,没有这个限制的话,它可能会一直“优化”下去,你的 API 账单也会一直涨。

3.3 跑通第一次协作

配置好之后,创建一张最最简单的任务卡:

openrig run --task "在 src/lib 下新增一个 readFileAsBase64 工具函数,并在 src/api 中调用它"

这个任务的意图就是让 claude-worker 独立完成,Codex 不掺和。跑完之后你会看到 OpenRig 的输出里有一个任务卡文件,里面记着 Agent 每一步做了什么。第一次跑通之后,再尝试跨工位任务,也就是需要两个 Agent 配合的那种。一开始可以把任务写得非常小,小到只有一个文件新增、一个文件调用,跑通这个流程,后面再放复杂需求。

提示:如果你的代码库很大,第一次跑openrig init后建议先手动删掉.rig/tasks里的历史任务卡,避免 Agent 被上一次的旧结论干扰。

4. 任务拆解、上下文隔离与交接机制:组队的隐藏骨架

配置只是表面,真正让双 Agent 协作成立的是任务拆解的思路和上下文隔离的手段。这一节可能是全文里最值得反复看的部分,因为大多数双 Agent 项目跑崩,不是工具不行,是拆活和交接没做好。

4.1 按“文件边界”拆,不按“语言”拆

我见过最典型的错误,是把任务拆成“前端用 React 写,后端用 Python 写”。听起来很合理,但实际上前后端之间往往共享类型定义、接口文档、工具函数。一个改接口字段,另一个就要跟着改调用,边界完全没隔开。

正确做法是按文件目录拆,而且要选那种依赖关系少的目录边界。比如src/api和src/pages之间只通过接口文件交互,那这两个目录就可以分别交给两个 Agent。拆任务卡的时候,你要问自己一个问题:如果这两个 Agent 之间完全没有实时通信,各自做完各自的事,最终能不能拼起来?如果能,这个拆分就是好的;如果不能,说明你们之间的隐性依赖太多了。

4.2 上下文隔离:让 Agent 只看自己该看的东西

OpenRig 的上下文隔离是通过三层机制实现的。第一层是cwd,Agent 默认只能看到这个目录下的文件,不会一上来就扫描整个仓库。第二层是ownership,即使 Agent 通过某些方式读到了其他目录的文件,修改动作也会被拦截。第三层是 role 提示词,告诉 Agent 你是谁、你在为谁工作、你的产出由谁消费。

这三层隔离最大的价值不是减少 token 消耗,而是减少“上下文污染”。单 Agent 项目里,模型经常因为看到了太多无关代码,然后在生成时把某些旧约定的风格带进来。隔离之后,每个 Agent 看到的都是一个小而清晰的世界,输出的一致性和稳定性能明显提升。我在实际项目里跑一个中型仓库时,隔离后的代码修改行数比隔离前少了大概一半——因为 Agent 不再因为看到奇怪的历史代码而“画蛇添足”。

4.3 交接不靠聊天记录,靠任务卡

两个 Agent 之间怎么交接?很多工具的做法是把上一个 Agent 的对话记录直接塞给下一个 Agent。这个方案的问题在于:对话记录里有大量的“尝试”“不对”“换一种思路”这类噪音,真正有用的结论只占 10%。把 90% 的垃圾喂给下一个 Agent,纯粹是在燃烧你的上下文预算。

OpenRig 的交接机制是任务卡。每个 Agent 完成一轮之后,必须更新.rig/tasks/<task-id>.md,把状态推进到下一步。任务卡有约定格式,模板长这样:

# 任务卡:批量图片压缩功能 ## 目标 给 report 命令增加一个 --compress 选项,支持对输出目录中的图片做批量压缩。 ## 当前状态 - [x] 确认现有 report 命令的输入输出格式 - [x] 在 src/lib 新增 imageCompressor.py 基础压缩接口 - [ ] 在 CLI 入口接入 --compress 参数(待 codex-worker 处理) - [ ] 更新 README 中参数说明 ## 给下一个 Agent 的交接说明 CLI 入口在 src/cli/main.py 的 arg_parser 部分,压缩接口已经暴露为 compress_image(input_path, output_path, quality=85),直接调用即可。 不要在 src/lib 下再新建其他文件。

这个格式的核心是“给下一个 Agent 的交接说明”,必须具体到文件路径、函数名和禁忌。你写清楚这三个信息,下一个 Agent 几乎不需要猜测就能继续干。写不清楚的话,它大概率会重新读一堆代码,而且可能读错方向。

4.4 git worktree 和分支隔离的实践

除了任务卡,我在实际项目中还会给每个 Agent 开独立的 git worktree。这样即使它们同时改同一份代码,也不会在物理上产生文件冲突。OpenRig 的配置里加一句branch_strategy: worktree-per-worker就能开启。每个 Agent 在独立的工作目录里干活,完成后 OpenRig 把各自的改动 cherry-pick 回主分支,或者生成一个合并请求让我手动审。

这个机制最大的好处是,即使某个 Agent 改崩了,也不会污染另一个 Agent 的工作区。你在主分支该干嘛干嘛,等它们产出稳定了再合并。这种“连坐都不坐”的隔离方式,特别适合那些模型偶尔会抽风的任务场景。

5. 实战:给 demo-rig 项目加批量图片压缩功能的全程记录

光讲理论没意思,说一个我实际跑的完整例子。项目不重要,随便起个名,叫 demo-rig,是一个用 Python 生成 HTML 报告的内部小工具。需求是加一个批量图片压缩功能,用户希望在命令行里输入一个目录,然后工具递归处理目录下所有图片,输出压缩后的版本,同时保留原文件的元信息。

5.1 我作为“vibecoding 掌门人”只做了三件事

第一件,写需求卡片。第二件,在rig.config.yaml里把任务拆给两个 Agent。第三件,等它们干完,我做 code review。整个过程我没写过一行代码。

任务拆分的思路是:压缩算法和文件遍历属于后端逻辑,归 claude-worker;CLI 参数解析和 README 文档更新属于用户交互层,归 codex-worker。我创建任务卡:

openrig run --task "为 demo-rig 增加批量图片压缩功能" --plan-only

--plan-only是 OpenRig 一个挺实用的模式,只让调度器拆解任务并生成子任务卡,不实际执行。拆出来的结果如果我觉得边界不合理,可以直接改任务卡再放行。这个步骤强烈建议每次都用,等于你先审一遍“施工图”,再让 AI 进场。

5.2 两个 Agent 的实际运行过程

任务卡确认后,我执行正式跑:

openrig run --task ".rig/tasks/compress-image-task.md"

运行日志很有意思,两个 Agent 几乎是并行开工的。claude-worker 先花了几轮探索src/lib下现有的文件结构,然后开始写压缩模块;codex-worker 同时在看src/cli/main.py的现有参数解析逻辑。大约两分钟之后,claude-worker 更新了任务卡,标注“压缩接口已完成”,并给 codex-worker 留了交接说明:函数签名是compress_image(input_path, output_path, quality=85),CLI 入口需要加--compress参数。

codex-worker 拿到任务卡后,没有重新去看压缩模块的源码,直接按照交接说明调用接口。这就是任务卡机制的价值——如果靠对话记录,codex-worker 可能要花十轮去理解压缩模块的实现;靠任务卡,它一步就接上了。整个过程大概跑了 9 分钟,两个 Agent 合计迭代了 28 轮,产出了一个新增模块、一个 CLI 参数改动和一份 README 更新。

5.3 最终产出与我的验收方式

最后我打开.rig/workspace/demo-rig工作区,里面是两个 Agent 的合并结果。我先跑了一遍测试:

cd demo-rig python -m pytest tests/

一次通过。然后我手动跑了一下压缩命令,确认生成的 HTML 报告里图片路径没有变化,压缩后的图片也能正常打开。验收通过,我把改动合并到了主分支,任务卡归档到.rig/archive/。

这次体验给我最大的感受是:vibecoding 的掌控感不在于你写不写代码,而在于你能不能把需求拆到“即使是最笨的 Agent 也能做对”的粒度。我全程没碰代码,但每一步决策我都参与了。

6. 踩坑实录:文件冲突、请求风暴与上下文污染

这个部分没有实操之外的侥幸,全是真金白银换来的教训。我把这一个礼拜踩过的坑按严重程度排一遍,希望你看到的时候能少交一点学费。

6.1 坑:所有权地图漏配,两个 Agent 同时改一个文件

第一次跑协作任务时,我的配置里ownership只写到目录粒度,没有精确到单个文件。没想到有一个公共的src/shared/constants.py两个模块都会用到,claude-worker 和 codex-worker 几乎是同一时间对这个文件做了修改。结局非常精彩:一个是改常量名,一个是在文件末尾加新常量,合并时 git 直接报冲突,两个 Agent 都以为对方改坏了。

后来我把ownership细化到这个公共文件只归 claude-worker 管,并且要求 codex-worker 如果要改公共文件,必须先在任务卡里提出“修改申请”,由 claude-worker 执行修改。这样一来,公共区域有了唯一主人,冲突自然消失。记住:所有权必须精确到文件,而不是只到目录。

6.2 坑:任务拆得太碎,Agent 之间互相等待

有一次我为了追求“每个任务卡都很小”,把一个需求拆成了六个子任务卡,结果两个 Agent 频繁进入等待状态,调度器空转,整个流程比单 Agent 还慢。原因很简单:任务之间的依赖太强,A 的产出必须被 B 读取,B 完成之前 A 又无法继续,流水线被拉成了串行。

正确的拆法应该是“尽量并行,少搞流水线”。你要让每个 Agent 手里的任务都能独立推进到可验收的状态,而不是一个接一个传接力棒。依赖无法避免时,尽量把依赖点压缩到一两个明确的关键交接处,比如“等 claude-worker 完成接口定义后,codex-worker 一次性接入”,而不是每改一个函数都要等对方。

6.3 坑:上下文污染,Agent 遗忘了约定

之前我提过上下文隔离,但还有一类污染来自“规范性约定”,比如“函数命名用 snake_case”“日志格式必须包含时间戳”“错误处理要返回结构化响应”。这些约定分散在仓库各处,Agent 不会每次自动读全。

OpenRig 提供的解决方式是AGENTS.md文件,放在仓库根目录,每个 Agent 启动时用--sync模式拉取。我的建议是,所有只允许“人”决定、不允许“模型”自由发挥的规定,都写进这个文件里。比如:

# AGENTS.md - 所有新函数必须附带 docstring,说明输入输出 - 错误处理统一返回 { "error": "消息" } 结构 - 不要修改 tests/ 以外的测试文件 - 改接口前先更新接口文档

有了这份文件,Agent 至少不会在第一天记住了约定、第三天忘记。我一开始没建这个文件,结果 claude-worker 和 codex-worker 各自生成了风格完全不一致的日志格式,光统一格式就花了我半天,纯属自找麻烦。

6.4 坑:API 费用失控,请求风暴

双 Agent 意味着双份 token 消耗,如果任务不设上限,费用起来真的很快。我第一次跑没有配max_iterations,一个 Agent 在一个简单任务上反复重试了四十多轮,每轮都在读取大文件,看着账单我血压直接上来了。

后来我总结了一组保命配置:

配置项建议值说明
max_iterations20-30单任务最大迭代轮数,超出就标记失败
request_timeout600单轮请求超时时间,单位秒
parallel_workers2同时跑几个 Agent,别贪多
burn_rate_limit0.1每秒 API 调用上限,防突发风暴
dry_runfalse调试阶段可以开,只生成计划不执行

另外小技巧:每一轮迭代之间加cooldown_seconds: 5,让两个 Agent 的请求错峰发送。虽然只差几秒,但能明显减少 429 rate limit 错误,而且两个 Agent 的 token 峰值不会同时顶到上限。省钱这件事,本质上靠的是“限制和节奏”,不是靠换更便宜的模型。

写在最后的一点体会

玩了一个多星期的 OpenRig 双 Agent 工作流,我最直观的感受是:以前写代码像自己下地干活,现在更像包工头——只管派活、验收,偶尔处理一下工人之间的矛盾。这个转变一开始有点不习惯,总觉得不亲手写点什么就不踏实,但后来想通了,模型能干好的事就该让模型干,我留着精力去确认“方向对不对”以及“合入的代码风格是否能长期维护”。如果你也想试,别一上来就管理三个以上的 Agent,先把一个后端 Agent 和一个前端 Agent 跑顺,再把任务卡的粒度慢慢调大。等你有把握说清楚“哪些文件归谁管、什么算完成”的时候,你会发现,vibecoding 这种看似邪修的玩法,其实比很多正统流程都更接近工程的本質。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询