11.1 Gateway 的角色与设计目标
生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~160,000 tokens,输出 ~12,000 tokens(本章合计)
从本章开始,我们正式进入 OpenClaw 最核心的子系统——Gateway 控制平面的源码分析。Gateway 是整个 OpenClaw 系统的心脏,搞懂它的设计思路和实现细节,才算真正理解了这个项目。
11.1.1 "控制平面"(Control Plane)的含义
衍生解释:控制平面(Control Plane)是一个源自网络工程和分布式系统的概念。在计算机网络中,控制平面负责决策——决定数据包应该被转发到哪里;而数据平面(Data Plane)负责执行——实际转发数据包。类似地,在微服务架构中,控制平面(如 Kubernetes API Server)负责管理和协调,而各个工作节点负责实际执行任务。
在 OpenClaw 中,Gateway 就扮演控制平面的角色。它本身不执行 AI 推理(那是 Pi Agent 运行时的工作),也不直接处理消息格式转换(那是通道适配器的工作)。它做的是协调:接收来自各方的请求和事件,做出路由决策,调度执行,分发结果。
Gateway 的核心职责可以分为六大领域:
1. 连接管理
Gateway 维护两种不同性质的连接,理解它们的区别至关重要:
通道(Channels)——嵌入式消息适配器
通道不是通过网络连接到 Gateway 的外部服务,而是作为插件/适配器嵌入在 Gateway 进程内部。Gateway 启动时会调用 startChannels()(src/gateway/server-channels.ts)来初始化所有已配置的通道。通道与 Gateway 之间的通信是进程内函数调用。
每个通道负责与其对应的外部消息平台通信:
Telegram:使用 grammY 库通过 HTTP 长轮询(或 Webhook)与 Telegram 服务器通信
WhatsApp:使用 Baileys 库通过 WebSocket 与 WhatsApp 服务器通信
Discord:使用 discord.js 库通过 WebSocket 与 Discord 网关通信
Slack:使用 Bolt 库通过 WebSocket(Socket Mode)或 HTTP 事件与 Slack 通信
注意:这里的"通信"是指通道与外部平台服务器之间的网络通信。通道与 Gateway 之间没有网络通信——它们在同一个 Node.js 进程中,通过函数调用传递消息。
客户端(Clients)——WebSocket 远程连接
客户端是通过 WebSocket 协议连接到 Gateway 的外部程序,监听端口为 18789。客户端分为两种角色:
操作者(operator):macOS 菜单栏应用、CLI 工具、Web 控制台。用于监控 Agent 运行状态、审批命令执行、管理会话和配置。
节点(node):macOS/iOS/Android 设备节点。用于向 Agent 暴露设备能力——摄像头、屏幕录制、位置信息、Canvas 画布等。
每个客户端连接都有身份认证、权限级别和事件订阅状态。Gateway 跟踪所有活跃连接,并在状态变更时向相关方推送事件。
关键区分:在简单的消息问答场景中(如用户在 Telegram 上发消息、Agent 回复),客户端完全不参与。消息从通道进入 Gateway → 路由到 Agent → Agent 生成回复 → 回复通过通道发回用户,整个过程在 Gateway 进程内完成。客户端只在以下场景中参与:
Agent 需要执行危险命令,需要操作者审批(exec approval)
Agent 需要调用设备能力(如拍照、录屏),需要节点配合
操作者主动查看 Agent 运行状态或管理会话
2. 消息路由
当一条消息从任何通道进来时,Gateway 需要决定:
这条消息应该交给哪个 Agent 处理?(多 Agent 路由)
使用哪个会话?(会话键生成)
该会话当前是否有运行中的 Agent?(队列管理)
回复应该发回哪个通道?(出站路由)
3. 会话管理
会话是 OpenClaw 中对话上下文的容器。Gateway 管理会话的完整生命周期:创建、读写、重置、过期、压缩、删除。
4. Agent 调度
当需要 AI 处理时,Gateway 启动 Agent 运行,管理队列、超时和取消。Agent 运行的结果通过事件流推送给所有感兴趣的客户端。
5. 工具基础设施
某些工具(如 Cron 调度、浏览器控制、节点调用)需要 Gateway 层面的支持。Gateway 提供这些工具所需的基础设施。
6. 配置与运维
Gateway 负责加载、校验、热重载配置,提供健康检查端点,管理守护进程生命周期。
11.1.2 单 Gateway 实例约束
OpenClaw 有一个重要的设计约束:每台主机只运行一个 Gateway 实例。这在 docs/concepts/architecture.md 中被明确为不变量(Invariant):
"Exactly one Gateway controls a single Baileys session per host."
这个约束来自 WhatsApp 的限制——Baileys(WhatsApp Web 协议的非官方实现)只允许一个活跃的 Web 会话。如果两个进程同时打开同一个 WhatsApp 账号的 Web 会话,前一个会被踢下线。
OpenClaw 通过文件锁和端口独占来强制这一约束。如果你尝试在同一台机器上启动第二个 Gateway,它会检测到端口已被占用并报错。相关实现在 src/infra/ports.ts 中:
11.1.3 Gateway 的职责边界
搞清楚 Gateway 不做什么同样重要:
WebSocket/HTTP 服务器管理
AI 模型推理(交给 Pi Agent)
消息路由与会话键解析
通道协议实现(交给通道适配器)
Agent 运行调度与队列管理
具体工具执行(交给工具系统)
事件广播与客户端通知
原生应用 UI 渲染(交给客户端)
配置加载与热重载
模型选择与 Auth Profile 管理(交给 Agent)
安全认证与设备配对
Markdown 渲染(交给通道出站处理)
这种清晰的职责边界使得 Gateway 的代码虽然文件数量多(128 个文件),但每个文件的职责都比较单一。以 src/gateway/ 下的文件命名为例:
每个文件名都直观地反映了它的职责。这种命名约定贯穿了整个 OpenClaw 代码库。
Last updated