五个 Gateway 进程共存:AI Agent 消息平台 Token 锁冲突
本文最后更新于 2026年8月5日 凌晨
每次给 AI Agent 开一个新 profile(韩梅梅、李雷、露西……),都会顺手起一个 hermes gateway run。一个 profile 一个进程,五个 profile 五个进程,听着很合理——直到微信 bot 突然全线失联,日志里全是 “Weixin bot token already in use”。
这就是多 Gateway 进程的 Token 锁冲突。表面看是微信 bot 连不上,实际上是 Hermes 的消息平台 Token 在进程级共享,而每个 Gateway 都认为自己拿到了所有权。
问题的发现
日志不会撒谎。这是某次排查时的现场记录:
1 | |
注意到 token already in use (PID 1097147) 了吗?PID 1097147 是另一个 Gateway 进程,它比当前进程先连上了微信。当前 Gateway 被卡在了一个指数退避重连循环里(60s → 120s → 240s),永远等不到释放。
为什么会冲突
Hermes 的 Gateway 架构里,消息平台接入(微信、飞书、API Server 等)走的是同一套平台适配器,而微信 bot 的 Token 是一个全局共享资源——不是每个 profile 一份。
这意味着:
- 微信 bot Token 只能被一个 Gateway 持有。无论起多少个进程,第一个连上的就是唯一能收消息的那个。
- 飞书和 API Server 没有这个限制。飞书 WebSocket 是每个 app 一个连接,API Server 是 HTTP 端口监听,两者都不存在 Token 互斥。
--replace参数只替换本 profile 的 Gateway 进程,不会去停别的 profile 的进程。
实际现场:六个 Hermes 进程同时在线——
| PID | Profile | 状态 | 微信 |
|---|---|---|---|
| 1003464 | default (main) | running | ✅ 持有 Token |
| 1003504 | hanmeimei | running | ✗ Token 被占 |
| 1003614 | lilei | running | ✗ Token 被占 |
| 1003765 | lucy | running | ✗ Token 被占 |
| 1003891 | polly | running | ✗ Token 被占 |
| 1003994 | xiaomei | running | ✗ Token 被占 |
hanmeimei 到 xiaomei 这五个子进程的微信通道,全部是死的。
除了微信 Token 锁,还有一个并行问题:Kanban Dispatcher 的锁文件 /home/tony/.hermes/kanban/.dispatcher.lock 也是进程级互斥。同一时刻只能有一个 Gateway 持有 dispatcher lock,其他进程只会输出:
1 | |
这不是 Bug,是设计行为——多个 Gateway 共享同一个 Task Queue,必须保证调度不重复。真正需要排查的是平台 Token,而不是 dispatcher lock。
根本原因
| 项目 | 说明 |
|---|---|
| 平台 Token 共享 | 微信 bot Token 在所有 profile 间共享,不随 profile 隔离 |
| 没有 Token 抢占 | Hermes 没有”踢掉旧进程、抢 token”机制,后来者只能被动等待 |
| 退避重连无上限 | 退避间隔只增不减,最长 240s,理论上永远等不到 |
--replace 不跨 profile |
只重启本 profile,不会清理其他 profile 的连接 |
换句话说:微信 bot 在设计上就是单点接入的,而多 Gateway 部署没有做 Token 路由。
怎么修
方案 A:只留一个主 Gateway 接微信
最稳妥的做法。微信 bot 只配在 main profile(default),其他子 profile 的 config 里直接 weixin: { enabled: false }。
1 | |
这样只有 main Gateway 接微信,其他进程专心处理本 profile 的飞书/Telegram 等独立平台。
方案 B:子 profile 走不同消息通道
每个 AI Agent 用自己的消息通道,避免 Token 碰撞:
- 韩梅梅 → Telegram bot(独立 token)
- 李雷 → Discord(独立 bot)
- 露西 → Slack(独立 app)
- 主进程 → 微信 + API Server
Hermes 对 Telegram、Discord、Slack 的支持是每个 bot/app 一个连接,天然互不干扰,不存在 Token 锁。
方案 C:手动轮转(不推荐)
如果确实需要所有 profile 都能接微信,只能:
ps aux | grep "hermes gateway"确认所有 Gateway 的 PID- 找到持有微信 Token 的进程,
kill它 - 重启目标 profile 的 Gateway
- 验证日志无
token already in use
这只能应急,不能当常态。每次新进程上来还是会撞。
验证方法
1 | |
经验教训
多 Gateway 部署的本质问题是资源粒度不匹配:Gateway 是 profile 级进程,但消息平台 Token 是全局级资源。架构上的不对称必然导致冲突。
解决思路只有两条路:
- 资源下沉——让每个 profile 拥有独立的平台 Token(方案 B),适合多平台异构接入;
- 资源上收——把全局资源只配在主 profile,子 profile 不碰(方案 A),适合微信这类单一接入的平台。
不要试图在 Hermes 现有的 --replace 机制上打补丁,那个参数只负责进程替换,不负责资源协调。