OpenClaw 源码解析(七):Gateway 控制平面与 WebSocket RPC 机制
1. 本期目标
上一期我们分析了 openclaw agent --message "..." 的执行链路。表面上看,这条命令只是从命令行发送一条消息,但源码中实际经历了参数校验、Agent 选择、Session 选择、模型覆盖、Gateway 调用、本地 fallback 等多个环节。
这一期继续往下看:
为什么 OpenClaw 要把 Agent 请求交给 Gateway?
Gateway 在系统里到底扮演什么角色?
CLI、Web UI、移动端节点、Channel 为什么都要连接 Gateway?
Gateway 的 WebSocket RPC 请求是如何组织的?
Gateway 如何根据 method 找到对应处理函数?
OpenClaw 官方架构文档明确说明:Gateway 是一个长期运行的进程,负责维护消息渠道连接,并通过 WebSocket API 暴露请求、响应和服务端推送事件;CLI、Web UI、macOS app、自动化任务等控制平面客户端都通过 WebSocket 连接到 Gateway,默认地址是 127.0.0.1:18789。(OpenClaw)
所以本期的核心问题可以概括为一句话:
Gateway 是 OpenClaw 的控制平面,它把 CLI、Channel、Agent、Tools、Sessions、Nodes 和 Control UI 统一连接到一个长期运行的本地服务中。
2. 为什么要单独讲 Gateway?
前面几期已经反复提到 Gateway,但还没有真正拆开它。
在 OpenClaw 里,Gateway 不是一个普通 HTTP 后端,也不是单纯的模型转发服务。它更像整个个人 AI 助手系统的“中枢”。
官方架构文档中写到,Gateway 是一个单一、长期运行的进程,负责所有消息入口,例如 WhatsApp、Telegram、Slack、Discord、Signal、iMessage、WebChat 等;同时,控制平面客户端通过 WebSocket 接入 Gateway,节点设备也通过同一个 WebSocket 服务接入,只是会声明 role: node 并携带自己的能力和命令。(OpenClaw)
可以先用下面这张图理解:
CLI
Web UI
macOS App
iOS / Android Node
Telegram / Slack / Discord / WebChat
Automation / Cron
↓
Gateway
↓
Agent Runtime
Sessions
Tools
Skills
Channels
Nodes
Config
也就是说,Gateway 的作用不是“替模型回答问题”,而是:
统一接收请求;
统一验证身份和权限;
统一管理会话和状态;
统一调度 Agent 运行;
统一处理 Channel 连接;
统一推送事件给客户端。
这也是为什么上一期 openclaw agent 默认优先走 Gateway,而不是直接在 CLI 进程里调用模型。
3. Gateway 的运行模型
OpenClaw 的 Gateway 是一个 always-on 进程。
官方 Gateway runbook 中说明,它是一个长期运行的进程,承担路由、控制平面和 Channel 连接;同一个端口同时承载 WebSocket 控制 / RPC、OpenAI-compatible HTTP API、插件 HTTP 路由、Control UI 和 hooks,默认绑定模式是 loopback,并且默认需要认证。(OpenClaw)
这说明 Gateway 至少承担四类能力:
第一类:控制平面 RPC
例如 health、status、agent、send、config、sessions、tools 等。
第二类:消息渠道连接
例如 Telegram、Slack、Discord、WebChat 等。
第三类:前端和可视化
例如 Control UI、Canvas、A2UI 等。
第四类:兼容接口和插件接口
例如 /v1/models、/v1/chat/completions、/tools/invoke、插件 HTTP 路由等。
所以它不是一个“启动一次就结束”的命令,而是一个长期存在的服务进程。
可以把 Gateway 理解成:
OpenClaw CLI:
负责发起操作。
OpenClaw Gateway:
负责维护长期状态、连接和运行时环境。
OpenClaw Agent:
负责具体理解和执行任务。
4. Gateway 为什么使用 WebSocket?
OpenClaw Gateway 的协议文档说明,Gateway WS protocol 是 OpenClaw 的单一控制平面和节点传输协议。CLI、Web UI、macOS app、iOS / Android nodes、headless nodes 都通过 WebSocket 连接,并在握手时声明自己的角色和权限范围。(OpenClaw)
这里的关键点是:OpenClaw 需要的不只是一次请求一次响应。
它还需要:
Agent 执行过程中的流式事件;
工具调用过程中的实时状态;
会话变化通知;
节点状态变化;
Channel 连接状态;
Gateway 健康状态;
任务执行进度;
长时间运行任务的事件推送。
HTTP 请求当然也能做一部分工作,但 WebSocket 更适合长期连接和服务端主动推送。
官方架构文档中的单客户端连接生命周期也体现了这一点:客户端先 connect,Gateway 返回 hello-ok,随后 Gateway 可以推送 presence、tick 等事件;客户端发送 req:agent 后,Gateway 先返回 accepted ack,再通过 event:agent 推送流式执行事件,最后返回 final summary。(OpenClaw)
可以画成:
Client
↓ connect
Gateway
↓ hello-ok
Client
↓ req: agent
Gateway
↓ res: accepted
Gateway
↓ event: agent streaming
Gateway
↓ res: final summary
这就是 Gateway 不只是“收一个请求,回一个结果”的原因。
5. WebSocket 协议的基本格式
OpenClaw Gateway 协议使用 WebSocket 文本帧,内容是 JSON payload。协议文档中明确说明:第一个 frame 必须是 connect 请求;握手成功后,请求、响应和事件分别使用固定结构。(OpenClaw)
基本结构可以简化为:
{
"type": "req",
"id": "...",
"method": "agent",
"params": {}
}
响应结构是:
{
"type": "res",
"id": "...",
"ok": true,
"payload": {}
}
事件结构是:
{
"type": "event",
"event": "agent",
"payload": {}
}
官方架构文档也把 wire protocol 总结为:请求是 {type:"req", id, method, params},响应是 {type:"res", id, ok, payload|error},事件是 {type:"event", event, payload, seq?, stateVersion?}。(OpenClaw)
这三个结构非常重要。
后续看源码时,只要看到某个方法名,比如:
agent
chat.send
sessions.list
config.get
tools.invoke
channels.status
就可以理解为:
客户端发出一个 method;
Gateway 根据 method 找到对应 handler;
handler 执行后通过 res 或 event 返回结果。
6. Gateway 握手:为什么第一个请求必须是 connect?
Gateway 协议规定,第一个 frame 必须是 connect 请求。握手时,客户端会声明协议版本、客户端信息、role、scopes、caps、commands、auth、device 等信息;Gateway 返回 hello-ok,其中包含协议版本、server 信息、features、snapshot、auth 和 policy。(OpenClaw)
可以理解为:
普通请求:
我想调用某个功能。
connect 请求:
我是谁?
我是什么角色?
我有哪些权限?
我支持哪些能力?
我如何认证?
Gateway 当前支持哪些方法和事件?
握手成功后,Gateway 才能知道:
这是 CLI 还是节点?
这是 operator 还是 node?
它有没有 operator.read / operator.write 权限?
它能不能调用 agent?
它能不能调用 config.set?
它能不能作为 node 暴露 camera、canvas、screen 等命令?
所以 Gateway 的第一步不是“执行请求”,而是“建立可信连接上下文”。
7. role、scope 和 device pairing
OpenClaw Gateway 不是所有连接都一视同仁。
官方架构文档说明,所有 WebSocket 客户端都需要携带 device identity;新 device id 需要 pairing approval,直接本地 loopback 连接可以自动批准,以保证同主机体验流畅;非本地连接仍然需要显式批准;Gateway auth 对本地和远程连接都适用。(OpenClaw)
这里可以拆成三层:
role:
连接是什么角色,例如 operator 或 node。
scope:
这个角色具体有哪些权限,例如 operator.read、operator.write、operator.admin。
device identity / pairing:
这个连接来自哪个设备,这个设备是否被批准。
对于 CLI 来说,它通常是控制平面客户端。
对于移动端节点来说,它会声明 role: node,并声明自己具备哪些 caps 和 commands,例如 camera、canvas、screen、location、voice 等。协议文档给出的 node 示例中,node 会在 connect 参数中声明 caps 和 commands。(GitHub)
这说明 Gateway 的设计不是只靠一个 token,而是结合了:
连接认证;
角色识别;
权限范围;
设备身份;
设备配对;
本地 / 远程连接策略。
这对于一个可以控制本地工具、消息渠道和设备节点的个人 AI 助手系统非常重要。
8. Gateway 方法:method 是如何被分发的?
理解 Gateway 的关键,是理解 method 到 handler 的映射。
在 src/gateway/server-methods.ts 中,OpenClaw 定义了大量 Gateway RPC 方法,并通过 createLazyCoreHandlers 进行懒加载注册。例如源码中可以看到 health、status、channels.status、chat.history、chat.send、config.get、config.set、tools.invoke、sessions.list、sessions.send、agent、agents.list 等方法都会被注册到 coreGatewayHandlers 中。(GitHub)
这说明 Gateway 的方法体系大致是这样的:
health / status
↓
健康检查和状态查询
channels.*
↓
渠道状态、启动、停止、登出
chat.*
↓
聊天历史、发送、注入、终止
config.*
↓
配置读取、修改、schema 查询
sessions.*
↓
会话列表、会话创建、会话发送、会话重置、会话压缩等
tools.*
↓
工具目录、有效工具、工具调用
agent / agent.wait
↓
触发 Agent run 或等待 Agent 结果
agents.*
↓
Agent 列表、创建、更新、删除、文件读写
换句话说,Gateway 并没有把所有请求都写在一个巨大的 switch 里,而是通过 method registry 和 handler 模块组织起来。
9. lazy handler 的意义
源码中 server-methods.ts 使用了 lazyHandlerModule 和 createLazyCoreHandlers。从代码结构看,每一类 handler 都通过动态 import 加载,例如 agent 相关方法加载 ./server-methods/agent.js,sessions 相关方法加载 ./server-methods/sessions.js,config 相关方法加载 ./server-methods/config.js。(GitHub)
这是一种很常见的大型系统设计:
Gateway 启动时:
先建立方法注册表。
真正请求到来时:
再加载对应 handler 模块。
这样做有几个好处:
第一,降低启动时加载压力。
第二,让不同方法模块保持独立。
第三,避免所有 Gateway 功能挤在一个文件里。
第四,插件或扩展方法更容易接入。
第五,后续调试时可以按 method 找到对应源码文件。
比如,当我们看到:
method: "agent"
就可以沿着源码找到:
src/gateway/server-methods.ts
↓
loadAgentHandlers
↓
src/gateway/server-methods/agent.ts
当看到:
method: "sessions.send"
就可以找:
src/gateway/server-methods.ts
↓
loadSessionsHandlers
↓
src/gateway/server-methods/sessions.ts
这样就形成了非常清晰的源码阅读路径。
10. handleGatewayRequest 的处理流程
Gateway 收到一个请求后,并不是直接执行 handler。
server-methods.ts 中的 handleGatewayRequest 会先构建或获取 method registry,然后做权限校验、启动期不可用判断、控制平面写操作限流、handler 查找,最后才调用具体 handler;handler 调用还会包在 plugin runtime gateway request scope 里,以便插件运行时和子 Agent 等场景可以在正确的 Gateway 请求上下文中执行。(GitHub)
可以简化成下面这条链路:
收到 req
↓
读取 method
↓
构建 method registry
↓
authorizeGatewayMethod 权限检查
↓
判断 Gateway startup 阶段该 method 是否可用
↓
如果是控制平面写操作,检查 rate limit
↓
根据 method 找 handler
↓
找不到则返回 unknown method
↓
找到则执行 handler
↓
返回 res 或推送 event
这说明 Gateway 请求处理至少有四层保护:
第一层:连接握手和认证。
第二层:role / scope 方法权限检查。
第三层:启动状态和方法可用性检查。
第四层:控制平面写操作限流。
所以 Gateway 不是简单“method 反射调用”,而是带有控制面安全边界的 RPC 分发系统。
11. agent RPC 在 Gateway 中的位置
上一期我们讲过,openclaw agent 默认会通过 Gateway 发送一次 agent 请求。
在 Gateway 方法注册表里,agent、agent.identity.get、agent.wait 会被挂载到 agent handler 模块。server-methods.ts 中可以看到这几个 method 由 loadAgentHandlers 负责加载。(GitHub)
而 src/gateway/server-methods/agent.ts 中可以看到大量与 Agent run 相关的逻辑,包括 session key 解析、agent workspace 解析、sandbox 配置、模型支持能力、delivery plan、chat abort controller、任务状态跟踪、dedupe key、dispatchAgentRunFromGateway 等。(GitHub)
所以 agent RPC 不是简单调用一次模型,而是会处理:
这次请求属于哪个 agent;
这次请求属于哪个 session;
是否需要模型覆盖;
是否需要 reset session;
是否需要处理附件;
是否需要 delivery;
是否需要 task tracking;
是否需要去重;
是否需要处理 abort;
是否需要更新 session 状态;
是否需要广播 sessions.changed;
是否需要通过 Channel 投递回复。
这也解释了为什么 OpenClaw 要通过 Gateway 来承载 Agent run:因为 Agent 的运行涉及的不只是模型本身,还涉及系统状态、会话、投递、任务、权限、工具、渠道和事件。
12. accepted、streaming 和 final
OpenClaw 的 Agent 请求不是只有一个最终响应。
官方架构文档中的连接生命周期显示,客户端发送 req:agent 后,Gateway 会先返回一个 accepted ack,其中包含 runId 和状态;随后通过 event:agent 推送流式执行事件,最后返回 final,其中包含 runId、status 和 summary。(OpenClaw)
这可以理解为三阶段:
第一阶段:accepted
Gateway 已经接受请求,并分配 runId。
第二阶段:streaming events
Agent 运行中,不断产生增量事件、状态事件或工具事件。
第三阶段:final
Agent run 结束,返回最终状态和摘要。
这种设计特别适合长任务。
比如用户让 Agent 做一个多步骤任务:
读取文件;
调用工具;
分析日志;
生成报告;
发送到某个 Channel。
如果只等最终响应,用户体验会很差。通过 event stream,客户端可以实时展示:
Agent 开始运行;
正在调用工具;
工具返回结果;
正在生成回答;
任务已完成或失败。
13. Gateway 和配置热重载
Gateway 还有一个非常重要的能力:配置热重载。
官方 runbook 中说明,Gateway 会监听 active config file path;默认 reload mode 是 gateway.reload.mode="hybrid"。第一次成功加载后,运行中的进程会服务 active in-memory config snapshot;后续成功 reload 会原子替换这个 snapshot。(OpenClaw)
这说明 OpenClaw 的配置不是“启动时读一次就结束”。
它的模型更接近:
openclaw.json
↓
Gateway 读取配置
↓
形成内存配置快照
↓
运行时使用该快照
↓
配置文件变更
↓
校验成功后原子替换快照
这个设计很适合长期运行的个人助手系统。
因为用户可能随时调整:
模型 provider;
默认 agent;
Channel allowlist;
dmPolicy;
sandbox 配置;
tools 配置;
cron 任务;
UI / media / networking 配置。
如果每次改配置都要手动重启 Gateway,使用体验会比较差。
14. Gateway 和 Control UI 的关系
第二期和第三期提到过 Control UI。
官方配置文档说明,用户可以打开 127.0.0.1:18789 使用 Config tab;Control UI 会根据 live config schema 渲染表单,并提供 Raw JSON editor;Gateway 还暴露 config.schema.lookup 来获取某个路径下的 schema 节点和子项摘要。(OpenClaw)
这说明 Control UI 不是独立系统,而是 Gateway 的一个可视化客户端。
可以理解为:
Control UI
↓ WebSocket / Gateway API
Gateway
↓
config.get / config.set / config.schema.lookup
↓
openclaw.json / in-memory config snapshot
所以后续分析 UI 时,重点不是“前端页面怎么画”,而是:
前端调用了哪些 Gateway method;
Gateway 返回了哪些 schema 和状态;
配置修改如何通过 Gateway 写回;
Gateway 如何热重载这些配置。
15. Gateway 和 Channel 的关系
OpenClaw 的 Channel,例如 Telegram、Slack、Discord、WebChat 等,也由 Gateway 统一管理。
官方架构文档中说,Gateway 维护 provider connections,并发出 agent、chat、presence、health、heartbeat、cron 等事件。(OpenClaw)
这意味着 Channel 并不是各自独立调用模型。
更合理的理解是:
外部平台消息
↓
Channel adapter
↓
Gateway
↓
Session / Agent / Tools
↓
Gateway
↓
Channel adapter
↓
外部平台收到回复
所以 Gateway 是消息入口与 Agent Runtime 之间的中间层。
这也是 OpenClaw 能够支持多渠道接入的原因:不同 Channel 只负责把平台消息转换成内部消息事件,核心调度逻辑仍然回到 Gateway。
16. Gateway 和 Nodes 的关系
Nodes 是 OpenClaw 的另一类重要客户端。
官方架构文档说明,macOS、iOS、Android、headless nodes 也连接到同一个 WebSocket 服务,但会声明 role: node,并带有明确的 caps 和 commands;例如 canvas.*、camera.*、screen.record、location.get 等。(OpenClaw)
这说明 Gateway 还承担“设备能力路由”的角色。
可以理解为:
Agent 想拍照 / 读取位置 / 操作 Canvas
↓
Gateway 判断哪个 node 有能力
↓
向 node 发送命令
↓
node 执行后返回结果
↓
Gateway 把结果交给 Agent
这也是 OpenClaw 和普通 Chatbot 的差别之一:它不仅能在文本里回答,还能通过节点设备扩展输入输出能力。
17. 从 Gateway 看 OpenClaw 的系统边界
通过这一期可以看到,OpenClaw 的系统边界非常清楚:
CLI:
发起命令,适合人类或脚本操作。
Gateway:
长期运行,维护连接、状态、RPC、事件、安全边界。
Agent:
负责理解任务、调用模型、组织工具和技能。
Channel:
负责连接外部消息平台。
Node:
负责暴露设备能力。
Control UI:
负责可视化管理 Gateway 和 Agent 状态。
最核心的是 Gateway。
它把这些模块连接起来:
CLI / UI / Node / Channel
↓
Gateway
↓
Agent / Session / Tool / Config / Delivery
所以读 OpenClaw 源码时,Gateway 这一层必须先看懂。
18. 本期源码阅读建议
这一期建议重点看下面几个文件:
src/gateway/server-methods.ts
↓
看 Gateway method 如何注册、懒加载、鉴权和分发。
src/gateway/server-methods/agent.ts
↓
看 agent RPC 如何转化为一次 Agent run。
src/gateway/server/ws-connection.ts
↓
看 WebSocket 连接如何建立和管理。
src/gateway/server/ws-connection/message-handler.ts
↓
看 Gateway 如何处理 WebSocket frame、connect、request 和 event。
docs/gateway/protocol.md
↓
对照理解 Gateway WebSocket 协议。
docs/concepts/architecture.md
↓
从整体架构角度理解 Gateway、Client、Node、WebChat 的关系。
阅读时可以带着几个问题:
1. connect 请求什么时候完成认证?
2. method 是如何映射到 handler 的?
3. agent 请求为什么需要 idempotencyKey?
4. Gateway 什么时候返回 accepted,什么时候推送 event?
5. 哪些请求属于控制平面写操作?
6. role 和 scope 如何限制 method 调用?
7. sessions、tools、config、channels 方法分别对应哪些 handler 文件?
19. 我的理解
我认为 Gateway 是 OpenClaw 最关键的架构层。
如果没有 Gateway,OpenClaw 很容易退化成一个 CLI 包装的大模型调用工具:
openclaw agent
↓
调用模型
↓
输出文本
但有了 Gateway 之后,OpenClaw 才真正变成一个个人 AI 助手系统:
长期运行;
多渠道接入;
多客户端连接;
多会话管理;
工具调用;
设备节点;
事件推送;
配置热重载;
权限控制;
任务追踪。
所以理解 OpenClaw,不能只盯着“模型怎么调用”,还要看“Gateway 如何把模型调用放进一个长期运行的系统里”。
20. 本期重点理解
这一期可以总结为五点:
第一,Gateway 是 OpenClaw 的控制平面,是一个长期运行的本地服务进程。
第二,CLI、Web UI、macOS app、iOS / Android nodes、headless nodes 都通过 WebSocket 连接 Gateway。
第三,Gateway 协议使用 req / res / event 三类 JSON frame,第一个请求必须是 connect。
第四,Gateway 通过 method registry 和 lazy handler 把 agent、sessions、config、tools、channels 等方法分发到不同源码模块。
第五,agent RPC 不是简单模型调用,而是会涉及 session、delivery、dedupe、task tracking、abort、workspace、sandbox 和事件推送等系统级逻辑。
一句话概括:
Gateway 把 OpenClaw 从一个命令行 AI 工具提升为一个长期运行、多客户端、多会话、多渠道、可扩展的个人 AI 助手系统。
21. 本期小结
本期主要分析了 OpenClaw 的 Gateway 控制平面。Gateway 是一个长期运行的本地服务,默认通过 127.0.0.1:18789 对 CLI、Web UI、macOS app、iOS / Android nodes 和 headless nodes 提供 WebSocket 控制平面。Gateway 协议使用 JSON 文本帧,包含 req、res 和 event 三类消息;连接建立时必须先发送 connect 请求,以声明客户端身份、角色、权限、认证和设备信息。源码中,Gateway 通过 server-methods.ts 注册大量 RPC method,并使用 lazy handler 将不同方法分发到 agent、sessions、config、tools、channels 等模块。对于 agent 请求,Gateway 会进一步处理 session、workspace、delivery、dedupe、task tracking 和事件推送,因此它承载的是完整 Agent run,而不是一次简单模型补全。
这一期可以用一句话总结:
OpenClaw 的 Gateway 是整个系统的运行中枢:所有客户端先连接 Gateway,所有核心能力通过 Gateway method 进入系统,所有长期状态和实时事件也由 Gateway 统一维护。
下一期可以继续分析:
OpenClaw 源码解析(八):Session 会话模型与 sessionKey 设计
下一期重点看 sessionKey、sessionId、main session、channel session、subagent session、sessions store、transcript 文件和 sessions.* Gateway 方法,理解 OpenClaw 如何把不同用户、不同渠道、不同 Agent run 组织成可追踪的长期会话。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)