<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Gateway | 有志者事竟成</title><link>https://www.liwenshen.com/tags/gateway/</link><atom:link href="https://www.liwenshen.com/tags/gateway/index.xml" rel="self" type="application/rss+xml"/><description>Gateway</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>zh</language><lastBuildDate>Sat, 04 Jul 2026 11:00:00 +0800</lastBuildDate><image><url>https://www.liwenshen.com/media/icon_hu_dd5d76fef920c49e.png</url><title>Gateway</title><link>https://www.liwenshen.com/tags/gateway/</link></image><item><title>Gateway 网关：连接 20+ 平台的统一消息路由</title><link>https://www.liwenshen.com/note/hermes-agent-engineering/08-gateway/</link><pubDate>Sat, 04 Jul 2026 11:00:00 +0800</pubDate><guid>https://www.liwenshen.com/note/hermes-agent-engineering/08-gateway/</guid><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;系列：通过 Hermes 探秘 Agent 工程 | 第 8 篇&lt;/strong&gt;
上一篇：&lt;a href="https://www.liwenshen.com/note/hermes-agent-engineering/07-security/"&gt;安全防护体系：当 Agent 拥有终端时如何防止「做出格」的事&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="问题一个-agent20-个入口"&gt;问题：一个 Agent，20+ 个入口&lt;/h2&gt;
&lt;p&gt;当你安装 Hermes，你可能通过以下方式跟它聊天：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Telegram&lt;/strong&gt;：Ping bot&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discord&lt;/strong&gt;：服务器里召唤 Agent&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slack&lt;/strong&gt;：工作群里 /hermes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;微信&lt;/strong&gt;：公众号或企业微信机器人&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;命令行&lt;/strong&gt;：终端里直接 hermes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;REST API&lt;/strong&gt;：自己写的前端调用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hermes 需要在所有这些渠道里&lt;strong&gt;统一行为&lt;/strong&gt;——安全配置一样、工具权限一样、输出体验一样。&lt;/p&gt;
&lt;p&gt;Hermes 的解决方案是 &lt;strong&gt;Gateway&lt;/strong&gt;：一个长连接进程，作为所有消息渠道的统一入口。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="gateway-是什么"&gt;Gateway 是什么&lt;/h2&gt;
&lt;p&gt;Gateway 是一个独立的后台服务（systemd / launchd），管理所有平台适配器和会话状态。它不执行 LLM 推理本身——它只做&lt;strong&gt;消息接收、路由、响应下发&lt;/strong&gt;。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌─────────────────────────────────────────────────┐
│ GatewayRunner │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Telegram │ │ Discord │ │ Slack │ ... │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └─────────────┼─────────────┘ │
│ ▼ │
│ _handle_message() │
│ │ │
│ ┌──────────┼──────────┐ │
│ ▼ ▼ ▼ │
│ Slash cmd AIAgent Queue/BG │
│ dispatch creation sessions │
│ │ │
│ ▼ │
│ SessionStore │
│ (SQLite persistence) │
└─────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="session-模型"&gt;Session 模型&lt;/h2&gt;
&lt;h3 id="session-key-结构"&gt;Session Key 结构&lt;/h3&gt;
&lt;p&gt;Gateway 的每个对话都用一个 &lt;strong&gt;session key&lt;/strong&gt; 唯一标识：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;agent:main:{platform}:{chat_type}:{chat_id}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;agent:main:telegram:private:123456789&lt;/code&gt;（Telegram 私聊）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agent:main:discord:channel:987654321&lt;/code&gt;（Discord 频道）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agent:main:slack:group:ABC123&lt;/code&gt;（Slack 群组）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;加了话题的平台的 chat_id 里还包含线程 ID（如 Telegram 论坛主题、Discord Thread）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不要手动构造 session key&lt;/strong&gt;——始终使用 &lt;code&gt;gateway/session.py&lt;/code&gt; 里的 &lt;code&gt;build_session_key()&lt;/code&gt; 函数。session key 是数据库查询、缓存映射、路由匹配的唯一 key，拼写错误意味着创建一个孤儿会话或消息投递失败。&lt;/p&gt;
&lt;h3 id="sessionstore-持久化"&gt;SessionStore 持久化&lt;/h3&gt;
&lt;p&gt;所有会话数据存储在 SQLite 数据库里：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消息历史&lt;/li&gt;
&lt;li&gt;会话元数据（创建时间、来源渠道、启用配置等）&lt;/li&gt;
&lt;li&gt;工具守卫状态&lt;/li&gt;
&lt;li&gt;上下文压缩摘要&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;SessionStore&lt;/code&gt; 提供了一套原子 API，让 Gateway 在重启后可以从数据库恢复会话。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="消息流从平台到-aiagent"&gt;消息流：从平台到 AIAgent&lt;/h2&gt;
&lt;p&gt;一条消息到达 Gateway 后的完整路径：&lt;/p&gt;
&lt;h3 id="1-平台适配器--messageevent"&gt;1. 平台适配器 → MessageEvent&lt;/h3&gt;
&lt;p&gt;每个平台适配器（Telegram Adapter / Discord Adapter 等）接收各自平台的&lt;strong&gt;原始事件&lt;/strong&gt;，规范化成 Hermes 内部的 &lt;code&gt;MessageEvent&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;规范化包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提取发送者 ID、频道 ID、消息内容&lt;/li&gt;
&lt;li&gt;分离文本正文与附件&lt;/li&gt;
&lt;li&gt;识别是否为命令（以 &lt;code&gt;/&lt;/code&gt; 开头）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-基础适配器--两层守卫"&gt;2. 基础适配器 → 两层守卫&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;BasePlatformAdapter&lt;/code&gt; 定义了两层消息守卫机制：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;L1 — 适配器层守卫&lt;/strong&gt;：检查 &lt;code&gt;_active_sessions&lt;/code&gt;。如果当前会话里已经有 AIAgent 在运行，消息被放入 &lt;code&gt;_pending_messages&lt;/code&gt; 队列，并设置 interrupt 事件。这一步确保&lt;strong&gt;在消息进入 Gateway 主逻辑之前就被拦截&lt;/strong&gt;——多个平台的适配器并行运行，不需要每个平台自己实现检查逻辑。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;L2 — GatewayRunner 层守卫&lt;/strong&gt;：检查 &lt;code&gt;_running_agents&lt;/code&gt;。对在 AIAgent 运行期间到达的消息，做分流：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/stop&lt;/code&gt;、&lt;code&gt;/new&lt;/code&gt;、&lt;code&gt;/status&lt;/code&gt;、&lt;code&gt;/approve&lt;/code&gt;、&lt;code&gt;/deny&lt;/code&gt; 等&lt;strong&gt;管理员命令&lt;/strong&gt; → &lt;strong&gt;内联调度&lt;/strong&gt;（直接调用 &lt;code&gt;_message_handler()&lt;/code&gt; 异步执行）&lt;/li&gt;
&lt;li&gt;普通用户消息 → 触发 &lt;code&gt;running_agent.interrupt()&lt;/code&gt;，让 AIAgent 自己决定是打断当前工具执行还是排队处理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种内联调度避免了背景竞争条件：如果 &lt;code&gt;/approve&lt;/code&gt; 排队等待当前任务执行完，而当前任务其实在等用户去按 approve……就死锁了。&lt;/p&gt;
&lt;h3 id="3-gatewayrunner--aiagent"&gt;3. GatewayRunner → AIAgent&lt;/h3&gt;
&lt;p&gt;消息通过守卫后，GatewayResolver 决定如何处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Slash 命令&lt;/strong&gt;：发到 &lt;code&gt;gateway/run.py&lt;/code&gt; 的命令分发器&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模型切换中&lt;/strong&gt;：拦截 &lt;code&gt;/model&lt;/code&gt; 命令，返回&amp;quot;请等当前任务完成或 /stop&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;普通消息&lt;/strong&gt;：创建 &lt;code&gt;AIAgent&lt;/code&gt; 实例，传入当前 session 的配置（模型、工具集、安全设置）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AIAgent 开始执行 &lt;code&gt;run_conversation()&lt;/code&gt; 工具调度循环。中间产生的所有输出通过 &lt;code&gt;delivery.py&lt;/code&gt; 实时轨递到源平台。&lt;/p&gt;
&lt;h3 id="4-响应下发"&gt;4. 响应下发&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;gateway/delivery.py&lt;/code&gt; 负责消息的出站投递：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;直接回复&lt;/strong&gt;：发回到来源平台&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Home Channel 投递&lt;/strong&gt;：cron job 的输出路由到指定 channel&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨平投递&lt;/strong&gt;：可以指定把消息发到不同的平台（如 Discord 用户通过 Telegram 收回复）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;显式目标投递&lt;/strong&gt;：send 命令可以通过 &lt;code&gt;telegram:-100123456:17585&lt;/code&gt; 这样的 URL 指定任意目标&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cron job 的投递被&lt;strong&gt;刻意设计为不在 gateway session 历史里&lt;/strong&gt;——避免消息交替违规（某些平台限制机器人必须在用户消息后才能回复）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="多层授权"&gt;多层授权&lt;/h2&gt;
&lt;p&gt;Gateway 按顺序执行以下检查，任一通过即授权：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;平台级 allow-all&lt;/strong&gt;（如 &lt;code&gt;TELEGRAM_ALLOW_ALL_USERS&lt;/code&gt;）：该平台的全部用户被允许&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平台级 allowlist&lt;/strong&gt;（如 &lt;code&gt;TELEGRAM_ALLOWED_USERS&lt;/code&gt;）：逗号分隔的用户 ID&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DM pairing&lt;/strong&gt;：已授权的管理员可以生成配对码，新用户输入配对码完成授权&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全局 allow-all&lt;/strong&gt;（&lt;code&gt;GATEWAY_ALLOW_ALL_USERS&lt;/code&gt;）：所有平台的所有用户被允许&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;默认：拒绝&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这是&lt;strong&gt;纵深授权&lt;/strong&gt;——按粒度从粗到细排列。配对这个设计特别实用——管理员不需要编辑配置文件，直接通过聊天就能给用户解锁。配对状态持久化在 &lt;code&gt;gateway/pairing.py&lt;/code&gt;，重启后仍然有效。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="平台适配器插件体系"&gt;平台适配器：插件体系&lt;/h2&gt;
&lt;p&gt;绝大多数平台适配器写在 &lt;code&gt;plugins/platforms/&amp;lt;name&amp;gt;/adapter.py&lt;/code&gt;，少部分旧版直接写在 &lt;code&gt;gateway/platforms/&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;统一的适配器接口：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;connect()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;连接到该平台 API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disconnect()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;从容断开连接&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;send_message()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;发送消息到该平台&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;on_message()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;接收平台事件 → 生成 &lt;code&gt;MessageEvent&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;几个有趣的细节：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Token Locks&lt;/strong&gt;：用 &lt;code&gt;acquire_scoped_lock()&lt;/code&gt; 防止两个 profile 同时用同一个 bot token。这在部署多 profile（如&amp;quot;公司号&amp;quot;和&amp;quot;测试号&amp;quot;）时特别关键——同时重连会踢掉对方的 session。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;适配器隔离&lt;/strong&gt;：每个适配器独立运行在自己的 asyncio task 里。一个适配器崩溃（比如 Discord.py 异常）不会拖垮整个 Gateway——其他平台继续正常工作。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;中继适配器&lt;/strong&gt;（relay adapter）：当配置了 &lt;code&gt;GATEWAY_RELAY_URL&lt;/code&gt;，Gateway 会通过出站 WebSocket WebSocket 连接到一个&amp;quot;连接器&amp;quot;服务，然后接收 &lt;code&gt;descriptor&lt;/code&gt;、&lt;code&gt;inbound&lt;/code&gt; 帧。不知道——这样可以对接到没有适配器实现的平台（如某个小众即时通讯协议）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="配置来源"&gt;配置来源&lt;/h2&gt;
&lt;p&gt;Gateway 的配置来自三层：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;来源&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;~/.hermes/.env&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;API keys、bot tokens、平台凭证&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;~/.hermes/config.yaml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;模型设置、工具配置、显示选项&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;环境变量&lt;/td&gt;
&lt;td&gt;覆盖上面任何值&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;CLI 和 Gateway 的配置行为不同&lt;/strong&gt;：CLI 用 &lt;code&gt;load_cli_config()&lt;/code&gt; 内置了默认值字典，而 Gateway 直接读 YAML 配置。这意味着同一个配置字段，如果用户没写进 config.yaml，CLI 可能会给默认行为，但 Gateway 可能表现为不同行为。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="gateway-的运营运维"&gt;Gateway 的运营运维&lt;/h2&gt;
&lt;h3 id="服务安装"&gt;服务安装&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 安装为系统服务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hermes gateway install
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 管理服务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hermes gateway start
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hermes gateway stop
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hermes gateway restart
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hermes gateway status
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# systemd 日志&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;journalctl --user -u hermes-gateway -f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# macOS 日志&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tail -f ~/.hermes/logs/gateway.log
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装过程会自动生成 systemd &lt;code&gt;.service&lt;/code&gt; 文件（Linux）或 launchd &lt;code&gt;.plist&lt;/code&gt;（macOS），设置重启策略（&lt;code&gt;Restart=on-failure&lt;/code&gt; / &lt;code&gt;KeepAlive&lt;/code&gt;），确保 Gateway 崩溃后自动重启。&lt;/p&gt;
&lt;h3 id="优雅重启"&gt;优雅重启&lt;/h3&gt;
&lt;p&gt;Hermes Gateway 支持两种重启方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;systemd / launchd 重启&lt;/strong&gt;：SIGTERM → 超时 SIGKILL → 重启。这种重启会中断正在执行的 Agent 任务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SIGUSR1 重启&lt;/strong&gt;（Hermes 独有）：发送 SIGUSR1 信号 → GatewayRunner 捕获信号 → &lt;code&gt;request_restart(via_service=True)&lt;/code&gt; → 等待当前正在运行的 AIAgent 完成任务（最多 &lt;code&gt;agent.restart_drain_timeout&lt;/code&gt; 秒）→ 正常退出 → 服务管理器自动重启。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;SIGUSR1 重启是&lt;strong&gt;无损升级&lt;/strong&gt;的——新代码加载后，当前任务被完成，后续请求自动发到新进程版本。&lt;/p&gt;
&lt;h3 id="profile-支持"&gt;Profile 支持&lt;/h3&gt;
&lt;p&gt;Hermes Gateway 支持多 profile——相同机器上运行多个独立实例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hermes gateway run --profile prod &lt;span style="color:#75715e"&gt;# 生产实例（绑定 127.0.0.1:8080）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hermes gateway run --profile test &lt;span style="color:#75715e"&gt;# 测试实例（绑定 127.0.0.1:8081）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Profile 通过环境变量 &lt;code&gt;HERMES_PROFILE&lt;/code&gt; 隔离：不同的 &lt;code&gt;~/.hermes/profiles/&amp;lt;profile&amp;gt;/&lt;/code&gt; 目录存储独立配置、独立的数据库文件、独立的 profile Gateway 进程独立的 profile Gateway 实例。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Gateway 是 Hermes 的&lt;strong&gt;消息路由器&lt;/strong&gt;——不思考，只管连接、转发、持久化。它的核心设计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Session Key&lt;/strong&gt;：&lt;code&gt;agent:main:{platform}:{chat_type}:{chat_id}&lt;/code&gt; 格式，唯一标识一个对话工程模型&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;双层守卫&lt;/strong&gt;：适配器层 + GatewayRunner 层，既防止并发又支持 admin 命令打断&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;纵深授权&lt;/strong&gt;：从粗到细的授权检查 + DM pairing 这个很实用的自助授权模式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;插件适配器&lt;/strong&gt;：每个平台一个插件目录，共享 &lt;code&gt;BasePlatformAdapter&lt;/code&gt; 接口&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无损升级&lt;/strong&gt;：SIGUSR1 + drain timeout + 进程服务管理器自动重启&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下一篇，我们深入 Hermes 的 Provider 抽象层——如何让 Hermes 同时与 OpenAI、Anthropic、Gemini、本地 Ollama 等多种 LLM 提供商协作。&lt;/p&gt;</description></item></channel></rss>