OpenRig 多智能体编排实战:tmux 与 MCP 构建持久化协作系统

发布时间:2026/10/8 6:56:26
OpenRig 多智能体编排实战:tmux 与 MCP 构建持久化协作系统 1. 从一次性对话到常驻协作OpenRig 要解决的真实痛点如果你最近半年一直在折腾 AI Agent大概率经历过这样一个阶段一开始用单文件脚本调 API感觉挺爽接着开始加工具调用、加记忆、加多轮循环代码膨胀到几千行再往后想让两个 Agent 互相配合就彻底乱了——谁先跑、谁等谁、状态存哪、崩了怎么恢复全靠一堆asyncio.gather硬撑。跑一次能出结果跑十次有三次卡死剩下七次结果还不一样。OpenRig 这个项目瞄准的就是这个阶段之后的痛点。它做的事情用一句话概括把一堆各自为战的离散 AI Agent编织成一个能长期存活、可恢复、可观测的协作系统。注意这里的关键词是持久化和协作不是再写一个 Agent 框架。市面上不缺 Agent 框架缺的是让多个 Agent 像一支真正的团队那样持续运转的编排层。我最初关注到 OpenRig是因为它的技术栈组合很有意思底层用tmux做进程与终端会话的持久化载体中间用MCPModel Context Protocol做工具与能力的标准化接入整体编排逻辑偏重会话即资源的思路。这套组合不是拍脑袋来的它对应着多智能体系统里最容易被忽视的三个问题进程生命周期管理、能力标准化、状态可恢复性。这篇文章适合谁看如果你已经写过至少一个能跑通的 Agent正在被多 Agent 协作折磨或者你在设计一个需要 7x24 小时运行、任务可能持续几十分钟甚至几小时的自动化系统那这篇内容会对你有直接帮助。如果你还停留在什么是 Agent的阶段建议先补一下工具调用和 ReAct 循环的基础再回来看编排层的东西收获会更大。我会从 OpenRig 的核心设计动机讲起拆解它为什么选 tmux 而不是纯进程池为什么把 MCP 放在能力接入的核心位置然后给出可复现的搭建步骤、协作拓扑设计方法、并发与容错处理最后分享几个我在实际编排中踩过的坑。全程按为什么这么设计来讲而不是只丢一堆配置。2. 拆解 OpenRig 的编排内核为什么是 tmux MCP 这套组合2.1 持久化到底持久的是什么很多人第一次听到持久化协作系统会下意识理解成把对话历史存数据库。这只对了一半。OpenRig 语境下的持久化至少包含三个层次缺一个都撑不起常驻这个词。第一层是会话持久化。Agent 运行时的上下文、当前执行到哪一步、打开了哪些工具通道这些不能只活在内存里。进程一挂全没了那就不叫持久。第二层是进程持久化。Agent 本质是个长时间运行的程序它需要有一个稳定的宿主环境不能因为主控脚本退出就被连带杀掉。第三层是状态可恢复。系统重启后能知道上次谁在干什么、干到哪了、下一步该谁接手。这三层里最容易被低估的是第二层。你写个 Python 脚本subprocess.Popen起一个 Agent主脚本一 CtrlC子进程跟着走。想让 Agent 独立存活你得用nohup、setsid、systemd 或者容器。但这些方案要么太重要么不便于实时观察 Agent 的思考过程。2.2 tmux 在这里扮演的角色不只是终端复用tmux 常被当成分屏工具但在 OpenRig 这类系统里它的价值被重新定义了tmux 是一个轻量级的、可 attach 的、带命名空间的进程会话管理器。具体来说tmux 提供了几个别的方案很难同时满足的特性会话与终端解耦tmux new-session -d创建的会话在后台独立运行你的 SSH 断了、主控脚本退了会话照样活着。这天然解决了进程持久化问题。可随时 attach 观察tmux attach -t agent_worker_01你能实时看到这个 Agent 此刻在打印什么、卡在哪一步。调试多 Agent 系统时这个能力价值极高——比翻日志快十倍。命名即寻址每个 Agent 一个命名会话编排层通过会话名就能定位、发送指令、读取输出相当于给每个 Agent 分配了一个稳定的工位。发送按键与捕获输出tmux send-keys和tmux capture-pane让编排层可以用模拟终端输入输出的方式与 Agent 交互这对那些没有提供 API、只能跑在终端里的 Agent 特别友好。我实测下来最深的一点体会是tmux 把Agent 是一个活着的进程这件事变得可触摸了。你不再是面对一堆抽象的协程而是能 attach 进去看它到底在干嘛。多 Agent 系统最难的就是看不见tmux 恰好补上了这块。当然tmux 不是银弹。它的输出捕获是屏幕快照式的解析起来比结构化日志麻烦会话数量多了之后管理成本上升跨机器编排需要额外方案。这些后面会专门讲怎么绕。2.3 MCP 为什么成了能力接入的事实标准MCPModel Context Protocol这两年被讨论得非常多从 IDE 插件到各类工具桥接几乎成了给模型接工具的通用语言。OpenRig 把 MCP 放在能力接入的核心位置逻辑很清晰编排层不应该关心每个工具的具体实现只应该关心这个 Agent 能调用哪些标准化的能力。在没有 MCP 之前你给 Agent 加一个能力往往要写一堆胶水代码这个工具是 HTTP 接口那个是本地命令行还有一个是某个软件的插件。每个都要单独适配Agent 之间的能力无法复用。MCP 把这些统一成服务端暴露工具、客户端按协议调用的模式Agent 只要会说 MCP就能接入所有实现了 MCP 的工具。对 OpenRig 这种多智能体系统来说MCP 带来的最大好处是能力的可组合性。你可以让 Agent A 通过 MCP 接入文件系统工具Agent B 接入数据库工具Agent C 接入某个设计软件的桥接工具然后编排层根据任务需要把不同能力动态分配给不同 Agent。能力成了积木而不是焊死在某个 Agent 里的硬编码。提示MCP 服务端有本地进程stdio和远程SSE/HTTP两种常见形态。本地 stdio 适合单机、低延迟、工具需要访问本机资源的场景远程形态适合多机共享、工具集中部署的场景。选哪种取决于你的 Agent 是否跨机器。2.4 三者如何咬合成一个整体把 tmux 和 MCP 放在一起看OpenRig 的架构轮廓就出来了层次承担职责对应技术会话层Agent 进程存活、可观察、可寻址tmux 会话能力层工具标准化接入、动态分配MCP 服务端/客户端编排层任务分发、协作拓扑、状态恢复编排逻辑调度器状态层任务进度、会话映射、恢复点持久化存储会话层保证Agent 活着能力层保证Agent 能干标准化的活编排层决定谁在什么时候干什么状态层保证崩了能接上。四层各司其职任何一层缺失系统都撑不起持久化协作这四个字。理解了这套分层后面所有的实操才有落脚点。很多人上来就抄配置结果不知道每个配置项对应哪一层出问题就抓瞎。先把分层想清楚再动手。3. 搭建一个最小可用的 OpenRig 协作环境3.1 环境准备里最容易被忽略的三件事搭建之前先把基础环境理清楚。这部分看起来简单但坑基本都埋在这里。第一件事是tmux 版本。老版本 tmux 在capture-pane的参数支持上不完整尤其是带范围捕获-S、-E和保留转义序列的选项。建议 3.0 以上3.2 更稳。用tmux -V确认别嫌麻烦。第二件事是会话命名规范。OpenRig 靠会话名寻址命名必须机器可解析。我建议统一成rig_role_id的格式比如rig_planner_01、rig_worker_03、rig_reviewer_01。角色和编号分开编排层用正则就能提取角色做路由和统计都方便。千万别用中文名或者带空格的会话名send-keys和脚本解析时会让你怀疑人生。第三件事是MCP 服务端的启动方式。本地 stdio 型 MCP 服务端通常是被客户端按需拉起的子进程但如果你希望它常驻多个 Agent 共享就得自己把它托管起来同样可以用 tmux 会话托管。这里有个细节MCP 服务端如果被多个客户端同时连接要确认它是否支持并发会话不支持的话就得给每个 Agent 起独立实例或者加一层连接池。# 确认 tmux 版本 tmux -V # 创建一个托管的 MCP 服务端会话示例具体命令按你的服务端来 tmux new-session -d -s rig_mcp_filesystem npx -y modelcontextprotocol/server-filesystem /data/workspace # 确认会话已建立 tmux ls3.2 用 tmux 会话托管 Agent 进程的标准姿势托管一个 Agent核心就三步建会话、跑命令、留活口。但每一步都有讲究。建会话时用-d让它后台运行用-s指定名字。跑命令时建议把 Agent 的启动命令写成一个脚本而不是直接塞一长串命令进send-keys因为长命令在终端里容易被截断或转义出错。留活口的关键是Agent 进程本身要能处理没有输入时保持存活如果你的 Agent 是跑完就退出的类型那 tmux 会话会跟着结束持久化就无从谈起。# 推荐把启动逻辑写成脚本 cat /opt/rig/start_worker.sh EOF #!/bin/bash cd /opt/rig/workspace export AGENT_ROLEworker export AGENT_ID03 # 这里换成你的 Agent 启动命令 exec python3 /opt/rig/agent_main.py --role worker --id 03 EOF chmod x /opt/rig/start_worker.sh # 用 tmux 托管 tmux new-session -d -s rig_worker_03 /opt/rig/start_worker.sh # 验证进程活着 tmux has-session -t rig_worker_03 echo worker_03 alive这里有个我踩过的坑别在 tmux 会话里用把 Agent 再丢到后台。这样 Agent 会脱离 tmux 的进程树capture-pane抓不到它的输出attach 进去也是空的。tmux 会话本身就是你的后台不需要再套一层。3.3 让 Agent 通过 MCP 拿到标准化能力Agent 接入 MCP 的典型流程是配置 MCP 服务端地址本地就是启动命令远程就是 URL客户端初始化连接拉取工具列表把工具描述注入到模型的工具定义里。不同语言和框架的 MCP 客户端实现不同但逻辑一致。以常见的 stdio 型 MCP 为例配置大致长这样{ mcpServers: { filesystem: { command: npx, args: [-y, modelcontextprotocol/server-filesystem, /data/workspace] }, database: { command: python3, args: [/opt/rig/mcp_db_server.py], env: { DB_URL: sqlite:///data/rig.db } } } }配置好之后Agent 启动时会自动连接这些服务端拿到read_file、write_file、query之类的工具。编排层不需要知道这些工具怎么实现只需要在任务描述里告诉 Agent你可以用文件系统工具。注意MCP 工具列表是动态的服务端重启后工具可能变化。编排层如果缓存了工具列表要设计失效重拉机制否则会出现Agent 以为有某个工具实际调用报错的情况。3.4 跑通第一个双 Agent 协作任务环境搭好后先别急着上复杂拓扑。用一个最小任务验证链路Planner 拆解任务Worker 执行结果写回文件。具体做法起两个 tmux 会话rig_planner_01和rig_worker_01。Planner 通过 MCP 文件工具把任务拆解结果写到/data/workspace/task.jsonWorker 轮询这个文件读到任务就执行执行完写/data/workspace/result.json。编排层只负责起会话和监控文件变化。这个文件当信箱的做法很土但它把Agent 之间怎么通信这个核心问题用最简单的方式跑通了。跑通之后你再换成消息队列、数据库或者 MCP 的某种通信工具心里就有底了。先跑通再优化这是多 Agent 系统搭建的铁律一上来就设计完美架构大概率卡在某个细节上出不来。4. 协作拓扑设计让多个 Agent 真正配合而不是各跑各的4.1 三种基础拓扑及其适用场景多 Agent 协作不是Agent 越多越好拓扑选错了加再多 Agent 也只是增加混乱。实践中常用的有三种基础拓扑。流水线型PipelineAgent 按顺序接力A 的输出是 B 的输入B 的输出是 C 的输入。适合有明确阶段划分的任务比如抓取数据 → 清洗 → 分析 → 生成报告。优点是逻辑清晰、易调试缺点是任何一个环节卡住整条线都停。主从型Orchestrator-Worker一个主 Agent 负责拆解和分派多个 Worker 并行执行子任务主 Agent 汇总结果。适合可并行拆解的任务比如同时处理 20 个文件。优点是吞吐高缺点是主 Agent 容易成为瓶颈且子任务结果汇总逻辑要设计好。对等协商型Peer多个 Agent 地位平等通过共享状态或消息互相协调。适合需要多视角讨论的任务比如方案评审。优点是灵活缺点是没有中心容易死锁或反复拉扯必须有明确的终止条件。拓扑适用场景主要风险关键设计点流水线阶段明确的任务单点阻塞阶段间契约、超时处理主从可并行拆解的任务主节点瓶颈分派策略、结果聚合对等多视角协商任务死锁、无限循环终止条件、发言权控制选拓扑的原则很简单任务本身的结构决定拓扑而不是反过来。别为了用某个拓扑去硬套任务。4.2 用 tmux 会话名做路由的实操方法拓扑定下来后编排层要能把任务路由到正确的 Agent。前面强调的会话命名规范在这里发挥作用了。假设命名是rig_role_id编排层可以这样路由# 列出所有 worker 会话 tmux ls | grep -oE rig_worker_[0-9] # 向指定 worker 发送任务通过 send-keys 触发它读取任务文件 tmux send-keys -t rig_worker_03 run-task /data/workspace/task_003.json Enter # 捕获某个会话的当前输出判断它是否完成 tmux capture-pane -t rig_worker_03 -p | tail -n 20这套会话名即路由表的做法好处是编排层不需要维护额外的注册中心tmux 本身就是注册中心。缺点是会话名一旦被误改路由就断了所以要有命名校验。4.3 Agent 之间怎么传递上下文而不互相污染多 Agent 系统里一个隐蔽的坑是上下文污染A 的中间推理过程被完整传给 BB 又被传给 C最后 C 拿到的上下文里塞满了无关信息模型开始跑偏。我的做法是分层传递Agent 之间只传结构化结果不传完整对话历史。比如 Planner 给 Worker 的是一份明确的任务描述目标、输入、输出格式、约束而不是 Planner 自己的思考过程。Worker 给下游的是执行结果和关键决策点不是它调了多少次工具。具体落地时可以约定一个 Agent 间消息格式{ from: rig_planner_01, to: rig_worker_03, task_id: t-20240612-001, goal: 清洗 /data/raw/sales.csv 并输出到 /data/clean/sales.csv, inputs: [/data/raw/sales.csv], outputs: [/data/clean/sales.csv], constraints: [保留原始列名, 缺失值用中位数填充], deadline: 2024-06-12T15:00:00Z }这个格式强制 Agent 只传必要信息上下文自然就干净了。上下文管理是多 Agent 系统里最容易被忽视、又最影响效果的一环比选什么模型重要得多。4.4 共享状态放哪里文件、数据库还是消息队列Agent 之间除了点对点传消息往往还需要共享状态。三种常见载体各有取舍。文件最简单适合小规模、低频读写。缺点是并发写有竞争需要加锁或约定谁写哪个文件。前面最小示例用的就是文件。数据库适合需要查询、事务、多字段状态的场景。SQLite 单机够用PostgreSQL 适合多机。缺点是 Agent 要会写 SQL 或通过 MCP 数据库工具操作增加了一层。消息队列适合高频、异步、需要解耦的场景。Redis Stream、RabbitMQ 都行。缺点是引入了额外组件运维成本上升。我的经验是从文件开始遇到瓶颈再升级。很多团队一上来就上 Kafka结果 90% 的场景根本用不到反而被运维拖累。文件方案在 Agent 数量少于 20、任务频率不高时完全够用。5. 并发、容错与状态恢复让系统扛得住真实负载5.1 AI Agent 怎么扛并发先分清三种并发AI Agent 怎么扛并发是最近被问得最多的问题之一。但很多人没分清并发到底指什么。在多 Agent 系统里至少有三层并发。会话并发同时有多少个 Agent 会话在跑。这层受限于机器资源CPU、内存、tmux 会话数一般几十到上百个没问题。任务并发同时有多少个任务在被处理。这层受限于 Agent 数量和每个 Agent 的处理能力。模型调用并发同时有多少个请求打到模型服务。这层受限于 API 的速率限制和配额往往才是真正的瓶颈。很多人以为多起几个 Agent 就能扛并发结果发现模型 API 先被打爆了。真正的并发瓶颈通常在模型调用层而不是 Agent 层。所以设计时要先算清楚你的模型配额是多少 QPS每个任务平均要调多少次模型然后反推能支撑多少任务并发。5.2 用 tmux 会话池控制并发上限控制会话并发最直接的办法是维护一个会话池。编排层不直接new-session而是从池里取空闲会话用完归还。# 简化的会话池逻辑伪代码思路 # 1. 预创建 N 个 worker 会话 for i in $(seq -w 1 10); do tmux new-session -d -s rig_worker_$i /opt/rig/start_worker.sh done # 2. 编排层维护空闲/忙碌状态可存文件或数据库 # 3. 有任务时取一个空闲会话send-keys 派发 # 4. 任务完成后标记会话空闲池化之后并发上限就是池的大小可控。想扩容就加会话想缩容就减会话。比来一个任务起一个会话要稳得多也避免了会话数失控。5.3 会话挂了怎么发现、怎么重启Agent 会话挂掉是常态不是异常。可能因为模型调用超时、工具报错、内存溢出。关键是能发现、能重启、能续上。发现靠心跳。让每个 Agent 定期往一个心跳文件或数据库表写时间戳编排层定期扫描超过阈值没心跳就判定为挂。# 检查会话是否还存在 if ! tmux has-session -t rig_worker_03 2/dev/null; then echo worker_03 已挂准备重启 tmux new-session -d -s rig_worker_03 /opt/rig/start_worker.sh fi重启之后要能续上靠的是状态层。Agent 启动时先读自己的上次进度从断点继续而不是从头再来。这就要求 Agent 的执行逻辑是可中断、可恢复的每个关键步骤完成后都要落一次状态。这一点在设计 Agent 时就要考虑进去事后补很痛苦。5.4 状态恢复的检查点设计检查点checkpoint是状态恢复的核心。设计检查点要回答三个问题存什么、什么时候存、怎么读回来。存什么至少包括当前任务 ID、已完成步骤、当前步骤的中间结果、下一步动作。不要存整个对话历史太大且没必要。什么时候存每个原子步骤完成后存一次。所谓原子步骤就是要么全做完、要么全没做的最小单元。比如调用工具并拿到结果是一个原子步骤调用工具和处理结果之间不该存检查点否则恢复时状态不一致。怎么读回来Agent 启动时先查有没有未完成的检查点有就从检查点恢复没有就从头开始。恢复逻辑要幂等重复恢复不能产生副作用。# 检查点读写示意 def save_checkpoint(task_id, step, state): with open(f/data/checkpoints/{task_id}.json, w) as f: json.dump({step: step, state: state, ts: time.time()}, f) def load_checkpoint(task_id): path f/data/checkpoints/{task_id}.json if os.path.exists(path): with open(path) as f: return json.load(f) return None这套机制看起来朴素但它是持久化协作能成立的底层保障。没有检查点所谓持久化就只是进程不退出一旦退出就前功尽弃。6. 实战踩坑记录那些文档里不会写的细节6.1 capture-pane 抓输出为什么总是不完整tmux capture-pane默认只抓当前可见区域Agent 如果输出很长滚上去的部分就抓不到。要用-S指定起始行-S -表示从历史缓冲区最开头抓。# 抓取整个历史缓冲区 tmux capture-pane -t rig_worker_03 -p -S - # 抓取最近 500 行 tmux capture-pane -t rig_worker_03 -p -S -500但即使这样输出里还混着终端控制字符、进度条残留、光标移动序列。解析前要先清洗。我的做法是让 Agent 把关键结果同时写到一个结构化文件capture-pane只用来做人工观察和兜底不作为主要数据来源。别把屏幕抓取当 API 用这是血泪教训。6.2 send-keys 的转义地狱send-keys发送的内容如果包含特殊字符引号、反斜杠、$、!会被 shell 或 tmux 解释导致发过去的命令面目全非。最稳的做法是不直接发命令而是发一个信号让 Agent 自己去读文件。# 不推荐直接发复杂命令 tmux send-keys -t rig_worker_03 process --input /data/a b.json --flag \$X Enter # 推荐发一个简单信号Agent 自己读任务文件 tmux send-keys -t rig_worker_03 TASK_READY EnterAgent 收到TASK_READY后去约定的路径读任务。这样彻底绕开了转义问题也让任务内容可以很复杂而不受终端限制。6.3 MCP 服务端被多个 Agent 抢连接本地 stdio 型 MCP 服务端通常一个客户端连接对应一个服务端进程。如果你让 10 个 Agent 都去连同一个 stdio 服务端要么连不上要么互相干扰。解决办法有两个每个 Agent 起独立服务端实例或者改用支持多连接的远程形态。我一般推荐前者因为独立实例隔离性好一个崩了不影响其他。代价是资源占用上升但 Agent 数量不多时完全可接受。如果工具本身是有状态的比如操作同一个数据库那就要用远程形态加连接池并处理好并发写。6.4 Agent 陷入死循环的三种典型形态多 Agent 系统最怕死循环而且往往不是简单的while True而是更隐蔽的形态。第一种是互相等待A 等 B 的结果B 等 A 的结果谁都不动。这在对等拓扑里常见。解法是引入超时和打破僵局的规则比如超时后由某个 Agent 强制推进。第二种是反复协商两个 Agent 对方案反复讨论每次都觉得还能再改改永远达不成一致。解法是设定最大轮次到轮次就强制收敛。第三种是任务重试风暴任务失败后自动重试重试又失败无限重试。解法是重试要有上限和退避超过上限就标记为需人工介入。提示给每个 Agent 的执行循环都加上最大步数限制是最简单有效的防死循环手段。超过步数就停下来报告而不是继续烧 token。6.5 日志与可观测性别等出事才想起来多 Agent 系统出问题时最难的是定位是哪个 Agent 在哪一步出的问题。所以日志要结构化、带会话标识、带任务标识。我的做法是每个 Agent 的输出都带前缀[rig_worker_03][task-001][step-5]。这样grep一下就能把某个任务的全链路日志捞出来。同时关键事件任务开始、步骤完成、任务结束、异常单独写一份事件日志方便做统计和告警。可观测性不是上线后再补的东西而是从第一天就要设计的。多 Agent 系统的复杂度是单 Agent 的数倍没有好的可观测性排查问题的时间会指数级上升。7. 从能跑到好用几个让系统更稳的进阶思路7.1 给 Agent 加能力声明让编排层智能匹配前面说 MCP 让能力标准化了但编排层怎么知道哪个 Agent 能干哪个活答案是让 Agent 启动时声明自己的能力。每个 Agent 在启动时往一个注册表写自己的角色、可用工具、擅长任务类型。编排层分派任务时先查注册表匹配最合适的 Agent。这样加新 Agent 或改能力时不用改编排逻辑只改声明。{ session: rig_worker_03, role: worker, capabilities: [file_ops, data_cleaning, csv_processing], mcp_servers: [filesystem, database], max_concurrent_tasks: 1 }这套能力声明 匹配的机制是系统从硬编码路由走向动态编排的关键一步。7.2 用任务优先级和队列避免饿死任务多了之后如果都平等对待长任务会一直占着 Agent短任务排不上队。引入优先级队列让紧急任务插队长任务在后台慢慢跑。实现上可以用一个带优先级的任务表编排层按优先级取任务分派。同时给每个任务设最长占用时间超时就暂停它、让出 Agent稍后再续。这样既保证紧急任务响应又不让长任务被彻底饿死。7.3 灰度与回滚改编排逻辑时怎么不翻车编排逻辑一改可能影响所有 Agent。直接全量上线风险太大。做法是灰度先让一小部分任务走新逻辑观察没问题再逐步扩大。具体可以按任务 ID 哈希取模比如hash(task_id) % 10 1的走新逻辑其余走旧的。出问题就调小比例甚至回滚。这套思路和传统服务的灰度发布一样只是对象从请求变成了任务。7.4 成本控制别让 Agent 悄悄烧钱多 Agent 系统烧钱速度比单 Agent 快得多因为并发调用多、重试多、上下文长。几个控制点给每个任务设 token 预算超了就停给重试设上限定期清理无用的长上下文对简单任务用小模型复杂任务才用大模型。我见过最夸张的案例是一个死循环的 Agent 一晚上烧掉几百刀。成本控制不是优化项是必需项尤其是系统刚上线、逻辑还不稳定的时候。8. 我在这套编排实践里最想分享的几点体会折腾 OpenRig 这类多智能体编排系统大半年最大的感受是难点从来不在让 Agent 跑起来而在让它们稳定地一起跑下去。单 Agent 的坑是技术性的多 Agent 的坑是系统性的——进程管理、状态一致性、通信协议、容错恢复每一个都是独立的工程问题。tmux 这套方案一开始我也觉得太土了但用下来发现它恰好补上了多 Agent 系统最缺的可观察性和进程持久化。attach 进去看 Agent 实时输出的那种踏实感是任何日志系统都给不了的。MCP 则解决了能力复用的问题让 Agent 之间的能力可以像积木一样组合。如果让我给正在入坑的朋友一句建议先把两个 Agent 的协作跑稳再谈扩展。很多人一上来就设计五六个 Agent 的复杂拓扑结果连两个都协调不好。系统的复杂度是随 Agent 数量非线性上升的两个跑稳了加第三个才有意义。最后分享一个我一直在用的小技巧给每个 Agent 会话起名时在名字里带上它当前负责的任务 ID 后缀比如rig_worker_03_t001。这样tmux ls一眼就能看出每个 Agent 在忙什么排查问题时省下大量时间。任务完成后把会话名改回空闲态。这个习惯看起来微不足道但在 Agent 数量上到两位数之后它带来的效率提升非常明显。