Hermes Agent 深度剖析(4/7):多平台网关——一个进程接住 16 个消息平台

简介: 一个 Agent 要同时接住 Telegram、Discord、Slack、WhatsApp、Signal、Matrix、CLI 十几个入口,最省事的做法是上消息队列,把每个平台当成独立服务。Hermes Agent 反其道而行:所有平台连接塞进同一个进程。本文拆它为什么敢这么做、八段消息管道怎么走、会话路由的 30 分钟窗口是什么、能力协商如何把说什么和怎么说拆开。

摘要:一个 Agent 要同时接住 Telegram、Discord、Slack、WhatsApp、Signal、Matrix、CLI 十几个入口,最省事的做法是上消息队列,把每个平台当成独立服务。Hermes Agent 反其道而行:所有平台连接塞进同一个进程。本文拆它为什么敢这么做、八段消息管道怎么走、会话路由的 30 分钟窗口是什么、能力协商如何把"说什么"和"怎么说"拆开,以及这条路和消息总线方案的真实差距。

这是「Hermes Agent 深度剖析」系列的第 4 篇,全系列 7 篇:

01 总览:25 万 Star 的自改进 Agent 到底强在哪
02 三层记忆架构:会话记忆、持久记忆与用户模型怎么分工
03 技能学习闭环:Agent 怎么自己写技能文档
04 多平台网关:一个进程接住 16+ 个消息平台(本文)
05 安全架构:容器沙箱、技能扫描与人在回路
06 从零到生产:四种部署方式与成本账
07 vs OpenClaw:十二个维度的选型对比


一、起点不是"多平台",是"协议异构"

很多人以为多平台接入的难点是"平台数量多",其实真正的难点是每个平台的连接语义完全不同。同样是"收一条消息",六个平台的实现路径几乎没有交集:

平台 消息入站方式 保活机制 特殊约束
Telegram Long Polling 或 Webhook 无心跳,靠长轮询超时重连 Webhook 需要公网 HTTPS 端点
Discord WebSocket Gateway HELLO 下发心跳间隔,实务上约 41 秒一次 需要 Gateway Intents 声明订阅范围
Slack Socket Mode(WebSocket) 服务端定时发 ping,需快速回 pong 消息事件有 3 秒 ACK 窗口
WhatsApp Cloud API Webhook 由 Meta 侧回调,无长连接 模板消息审核、24 小时会话窗口
Signal 本地 signal-cli 守护进程 守护进程自身维护 需要设备关联,媒体走加密链路
Matrix /sync 长轮询 since token 增量同步 房间状态需自行维护,E2EE 可选
CLI 标准输入 无 无富媒体、无按钮

一张表看完就明白:这不像是"接几个 API",更像是把七种通信模型塞进同一个事件循环。Discord 的心跳、Slack 的 ACK、Matrix 的增量同步、Telegram 的 webhook 回调——它们对"连接还活着吗"的定义都不一样。

如果按微服务思路做,你会得到七个服务、七套部署、七个健康检查、七份日志。Hermes 的选择是把这七件事压进一个进程。

二、单进程架构:一个 Gateway 装下所有连接

整体链路是一条自左向右的箭头链:

平台 Adapter(每平台一个)
  → Normalizer(消息标准化)
  → Identity Resolver(身份解析,跨平台用户对齐)
  → Session Router(会话路由)
  → Context Builder(记忆 + 技能 + 历史注入)
  → Agent Engine(LLM 推理 + 工具调用)
  → Capability-aware Dispatcher(能力感知分发)
  → 目标平台 Adapter(渲染 + 发送)

所有 Adapter 共享同一个事件循环、同一份会话表、同一套记忆索引。

2.1 单进程换来的三个确定性

第一,零延迟的上下文同步。 用户在 Telegram 说了一半,切到 Discord 继续说,Agent 需要立刻知道"这是同一个人的同一个话题"。如果是多进程 + 外部存储,中间至少隔着一次序列化、一次网络往返、一次反序列化。单进程里,这就是一次内存对象读取。

第二,会话操作是原子的。 跨平台继续对话时,要做"关掉旧会话的活跃标记 + 挂到新会话 + 迁移上下文"三件事。在单进程里这是一个临界区,加把锁就完事;在多进程里就是分布式事务,要么上两阶段提交,要么接受中间态不一致。

第三,运维面被压到最小。 一个二进制、一个数据目录、一份日志。不需要 Redis 存会话、不需要消息队列做缓冲、不需要服务发现。对个人 Agent 这个定位来说,这一点比性能更重要——用户不会为了一个私人助理去维护一套中间件。

2.2 三个必须承认的代价

代价 具体表现 Hermes 的缓解手段
单点故障 进程挂了,所有平台一起断 适配器级错误边界:单个 Adapter 崩溃只影响该平台,并按指数退避自动重启
资源竞争 一个平台的大文件上传可能拖慢其他平台 每个 Adapter 有独立队列与并发上限,出站发送走异步池
规模上限 单进程的并发会话数有天花板 官方定位是个人/小团队场景,数百并发会话量级够用

这里要说清楚:单进程不是"更先进",而是"在这个场景下更划算"。如果你要做的是面向百万用户的多租户 Agent 平台,单进程会立刻成为瓶颈,消息队列和水平扩展是必需的。但个人 Agent 的典型负载是"一个人 + 几个群",单进程的性能余量大到用不完。

三、八段消息管道:每一段在防什么

管道化的价值不在于"分了几段",而在于每一段都能独立测试、独立替换:

阶段 输入 → 输出 不这么做会怎样
1. 反序列化 平台原始事件 → 平台消息对象 各平台细节散落到业务逻辑里
2. 标准化 平台消息 → UnifiedMessage 下游每处都要写 if platform == ...
3. 身份解析 平台用户 ID → 统一身份 同一个人在 Telegram 和 Discord 被当成两个人
4. 会话路由 统一身份 + 消息 → 会话 ID 每次说话都开新会话,上下文永远接不上
5. 上下文构建 会话 ID → 完整上下文 Agent 每次都要自己"找之前聊了什么"
6. 推理执行 上下文 → 回复内容 + 工具调用 —
7. 能力查询 回复内容 + 目标平台 → 渲染方案 Agent 被迫关心"我在哪个平台"
8. 出站发送 渲染结果 → 平台 API 调用 平台限流直接打到 Agent 引擎上

第 2 段和第 7 段是最容易被低估的。前者决定了系统的可扩展性(新增平台只需实现 Adapter → UnifiedMessage 的映射),后者决定了系统的体验上限(同一个语义回复在不同平台呈现成不同形态)。

四、统一消息模型:最大公约数,不是最小公分母

统一消息模型常见的两种做法:

做法 结果 问题
最小公分母 只保留所有平台都支持的字段(纯文本 + 发送者) 丢掉按钮、引用、附件、表情回应,体验降级到短信水平
最大公约数 + 扩展位 通用字段统一建模,平台特有信息放扩展字段 需要下游知道"什么时候该看扩展字段"

Hermes 走的是第二条路。核心字段大致是:

字段 含义 备注
platform 来源平台标识 telegram / discord / slack / ...
chat_id 会话(房间/频道/私聊)ID 平台原生 ID
user_id 平台内用户 ID 与统一身份做映射
text 文本内容 标准化后的纯文本
attachments 附件列表 统一为 url + mime + size
reply_to 引用消息 ID 用于"回复某条"的语义
thread_id 话题/线程 ID Discord thread、Slack thread
raw 平台原始事件 兜底,处理特殊场景
capabilities 目标平台能力快照 供第 7 段能力协商使用

raw 这个字段很关键。标准化不可能穷尽所有平台特性,留一个原始事件的逃生舱,比事后改模型安全得多。

五、会话路由:平台优先,再退到 30 分钟窗口

路由逻辑本身很短,但它是整个"跨平台连续对话"体验的开关:

def resolve_session(msg: UnifiedMessage, registry: SessionRegistry) -> Session:
    # 1. 优先:同平台同会话的活跃 session
    s = registry.find_active(platform=msg.platform, chat_id=msg.chat_id)
    if s:
        return s

    # 2. 退一步:同平台内该用户的最近活跃 session
    s = registry.find_recent_by_user(msg.platform, msg.user_id)
    if s:
        return s

    # 3. 再退一步:跨平台的活跃 session(30 分钟窗口)
    s = registry.find_cross_platform_active(msg.user_id, window_minutes=30)
    if s:
        registry.attach(msg.platform, msg.chat_id, s)
        return s

    # 4. 都没有:新建
    return registry.create(msg)

为什么是 30 分钟,而不是"用 LLM 判断这句话是不是延续上文"?

方案 成本 可靠性 失败模式
LLM 意图判断 每条消息一次额外推理 中(模型判断有波动) "继续"两个字被判定为新话题
时间窗口启发式 零额外推理 高(规则确定) 超过 30 分钟的延续会被当成新会话

第 3 步是精髓:用户从 Telegram 切到 Discord,只要在 30 分钟内,说的第一句话就会被自动挂到原会话上。这覆盖了绝大多数"换设备继续聊"的场景,而代价只是几行注册表查询。

六、能力协商:Agent 说"说什么",Gateway 管"怎么说"

这是这套设计里我认为最值得抄走的部分。

每个 Adapter 除了协议转换,还要声明自己的能力矩阵:

enum Capability {
   
  TEXT = "text",
  MARKDOWN = "markdown",
  IMAGE = "image",
  FILE = "file",
  REACTION = "reaction",
  BUTTONS = "buttons",
  THREADS = "threads",
  EDIT = "edit",          // 可编辑已发送消息
  READ_RECEIPT = "read_receipt",
}

interface PlatformAdapter {
   
  readonly platform: string;
  readonly capabilities: Set<Capability>;
  start(): Promise<void>;
  stop(): Promise<void>;
  send(chatId: string, payload: RenderedMessage): Promise<void>;
}

能力矩阵大致长这样:

能力 Discord Telegram Slack Matrix CLI
富文本 Markdown ✅ ✅ ✅(mrkdwn) ✅ ❌
内联按钮 ✅ Components ✅ Inline Keyboard ✅ Block Kit ⚠️ 需 Widget ❌
表情回应 ✅ ✅ ✅ ✅ ❌
消息编辑 ✅ ✅ ✅ ✅ ❌
已读回执 ⚠️ 有限 ❌ ✅ ✅ ❌
文件附件 ✅ ✅ ✅ ✅ ⚠️ 仅路径

于是,Agent 侧只需要生成语义回复,不需要知道目的地:

Agent 生成:"问题已定位,是否执行修复?[确认] [取消]"
  → Gateway 查目标平台能力
  → Discord:支持按钮 → 渲染为 Message Components
  → Telegram:支持按钮 → 渲染为 Inline Keyboard
  → Slack:支持按钮 → 渲染为 Block Kit Actions
  → CLI:不支持按钮 → 降级为 "回复 1 确认 / 2 取消"

这个降级链是必须的。没有能力协商,你要么让 Agent 自己判断平台(污染推理),要么在每个平台分支里写渲染逻辑(污染适配器)。

6.1 新增一个平台要写多少代码

平台复杂度 适配器规模 主要工作量 代表平台
简单 ~200 行 文本收发 + 会话映射 CLI
中等 ~500 行 WebSocket 连接 + 消息模型转换 Slack、Matrix
复杂 ~1000 行 Gateway Intents + 交互组件 + 频道管理 Discord
极复杂 ~1500 行 端到端加密 + 媒体交付 + 回执 Signal、WhatsApp

新增平台的流程只有三步:实现 PlatformAdapter 接口、注册到 AdapterRegistry、配置平台凭证。

但我想强调:插件化的真正价值不是"易扩展"。 大多数讲插件化的文章都会说"新增平台只需写一个适配器",这当然对,但真正的价值在能力协商——它把 Agent 引擎和平台适配器彻底解耦,两者可以独立演进。新增平台不需要动 Agent 一行代码,Agent 增加新回复形态(比如"卡片")也不需要动所有适配器,只要适配器声明"我不支持",网关自动降级。

七、和消息总线方案的真实差距

另一条主流路线是消息总线:每个平台一个服务,消息统一进队列,再由调度器分发。

维度 消息总线方案 单进程 Gateway
架构 中心化总线 + 意图路由 统一入口 + 管道处理
上下文 外部存储(缓存/数据库),按需加载 进程内存 + 全文索引,始终在线
跨平台会话 用户 ID 映射 + 外部关联表 进程内注册表 + 30 分钟窗口
平台扩展 新增服务 + 注册到总线 实现接口 + 自动能力协商
部署依赖 队列 + 缓存 + 数据库 单二进制,零外部依赖
故障隔离 队列天然解耦 适配器级错误边界
流量削峰 队列缓冲,天然支持 每适配器独立队列

消息总线的优势是真实的:解耦彻底、能削峰、便于水平扩展、天然适合链路追踪。但它在一个具体场景上会翻车。

7.1 一个"继续"引发的故障

场景:用户在 Telegram 发起一个复杂的数据分析任务,中途切到 Discord 发一句"继续"。

消息总线方案:
1. Telegram 消息进总线 → 意图识别判定"复杂任务" → 路由到多 Agent 流程
2. 用户切到 Discord,发"继续"
3. Discord 消息进总线 → 意图识别看到只有两个字 → 判定"简单消息"
   → 路由到直接 LLM 通道
4. 直接 LLM 不知道"继续"指什么 → 只能回头查外部存储找上下文 → 拼回去重推理

单进程 Gateway:
1. Telegram 消息 → 标准化 → 建会话 session_001 → 推理
2. Discord 的"继续" → 标准化 → 查注册表,命中 session_001(30 分钟窗口内)
   → 加载完整上下文 → 直接接着推理

根因很清楚:意图识别和上下文管理在两个地方,而意图识别只看当前这条消息。用 AI 判断"该用哪个 AI 来处理",本身就引入了额外的不确定性和延迟。

7.2 我的看法:消息总线在 Agent 场景下是"过度企业化"

消息总线是 ESB(企业服务总线)思路的延续。它在企业系统集成里非常正确——那边要解决的是异构协议、消息路由、流量控制。但 Agent 的多平台接入和企业集成有个根本差别:

维度 企业系统集成 Agent 多平台接入
核心目标 异构系统互通 统一用户体验
关键指标 吞吐量、可靠性 上下文连续性、回复质量
消息特征 结构化、可预测 非结构化、对话式
路由依据 规则(内容/Header) 上下文(历史/意图)
扩展方式 水平扩容 垂直加能力

消息总线把"消息"当成需要路由的数据包,而 Agent 场景下"消息"是需要理解的对话。 一段对话被拆成数据包在总线上流转时,连续性就丢了。

所以我更认同 Hermes 的取向:多平台 Agent 的核心不是"消息路由",而是"上下文管理"。上下文只要完整、一致、即时可用,消息从哪来、回到哪去,只是最后的呈现问题。

八、平台深度 vs 平台数量:版本演进看什么

一个框架宣称"支持 20+ 平台"时,值得追问一句:支持的到底是能收发文本,还是能原生交互?

看 Hermes 近几个版本的更新方向,能看出它选的是后者(以下能力在各版本中陆续加入,写作本文时最新版本为 v0.22.5):

平台 新增能力 解决的问题
Matrix 表情回应 + 已读回执 "Agent 到底看没看到我的消息"
Discord 频道创建/慢速模式/归档 Agent 能否按任务组织自己的环境
Signal 全类型媒体加密交付 E2EE 下的图片/视频/文档收发
Mattermost 文件附件 企业场景的代码审查、文档协作

其中已读回执这个功能特别值得说。在没有它之前,用户发完消息只能干等——不知道 Agent 是在处理、消息丢了、还是进程崩了。一个"已读"标记,把这种不确定感直接消掉了。

我的判断是:个人 Agent 的用户通常只活跃在 2-3 个平台上,所以"覆盖 20 个平台但每个都只能发纯文本",价值远低于"覆盖 6 个平台但每个都能用原生交互"。平台的深度比数量更能决定体验。

九、四个可以抄走的模式

从这套网关设计里,我提炼出四个与平台无关、可以直接用在别处的模式:

模式 结构 适用场景
管道化处理 反序列化 → 标准化 → 身份 → 路由 → 上下文注入 任何异构输入的统一接入
能力协商 业务侧只产出语义,呈现侧按目标能力渲染 一端内容、多端展示
时间窗口会话复用 先同平台精确匹配,再退到跨平台时间窗 低成本实现"接着上次聊"
适配器错误边界 每适配器独立队列 + 指数退避重启 单进程内的软隔离

第四个模式最容易被忽略。单进程架构最怕的就是"一个坏适配器拖死所有人",而错误边界是唯一不需要引入额外进程就能做到的软隔离。

十、总结

Hermes 的多平台网关代表了一次方向选择:从"消息路由"转向"上下文管理"。

关键要点:

  1. 单进程是刻意的减法,用零延迟上下文同步、原子会话操作、最小运维面,换取规模上限的让渡。个人 Agent 的负载撑得起这个取舍。
  2. 八段管道把复杂度关进了盒子,每段职责单一、可独立替换,标准化和能力协商是其中最关键的两段。
  3. 30 分钟窗口是性价比极高的启发式,用几行注册表查询,覆盖了绝大多数跨平台续聊场景,避免了每条消息一次意图推理。
  4. 能力协商解耦了"说什么"和"怎么说",Agent 不需要知道自己在哪个平台,网关自动按目标能力渲染或降级。
  5. 平台深度优于平台数量,已读回执、表情回应、媒体交付这些"小功能"才是浅层集成和深度集成的分水岭。

给正在设计多平台 Agent 的同行一个建议:把 80% 的精力放在上下文管理上,而不是消息路由上。路由是术,上下文是道。上下文做对了,路由自然简单;上下文做错了,再漂亮的总线也只是把问题分散到更多服务里。


上一篇:技能学习闭环:Agent 怎么自己写技能文档

下一篇:《安全架构:容器沙箱、技能扫描与人在回路》——当 Agent 能执行代码、能装技能、能读写文件时,怎么保证它不越界。

延伸阅读

这套「拆开源 Agent 源码」的连载还在继续,下一篇讲安全架构。也想听听你的场景:你的 Agent 现在接了几个平台?跨平台续聊这件事,是靠人肉复制上下文,还是框架自己记得住?

相关文章
|
27天前
|
运维 监控 安全
国家评测机构首次给智能体分五级:这套五维框架,测试团队明天就能抄成上线验收清单
智能体上线评审常陷“五人五义”困局。全国首个五级智能体评测证书揭示破局关键:将主观判断拆为功能性、稳定性、安全、工程化、场景适配五大可证维度,每维设独立判据与证据链,推动验收从经验走向可审计、可复现、可追责。(239字)
国家评测机构首次给智能体分五级:这套五维框架,测试团队明天就能抄成上线验收清单
|
3月前
|
数据采集 存储 缓存
什么是API选品比价?一篇带你从零到一
API选品比价是通过调用电商/供应商API,自动获取、清洗、比对商品价格与参数,实现7×24小时实时、规模化、多维度(价格、评分、物流等)智能选品的技术方案,助力企业降本增效。
|
4月前
|
Kubernetes 安全 开发者
手写 Harness 底层架构: 基于 Deep Agents 深入底层 Sandbox沙盒Infra 基础设施架构
手写 Harness 底层架构: 基于 Deep Agents 深入底层 Sandbox沙盒Infra 基础设施架构
手写 Harness 底层架构: 基于 Deep Agents 深入底层 Sandbox沙盒Infra 基础设施架构
|
3月前
|
数据采集 监控 API
【淘宝API】商品列表采集
本项目通过Taobaoapi2014调用jd.item_search接口,无需卖家权限,POST方式+Bearer鉴权,一键批量获取淘宝/天猫搜索页商品数据(标题、价格、销量、店铺等),支持导出Excel/CSV/数据库,适用于电商分析与竞品监控。(238字)
|
3月前
|
自然语言处理 数据可视化 算法
Agent时代的知识图谱,到底还能怎么玩?
本文探讨知识图谱在Agent时代的转型路径:指出其不可替代的三大价值——结构化行为约束、多Agent语义协调、长期记忆组织;厘清“别碰”“同质化”与“值得投入”的18个方向;强调知识图谱须从静态知识库升级为动态、可验证、嵌入式的行为与记忆基础设施。
|
3月前
|
数据采集 人工智能 搜索推荐
AI搜索引擎引用源选择机制的数据分析与技术解析
本文基于45条AI搜索引用源数据,分析技术内容被引用的平台偏好(CSDN、海外博客、官方文档占55.5%)、内容特征(答案前置、列表密度≥3.2/千字、数字密度≥18.5/千字)及时间窗口(30–90天稳定被引),揭示平台推荐是关键过滤环节,为技术创作者提供可量化的发布策略参考。
220 4
|
4月前
|
人工智能 自然语言处理 数据库
智能分诊+AI问诊+电子处方,互联网医院系统源码功能开发技术架构揭秘
本文从软件开发与系统架构视角,深入解析互联网医院系统源码的核心设计逻辑,重点拆解智能分诊、AI问诊与电子处方三大核心模块,并结合微服务架构、高并发设计、医疗数据安全与AI大模型接入等关键技术。
|
4月前
|
监控 API Windows
WGCLOUD v3.6.8 正式更新
WGCLOUD v3.6.8发布:修复CPU/内存等指标偶现为0、大屏离线数据不显示等Bug;新增Windows系统服务列表及开放API;优化告警脚本执行与SNMP设备运行时间兼容性。升级方式详见官方图示。
|
4月前
|
关系型数据库 数据库 PostgreSQL
阿里云RDS PostgreSQL全方位对接使用指南与SQL语法深度解析
本文系统讲解阿里云RDS PostgreSQL从创建实例、配置白名单、建立数据库与账号到多方式连接的全流程,同时深度剖析PostgreSQL核心SQL语法,涵盖窗口函数、公用表表达式、JSONB数据类型、PL/pgSQL存储过程编程及高级索引优化等关键技术点,并通过实战代码示例帮助开发者快速掌握云端PostgreSQL的全部能力。
|
4月前
|
机器学习/深度学习 人工智能 网络架构
深度解析:Transformer 的“灵魂”——QKV 变换的物理直觉
本文用图书馆检索等生活隐喻,从物理意义与认知科学角度解析Transformer中QKV设计的精妙本质:解耦查询(q)、键(k)、值(v)三重角色,实现语义分离、避免自注意力“自恋”,模拟人类动态信息路由的认知过程。(239字)
902 13