ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

血与泪的教训:一台腾讯云服务器跑两个 Hermes AI Agent,各绑独立飞书机器人,踩坑全记录(TaoToken 统一 Key 版)

血与泪的教训:一台腾讯云服务器跑两个 Hermes AI Agent,各绑独立飞书机器人,踩坑全记录(TaoToken 统一 Key 版) 1. 单机双 Hermes AI Agent 绑定独立飞书机器人的真实部署场景一台腾讯云轻量服务器Ubuntu 22.042 核 4G公网 IP 固定。上面已经跑着一个 Hermes AI Agent通过飞书机器人 A 对外服务日常用来查资料、写文案、处理一些轻量任务。后来需求变了想让另一个机器人 B 专门处理代码和数据类任务权限收窄只对特定几个人开放而且不希望 B 能碰到 A 的会话历史和系统权限。最直觉的做法就是再跑一个 Hermes 实例绑另一个飞书机器人。听起来就是复制一份配置、改个 App ID 的事但实际操作下来环境变量加载顺序、systemd 服务隔离、Profile 目录这几个点会连环出问题。我在这上面耗了大半天最后把配置模板固化下来现在重新部署一套只需要十分钟左右。这篇文章聚焦的就是这个场景单台腾讯云服务器上并行运行两个 Hermes AI Agent各自绑定独立飞书机器人通过 systemd 做服务隔离用分文件加载的方式解决环境变量冲突。同时会说明怎么用 TaoToken 的统一 Key 和 API 通道来管理两个 Agent 的模型调用凭据避免每个 Agent 各配一套 Key 带来的混乱。适合谁看已经在用 Hermes Agent 或者类似框架、想在单机上做多实例隔离、被 systemd 环境变量和 .env 覆盖问题折腾过的人。如果你还没跑起来第一个 Agent建议先把单实例跑通再来看这篇。核心检索词先明确腾讯云服务器多 Hermes AI Agent 部署、飞书机器人独立绑定、systemd 环境变量隔离。这三个词贯穿全文后面每一步都围绕它们展开。架构上其实很清晰飞书 App A (主 Agent) ──→ Gateway A (主进程) ──→ Profile ~/.hermes/ ↓ 飞书 App B (Agent-B) ──→ Gateway B (子进程) ──→ Profile ~/.hermes/profiles/agent-b/两个 Hermes 进程各自独立运行各自绑定不同的飞书 App 凭证各自使用独立的 Profile 目录。主 Agent 可以通过 terminal 工具管理 Agent-B反过来不行。模型调用凭据统一走 TaoToken 的 API 通道两个 Agent 共用一套 Key 管理逻辑但各自的环境变量文件分开。这里有个前提要说清楚飞书开放平台那边你需要创建两个企业自建应用分别拿到各自的 App ID 和 App Secret。这是唯一必须手动在网页上完成的部分剩下的 systemd 配置、.env 文件、重启验证都可以在服务器上完成。我试过把两个 Agent 的配置混在一个 .env 里结果就是互相覆盖排查起来非常痛苦。所以下面的方案核心就一条每个 Agent 一个 Profile 目录一个独立的 .env 文件一个独立的 systemd unit环境变量通过 systemd 的 EnvironmentFile 分文件加载绝不共用。2. TaoToken 统一 Key 管理多 Agent 模型调用凭据的前置配置两个 Agent 跑起来之后模型调用这块如果各配各的 Key会有几个麻烦一是 Key 分散在不同文件里轮换的时候容易漏二是用量和额度不好统一看三是如果某个 Agent 的 Key 出问题排查时要分别登录不同地方确认。TaoToken 这边提供的是统一的 API 通道Base URL 是https://taotoken.net/api两个 Agent 都可以指向同一个入口用同一套 Key 体系来管理。这样模型调用凭据就收敛到一处Agent 本身只关心自己的飞书凭证和 Profile 隔离。先说你需要在 TaoToken 控制台做的事。打开 https://taotoken.net/api 进入 console 页面创建一个 API Key。这个 Key 后面会写进两个 Agent 各自的环境变量文件里。如果你想让两个 Agent 用不同的 Key 做额度区分也可以创建两个但通道入口是同一个。模型 ID 这块Hermes 的 config.yaml 里需要指定。常见的写法是在 config.yaml 的 model 字段填具体的模型标识比如claude-sonnet-4-20250514这类。两个 Agent 可以用同一个模型也可以按需区分主 Agent 用通用模型Agent-B 用更偏向代码的模型。这个在各自的 config.yaml 里改就行互不影响。关键点在于TaoToken 的 Base URL 和 Key 通过环境变量注入而不是硬编码在 config.yaml 里。这样做的原因是systemd 启动时可以把环境变量传给进程而 .env 文件负责补充其他配置。两者分工明确避免后面说的 override 覆盖问题。具体来说每个 Agent 的 .env 文件里会有这么几行# TaoToken 统一 API 通道 OPENAI_BASE_URLhttps://taotoken.net/api OPENAI_API_KEYsk-你的TaoTokenKey # 或者按 Hermes 实际读取的变量名来比如 HERMES_API_BASEhttps://taotoken.net/api HERMES_API_KEYsk-你的TaoTokenKey注意变量名要以 Hermes 实际读取的为准。不同版本的 Hermes 可能用OPENAI_API_KEY也可能用自定义的HERMES_API_KEY这个去翻一下你本地 Hermes 的文档或者源码里os.getenv的部分就能确认。我这边实测下来Hermes 的 gateway 在初始化模型客户端时会优先读OPENAI_BASE_URL和OPENAI_API_KEY所以这两个变量名是稳妥的。如果你用的是 Claude Code 或者类似的编码 Agent 场景TaoToken 也支持 Anthropic 兼容的通道。对应的接入文档在 https://taotoken.net/api 的 doc 页面可以查到Base URL 和 Key 的用法跟上面一致只是模型 ID 换成 Claude 系列的标识。这里要强调一个隔离原则飞书凭证FEISHU_*和模型凭证API Key要分开管理。飞书凭证每个 Agent 必须不同因为绑的是不同的机器人模型凭证可以共用同一套 TaoToken Key也可以分开。但不管怎样它们都写在各自的 .env 文件里通过 systemd 的 EnvironmentFile 加载不混用。还有一个前置动作确认你的腾讯云服务器安全组放行了出站流量。Hermes 连飞书走的是 WebSocket 长连接连 TaoToken 走的是 HTTPS 出站这两个都是主动外连不需要入站端口。但有些云厂商默认出站全放有些会限制这个在腾讯云控制台的安全组里确认一下就行。3. 可复制的 systemd unit 与环境变量分文件加载配置这一节是全文最核心的部分直接给可复制的配置。两个 Agent 各有一套 systemd unit 和 .env 文件路径和变量名都按实际部署来写。先建目录结构。假设主 Agent 已经在~/.hermes/下跑着现在给 Agent-B 建独立的 Profilemkdir -p ~/.hermes/profiles/agent-b cp ~/.hermes/config.yaml ~/.hermes/profiles/agent-b/config.yaml touch ~/.hermes/profiles/agent-b/.env然后编辑 Agent-B 的 config.yaml把模型、权限、超时这些跟主 Agent 区分开。重点改 model 字段和权限相关的配置让它跟主 Agent 不一样。接下来是 Agent-B 的 .env 文件路径~/.hermes/profiles/agent-b/.env# 飞书凭证Agent-B 专属 FEISHU_APP_IDcli_你的AgentB的AppID FEISHU_APP_SECRET你的AgentB的AppSecret FEISHU_DOMAINfeishu FEISHU_CONNECTION_MODEwebsocket FEISHU_ALLOW_ALL_USERSfalse FEISHU_ALLOWED_USERSou_用户ID1,ou_用户ID2 FEISHU_GROUP_POLICYopen # TaoToken 模型通道可与主 Agent 共用 OPENAI_BASE_URLhttps://taotoken.net/api OPENAI_API_KEYsk-你的TaoTokenKey注意FEISHU_ALLOW_ALL_USERS这里设成 false然后用FEISHU_ALLOWED_USERS指定白名单。这是 Agent-B 权限收窄的关键。主 Agent 那边可以设成 true 或者用不同的白名单。然后是 systemd unit 文件路径/etc/systemd/system/hermes-agent-b.service[Unit] DescriptionHermes Agent-B Gateway (独立实例) Afternetwork-online.target Wantsnetwork-online.target [Service] Typesimple Userubuntu WorkingDirectory/home/ubuntu/.hermes EnvironmentHERMES_HOME/home/ubuntu/.hermes/profiles/agent-b EnvironmentFile/home/ubuntu/.hermes/profiles/agent-b/.env ExecStart/home/ubuntu/.hermes/hermes-agent/venv/bin/python \ -m hermes_cli.main gateway run --replace --accept-hooks Restarton-failure RestartSec5 [Install] WantedBymulti-user.target这里的关键改动是不再用Environment逐条写飞书凭证而是用EnvironmentFile指向 Agent-B 专属的 .env 文件。这样 systemd 启动时会把 .env 里的变量加载进进程环境而 Hermes 内部的load_dotenv(overrideTrue)再加载同一个文件时值是一致的不会出现覆盖冲突。主 Agent 的 systemd unit 也建议改成同样的模式路径/etc/systemd/system/hermes-agent.service[Unit] DescriptionHermes Agent Gateway (主实例) Afternetwork-online.target Wantsnetwork-online.target [Service] Typesimple Userubuntu WorkingDirectory/home/ubuntu/.hermes EnvironmentHERMES_HOME/home/ubuntu/.hermes EnvironmentFile/home/ubuntu/.hermes/.env ExecStart/home/ubuntu/.hermes/hermes-agent/venv/bin/python \ -m hermes_cli.main gateway run --replace --accept-hooks Restarton-failure RestartSec5 [Install] WantedBymulti-user.target两个 unit 的差异只有三处Description、HERMES_HOME、EnvironmentFile 路径。这样隔离得干干净净。如果你用的是 Cline MCP 或者 Codex 这类工具配置文件的写法会不一样。Cline MCP 的配置通常在settings.json里Codex 用auth.json。但核心原则一样Base URL 填https://taotoken.net/apiKey 填 TaoToken 的 KeyModel ID 填具体模型标识。这三件套在任何一个工具里都不能少。改完 unit 文件后执行sudo systemctl daemon-reload sudo systemctl enable hermes-agent-b sudo systemctl start hermes-agent-b sudo systemctl status hermes-agent-b状态显示 active (running) 就说明进程起来了。但起来不等于连上了飞书下一步要验证。4. 验证两个飞书机器人互不串扰的请求与日志检查进程起来之后要确认两件事一是两个 Agent 各自连上了自己的飞书机器人二是消息不会串到对方那里去。先看进程ps aux | grep hermes_cli.*gateway | grep -v grep应该看到两个进程各自的命令行里带着不同的 HERMES_HOME 环境变量。如果只看到一个说明另一个没起来去看 journalctl 日志。然后看 Agent-B 的 WebSocket 连接日志sudo journalctl -u hermes-agent-b --no-pager | grep connected to wss正常的话会看到类似connected to wss://open.feishu.cn/...的输出。主 Agent 那边同样查一遍sudo journalctl -u hermes-agent --no-pager | grep connected to wss两个日志里的 wss 地址应该对应各自的飞书 App。如果 Agent-B 的日志里出现了主 Agent 的 App ID 相关字样说明环境变量串了回去检查 .env 和 systemd unit。接下来做实际的消息验证。去飞书里分别给两个机器人发消息给机器人 A 发「你好」应该由主 Agent 回复。给机器人 B 发「你好」应该由 Agent-B 回复。然后交叉验证给机器人 A 发一条只有 Agent-B 才能处理的任务比如 Agent-B 特有的代码分析指令看主 Agent 是不是正常回复「这个我不处理」或者按主 Agent 的逻辑走而不是被 Agent-B 截胡。更严格的验证是看日志里的 App ID。在 Agent-B 的日志里搜sudo journalctl -u hermes-agent-b --no-pager | grep -i app_id\|cli_确认出现的都是 Agent-B 的 App ID没有主 Agent 的。反过来在主 Agent 日志里搜也不应该出现 Agent-B 的 App ID。还有一个验证点是用户白名单。Agent-B 设了FEISHU_ALLOW_ALL_USERSfalse和FEISHU_ALLOWED_USERS那么用一个不在白名单里的飞书账号给机器人 B 发消息应该被拒绝或者不响应。而给机器人 A 发消息按主 Agent 的策略走。这一步能确认权限隔离生效了。模型调用这块在 Agent-B 的日志里搜 TaoToken 相关的请求sudo journalctl -u hermes-agent-b --no-pager | grep -i taotoken\|api应该能看到向https://taotoken.net/api发起的请求记录。如果看到的是其他 API 地址说明 .env 里的OPENAI_BASE_URL没生效或者被其他变量覆盖了。两个 Agent 都验证通过后可以做一个压力测试同时给两个机器人发消息看回复是否各自独立、有没有延迟或错乱。正常情况下两个进程互不干扰各自处理各自的 WebSocket 消息。5. 本篇常见错误排查401、local proxy failed、reading choices 与 OAuth部署过程中最容易撞上的几类报错这里逐个对照。401 认证失败。这个最常见分两种飞书侧 401 和模型侧 401。飞书侧 401 通常是 App ID 和 App Secret 不匹配或者 Secret 过期。检查方法是把 .env 里的FEISHU_APP_ID和FEISHU_APP_SECRET复制到飞书开放平台的应用凭证页面核对。模型侧 401 是 TaoToken Key 的问题检查OPENAI_API_KEY是否填对、是否有多余空格、Key 是否被禁用。如果两个 Agent 共用一个 Key确认这个 Key 的额度还够。local proxy failed。这个报错通常出现在网络层意思是 Hermes 尝试连接某个地址时失败了。在腾讯云服务器上先确认出站流量正常curl -I https://taotoken.net/api curl -I https://open.feishu.cn两个都返回 200 或 401 之类的 HTTP 响应就说明网络通。如果 curl 都失败检查安全组出站规则和 DNS 解析。注意这里不要用任何代理类工具服务器直连即可。reading choices 报错。这个通常出现在模型返回格式不符合预期时。Hermes 期望的是标准的 chat completion 响应结构里面要有choices字段。如果 TaoToken 通道返回的格式有差异或者模型 ID 填错了导致返回了错误信息就会报这个。检查 config.yaml 里的 model 字段是否跟 TaoToken 支持的模型 ID 一致。另外确认OPENAI_BASE_URL结尾没有多余的斜杠正确写法是https://taotoken.net/api。OAuth 相关报错。如果 Hermes 的某个插件或者工具需要 OAuth 授权而你在多 Agent 环境下共用了一些凭证文件可能会出现 OAuth token 冲突。排查方法是确认每个 Agent 的 Profile 目录下有独立的凭证缓存。如果某个工具把 token 写到了共享路径两个 Agent 会互相覆盖。解决办法是在 config.yaml 里把该工具的缓存路径指到各自的 Profile 目录下。环境变量覆盖导致的「连上了但不响应」。这个是最隐蔽的。现象是日志显示 WebSocket 已连接但发消息没反应。根因是load_dotenv(overrideTrue)让 .env 里的值覆盖了 systemd 传入的值而 .env 里可能有残留的旧配置。排查命令# 看进程实际环境变量 PID$(pgrep -f hermes_cli.*gateway.*agent-b) sudo cat /proc/$PID/environ | tr \0 \n | grep FEISHU注意/proc/PID/environ显示的是进程启动时的初始环境Python 里os.getenv()返回的是 load_dotenv 覆盖后的值两者可能不一样。要确认最终生效的值最可靠的办法是在 Hermes 启动日志里加一行打印或者直接看飞书开放平台的长连接状态页面。两个 Agent 消息串扰。如果给机器人 A 发消息结果 Agent-B 回复了说明两个进程读了同一份飞书凭证。检查两个 systemd unit 的EnvironmentFile是否指向了不同的 .env 文件以及两个 .env 里的FEISHU_APP_ID是否确实不同。还有一种可能是两个进程的HERMES_HOME指向了同一个目录导致 Profile 混用。对照表整理一下报错现象可能原因检查动作401App Secret 或 API Key 错误核对 .env 中的凭证local proxy failed出站网络不通curl 测试 TaoToken 和飞书地址reading choices模型 ID 错误或响应格式异常检查 config.yaml 的 model 字段OAuth 冲突凭证缓存路径共享确认各 Profile 目录独立连上但不响应.env 覆盖 systemd 变量对比 .env 和进程实际环境变量消息串扰飞书凭证或 Profile 混用检查 EnvironmentFile 和 HERMES_HOME6. 多 Agent 长期运行的凭据管理与接入入口两个 Agent 稳定跑起来之后日常维护主要就是凭据轮换和额度监控。TaoToken 的统一 Key 在这里的优势就体现出来了模型调用凭据只有一套轮换的时候改两个 .env 文件就行不用去每个 Agent 的 config 里翻。飞书凭证虽然每个 Agent 不同但飞书那边的 Secret 一般不会频繁换换的时候也是改对应的 .env 然后重启服务。如果你后面要加第三个、第四个 Agent流程是一样的建 Profile 目录、写 .env、写 systemd unit、启动验证。唯一要注意的是每个 Agent 的飞书 App 必须不同模型通道可以共用 TaoToken 的同一个 Base URL 和 Key。对于长期编码和 Agent 场景TaoToken 的 Coding Plan 适合把多个 Agent 的模型调用统一到一个计划下管理。接入文档在 https://taotoken.net/api 的 doc 页面里面有 Base URL、Key 和 Model ID 的完整说明。模型对话的入口在 https://taotoken.net/api 的模型对话页面可以用来快速验证 Key 和模型 ID 是否配对正确。API Keys 管理在 console 页面轮换和查看额度都在那里。实际维护中建议给每个 Agent 的 systemd 服务加一个简单的健康检查脚本定时 curl 一下本地端口或者检查进程状态异常时自动重启。这个脚本可以放在 crontab 里也可以用 systemd timer。但注意健康检查本身不要引入新的环境变量依赖保持简单。最后说一个实操细节两个 Agent 的日志分开看。journalctl -u hermes-agent和journalctl -u hermes-agent-b各自独立排查问题时先确认是哪个 Agent 出的错再去对应的日志里找。不要混着看容易误判。整套配置固化下来之后重新部署一套双 Agent 环境确实十分钟能搞定。真正花时间的是第一次踩坑和排查希望这篇能帮你把这部分省掉。
返回列表