我的 Hermes 助手一直挂在 Telegram 和微信上。最近想让它在微信上多一个身份:独立的会话、独立的记忆,跟主号互不干扰——大概是”工作号”和”生活号”的关系。
直觉方案先被内存否掉
最直接的想法是再起一个网关进程。动手前顺手看了一眼机器:可用内存只剩一点点,swap 已经在撑着。
一台本来就跑着七八个服务的小机器,一个网关已经吃掉不少内存。再起一个进程不是”多花点内存”,是直接压爆。
于是换思路。Hermes 支持一种更省的模式:一个网关进程服务多个 profile。profile 是 Hermes 的隔离单元——每个 profile 有自己的会话、记忆、技能、cron 任务,但它们可以由同一个进程调度。这正是我想要的:身份隔离,进程不隔离。
微信这条路是怎么走的
Hermes 的微信通道走的是 iLink 的 bot 接口。绑定方式很朴素:调一次接口拿二维码,用微信扫,确认之后返回一个 account_id 和 token,落盘到对应 profile 的目录里。
也就是说,扫码的那个微信号,本身就是 bot 的身份。想让助手有第二个微信身份,就得用第二个微信号去扫一次。
顺手确认了一件事:这个文件权限是 600,token 从来没有进过聊天记录。这类凭据的正确处理方式就是只落文件。
坑一:克隆 profile 刻意不带消息通道
建 profile 的时候我用 --clone,把配置、技能、性格文件都复制过来,省得重新配模型和 API key。命令跑完输出里有一句很关键的提示:
Messaging channels were NOT cloned: a copied bot token or allowlist would make two gateways fight over one bot.
两个 profile 拿着同一个 bot token,就是两个网关抢一个微信号——消息会被随机一半投递到错误的身份里去。所以这一步的”不复制”不是遗漏,是设计。第二个号得自己扫码、自己配。
坑二:二维码渲染缺库
扫码流程需要渲染二维码图片。运行时的 Python 环境里装了 aiohttp、cryptography、PIL,唯独没有 qrcode,而且那个 venv 里连 pip 都没有。
解决办法不是去动这个受管环境,而是把 qrcode 装到一个独立目录,用 PYTHONPATH 指过去。纯 Python 包,不影响任何全局状态。
坑三:迁移会等我,而我正在迁移
把开关打开之后要重启网关。我直接跑了 hermes gateway migrate -y,然后看到这样的输出,一直循环:
⏳ still draining — xxxxs left before the forced restart
waiting on 1 active work unit(s):
• chat turn agent:main:telegram:dm:... running 5m05s
它在等”进行中的对话”结束才能重启网关——而那个进行中的对话就是我,我正在这条命令里面。
这不是 bug,恰恰是它够谨慎:不能一边对话一边把网关掐了。最后我在这一轮结束后,迁移自己跑完了。后来验证:
✓ default (current)
✓ wx2 — served by the default multiplexer
一个进程,两个 profile,第二个微信号也顺利连上。内存没有翻倍。
坑四:第一次说话要审批
第二个号默认是 pairing 策略:陌生人发来第一句,bot 不回内容,而是给一个配对码,等 owner 批准。
这个设计我很喜欢。因为这类助手的权限是 shell——一条没审批的消息就能执行任意命令。配对码有效期一小时,批准之后才会被识别。
批准的方式是一行命令,我在主号这边执行完,那边的对话立刻正常。
定时任务也要拆
原本的结单监控 cron 挂在主 profile 上,推到 Telegram 和 QQ。现在希望微信那份从第二个号发出去——但不同 bot 的 peer 标识不能跨号投递,只能在那边的 profile 里单独建一个任务。
两个任务跑同一份脚本,于是又多两件事要处理:
- 文件锁:两个任务同时触发时串行执行,否则会并发写数据库,可能重复记账;
- 报告缓存三小时:第一个任务处理完新文件之后,第二个任务看到”没有新文件”就会沉默——微信那份就收不到了。所以脚本会把最近的报告留三小时,允许另一个渠道重发一次。
细节都是被坑出来的。
小结
这件事最值得记的不是配置步骤,而是那句”先看资源再设计”。我的第一版方案(再加一个进程)在纸面上完全成立,唯一的错误是没有先看一眼 free -h。
多身份不等于多进程。而隔离这件事,靠配置能解决的时候,就别靠机器。