ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

openrig:基于YAML与tmux的多智能体协作脚手架实战

openrig:基于YAML与tmux的多智能体协作脚手架实战 1. 项目缘起当多智能体协作遇上终端复用第一次看到openrig这个词是在几个折腾 Claude Code 和 Codex 的群里。有人甩出一张截图左边窗口跑着 Claude Code 在改一个 Python 脚本右边窗口 Codex 在同步生成单元测试底下还有一个 tmux 会话在实时打印两个 Agent 的日志流。配文只有一句“openrig 搭好了终于不用来回切窗口了。”这个场景戳中了很多人的痛点。Claude Code 和 Codex 这类终端智能体工具单用的时候很爽但一旦你同时跑两个以上的任务问题就来了每个工具都要占一个终端窗口日志混在一起看不清任务之间的上下文没法共享切换成本高得离谱。openrig本质上就是解决这个问题的——它是一套基于 YAML 配置和 tmux 会话管理的多智能体协作脚手架让你在一个统一的终端环境里编排 Claude Code、Codex 等多个 Agent 的工作流。说得再直白一点openrig不是某个官方产品而是社区里逐渐形成的一套实践方案。核心思路是用 YAML 定义每个 Agent 的角色、任务、工作目录和启动命令然后用 tmux 把它们组织成一个个独立的 pane 或 window最后通过一个统一的入口脚本拉起整个环境。你不需要记住每个工具的具体启动参数也不需要手动开五六个终端标签页一条命令下去整个协作环境就就绪了。这套东西适合谁如果你已经在用 Claude Code 或 Codex 做日常开发并且开始觉得“一个 Agent 不够用”那openrig的思路就值得你花时间研究。如果你还没接触过这两个工具建议先把 Claude Code 和 Codex 的基本用法跑通再来看多 Agent 编排的部分否则容易一头雾水。下面我会从设计思路、YAML 配置细节、tmux 会话管理、实操步骤和常见坑几个维度把这套方案拆开讲清楚。2. 整体设计思路为什么是 YAML 加 tmux2.1 多 Agent 协作的核心矛盾同时跑多个终端智能体最直接的问题有三个。第一是窗口管理混乱Claude Code 一个窗口Codex 一个窗口如果还要跑测试或日志监控窗口数量直接爆炸。第二是上下文隔离与共享的平衡每个 Agent 需要独立的工作目录和会话状态但有时候又需要它们看到同一份文件变更。第三是启动流程重复每次开工都要手动 cd 到项目目录、设置环境变量、输入一长串启动命令效率极低。openrig的设计就是冲着这三个问题去的。YAML 负责声明式地描述“我要跑哪些 Agent、它们各自什么角色、在哪个目录、用什么命令启动”tmux 负责把这些声明变成实际的终端会话和窗格布局。两者结合既保留了终端工具的灵活性又获得了类似容器编排的便利性。2.2 为什么选 YAML 而不是 JSON 或 TOMLYAML 在这个场景下的优势很明显。首先它支持注释你可以在配置里写清楚每个 Agent 的用途和注意事项这对团队协作和后续维护非常关键。其次YAML 的层级结构天然适合描述“多个 Agent、每个 Agent 多个属性”这种嵌套关系可读性比 JSON 好很多。TOML 虽然也支持注释但在表达列表和嵌套对象时不如 YAML 直观。更重要的是Claude Code 和 Codex 本身都在不同程度上使用 YAML 作为配置文件格式社区里关于yolov10 yaml文件怎么创建、rstudio的yaml在哪里这类问题的讨论也说明 YAML 在开发者群体中的接受度很高。用 YAML 来写openrig配置学习成本几乎为零。2.3 tmux 的角色不只是窗口管理器很多人对 tmux 的理解停留在“终端复用工具”层面但在openrig里tmux 承担的是会话编排层的职责。每个 Agent 跑在独立的 tmux window 或 pane 里这意味着你可以随时 detach 整个会话让 Agent 在后台继续跑第二天再 attach 回来看结果。这种能力对于长时间运行的任务比如让 Claude Code 重构一个模块同时 Codex 在另一个窗口生成文档非常关键。另外tmux 的send-keys和capture-pane命令为自动化提供了可能。你可以在启动脚本里用send-keys向指定 pane 发送命令也可以用capture-pane抓取某个 Agent 的输出做日志分析。这些能力在纯 GUI 终端里是很难实现的。注意tmux 的 pane 和 window 概念容易混淆。简单说一个 window 可以分割成多个 panewindow 是标签页级别的切换单位pane 是同一屏幕内的分割区域。openrig的常见做法是每个 Agent 占一个 window需要对比输出时再临时分割 pane。3. YAML 配置详解从零写一份 openrig 配置3.1 配置文件的基本结构一份典型的openrigYAML 配置长这样session_name: my-project-rig root_dir: ~/projects/my-app agents: - name: claude-main tool: claude-code role: 主开发 workdir: ./src command: claude --model claude-sonnet-4-20250514 env: ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} auto_start: true - name: codex-review tool: codex role: 代码审查 workdir: ./src command: codex --model gpt-5 env: OPENAI_API_KEY: ${OPENAI_API_KEY} auto_start: true - name: test-runner tool: shell role: 测试监控 workdir: . command: watch -n 30 pytest tests/ -x --tbshort auto_start: false这个结构里session_name是 tmux 会话名root_dir是所有相对路径的基准目录agents列表定义了每个 Agent 的配置。每个 Agent 至少需要name、tool、workdir和command四个字段。3.2 关键字段的取值逻辑tool字段决定了启动脚本如何构造命令。对于claude-code脚本会检查claude命令是否在 PATH 中并自动注入--dangerously-skip-permissions之类的常用参数如果你在配置里显式写了command则以command为准。对于codex脚本会处理codex auth token is unavailable这类常见错误的预检。对于shell就是直接执行命令。workdir支持相对路径和绝对路径。相对路径基于root_dir解析。这个设计是为了让配置可以跟着项目走不同机器上只要改root_dir就行。env字段用来注入环境变量。这里有个细节YAML 里的${VAR}语法不会自动展开需要在启动脚本里用envsubst或类似工具处理。我试过直接在 YAML 里写${ANTHROPIC_API_KEY}结果启动脚本把它当字面量传进去了Agent 启动后报认证失败。后来在脚本里加了一行eval才解决。auto_start控制该 Agent 是否在会话创建时自动启动。像测试监控这种不需要一直跑的任务可以设为false需要时手动在对应 window 里执行。3.3 多环境配置的拆分策略实际项目里我建议把配置拆成两层一层是openrig.base.yaml放通用的 Agent 定义和命令模板另一层是openrig.local.yaml放机器相关的路径和密钥引用。启动脚本先加载 base再用 local 覆盖。这样做的好处是base 配置可以提交到 Git 仓库团队共享local 配置放在.gitignore里每个人根据自己的环境调整。合并逻辑可以用yq工具实现yq eval-all select(fileIndex 0) * select(fileIndex 1) openrig.base.yaml openrig.local.yaml /tmp/openrig.merged.yamlyq的*操作符做的是深度合并嵌套的 map 会递归合并列表则直接替换。如果你希望列表也合并需要用*操作符但那样容易产生重复项我一般不用。4. tmux 会话编排从配置到实际窗口4.1 会话创建与窗口布局启动脚本的核心逻辑是先检查目标会话是否已存在如果存在就 attach不存在就创建。创建流程大致如下#!/usr/bin/env bash set -euo pipefail CONFIG${1:-openrig.yaml} SESSION$(yq .session_name $CONFIG) ROOT_DIR$(yq .root_dir $CONFIG | sed s|~|$HOME|) # 检查会话是否存在 if tmux has-session -t $SESSION 2/dev/null; then echo 会话 $SESSION 已存在直接 attach tmux attach -t $SESSION exit 0 fi # 创建会话第一个 Agent 占第一个 window FIRST_AGENT$(yq .agents[0].name $CONFIG) tmux new-session -d -s $SESSION -n $FIRST_AGENT -c $ROOT_DIR # 为剩余 Agent 创建 window AGENT_COUNT$(yq .agents | length $CONFIG) for ((i1; iAGENT_COUNT; i)); do AGENT_NAME$(yq .agents[$i].name $CONFIG) AGENT_WORKDIR$(yq .agents[$i].workdir $CONFIG) tmux new-window -t $SESSION -n $AGENT_NAME -c $ROOT_DIR/$AGENT_WORKDIR done tmux attach -t $SESSION这段脚本里有个容易踩的坑tmux new-window的-c参数指定的是启动目录但如果目录不存在tmux 会静默失败window 还是会创建但工作目录会落到默认的 home 目录。我建议在脚本里加一个目录存在性检查if [ ! -d $ROOT_DIR/$AGENT_WORKDIR ]; then echo 警告目录 $ROOT_DIR/$AGENT_WORKDIR 不存在跳过 Agent $AGENT_NAME continue fi4.2 向指定窗口发送启动命令窗口创建好之后下一步是把每个 Agent 的启动命令发到对应的 window 里。这里用tmux send-keysfor ((i0; iAGENT_COUNT; i)); do AGENT_NAME$(yq .agents[$i].name $CONFIG) AUTO_START$(yq .agents[$i].auto_start // true $CONFIG) if [ $AUTO_START ! true ]; then continue fi COMMAND$(yq .agents[$i].command $CONFIG) ENV_VARS$(yq .agents[$i].env // {} | to_entries | .[] | \export \(.key)\(.value)\ $CONFIG) # 先发送环境变量 while IFS read -r line; do [ -n $line ] tmux send-keys -t $SESSION:$AGENT_NAME $line C-m done $ENV_VARS # 再发送启动命令 tmux send-keys -t $SESSION:$AGENT_NAME $COMMAND C-m doneC-m是回车键的 tmux 表示法。注意send-keys发送的命令是异步的脚本不会等待命令执行完成。如果你需要确认 Agent 是否成功启动可以在发送后加一个短暂的 sleep然后用capture-pane抓取输出做检查。4.3 会话持久化与恢复tmux 会话的一个核心优势是持久化。你可以在下班前 detach 整个会话Agent 继续在后台跑第二天 attach 回来看结果。但这里有个问题如果机器重启了tmux 会话就没了。解决方案是用tmux-resurrect或tmux-continuum插件做会话快照和自动恢复。不过对于openrig场景我更推荐直接用启动脚本重建会话。因为 Agent 的状态比如 Claude Code 的对话历史通常保存在工具自己的配置目录里重建会话后重新启动 Agent历史记录还在。tmux 层面只需要恢复窗口布局和启动命令这些信息都在 YAML 里重建成本很低。实操心得如果你的 Agent 任务运行时间很长建议在启动命令前加script -q -c 命令 /tmp/agent-log.txt这样即使 tmux 会话意外终止日志也保留在文件里方便事后排查。5. 实操全流程从零搭建一个双 Agent 协作环境5.1 环境准备与依赖安装假设你在一台 Ubuntu 机器上从零开始。第一步是安装基础工具# 安装 tmux sudo apt update sudo apt install -y tmux # 安装 yqYAML 处理工具 sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 sudo chmod x /usr/local/bin/yq # 安装 Claude Code以 npm 方式为例 npm install -g anthropic-ai/claude-code # 安装 Codex CLI npm install -g openai/codex安装完成后分别运行claude --version和codex --version确认安装成功。如果遇到claude code安装相关的问题最常见的原因是 Node.js 版本过低建议用 Node 20 或以上。5.2 编写第一份 openrig 配置在项目根目录创建openrig.yamlsession_name: demo-rig root_dir: ~/projects/demo agents: - name: claude-dev tool: claude-code role: 功能开发 workdir: . command: claude env: ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} auto_start: true - name: codex-test tool: codex role: 测试生成 workdir: ./tests command: codex env: OPENAI_API_KEY: ${OPENAI_API_KEY} auto_start: true这里claude-dev负责在项目根目录做功能开发codex-test在 tests 目录下生成测试用例。两个 Agent 共享同一个项目目录但工作目录不同避免了文件冲突。5.3 启动脚本的编写与调试把前面章节的启动脚本保存为openrig.sh加上执行权限chmod x openrig.sh第一次运行前先做一次 dry-run 检查配置解析是否正确yq .agents[].name openrig.yaml应该输出claude-dev和codex-test。如果报错检查 YAML 缩进——YAML 对缩进极其敏感两个空格和四个空格混用是最常见的错误来源。确认无误后启动./openrig.sh openrig.yaml你会看到 tmux 会话创建两个 window 分别命名为claude-dev和codex-test每个 window 里对应的 Agent 正在启动。用Ctrl-b w可以在 window 之间切换Ctrl-b d可以 detach 整个会话。5.4 验证 Agent 协作效果启动后在claude-dev窗口里让 Claude Code 创建一个简单的 Python 函数请创建一个 calculate.py包含一个 add 函数返回两个数的和。然后在codex-test窗口里让 Codex 为这个函数生成测试为 ../calculate.py 中的 add 函数生成 pytest 测试用例保存为 test_calculate.py。两个 Agent 在同一个文件系统上工作Claude Code 创建的文件 Codex 能直接看到。这就是openrig协作的基本形态文件系统是共享的上下文tmux 是隔离的执行环境。6. 常见问题与排查技巧实录6.1 Agent 启动失败类问题问题一cc switch local proxy failed while handling codex endpoint /responses这个报错通常出现在同时使用 Claude Code 和 Codex 且配置了本地代理的情况下。根本原因是两个工具对本地端口的占用冲突。排查步骤先确认是否有其他进程占用了 Codex 默认的本地端口用lsof -i :端口号检查。如果确实冲突在openrig.yaml里为 Codex 指定不同的端口env: CODEX_PORT: 14514问题二codex auth token is unavailableCodex 的认证 token 过期或未正确配置。先单独在终端运行codex login完成认证确认~/.codex/auth.json存在且有效。然后在openrig.yaml的 env 里确保没有覆盖CODEX_HOME之类的路径变量。问题三your organization has disabled claude subscription access for claude code这是账号权限问题不是openrig配置问题。需要确认你的 Claude 订阅是否支持 Claude Code 访问。如果是团队账号联系管理员确认权限设置。6.2 tmux 会话管理类问题问题window 创建了但 Agent 没启动最常见的原因是send-keys发送命令时目标 window 的 shell 还没准备好。解决方案是在创建 window 后加一个短暂延迟tmux new-window -t $SESSION -n $AGENT_NAME -c $WORKDIR sleep 0.5 tmux send-keys -t $SESSION:$AGENT_NAME $COMMAND C-m0.5 秒在大多数机器上够用如果机器负载高可以加到 1 秒。问题detach 后 Agent 停止运行检查 Agent 启动命令是否依赖前台终端。有些工具在检测到 stdin 不是 TTY 时会自动退出。解决方案是用tmux send-keys而不是在脚本里直接执行命令确保命令是在 tmux 的伪终端里运行的。6.3 配置解析类问题问题YAML 里的环境变量没有展开前面提过YAML 本身不做变量展开。如果command字段里写了$HOME/projects实际传给 tmux 的是字面量。解决方案是在启动脚本里用envsubst处理COMMAND$(yq .agents[$i].command $CONFIG | envsubst)但要注意envsubst会替换所有$VAR形式的字符串如果命令里本身包含$符号比如 awk 脚本需要转义。问题多行 command 在 YAML 里怎么写用 YAML 的块标量语法command: | cd /tmp \ python -m pytest tests/ -v|保留换行把换行折叠成空格。对于 shell 命令通常用|更直观。6.4 常见问题速查表现象可能原因排查命令解决方案Agent 窗口空白命令未发送成功tmux capture-pane -t 会话:窗口 -p检查 send-keys 目标名是否正确认证失败环境变量未注入tmux show-environment -t 会话在 YAML env 里显式声明密钥端口冲突多个 Agent 抢同一端口lsof -i :端口为每个 Agent 分配独立端口YAML 解析报错缩进或特殊字符问题yq . 配置文件用 yq 验证统一用两个空格缩进会话无法 attach会话已被其他客户端占用tmux list-clients -t 会话先 detach 其他客户端再 attach7. 进阶玩法让 openrig 更贴合你的工作流7.1 动态 Agent 注册基础版的openrig在启动时就确定了所有 Agent。但实际工作中你可能希望按需启动额外的 Agent。一个做法是在 tmux 里预留一个“控制窗口”里面放一个简单的 shell 函数spawn_agent() { local name$1 local cmd$2 tmux new-window -t $SESSION -n $name tmux send-keys -t $SESSION:$name $cmd C-m }把这个函数写进~/.bashrc在控制窗口里随时spawn_agent debug claude就能拉起一个新 Agent。7.2 日志聚合与监控多个 Agent 同时跑日志分散在各个 window 里排查问题很不方便。可以在openrig.yaml里加一个专门的日志 Agent- name: log-aggregator tool: shell role: 日志聚合 workdir: . command: tail -f /tmp/agent-*.log auto_start: true然后让其他 Agent 的启动命令把输出重定向到/tmp/agent-name.log。这样所有日志在一个窗口里实时滚动一眼就能看到哪个 Agent 出了问题。7.3 与 IDE 的配合如果你在用 VS Code可以在openrig启动后用 VS Code 的 integrated terminal attach 到 tmux 会话tmux attach -t demo-rig这样你既能在 VS Code 里编辑代码又能在同一个窗口里看到 Agent 的实时输出。VS Code 的终端对 tmux 的支持很好Ctrl-b前缀键不会和 VS Code 快捷键冲突前提是你没改过 VS Code 的终端快捷键。注意在 VS Code 终端里 attach tmux 后鼠标滚轮默认是发送方向键而不是滚动历史。可以在 tmux 配置里加set -g mouse on开启鼠标模式但这样会失去终端原生的文本选择功能。我的做法是保持鼠标模式关闭用Ctrl-b [进入 copy mode 来滚动查看历史。7.4 配置模板化与团队共享如果你在团队里推广openrig建议把配置拆成“角色模板”和“项目实例”两层。角色模板定义常见角色如developer、reviewer、tester的标准配置项目实例只引用模板并覆盖少量字段。YAML 的锚点和别名语法可以部分实现这个效果templates: developer: developer tool: claude-code command: claude env: ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} agents: - name: claude-dev : *developer role: 功能开发 workdir: ./src:是 YAML 的合并键会把锚点指向的 map 合并进来。但注意合并键是浅合并嵌套的envmap 会被整体替换而不是逐键合并。如果需要深度合并还是得用yq在启动脚本里处理。8. 我踩过的几个坑和对应的解法第一个坑是tmux 会话名和 window 名的大小写敏感。有一次配置里写了session_name: MyRig启动脚本里用tmux has-session -t myrig检查结果永远返回不存在每次都创建新会话最后机器上堆了七八个同名会话。后来统一改成小写加连字符的命名规范问题消失。第二个坑是Agent 启动命令里的引号嵌套。YAML 里写command: echo hello world经过yq解析和send-keys发送后引号可能被 shell 吃掉。解决方案是用 YAML 的单引号包裹整个命令内部用双引号command: echo hello world。如果命令里同时需要单双引号就用块标量语法。第三个坑是Claude Code 和 Codex 的工作目录冲突。两个 Agent 如果在同一个目录下同时写文件偶尔会出现文件被覆盖的情况。后来我在openrig.yaml里给每个 Agent 分配了独立的子目录通过符号链接共享需要协作的文件。这样既避免了写冲突又保持了文件可见性。第四个坑是长时间运行后的内存泄漏。Claude Code 在连续运行超过 8 小时后内存占用会明显上升。我的做法是在openrig里加一个定时重启的 Agent每 6 小时向 Claude Code 窗口发送一次退出和重启命令。虽然粗暴但实测有效。这套openrig方案我从去年开始在自己的项目里用从最初的手动开窗口到后来写脚本再到现在的 YAML 配置化前后迭代了七八个版本。最深的体会是多 Agent 协作的瓶颈往往不在 Agent 本身而在编排层。把编排层做扎实了Agent 的能力才能被真正释放出来。如果你也在折腾类似的东西建议先从最简单的双 Agent 配置开始跑通了再逐步加复杂度别一上来就搞五六个 Agent那样排查问题的成本会指数级上升。
返回列表