第六章 统一网关:一个入口,连接所有渠道
核心问题:OpenClaw 怎样把 Telegram、Discord、Slack、WhatsApp 等不同平台的消息统一接入,并在多渠道下尽量保持连续的协作体验?
上一章讲的是消息进来以后怎么排队、怎么执行、怎么不串线。
这一章要补上更前面的一层:这些消息到底从哪里来,又是怎么进入系统的。
如果 Agent 只活在一个聊天窗口里,这个问题不复杂。但 OpenClaw 面向的是现实世界里的多个渠道。平台一多,系统就不只要处理“用户说了什么”,还要处理:
- 消息来自哪个平台
- 这个平台怎么认证
- 这个平台的用户 ID 怎么表示
- 回复该发回哪里
- 跨平台时,系统能不能认出还是同一个人
- 不同平台能力不一样时,回复该怎么展示
所以统一网关的作用,不只是“多接几个平台”,而是把平台差异挡在外层,让 Agent 内部尽量只处理统一的“人、会话、消息”。
第一节 为什么需要统一网关
这一节只回答一个问题:为什么 OpenClaw 不能让每个平台直接连到 Agent,而必须先经过一层统一网关。
1.1 这不只是“多接几个平台”
不同平台的差异很大。下面这张表只是常见示意,实际字段名和认证方式要以当前渠道实现为准:
| 平台 | ID 例子 | 文本字段示意 | 常见接法 |
|---|---|---|---|
| Telegram | 数字 ID | message.text | Bot Token |
| Discord | Snowflake ID | message.content | Bot Token / OAuth |
| Slack | U... 这类成员 ID | 事件对象里的字段 | App Token / OAuth |
| 飞书 | open_id 或 user_id | 平台事件里的字段 | tenant token |
除此之外,平台之间还常常有这些差别:
- 私聊和群聊结构不同
- 线程支持不同
- 流式输出能力不同
- 单条消息长度限制不同
- 回复、编辑、附件处理方式不同
如果没有统一网关,每接一个新平台,Agent 核心里就会多一层平台判断。
短期看,这些 if-else 都能跑;长期看,系统会越来越像一团打结的线。所以统一网关的第一层意义不是“让架构显得高级”,而是:把平台差异拦在最外层,不让它们一路流进 Agent 核心。
1.2 真正麻烦的,不只是字段不同
字段不同只是工程问题。
更影响体验的是:同一个人换个平台后,系统到底认不认得出来。
这里先分清三个词:
| 词 | 可以先理解成什么 |
|---|---|
| 渠道 | 你从哪个平台来 |
| 身份 | 这个人到底是谁 |
| 会话 | 当前这一段具体对话现场 |
这三层不是一回事。
在 OpenClaw 的现有文档里,这一块主要和 identityLinks、dmScope 等配置有关。也就是说:
- 系统要先判断“这几个平台 ID 是不是同一个人”
- 还要再判断“这些消息要不要算同一段会话”
这两件事会互相影响,但不应该混成一件事。
一个更稳的理解是:
- 身份是否统一,看你有没有做身份关联
- 会话是否合并,看你的会话粒度怎么配
这里还要多加一句:identityLinks 更像给 DM session key 做 canonicalization 的辅助配置,不是自动把所有渠道上下文都焊在一起的总开关。
所以不要默认“跨平台一定合并”,也不要默认“跨平台一定分开”。这要看配置和你的真实目标。
1.3 统一网关保护的,是 Agent 核心
走到这里,就能更准确地理解 Gateway 的角色了。它不是一个“消息转发器”那么简单,更像一点的说法是:Gateway 是 Agent 的感官系统,也是外部世界和内部推理之间的翻译层。
可以想象成:
平台原始事件
→ Gateway 先读懂
→ 转成系统内部统一消息
→ 再交给 Agent 判断反过来也一样:
Agent 先产出统一回复
→ Gateway 再按当前平台能力发回去这样一来,Agent 核心就能长期只关心几件事:
- 谁在找我
- 现在是哪段会话
- 用户说了什么
- 下一步该怎么推进
至于“这是哪个平台”“平台支不支持线程”“要不要分块发”“要不要流式更新”,这些差异都留在网关层。
第二节 它是怎么跑起来的
这一节要回答的问题是:一条来自外部平台的消息,进入 OpenClaw 以后,到底会经历哪些步骤,最后又怎样变成一条合适的回复发回去。
2.1 第一步:先把平台原始事件转成统一消息
不同平台的原始事件长得很不一样,所以 Gateway 先做的不是路由,而是标准化。
可以把这一步理解成:
平台原始事件
→ 渠道适配层读取并解析
→ 提取统一字段
→ 形成系统内部消息这一章里,你可以把这层适配器统称为渠道插件。在本仓库前面的构建章节里,也会把它写成 ChannelPlugin。你可以把它理解成“平台翻译层”。
它至少要解决两件事:
- 入站时,把平台事件翻成统一格式
- 出站时,把统一回复翻回平台格式
2.2 第二步:再决定交给哪个 Agent
标准化之后,系统才开始路由。这里的核心问题是:这条消息该交给哪个 Agent。
在 OpenClaw 里,系统不一定只有一个 Agent。不同渠道、不同账号、不同群组,可能默认归不同 Agent。
从机制上看,这一层对应的就是路由解析逻辑。你不需要死记函数名,但最好知道它大致在做什么:系统会根据当前渠道、账号、对话对象,以及你写下的 bindings 规则,从更具体的匹配一路走到更通用的匹配,最后找到最合适的 Agent。
这一层通常和这些信息有关:
| 名字 | 可以先理解成什么 |
|---|---|
channel | 哪个平台 |
account | 这个平台上的哪个机器人账号 |
peer | 这条消息来自哪个聊天对象 |
bindings | “这类消息交给哪个 Agent” 的规则 |
可以把过程看成:
先看更具体的绑定
→ 再看默认归属
→ 最后落到某个 Agent这一层的重点很朴素:先交对人,后面才有意义。
默认情况下,OpenClaw 还是为一条入站消息选一个 Agent;只有在 broadcast groups 这类特定配置下,同一条消息才会 fan-out 给多个 Agent。
2.3 第三步:再决定进哪段会话
找到 Agent 以后,还不能立刻开始处理。因为“交给哪个 Agent”和“落到哪段会话”是两件事。
这里可以把它理解成“会话键”。仓库文档里给过一些常见示意:
| 来源 | 常见会话键格式 |
|---|---|
| 私聊默认 | agent:<agentId>:<mainKey>(常见示例是 agent:main:main) |
| 群聊 | agent:<agentId>:<channel>:group:<id> |
| Cron | cron:<job.id> |
这也是为什么 Gateway 和上一章的消息循环是连着的。上一章解决的是“同一条 lane 里的消息怎么排队”;这一章在它前面补上了另一半:什么叫“同一条 lane”,是谁来决定的。
这里还有两个必须一起看的配置:
| 配置 | 主要解决什么 |
|---|---|
dmScope | 私聊会话按多细的粒度拆开 |
identityLinks | 不同平台上的 ID 是否视为同一个人 |
这一点需要特别说明:
按现有使用文档,默认私聊可能共享同一条主会话;多人共用时,官方建议把 session.dmScope 设成 per-channel-peer 来隔离不同人。
同时,identityLinks 又可能让同一个人在多个平台上的 ID 关联起来。
但它只是帮助系统把 DM peer id 归一化;如果你用的是 per-channel-peer 或 per-account-channel-peer,channel / account 这一层仍然会保留下来,所以不会因为做了身份关联就自动跨平台共用同一段上下文。
因此,最终是“合并”还是“隔离”,要看你的 dmScope、身份关联和渠道场景一起怎么配。
一句话记住:先想清楚你要不要跨平台认人,再想清楚你要不要跨平台共用上下文。
2.4 第四步:Agent 回完以后,网关再按平台发出去
OpenClaw 内部先形成统一回复,再由 Gateway 决定怎么发回当前平台。
这里最重要的原则是:优雅降级。 能展示得更好,就展示得更好;做不到,也至少保证内容送达。
仓库里的相关文档已经明确提到一些平台侧能力,例如:
- 流式输出模式:
off/partial/block/progress - 线程绑定:不同平台可按线程继续对话
- 分块发送:长内容可以按块送出
但这些能力并不是每个平台、每种接法都一样。所以网关层通常要做这些判断:
- 当前平台支不支持流式输出
- 这段会话是不是应该回到原线程
- 长消息要不要分段
- 后续回复该沿哪条出站路径继续发
这里最后一点,在实现里可能有不同做法。更稳的说法是:系统通常需要记住最近一次有效的出站路径,避免后续回复跑偏。
2.5 第五步:优雅降级不只是样式问题
很多人一听“优雅降级”,会先想到富文本和纯文本。其实还不止这些。
网关层还要处理两类很现实的问题:
- 消息太长,一次发不下
- 这次发送失败了
所以一个成熟的 Gateway,通常不只是“把文本发出去”,还会先判断:
- 当前平台单条消息大概能发多长
- 代码块和列表要怎么切,才不难读
- 失败是暂时的,还是结构性的
- 值不值得重试
所以优雅降级的重点不是“好不好看”,而是:平台条件不理想时,内容也要尽量完整、稳定、可预期地送达。
2.6 第六步:为什么这层设计能持续扩展
到这里,整条链路就比较清楚了:
平台事件
→ 渠道适配
→ 标准化
→ 路由到 Agent
→ 归入正确会话
→ 进入消息循环
→ Agent 产出回复
→ 按平台能力发回去最后还差一个关键问题:为什么 OpenClaw 能不断接新平台,而不是每接一个平台就得重写系统? 答案就在 ChannelPlugin 这层插件边界上。
从设计角度看,插件机制最大的价值不是“代码组织更好看”,而是:系统终于可以把‘平台特有能力’和‘Agent 通用能力’拆开演化。
对一个新平台来说,最小要做的事情通常并不多:
- 告诉系统自己是谁;
- 能把平台事件读进来;
- 能把系统回复发回去。
这就是很典型的工程化思路:入口门槛低,上限又足够高。也是因为有了这层插件注册和能力声明,Gateway 才能真正做到:新增平台时,主要改插件,不改 Agent 核心。
也就是说,统一网关真正带来的不是“多平台炫技”,而是长期可维护的边界。
第三节 实际使用时怎么配
前两节讲的是“为什么存在”和“它怎么运转”,现在更实际的问题来了:如果你真的要开始用 OpenClaw 的 Gateway,该怎么配,才比较稳,比较不容易掉坑。
3.1 先跑通一条最小链路
人们最容易犯的错,是一上来就把很多平台一起接上,还顺手把 streaming、线程、富文本等增强能力全开。
更稳的做法是:先选一个最熟的平台,把最小链路跑通。
所谓最小链路,至少包括四步:
- 能收到消息
- 能路由到正确的 Agent
- 能落到正确的会话
- 能把回复发回正确的地方
如果你已经在前面的安装阶段配好了默认模型,下面这份配置片段就足够你先跑通“单渠道 + 默认 Agent + 每人独立私聊上下文”:
{
agents: {
defaults: {
workspace: "~/.openclaw/workspace"
}
},
channels: {
telegram: {
enabled: true,
botToken: "${TELEGRAM_BOT_TOKEN}",
dmPolicy: "pairing"
}
},
gateway: {
bind: "loopback",
auth: {
mode: "token",
token: "dev-token"
}
},
session: {
dmScope: "per-channel-peer"
}
}这个起手式的重点不是“功能全”,而是“变量少”:
- 先只接一个渠道,排掉多平台带来的干扰
- 先用默认 Agent,不急着一开始就拆多 Agent 路由
per-channel-peer会按“渠道 + 联系人”隔离私聊,最适合多人共用同一个机器人时避免串线;这也是官方安全审计对共享私聊场景给出的常见建议- 如果后面你要接第二个 Agent,再补
bindings去做显式路由就行
这里顺手提醒一句:示例里的 dev-token 只适合本地试跑。只要不是纯本地临时环境,就应该换成更严格的鉴权和凭证管理方式。
如果你想把这条最小链路真正跑通,建议紧接着按下面的顺序做一次最短验证:
openclaw config validate,先确认配置本身可解析;openclaw channels status --probe,确认渠道插件已经起来;- 给机器人发一条私信;如果你开了
dmPolicy: "pairing",先用openclaw pairing list telegram看待批准请求,再用openclaw pairing approve telegram <code>放行; openclaw agents bindings,确认当前渠道最终命中了你预期的 Agent。
只要这四步跑顺了,这一章的大部分核心机制其实就已经活起来了。这时候你再去接第二个平台,排错会轻松很多,因为你已经知道:Agent 核心本身是通的,问题大概率出在新增渠道的适配或配置上。
所以零基础同学最好的起手式不是“全开”,而是:单渠道先通,多渠道后加。
3.2 配之前先想清楚四件事
真正开始配 Gateway 时,建议先把这四个问题写下来:
这类消息应该交给谁处理?
这对应的是路由层。你要先明确:哪些渠道默认归哪个 Agent,哪些频道或群组要单独绑定,哪些账号只服务某一类任务。如果这一层没先想清楚,后面再怎么调显示效果都没意义。哪些平台 ID 其实是同一个人?
这对应的是identityLinks。这里最关键的不是“绑得越多越好”,而是:只在你真的确定是同一人的时候才绑定。 因为一旦绑错,系统就会把本不该共享的偏好或身份信息混到一起。哪些消息应该算同一段会话?
这对应的是sessionKey和dmScope相关思路。这里一定要记住一句话:同一个人,不等于同一个会话。 所以你要先判断:是希望不同渠道各自保留上下文,还是希望某些场景合并得更紧一些,私聊要拆得多细,群聊要不要按线程隔离。哪些增强能力要先开,哪些可以后开?
| 阶段 | 优先目标 |
|---|---|
| 第一层 | 先保证能收、能发、不串线 |
| 第二层 | 再去打开 streaming、threads、富文本或平台专属增强能力 |
因为“能用”和“好用”是两件事。先把“能用”做稳,后面才有资格讨论体验优化。
3.3 一定要分清“身份共享”和“上下文共享”
这是这一章最容易踩坑的地方。
更准确的说法是:
identityLinks主要回答“这是不是同一个人”dmScope等会话配置主要回答“这些消息算不算同一段会话”
这两者有关,但不是同一个开关。
你可以用下面这张表先想清楚目标:
| 目标 | 更稳的思路 |
|---|---|
| 只想跨平台认人 | 先做身份关联,再谨慎看会话是否合并 |
| 想让同一个人跨平台继续同一段私聊 | 身份关联和会话粒度要一起设计,而且要确认 dmScope 真的允许去掉 channel / account 维度 |
| 多人共用机器人但绝不串线 | 优先用 per-channel-peer 这类更细粒度隔离 |
| 群聊和线程要保持独立 | 继续按群或线程拆分会话 |
所以如果你未来要做跨平台协作,最重要的不是“有没有 identityLinks”,而是:你心里要先清楚,自己到底想共享哪一层。
可以先记两个最容易混淆、也最实用的目标:
| 目标 | 配置思路 | 结果 |
|---|---|---|
| 跨平台认人,但上下文仍分开 | 建 identityLinks,dmScope 保持 per-channel-peer 或更细 | 系统知道是同一个人,但 Telegram 和 Discord 仍各走各的私聊上下文 |
| 跨平台认人,并希望继续同一段私聊 | 建 identityLinks,并确认 dmScope 允许去掉 channel / account 维度 | 只有在会话粒度也一并放宽时,跨平台才可能真正共用一段上下文 |
3.4 多渠道优化,顺序最好是“先保底,再增强”
Gateway 很容易让人上头,因为一旦看到 streaming、按钮、线程回复、富文本卡片、typing 指示,你会很想全部打开。但从工程上讲,更推荐的顺序其实很朴素:
先保证内容一定送达
→ 再保证会话一定正确
→ 再保证展示效果更好
→ 最后才追求平台特有增强能力这背后的原因很简单:用户最先感知到的,不是“有没有流式输出”,而是:
- 回没回我;
- 回对地方没;
- 会不会串对话;
- 同一个人能不能认出来。
这些基础问题不稳时,越花哨的增强能力,越容易让你更难排障。
所以优雅降级不仅是系统内部设计原则,也应该成为你的配置原则:
先把所有平台都做成“至少稳稳能用”,再去追求“在某个平台上特别好用”。
3.5 遇到问题时,按固定顺序排错
Gateway 问题看起来很多,但通常可以按这个顺序收敛:
先看消息有没有真的进来。
先确认渠道插件是否启动,平台事件有没有成功送到本地,对应账号是否配置正确。如果消息压根没进系统,后面就不用看了。最常用的抓手是openclaw channels status和渠道日志。再看路由是不是命中了正确 Agent。
如果消息进来了,但去了错误的 Agent,通常要优先检查:bindings写没写对,默认账号和默认归属是不是配错,某条更具体的规则有没有把它截走。这里最直接的抓手是openclaw agents bindings。再看会话是不是算对了。
如果 Agent 对人是对的,但上下文明显串线或断裂,就要看:sessionKey的粒度是不是不合适,dmScope是否把私聊拆得太粗或太细,identityLinks是否把不该合的人绑在一起。先回到配置里核对session.dmScope,必要时再对照日志里的 session key。最后再看平台能力和出站适配。
比如,为什么没有 streaming,为什么按钮没显示,为什么长消息被切得不好看,为什么回复回到了错误渠道或错误位置。这时再去看平台能力声明、出站适配和最近一次回路信息,思路会清楚很多。
可以把这条顺序记成一句很短的话:
先看进没进来
→ 再看交没交对人
→ 再看会话算没算对
→ 最后再看显示和体验这样排错,通常比一上来就翻平台细节要快得多。
本章小结
这一章表面上讲的是 Gateway,实际上讲的是:OpenClaw 怎样把外部平台整理成 Agent 能稳定处理的统一入口。
最重要的理解可以收成下面几条:
统一网关不是“多平台附件”,而是系统边界。
它把平台差异挡在外层,避免污染 Agent 核心。网关处理的不只是消息格式,还包括路由和会话归属。
消息先交给正确的 Agent,再落到正确的会话。身份统一和会话统一不是一个问题。
identityLinks、dmScope和你的渠道策略需要一起看。优雅降级很关键。
平台能力强,就展示完整;平台能力弱,也要保证内容送达。适配层让系统真正能扩展。
新增平台主要改渠道适配,不必总去动 Agent 核心。
这就是 OpenClaw 的“感官系统”:把外面五花八门的平台世界,翻译成内部统一的协作现场。
下一章: 第七章 安全沙箱:自由与约束的平衡