血与泪的教训:一台腾讯云服务器跑两个 Hermes AI Agent,各绑独立飞书机器人,踩坑全记录
血与泪的教训:一台腾讯云服务器跑两个 Hermes AI Agent,各绑独立飞书机器人,踩坑全记录
一个下午的崩溃调试,换来的配置模板,现在你只需要 10 分钟
前言:为什么需要多个 Agent?
假设你已经在用 Hermes Agent 作为你的 AI 助手,通过飞书 Bot 和它对话。但有一天你发现:
- 你希望有一个"工作专用"的 Agent,只处理数据分析、代码任务
- 另一个"日常助手"的 Agent,用来查资料、写文案、闲聊
- 或者你想让朋友/同事也能用,但不想让他们看到你的完整系统权限
最直接的想法:跑两个 Hermes 实例,各绑一个飞书机器人。
听起来简单,但我踩了一下午的坑。这篇文章就是帮你把这半天省下来的——跟着做,10 分钟搞定。
而且有一个好消息:你只需要去飞书开放平台申请一个机器人,把 App ID 和 Secret 拿来;剩下的所有配置,只要把这个页面上的内容复制给你的 Hermes Agent,它就能帮你自动完成。
一、架构概览
本方案部署在腾讯云服务器(公网 IP: 49.232.246.96)上,Ubuntu 系统。所有操作都在云服务器上完成。
飞书 App A (主Agent) ──→ Gateway A (主进程) ──→ Profile ~/.hermes/ ↓ 飞书 App B (Agent-B) ──→ Gateway B (子进程) ──→ Profile ~/.hermes/profiles/agent-b/- 两个 Hermes 进程,各自独立运行
- 两个飞书应用,各自绑定不同的 Bot Token
- 两个 Profile 目录,配置完全隔离
- 只有主 Agent 能管理 Agent-B(通过 terminal 工具),反过来不行
二、创建第二个 Agent 的 Profile
Hermes 支持 Profile 机制,创建第二个实例只需要复制一份配置文件。我这篇文章就是把这个过程完整走了一遍,把我的实践经验直接给你用:
# 创建 profile 目录 mkdir -p ~/.hermes/profiles/agent-b # 复制主配置作为模板 cp ~/.hermes/config.yaml ~/.hermes/profiles/agent-b/ # 创建专属 .env cp ~/.hermes/.env ~/.hermes/profiles/agent-b/修改agent-b/config.yaml中的关键参数(如模型、权限、超时等),让它和主 Agent 有所区分。
三、创建飞书 Bot
1. 去 [飞书开放平台](https://open.feishu.cn) → 创建企业自建应用
2. 获取App ID(格式cli_xxxxxxxxxxxxxxxx)和App Secret←这是你唯一需要手动操作的部分
3. 开启机器人能力
4. 配置事件订阅 → 选择WebSocket 长连接模式
5. 添加权限:im:message、im:chat、contact:user等(跟主 Agent 一样即可)
6. 发布版本
💡拿到 App ID 和 App Secret 之后,把剩余的内容给 Hermes Agent 看,它就能帮你把 systemd 配置、.env 文件、重启验证全部完成。你只需要把本文剩下的命令和配置文件给 Agent 执行就行。
四、配置 systemd 服务
为了让 Agent-B 能开机自启、崩溃自动恢复,给它写一个 systemd 服务:
[Unit] Description=Hermes Agent-B Gateway (独立实例) After=network-online.target Wants=network-online.target [Service] Type=simple User=ubuntu WorkingDirectory=/home/ubuntu/.hermes # 关键:指定 Profile 目录 Environment=HERMES_HOME=/home/ubuntu/.hermes/profiles/agent-b # Agent-B 的飞书凭证(写在 .env 里也行,但这里直接写更可靠) Environment=FEISHU_APP_ID=cli_你的APP_ID Environment=FEISHU_APP_SECRET=你的APP_SECRET Environment=FEISHU_DOMAIN=feishu Environment=FEISHU_CONNECTION_MODE=websocket Environment=FEISHU_ALLOW_ALL_USERS=true Environment=FEISHU_GROUP_POLICY=open ExecStart=/home/ubuntu/.hermes/hermes-agent/venv/bin/python \ -m hermes_cli.main gateway run --replace --accept-hooks Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target然后执行:
sudo systemctl daemon-reload sudo systemctl enable hermes-agent-b sudo systemctl start hermes-agent-b sudo systemctl status hermes-agent-b # 确认正常运行⚠️ 五、血泪史第一大坑:环境变量覆盖问题(必看)
这是本文最有价值的部分——我在这上面浪费了一个下午。
问题现象
- Agent-B 的 WebSocket 日志显示
connected to wss://... - 飞书开放平台却显示"连接失败"
- 反复重启、升级 SDK、改 Ping 间隔,通通无效
事故还原
事情是这样的:我一开始先用了一个飞书机器人 A 来配置 Agent-B,跑了半天发现不行,于是换成了机器人 B。
然后我做了三件事:
1.改了 systemd 服务文件,把FEISHU_APP_ID换成了机器人 B
2.改了.env文件,也把FEISHU_APP_ID换成了机器人 B
3. 重启!自信满满!
结果还是连不上。为什么?
因为我的.env文件里,APP_ID 改成了 B,但 APP_SECRET 还留着机器人 A 的 Secret!
根因深挖
Hermes 的 Gateway 在启动时执行了这行代码:
# gateway/run.py,第 11097 行 load_dotenv(_env_path, override=True)注意最后的override=True!
完整的加载链路是这样的:
systemd Environment=FEISHU_APP_ID=机器人B ✅ 正确 systemd Environment=FEISHU_APP_SECRET=机器人B的Secret ✅ 正确 ↓ Python 进程启动,读取到 systemd 的值 ↓ load_dotenv(override=True) 加载 .env 文件 ↓ .env 中的 FEISHU_APP_ID=机器人B .env 中的 FEISHU_APP_SECRET=机器人A的Secret ←— 残留!覆盖了 systemd 的正确值! ↓ 进程用 机器人B + 机器人A的Secret 去连飞书 → 认证失败!override=True意味着.env中的值无条件覆盖systemd 已经设好的值。你改 systemd 是没用的——只要.env里有残留,最终用的是.env的。
而且更坑的是:我改完
.env的 APP_ID 后,自信地重启了,根本没检查 APP_SECRET 也要同步改。结果飞书用错配的 APP_ID + 旧 SECRET 连了半小时都说连接失败。
排查方法
如果你怀疑有这个问题,直接检查进程内的实际环境变量:
# 找到 Agent-B 的 PID ps aux | grep hermes | grep gateway # 查看它实际使用的环境变量 sudo cat /proc/<PID>/environ | tr '\0' '\n' | grep FEISHU注意:/proc/PID/environ显示的是进程启动时的初始环境。Python 中os.getenv()返回的是load_dotenv(override=True)覆盖后的值——这两个可能不一样!
正确配置方式
方案 A(推荐):让.env和 systemd 保持完全一致,逐项核对:
# 逐项对比 .env 和 systemd 中的 FEISHU 变量 echo "=== .env ===" grep '^FEISHU_' ~/.hermes/profiles/agent-b/.env echo "=== systemd ===" grep 'FEISHU_' /etc/systemd/system/hermes-agent-b.service检查清单:
| 变量 | .env | systemd | 一致? |
| FEISHU_APP_ID | ✅ | ✅ | ✅ |
| FEISHU_APP_SECRET | ❌ 旧Bot残留 | ✅ | ❌ 翻车! |
| FEISHU_ALLOW_ALL_USERS | false | true | ❌ 翻车! |
| FEISHU_ALLOWED_USERS | 主用户ID | (未设) | ❌ 翻车! |
| FEISHU_CONNECTION_MODE | websocket | websocket | ✅ |
| FEISHU_DOMAIN | feishu | feishu | ✅ |
我当初 APP_ID 和 SECRET 对了,但 ALLOW_ALL_USERS 是false——结果 Agent-B 能连上飞书,但拒绝响应任何人的消息,因为用户授权检查没通过。
方案 B(更安全):删除.env中的FEISHU_*变量,只靠 systemd 的Environment=传递。这样 dotenv 不会影响飞书配置。
六、第二大坑:Holographic Memory 镜像不完整
Hermes 的 Holographic Memory 插件支持将内置 Memory 自动镜像到 SQLite 事实库(fact_store)。这样即使 Session 结束,重要的信息也能在下次对话中召回。
但有一个 Bug:镜像代码只处理新添加(add),不处理更新(replace)。
def on_memory_write(self, action, target, content): if action == "add" and self._store and content: # ← 只处理 add self._store.add_fact(content, category=category)当 Memory 空间满了,你用replace更新旧记录时,fact_store不会同步更新。你会发现 Memory 里有这条信息,但 fact_store 里查不到——相当于没有持久化。
修复方法(一行代码):
# 修改前 if action == "add" and self._store and content: # 修改后 if action in ("add", "replace") and self._store and content:修改完重启 Hermes 即可。新创建的子 Agent 和主 Agent 共享同一份代码,所以只要修一次,两边都生效。
七、验证多 Agent 是否正常
重启后,逐一验证:
# 1. 两个进程都在运行 ps aux | grep "hermes_cli.*gateway" | grep -v grep # 2. Agent-B 日志显示 WebSocket 已连接 sudo journalctl -u hermes-agent-b --no-pager | grep "connected to wss" # 3. 去飞书开放平台确认"长连接状态:已连接" # 4. 分别给两个 Bot 发消息,都能正常回复八、总结
| 环节 | 关键点 |
| 你需要做的 | 去飞书开放平台申请一个机器人,拿到 App ID 和 Secret |
| Agent 帮你做的 | 配置 systemd 服务、写 .env 文件、重启、验证——剩下的全自动 |
| 部署环境 | 腾讯云服务器,Ubuntu,公网 IP |
| ⚠️ 第一坑 | load_dotenv(override=True)让.env覆盖 systemd——改 APP_ID 必须同步改 SECRET 和所有 FEISHU_* |
| ⚠️ 第二坑 | Holographic Memory 的 mirror 只处理add不处理replace |
| 安全隔离 | 主 Agent 可以操作一切,子 Agent 只在自己 Profile 范围内 |
一台服务器上跑多个 Hermes Agent 并不复杂——真正的难点在于理解环境变量的加载顺序和完整替换。你不需要在飞书配置页面上折腾、不需要写复杂的 Python 代码、不需要手动处理进程管理。
只需要去飞书开放平台申请一个机器人,把 App ID 和 Secret 给到 Hermes Agent……剩下的,Agent 能帮你搞定。
希望这篇文章能帮你省下这半天 🚀
