ai-bridge:把本机多个 AI 编程 CLI 收成一个 MCP 调度台
一句话:它把本机安装的 12 个 AI 编程 CLI(qoder / codely / opencode / workbuddy / atom-code / claude-code …) 收成 4 个 MCP 工具 + 一套 HTTP API,让任何支持 MCP 的客户端都能把任务派给它们,并带自动降级。
一、为什么需要它
本机同时装着好几个 AI 编程工具,各有各的登录态、参数和输出格式。真正干活时的痛点是:
- 切换成本:同一个任务想在 2–3 个工具上跑一遍对比,得手工复制粘贴;
- 长任务占会话:一个重构任务跑 10 分钟,主会话就干等着;
- 能力差异:Qoder 的订阅额度、OpenCode 的免费模型、Codely 的别名池,各有各的强项;
- 故障转移:某个 CLI 登录失效时,希望自动换下一个,而不是整条链路失败。
ai-bridge 就是这一层的粘合剂:统一入口、并行分发、自动降级、结果回收。
二、架构
MCP 客户端(qidicode / Claude Desktop / 任意 MCP Host)
│ stdio(bridge-stdio.js)
▼
ai-bridge Hub ── 127.0.0.1:9800(只绑本机,Bearer Token 鉴权)
│
├─ qoder (qodercli -p)
├─ codely / codely-k3
├─ opencode / opencode-flash / opencode-k3 / opencode-m31free
├─ workbuddy (codebuddy -p)
├─ atom-code (GLM)
├─ claude-code
└─ agnes-mcp / openclaw
三个关键文件:
tools.json:工具注册表(命令、参数模板、别名、描述);switches.json:每个工具的启停开关,持久化;clients-acl.json:允许接入的 MCP 客户端。
三、4 个 MCP 工具
| 工具 | 作用 | 参数 |
|---|---|---|
list_tools | 列出工具与可用/开关状态 | — |
list_switches | 只看开关(更简洁) | — |
toggle_tool | 开/关某个工具(持久化) | tool, enabled |
dispatch | 把任务分发给一个或多个工具 | task, tools[](空=全部已开启) |
四、HTTP API(不走 MCP 也能用)
# 鉴权:Authorization: Bearer $AI_BRIDGE_TOKEN
curl -s http://127.0.0.1:9800/api/tools -H "Authorization: Bearer $AI_BRIDGE_TOKEN"
curl -s http://127.0.0.1:9800/api/health -H "Authorization: Bearer $AI_BRIDGE_TOKEN"
curl -s http://127.0.0.1:9800/api/stats -H "Authorization: Bearer $AI_BRIDGE_TOKEN"
# 派活(缺 task 会返回 400 {"error":"缺少 task 参数"})
curl -s -X POST http://127.0.0.1:9800/api/dispatch \
-H "Authorization: Bearer $AI_BRIDGE_TOKEN" -H "Content-Type: application/json" \
-d '{"task":"给 utils.py 补 8 个边界用例","tools":["qoder","opencode-flash"]}'
# 异步任务的查询
curl -s http://127.0.0.1:9800/api/task/ -H "Authorization: Bearer $AI_BRIDGE_TOKEN"
Python 调用同样简单:
import json, os, urllib.request as u
TOKEN = os.environ["AI_BRIDGE_TOKEN"]
req = u.Request("http://127.0.0.1:9800/api/dispatch",
data=json.dumps({"task": "写一个 LRU 缓存", "tools": ["codely"]}).encode(),
headers={"Authorization": "Bearer " + TOKEN,
"Content-Type": "application/json"})
print(json.loads(u.urlopen(req, timeout=300).read()))
五、自动降级
dispatch 会按 tools.json 的注册顺序扫描可用工具。实测:当 Qoder 未登录(返回鉴权错误)时,
链路会自动落到下一个可用工具(例如 opencode-flash),整条请求仍然成功。
这就是"一台机器上多个订阅互补"的价值——任何一家掉线都不至于卡死。
六、和「子代理」不是一回事(重要)
| 维度 | ai-bridge dispatch | 原生子代理(spawn) |
|---|---|---|
| 本质 | 把任务交给外部 CLI | 宿主内置的父子会话 |
| 上下文 | 不共享,只收最终文本 | 独立但受宿主管理 |
| 生命周期 | Hub 管理,可异步查询 | 父会话管理 |
| 工具面 | 由对端 CLI 决定 | 宿主投影 |
所以它不能当作"嵌套子代理"用:没有父子链、没有深度约束、也拿不到对端的中间过程。 它的定位是委派:适合"这件事交给另一个 CLI 干完给我结果"。
七、踩坑清单
- Qoder 的 CLI 与桌面 IDE 是两个应用,登录态独立——IDE 登了不代表
qodercli登了; - 长文本必须走 stdin:arg 模式传多行任务会被截断(实测丢行),适配器已改为 stdin 传参;
- 结果有截断(约 2000 字符):要完整报告就让对方写文件,再从文件读;
- Hub 别用 shell 的 Start-Process 拉起:会被父进程的 Job Object 连带杀掉;用 WMI
Win32_Process.Create或注册服务; - 空返回等于失败:dispatch 无内容时按失败处理,别默认成功;
- 只绑 127.0.0.1:它是本机服务,不要暴露到局域网/公网(Token 只是最后一道闸)。
八、我们的实测数据
/api/stats 累计(截至 2026-10-27):
- 15,178 次调用,输入 37.75 亿 token、输出 171 万 token;
- 调用量前列:opencode 系、atom-code、qoder、workbuddy;
- 单次任务耗时从 20 秒(短问答)到 10+ 分钟(整文件重构)不等。
这些数字说明它已经在日常承担真实工作量,而不是玩具。
九、适合与不适合
| 适合 | 不适合 |
|---|---|
| 把长任务外包给另一个 CLI,主会话继续干别的 | 需要共享上下文的连续对话 |
| 同一任务多工具并行,比较产出质量 | 需要严格权限边界的敏感操作 |
| 某家额度用完时自动切换 | 把它当"更深一层的子代理" |
| 批量/定时任务(配合脚本) | 需要实时流式反馈的交互 |
小结
多 AI 工具并存的现实不会消失,与其在它们之间手工搬运,不如做一层协议化的调度: MCP 负责接入、Hub 负责分发、注册表负责能力声明、自动降级负责可用性。 这套东西不复杂,但它把"我有好几个工具"变成了"我有一个会用工具的系统"。