Gateway 网关:连接 20+ 平台的统一消息路由

如何用 session key 隔离多用户、用双层守卫防止并发、用 delivery 系统实现任意渠道回复

通过 Hermes 探秘 Agent 工程 | 第 11 篇 · 查看全部

上一篇:Provider 抽象层:让 Hermes 同时驾驭 30+ 个 LLM 提供商


[系列文章导航]

#文章定位
1Agent Loop:Agent 的核心执行循环入口
2System Prompt:身份、上下文与策略的三层架构认知层
3工具系统:从注册到调度工具层
4工具调度系统:从注册到执行的完整生命周期调度层
5安全防护体系:当 Agent 拥有终端时如何防止「做出格」的事安全层
6沙箱与代码执行:让 Agent 安全跑代码的 RPC 架构执行层
7上下文压缩:让 Agent 在有限窗口里「记得住」记忆层
8记忆系统:跨会话持久化的工程实现记忆层
9技能系统:Agent 如何把经验变成可复用的程序化记忆记忆层
10Provider 抽象层:让 Hermes 同时驾驭 30+ 个 LLM 提供商模型层
11Gateway 网关:连接 20+ 平台的统一消息路由接入层
12多 Agent 协作:委托、调度与看板协作层

问题:一个 Agent,20+ 个入口

Hermes 需要在所有这些渠道里统一行为——安全配置一样、工具权限一样、输出体验一样。

Hermes 的解决方案是 Gateway:一个长连接进程,作为所有消息渠道的统一入口。

Session 模型

Session Key 结构

agent:main:{platform}:{chat_type}:{chat_id}

例如:agent:main:telegram:private:123456789

不要手动构造 session key——始终使用 build_session_key() 函数。

SessionStore 持久化

所有会话数据存储在 SQLite 数据库里。SessionStore 提供了一套原子 API,让 Gateway 在重启后可以从数据库恢复会话。

消息流:从平台到 AIAgent

1. 平台适配器 → MessageEvent

每个平台适配器接收各自平台的原始事件,规范化成 Hermes 内部的 MessageEvent

2. 基础适配器 → 两层守卫

L1 — 适配器层守卫:检查 _active_sessions。如果当前会话里已经有 AIAgent 在运行,消息被放入队列并设置 interrupt 事件。

L2 — GatewayRunner 层守卫:检查 _running_agents。对在 AIAgent 运行期间到达的消息做分流:

  • 管理员命令(/stop、/new、/approve)→ 内联调度
  • 普通用户消息 → 触发 running_agent.interrupt()

3. GatewayRunner → AIAgent

AIAgent 开始执行 run_conversation()。中间产生的所有输出通过 delivery.py 实时轨递到源平台。

4. 响应下发

gateway/delivery.py 负责:直接回复、Home Channel 投递、跨平投递、显式目标投递。

Cron job 的投递被刻意设计为不在 gateway session 历史里——避免消息交替违规。

多层授权

Gateway 按顺序执行以下检查,任一通过即授权:

  1. 平台级 allow-all(如 TELEGRAM_ALLOW_ALL_USERS
  2. 平台级 allowlist(如 TELEGRAM_ALLOWED_USERS
  3. DM pairing:管理员生成配对码,新用户输入配对码完成授权
  4. 全局 allow-allGATEWAY_ALLOW_ALL_USERS
  5. 默认:拒绝

平台适配器:插件体系

绝大多数平台适配器写在 plugins/platforms/<name>/adapter.py

几个有趣的细节:

Token Locks:用 acquire_scoped_lock() 防止两个 profile 同时用同一个 bot token。

适配器隔离:每个适配器独立运行在自己的 asyncio task 里。一个适配器崩溃不会拖垮整个 Gateway。

中继适配器(relay adapter):当配置了 GATEWAY_RELAY_URL,Gateway 通过出站 WebSocket 连接到一个"连接器"服务。

配置来源

Gateway 的配置来自三层:

来源示例
~/.hermes/.envAPI keys、bot tokens、平台凭证
~/.hermes/config.yaml模型设置、工具配置、显示选项
环境变量覆盖上面任何值

CLI 和 Gateway 的配置行为不同:CLI 用 load_cli_config() 内置了默认值字典,而 Gateway 直接读 YAML 配置。

Gateway 的运营运维

优雅重启

SIGUSR1 重启是无损升级——新代码加载后,当前任务被完成,后续请求自动发到新进程版本。

Profile 支持

Hermes Gateway 支持多 profile——相同机器上运行多个独立实例:

hermes gateway run --profile prod
hermes gateway run --profile test

下一篇:多 Agent 协作:委托、调度与看板 — delegate_task、cron、kanban 三大支柱,让 Hermes 从单兵变成团队