双Agent架构:服务器上的AI楚汉争霸

双Agent架构:服务器上的AI楚汉争霸
摘要:一台服务器上同时运行着两套 AI Agent 系统——Hermes Python 与 OpenClaw Node.js,它们各有配置目录、各有凭据体系,却共用同一个飞书/企微入口。看起来像分工协作,实际是各自为政。飞书消息时而通、时而不通,究竟是哪里出了岔子?本文从进程排查到配置差异,带你复盘这场服务器上的"AI楚汉争霸",并给出 Hermes 脱离 OpenClaw 独立自主的完整方案。
一、故事的起点:一台服务器,两个"AI诸侯"
某日,运维同学收到飞书群里的一条消息,表情包带字:"Agent 又罢工了。"点开一看,企业微信的消息推送也断了。更诡异的是——重启服务后,飞书能发了,企微还是挂的;重刷企微凭据后,企微活了,飞书又死了。
登录服务器,ps aux | grep agent 一看:
root 12345 0.5 2.1 /usr/bin/python3 /opt/hermes/main.py
root 23456 1.2 3.4 node /opt/openclaw/server.js
两台 Agent 都在跑,各自活得好好的。但飞书和企微的消息推送功能,却是"你方唱罢我登场",从未同时正常过。这像极了楚汉争霸——项羽(Hermes)和刘邦(OpenClaw)同处一台服务器,都想控制信息通道这个"关中"。
本文将完整记录排查与解决过程,所有操作均在一台 Linux 服务器上完成,涉及的两套 Agent 系统分别为:
- Hermes Python —— Python 实现,配置目录
~/.hermes/ - OpenClaw Node.js —— Node.js 实现,配置目录
/root/.openclaw/
二、楚河汉界:进程排查方法论
2.1 从 ps aux 入手
排查的第一步,永远是从进程入手。但 ps aux 只能告诉你有什么在跑,跑在哪,不能告诉你它"实际在用哪份配置"。很多 Agent 框架支持通过环境变量或启动参数覆盖配置路径,只看启动命令容易被误导。
例如,Hermes 的启动脚本里可能写了 --config /root/.hermes/,但 OpenClaw 的 pm2 配置里也可能引用了同一个 .env 文件。如果不看 cwd(当前工作目录),你根本不知道谁在"吃"哪份配置。
2.2 /proc/PID/cwd——追查进程的"老巢"
Linux 的 /proc 文件系统藏着一切真相。对于任意进程 PID,/proc/PID/cwd 是一个软链接,指向该进程的当前工作目录。结合 /proc/PID/environ,可以拿到进程的环境变量——包括它加载了哪个 .env 文件。
# 查出两个 agent 的 PID
ps aux | grep -E '(hermes|openclaw)' | grep -v grep
# 查看 Hermes 的工作目录与运行路径
ls -la /proc/12345/cwd
cat /proc/12345/environ | tr '\0' '\n' | grep -E '^(FEISHU|WECOM|BOT|CORP|SECRET|ENV)'
# 查看 OpenClaw 的工作目录
ls -la /proc/23456/cwd
cat /proc/23456/environ | tr '\0' '\n' | grep -E '^(FEISHU|WECOM|BOT|CORP|SECRET|ENV)'
这一查不要紧。原来 Hermes 的 cwd 指向 /root/.hermes/,而 OpenClaw 的 cwd 指向 /root/.openclaw/——两台 Agent 各自守着自家的一亩三分地,互不相通。
2.3 配置隔离的真相
进一步检查两个目录中的配置文件:
# Hermes 的配置目录
ls -la ~/.hermes/
# 输出:.env config.yaml credentials/
# OpenClaw 的配置目录
ls -la /root/.openclaw/
# 输出:openclaw.json cert/ log/
两套系统的配置文件结构和格式完全不同。Hermes 使用 .env 文件 + YAML 配置,而 OpenClaw 使用单一的 openclaw.json。飞书和企业微信的凭据被打散在这两套配置中,各管各的,互不同步。
三、鸿门宴:飞书企微的凭据之谜
3.1 凭据散落各处
Hermes 的飞书/企微凭据写在 ~/.hermes/.env 中:
# ~/.hermes/.env
FEISHU_APP_ID=cli_xxxxxx
FEISHU_APP_SECRET=abc123...
WECOM_BOT_ID=wb_xxxxxx
WECOM_BOT_SECRET=def456...
而 OpenClaw 的凭据写在 /root/.openclaw/openclaw.json 中:
// /root/.openclaw/openclaw.json
{
"feishu": {
"appId": "cli_yyyyyy",
"appSecret": "ghi789..."
},
"wecom": {
"corpId": "ww_zzzzzz",
"corpSecret": "jkl012...",
"agentId": 1000002
}
}
看到问题了吗?Hermes 使用 WECOM_BOT_ID + WECOM_BOT_SECRET,而 OpenClaw 使用 corpId + corpSecret + agentId。它们根本不是在用同一种认证方式!
3.2 BotID+Secret ≠ CorpID+Secret
企业微信的机器人认证有两种截然不同的模式:
| 维度 | Bot 模式(Hermes) | 应用模式(OpenClaw) |
|---|---|---|
| 认证方式 | BotID + BotSecret | CorpID + CorpSecret + AgentID |
| 获取位置 | 企业微信后台 → 机器人管理 | 企业微信后台 → 应用管理 → 自建应用 |
| Token 端点 | /cgi-bin/bot/token |
/cgi-bin/gettoken |
| 消息推送 | 通过 Webhook URL 推送 | 通过 API 主动发送 |
| 权限范围 | 单机器人对话 | 应用消息 + 通讯录等 |
两个系统虽然都在"发企业微信消息",但走的是完全不同的 API 路径。当运维同学复制粘贴 corpSecret 到 Hermes 的 WECOM_BOT_SECRET 时,Hermes 拿着一个"应用密钥"去调用"机器人接口",自然会 401。反过来,OpenClaw 拿到了 BotSecret 去调 gettoken,也是鸡同鸭讲。
这就是"时而通、时而不通"的根源:每次重启或刷凭据,只有一方能拿到正确的凭据,另一方拿到的永远是另一套认证体系的东西。
3.3 飞书凭据同样不互通
飞书的情况稍微好一些——两套系统都使用 AppID + AppSecret 模式。但问题在于,Hermes 的 .env 里配的是自建应用的凭据,而 OpenClaw 的 openclaw.json 里配的是飞书开放平台的凭据。虽然格式相同,但 appId 值完全不同,导致两个 Agent 实际上连接的是飞书上两个不同的应用。
这形成了一种微妙的"平衡":有时候飞书消息正常,是因为任务恰好被路由到了持有正确凭据的那个 Agent;有时候企微正常,也是同样的原因。但没有任何一个 Agent 能同时拥有两套正确的凭据。
四、背水一战:Hermes 脱离 OpenClaw 独立自主
既然两套系统各自为政、互相干扰,最优解不是去"修复"OpenClaw,而是让 Hermes 独立自主——它将拥有完整的飞书和企业微信配置,不再依赖 OpenClaw 进行消息推送。
4.1 统一配置,集中管理
首先,在 Hermes 的配置目录中建立完整的凭据体系。不再依赖 .env 散装配置,而是建立一个结构化的 credentials 子目录:
mkdir -p ~/.hermes/credentials
# 飞书凭据
cat > ~/.hermes/credentials/feishu.env << 'EOF'
FEISHU_APP_ID=cli_xxxxxx
FEISHU_APP_SECRET=abc123...
EOF
# 企业微信凭据(使用 Bot 模式,从企业微信后台机器人管理页面获取)
cat > ~/.hermes/credentials/wecom.env << 'EOF'
WECOM_BOT_ID=wb_xxxxxx
WECOM_BOT_SECRET=def456...
EOF
如果 Hermes 需要支持企业微信应用模式(而非机器人模式),则需要额外配置 corpId 和 agentId:
cat > ~/.hermes/credentials/wecom_app.env << 'EOF'
WECOM_CORP_ID=ww_zzzzzz
WECOM_AGENT_ID=1000002
WECOM_CORP_SECRET=jkl012...
EOF
将配置按渠道分文件存放,既清晰又便于运维同学逐一核对。
4.2 修改 Hermes 配置入口
在 ~/.hermes/config.yaml 中,指定凭据加载路径:
# ~/.hermes/config.yaml
credentials:
feishu:
env_file: "{{ HERMES_HOME }}/credentials/feishu.env"
wecom:
env_file: "{{ HERMES_HOME }}/credentials/wecom.env"
# 如果使用应用模式,取消下一行注释
# app_env_file: "{{ HERMES_HOME }}/credentials/wecom_app.env"
notification:
# 消息推送使用 Hermes 自身的凭据,不依赖 OpenClaw
independent_mode: true
independent_mode: true 是一个关键开关,它告诉 Hermes:所有消息推送都使用自身配置,不向 OpenClaw 转发请求,不查询 OpenClaw 的配置文件。
4.3 重新启动,验证隔离
重启 Hermes,并验证它是否能独立完成飞书和企微的消息推送:
# 关闭旧的 Hermes 进程
kill 12345
# 验证 OpenClaw 仍然在跑(暂时不动它)
ps aux | grep openclaw
# 启动新的 Hermes(强制加载新配置)
cd ~/.hermes
python3 /opt/hermes/main.py --config ~/.hermes/config.yaml
# 验证进程的工作目录
HERMES_PID=$(pgrep -f 'python3 /opt/hermes/main.py')
ls -la /proc/$HERMES_PID/cwd
# 应该输出:/root/.hermes/
# 测试飞书推送
curl -X POST http://localhost:8080/api/test/feishu -d '{"msg":"Hello from Hermes"}'
# 测试企微推送
curl -X POST http://localhost:8080/api/test/wecom -d '{"msg":"独立自主!"}'
4.4 清理 OpenClaw 的残留影响
Hermes 独立后,还需要清理 OpenClaw 可能留下的"脏数据":
# 删除 Hermes 对 OpenClaw 配置的任何引用
rm -f ~/.hermes/openclaw.json
rm -f ~/.hermes/openclaw_sync.env
# 确保 Hermes 的环境变量中没有 OpenClaw 的残留
unset WECOM_CORP_ID
unset WECOM_CORP_SECRET
# 如果 OpenClaw 不再需要跑飞书/企微,可以关闭它的推送模块
# 但更彻底的方式是停掉整个 OpenClaw(如果确定它不再承担任务)
# systemctl stop openclaw # 按需执行
五、复盘:双 Agent 架构的经验教训
5.1 配置隔离 ≠ 配置自治
两台 Agent 各有各的配置目录,看似"隔离"了,实则并没有实现真正的"自治"。关键问题在于:共享资源(飞书/企微的消息通道)没有明确的"主人"。正确的做法是:谁拥有消息通道的配置,谁就对消息通道负责。另一个 Agent 如果需要发消息,应该通过 API 调用向"通道主人"请求,而不是自己另搞一套凭据。
5.2 进程排查是基本功
这次排查中,ps aux + /proc/PID/cwd 的组合拳立了大功。不少开发者遇到"时好时坏"的问题时,第一反应是重启、重装、重刷凭据,而不是去查进程"现在到底在用哪份配置"。学会通过 /proc 文件系统看进程"吃的是哪碗饭",是 Linux 运维的基本功,也是排查配置类问题的黄金路径。
5.3 认证方式的"异名同构"陷阱
企业微信的 Bot 模式和应用模式,虽然都叫"发企微消息",但底层 API 完全不同。BotID+Secret 与 CorpID+Secret 看起来差不多,实际上隔着一道鸿沟。在配置任何第三方 API 时,不能只看字段名相似就填一样的内容,必须去对应后台确认每个字段的真实含义。
5.4 什么是"独立自主"
对于 Hermes 来说,"脱离 OpenClaw 独立自主"意味着:
- 配置独立:所有凭据都在
~/.hermes/目录内,不依赖外部文件 - 认证独立:可以独立完成飞书和企微的认证流程,不通过 OpenClaw 中转
- 运行时独立:进程的工作目录、环境变量完全自洽,不受 OpenClaw 的启动参数影响
- 可观测独立:日志、监控、排查路径都在 Hermes 自己的体系内
结语:楚河汉界,终归一统
双 Agent 架构本身不是问题——Hermes 专注于 Python 生态的任务处理,OpenClaw 擅长 Node.js 的实时响应,各有所长。但共享消息通道时,必须明确"话事人"。经过本次排查与改造,Hermes 已经拥有了一整套独立的飞书和企业微信配置,不再仰仗 OpenClaw 的"鼻息"。
一台服务器上可以同时跑项羽和刘邦,但关中的玉玺只能由一个人执掌。双 Agent 可以分工,但消息通道必须统一。这就是这次"AI楚汉争霸"留给我们的终极教训。