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 参数中声明 capscommands。(GitHub)

这说明 Gateway 的设计不是只靠一个 token,而是结合了:

连接认证;
角色识别;
权限范围;
设备身份;
设备配对;
本地 / 远程连接策略。

这对于一个可以控制本地工具、消息渠道和设备节点的个人 AI 助手系统非常重要。


8. Gateway 方法:method 是如何被分发的?

理解 Gateway 的关键,是理解 method 到 handler 的映射。

src/gateway/server-methods.ts 中,OpenClaw 定义了大量 Gateway RPC 方法,并通过 createLazyCoreHandlers 进行懒加载注册。例如源码中可以看到 healthstatuschannels.statuschat.historychat.sendconfig.getconfig.settools.invokesessions.listsessions.sendagentagents.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 使用了 lazyHandlerModulecreateLazyCoreHandlers。从代码结构看,每一类 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 方法注册表里,agentagent.identity.getagent.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.recordlocation.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 文本帧,包含 reqresevent 三类消息;连接建立时必须先发送 connect 请求,以声明客户端身份、角色、权限、认证和设备信息。源码中,Gateway 通过 server-methods.ts 注册大量 RPC method,并使用 lazy handler 将不同方法分发到 agentsessionsconfigtoolschannels 等模块。对于 agent 请求,Gateway 会进一步处理 session、workspace、delivery、dedupe、task tracking 和事件推送,因此它承载的是完整 Agent run,而不是一次简单模型补全。

这一期可以用一句话总结:

OpenClaw 的 Gateway 是整个系统的运行中枢:所有客户端先连接 Gateway,所有核心能力通过 Gateway method 进入系统,所有长期状态和实时事件也由 Gateway 统一维护。

下一期可以继续分析:

OpenClaw 源码解析(八):Session 会话模型与 sessionKey 设计

下一期重点看 sessionKeysessionId、main session、channel session、subagent session、sessions store、transcript 文件和 sessions.* Gateway 方法,理解 OpenClaw 如何把不同用户、不同渠道、不同 Agent run 组织成可追踪的长期会话。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐