1. 为什么多终端后端是 HermesAgent 的刚需
HermesAgent 最容易被低估的能力,是它把「命令在哪执行」这件事做成了可插拔的抽象层。大多数 Agent 的终端能力是写死的——要么只跑本地,要么只跑 Docker 沙箱。但真实开发场景里,你可能上午在本地跑脚本,下午要把一段不可信代码丢进容器隔离,晚上又要连到远程服务器拉日志。如果每换一个环境就得改一遍 Agent 源码,那这套东西根本没法长期用。
HermesAgent 给出的答案是六种终端后端:Local、Docker、SSH、Modal、Daytona、Singularity。它们统一实现TerminalBackend抽象基类,对外暴露is_available()、execute()、cleanup()三个方法。Agent 核心只认接口,不认具体实现,所以运行时切换后端只是改一个配置字段的事。
而 Gateway 网关解决的是另一个维度的问题:Agent 的「耳朵和嘴巴」。它把 Telegram、Discord、Slack、飞书、钉钉等消息平台统一成PlatformAdapter,再和 CLI 共享同一套斜杠命令定义。你在终端敲/skills和在 Telegram 发/skills,走的是同一份命令注册表。
这篇聚焦落地配置:怎么写出可运行的 Gatewayconfig.toml骨架,怎么注册多终端后端,以及怎么通过 TaoToken 统一 Key 通道完成一次端到端连通性验证。适合已经在用 HermesAgent、想把 ACP 多终端接入统一管起来的开发者。
2. TaoToken 前置:统一 Key 与 API 通道
在配 Gateway 之前,先把模型通道理顺。HermesAgent 本身不绑定任何模型供应商,它通过 OpenAI 兼容接口调用 LLM。这意味着你只要有一个兼容/v1/chat/completions的端点,就能接进去。
TaoToken 在这里扮演的角色是统一入口:一个 Key 覆盖多种模型,省去在 HermesAgent 配置里维护多套 base_url 和 api_key 的麻烦。对多终端场景尤其重要——本地、Docker、SSH 三个后端如果各自读不同的环境变量,排障时会非常痛苦。统一成一个通道后,任何后端出问题,先怀疑网络和 Key,而不是「是不是这个后端的配置写错了」。
你需要准备两样东西:
- 一个 TaoToken API Key,在控制台的 API Keys 页面创建
- 确认 base_url 指向
https://taotoken.net/api
创建 Key 的入口在这里:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
接入文档(含各语言 SDK 示例和兼容性说明):https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
注意:base_url 填
https://taotoken.net/api,不要在后面手动加/v1。OpenAI 兼容客户端通常会自动补/v1/chat/completions,重复拼接会 404。
拿到 Key 后,先别急着写 Gateway 配置。用一条 curl 确认通道本身是通的:
export TAOTOKEN_API_KEY="sk-你的key" curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 8 }'返回里能看到choices[0].message.content就说明通道没问题。这一步很关键,因为后面 Gateway 报错时,你需要知道到底是模型通道挂了,还是网关配置写错了。把变量固定下来,别每次手输。
3. Gateway config.toml 骨架与多终端后端注册
HermesAgent 的 Gateway 配置分两块:一块是网关自身(监听哪些平台、session 存哪),一块是终端后端(命令在哪执行)。下面这份config.toml是我实测能跑通的最小骨架,你可以直接拿去改。
# ~/.hermes/config.toml [gateway] # 网关监听的消息平台,按需开启 enabled_platforms = ["telegram", "slack"] session_db = "~/.hermes/sessions.db" # 斜杠命令前缀,CLI 与各平台共享 command_prefix = "/" [gateway.telegram] bot_token = "${TELEGRAM_BOT_TOKEN}" allowed_chat_ids = ["123456789"] [gateway.slack] app_token = "${SLACK_APP_TOKEN}" bot_token = "${SLACK_BOT_TOKEN}" # ---- 模型通道:统一走 TaoToken ---- [llm] provider = "openai_compatible" base_url = "https://taotoken.net/api" api_key = "${TAOTOKEN_API_KEY}" model = "gpt-4o-mini" timeout = 60 # ---- 多终端后端注册 ---- [terminal] # 默认后端,可被单次调用覆盖 default_backend = "local" [terminal.local] enabled = true [terminal.docker] enabled = true image = "python:3.12-slim" memory_limit = "2g" network_enabled = false # 容器内也读同一个 Key,保证通道一致 env_passthrough = ["TAOTOKEN_API_KEY"] [terminal.ssh] enabled = true host = "10.0.0.12" user = "deploy" key_path = "~/.ssh/id_ed25519" # 远程机同样通过环境变量拿 Key remote_env = { TAOTOKEN_API_KEY = "${TAOTOKEN_API_KEY}" }几个容易踩的点,我逐个说清楚。
env_passthrough是 Docker 后端的关键字段。默认情况下容器是干净环境,不会继承宿主机的TAOTOKEN_API_KEY。如果你在容器里跑需要调模型的脚本,不加这行就会拿到空 Key,报 401。network_enabled = false时容器完全断网,适合跑不可信代码,但那种场景下容器内也调不了模型——这是设计取舍,不是 bug。
SSH 后端的remote_env解决的是同一类问题:远程机的环境变量和本地不一样。显式声明要传哪些变量,比在远程机.bashrc里硬编码 Key 安全得多。
后端注册完之后,可以在运行时切换。HermesAgent 的AIAgent接受terminal_backend参数:
from hermes.agent import AIAgent agent = AIAgent( terminal_backend="docker", # 或 "local" / "ssh" docker_image="python:3.12-slim", )CLI 里则通过--backend覆盖默认值:
hermes run --backend ssh --command "df -h"Gateway 收到消息后,会根据配置里的default_backend决定把命令发到哪。如果你想让某个平台固定用某个后端,可以在平台段里单独指定,比如[gateway.telegram]下加terminal_backend = "docker"。
4. 端到端连通性验证:从消息到命令执行
配置写完,最怕的是「看起来都对,但就是不通」。下面这套验证流程按依赖顺序走,每一步都能独立定位问题。
第一步,验证 Gateway 能起来:
hermes gateway --config ~/.hermes/config.toml --log-level debug正常输出会列出已加载的平台和后端。如果某个平台 token 没读到,这里会直接报错,不会等到收消息才炸。
第二步,验证模型通道。在 CLI 里发一条消息:
hermes chat --config ~/.hermes/config.toml -m "用一句话说明你当前使用的终端后端"Agent 会调用 LLM 并返回。如果这一步 401,问题在 TaoToken Key 或 base_url;如果超时,检查网络出口。
第三步,验证终端后端。让 Agent 执行一条命令:
hermes run --config ~/.hermes/config.toml --backend docker --command "python -c 'import os; print(os.environ.get(\"TAOTOKEN_API_KEY\", \"MISSING\")[:8])'"预期输出是 Key 的前 8 位。如果打印MISSING,说明env_passthrough没生效;如果容器起不来,检查 Docker 是否在运行、镜像是否已拉取。
第四步,验证 Gateway 全链路。在 Telegram 里给 bot 发:
/run --backend local echo hello-from-gateway你应该在聊天窗口收到hello-from-gateway。这条消息走完了「平台适配器 → Gateway → 命令解析 → 终端后端 → 结果回传」的完整路径。任何一环断了,前面的单步验证都能帮你缩小范围。
第五步,验证 ACP 接入。如果你用 VS Code 或 Zed,启动 ACP 服务器:
hermes acp --config ~/.hermes/config.toml --port 8765然后在 IDE 的 ACP 插件里填localhost:8765。连接成功后,IDE 里的对话和终端命令都会走同一套 Gateway 配置。这一步能通,说明你的多终端环境已经可以被 IDE 统一调用了。
5. 本篇常见错排查
报错一:401 Unauthorized且只在 Docker 后端出现。九成是env_passthrough漏了TAOTOKEN_API_KEY。容器是干净环境,不会自动继承宿主机变量。补上后重启 Gateway。
报错二:base_url拼接出/api/v1/v1/chat/completions。有些 OpenAI 兼容客户端会自己补/v1。如果你在配置里已经写了/api,就不要再手动加/v1。用第 2 节的 curl 确认正确路径,再对照客户端行为。
报错三:SSH 后端连接超时。先确认key_path指向的私钥权限是600,再确认远程机authorized_keys里有对应公钥。HermesAgent 不会帮你做这些系统层配置,它只负责调用。
报错四:Gateway 起来了但收不到消息。检查allowed_chat_ids是否包含你的 chat id。很多平台适配器默认只响应白名单内的会话,这是安全设计。调试阶段可以临时放宽,上线前务必收紧。
报错五:斜杠命令在某个平台不生效。不同平台的命令注册方式不同。Slack 需要在 App 配置里声明 slash command 的请求 URL,Telegram 则依赖 bot 的 command 菜单。命令定义本身是共享的,但平台侧的注册要各自完成。
报错六:session 串台。如果你在多个平台用同一个session_id,对话历史会混在一起。Gateway 的SessionStore按chat_id隔离,跨平台续接需要显式指定同一个 session。不确定时,先别开这个特性。
6. 把多终端网关跑成日常工具
配好之后,这套东西的价值在于「不用再想环境的事」。本地调试用--backend local,跑不可信脚本切--backend docker,要动生产服务器走--backend ssh,命令和对话历史都在同一个 Gateway 里。IDE 通过 ACP 接进来,消息平台通过适配器接进来,模型通道统一走 TaoToken。
如果你还在选模型或对比不同模型在终端任务上的表现,可以直接在模型对话里试:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite
长期跑编码任务、需要 Agent 持续在多个后端之间切换的,建议看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite
需要管理多个 Key、给不同后端分配不同权限的,控制台在这里:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
最后留一个我自己的习惯:把config.toml里的所有敏感值都写成${VAR}形式,用一个.env文件统一管理,.env加进.gitignore。这样配置可以进版本库,Key 不会泄露,换机器时只改.env就行。多终端场景下,这个习惯能省掉大量「为什么这台机器能跑那台不能」的排查时间。