第 1 章:引言

1.1 OpenClaw 项目概述

在人工智能快速发展的今天,如何高效地部署、管理和访问分布在不同设备上的 AI 代理已成为一个关键技术挑战。OpenClaw 作为一款开源的远程访问 AI 代理平台,通过创新的架构设计实现了对多设备、多代理的统一管控。无论是运行在家庭服务器上的自动化脚本,还是部署在云端的专业 AI 助手,OpenClaw 都能提供稳定、安全的远程连接能力。

OpenClaw 的核心优势在于其轻量级的部署方式和强大的跨平台兼容性。它不依赖复杂的 VPN 配置,而是利用现有的网络基础设施实现设备发现和连接建立。这种设计使得用户可以轻松地将任意位置的 AI 代理纳入统一的管理体系,极大地降低了运维成本和复杂度。

1.2 Gateway:单一控制平面的设计理念

在 OpenClaw 的架构设计中,Gateway 扮演着至关重要的角色——它作为整个系统的唯一控制平面,负责处理所有的连接管理、协议验证和事件分发工作。这种单一控制平面(Single Control Plane)的设计理念带来了显著的优势:

首先,统一入口简化了客户端的实现复杂度。无论设备位于何种网络环境,客户端只需要与 Gateway 建立连接,无需关心目标设备的具体网络拓扑。其次,集中化的认证和授权机制确保了系统的安全性,所有访问请求都必须通过 Gateway 的验证才能到达目标代理。最后,事件分发的集中处理使得实时状态同步和跨设备协作变得更加可靠。

Gateway 基于 WebSocket 协议构建,选择 WebSocket 是因为它支持全双工通信,能够在单条连接上同时发送请求和接收事件,非常适合需要长时间保持连接状态的 AI 代理场景。

1.3 文章结构说明

本文将深入解析 OpenClaw Gateway 的架构设计与实现细节。第二章介绍 Gateway 的核心职责和整体架构;第三章详细讲解 WebSocket 协议帧结构及其验证机制;第四章阐述连接生命周期与握手协议;第五章探讨事件分发机制的内部原理;第六章深入分析 JSON Schema 验证、心跳断线重连等关键技术要点。

第七章中,我们将通过完整的客户端代码示例,展示如何实际使用 Gateway 的连接和消息发送功能。第八章总结架构设计亮点,并展望未来的优化方向。

通过本文,读者不仅能够理解 OpenClaw Gateway 的设计理念,还能掌握将其应用于实际项目的能力。让我们正式开始这段技术探索之旅。

第 2 章:Gateway 核心架构

2.1 Gateway 核心职责

OpenClaw Gateway 作为系统的核心通信枢纽,承担着多重关键职责,确保分布式客户端系统的高效协作与安全通信。

2.1.1 渠道连接管理

Gateway 负责管理多种通信渠道的连接生命周期。通过 validateConnectParams 函数验证客户端连接参数,确保连接的合法性和安全性。连接参数包括:

  • 客户端身份信息:显示名称、设备族、模型标识符、实例 ID、版本号
  • 客户端类型:支持 cli、test、openclaw-control-ui、gateway-client、openclaw-macos、openclaw-ios、openclaw-android、node-host、fingerprint、openclaw-probe 等多种类型
  • 客户端模式:支持 node、cli、ui、test、backend、probe 等模式
  • 平台信息:操作系统平台标识
  • 协议版本协商:支持最小/最大协议版本范围
  • 权限范围声明:明确客户端拥有的操作权限
  • 认证凭据:支持令牌、密码、设备令牌等多种认证方式
  • 设备信息:设备 ID、公钥、签名、签名时间、随机数等硬件认证信息
2.1.2 WebSocket 服务

Gateway 基于 WebSocket 协议提供全双工通信服务。核心处理流程包括:

  • 握手验证:首个请求必须是 connect 方法,验证连接参数的合法性
  • 帧类型识别:区分 RequestFrame、ResponseFrame、EventFrame 三种帧类型
  • 会话管理:为每个连接分配唯一标识,维护连接状态、认证信息、订阅关系
  • 消息路由:根据请求的方法和参数,路由到相应的业务处理器
  • 健康监控:定期刷新健康状态,支持主动探测
  • 日志记录:详细记录连接、消息收发、错误等关键事件
2.1.3 协议验证与事件分发

Gateway 实现了严格的协议验证机制,使用 Ajv JSON Schema 验证器:

  • 请求帧验证:使用 validateRequestFrame 函数验证请求结构
  • 响应帧验证:通过 validateResponseFrame 确保响应格式正确
  • 事件帧验证:使用 validateEventFrame 处理各类事件消息
  • 业务参数验证85+ 个专门的验证函数,覆盖所有 API 方法的参数验证

2.2 整体架构描述

Gateway 采用分层架构设计,各层职责明确:

层级 职责
接入层 WebSocket 连接建立、认证授权、协议握手、防护机制
协议层 Frame 编解码、JSON Schema 验证、错误处理
业务层 业务方法调用、会话管理、Agent 操作、定时任务
事件层 事件订阅、过滤、分发,维护事件序列号和状态版本
传输层 多种传输方式、消息可靠投递、加密和压缩

2.3 核心数据结构

数据结构 说明
RequestFrame {type: "req", id, method, params?}
ResponseFrame {type: "res", id, ok, payload?, error?}
EventFrame {type: "event", event, payload?, seq?, stateVersion?}
StateVersion {health: number, presence: number}
ErrorShape {code, message, retryable?, retryAfterMs?, details?}

2.4 架构优势

  • 可扩展性:插件化设计、水平扩展、协议演进、模块化架构
  • 可靠性:心跳机制、断线重连、消息确认、熔断器
  • 安全性:多层认证、数据加密、审计日志、攻击防护

第 3 章:WebSocket 协议帧结构

OpenClaw Gateway 采用 JSON-over-WebSocket 协议进行通信。协议设计遵循请求 - 响应模式,并支持服务器主动推送事件。

3.1 帧类型定义

以下为简化示意,完整 TypeBox 定义见源码 protocol-schemas.d.ts

Request Frame(请求帧)【简化示意】
RequestFrame: {
  type: "req";
  id: string;
  method: string;
  params?: unknown;
}
Response Frame(响应帧)【简化示意】
ResponseFrame: {
  type: "res";
  id: string;
  ok: boolean;
  payload?: unknown;
  error?: { code: string; message: string; retryable?: boolean };
}
Event Frame(事件帧)【简化示意】
EventFrame: {
  type: "event";
  event: string;
  payload?: unknown;
  seq?: number;
  stateVersion?: { presence: number; health: number };
}

3.2 JSON Schema 验证流程

  1. 接收原始 JSON - 从 WebSocket 接收文本数据
  2. 解析 JSON - 验证 JSON 格式有效性
  3. 识别帧类型 - 根据 type 字段判断帧类型
  4. 选择验证器 - 选择对应的 Schema 验证器
  5. 执行验证 - 运行 JSON Schema 验证
  6. 处理错误 - 若验证失败,返回详细错误信息

3.3 协议版本管理

当前协议版本为 v3(源码:PROTOCOL_VERSION: 3)。

版本协商机制:

  • 客户端声明版本范围
  • 服务器协商版本(HelloOk 响应)
  • 版本不匹配拒绝连接

第 4 章:连接生命周期与握手协议

4.1 连接建立流程

客户端                              服务器
   |                                   |
   |-------- connect 请求 ------------->|
   |        (包含 auth 认证信息)         |
   |                                   | → 验证认证信息
   |                                   | → 协商协议版本
   |                                   | → 生成连接 ID
   |<------- hello-ok 响应 -------------|
   |                                   |
   |        连接已建立,可发送请求        |

源码验证:首个请求必须是 connect 方法,否则返回错误:"invalid handshake: first request must be connect"

4.2 ConnectParams 结构

字段 类型 说明
minProtocol number 最小协议版本
maxProtocol number 最大协议版本
client.id enum 客户端类型
client.version string 客户端版本
client.platform string 平台标识
auth.token string? Gateway Token
auth.password string? 密码认证
auth.deviceToken string? 设备令牌
scopes string[]? 权限范围

4.3 HelloOk 响应结构

字段 类型 说明
type "hello-ok" 响应类型标识
protocol number 协商后的协议版本
server.connId string 连接 ID
features.methods string[] 支持的方法列表
features.events string[] 支持的事件列表
snapshot Snapshot 状态快照
policy.tickIntervalMs number 心跳间隔

4.4 认证机制

认证类型 使用场景 参数位置
Token 服务端配置的令牌 auth.token
Password 密码认证 auth.password
Device Token 设备签名认证 auth.deviceToken

第 5 章:事件分发机制

5.1 事件类型体系

事件类型 说明
Agent 事件 运行状态变更、身份信息、摘要数据、文件条目
Chat 事件 聊天消息、历史记录、注入消息、发送参数
Presence 事件 在线状态条目,包含设备信息、时间戳
Health 事件 关闭事件、心跳事件、诊断集成
Tick 事件 心跳响应,包含时间戳 {ts: number}
Cron 事件 定时任务定义、运行日志、任务监控

5.2 事件序列号与状态版本

  • seq:单调递增序列号,用于事件排序和重复检测
  • StateVersion{health: number, presence: number} 全局状态版本控制

5.3 事件订阅与过滤机制

订阅模型:频道订阅、通配符支持、动态订阅、权限控制

过滤策略:类型过滤、来源过滤、内容过滤、时间过滤、频率限制

分发优化:批量分发、优先级队列、背压控制、压缩传输

第 6 章:技术要点深度解析

6.1 JSON Schema 验证流程

// 验证逻辑伪代码
if (!validateRequestFrame(parsed)) {
  send({
    type: "res",
    id: parsed?.id ?? "invalid",
    ok: false,
    error: { code: "INVALID_REQUEST", message: "invalid request frame" }
  });
  return;
}

6.2 心跳机制与断线重连

  • TickEvent:服务器定期发送,包含时间戳
  • 断线检测:WebSocket close 事件、心跳超时
  • 重连策略:指数退避(1s→2s→4s→8s...),上限 60 秒

6.3 请求去重与幂等性处理

多个 API 支持 idempotencyKey 字段实现幂等性:

  • send 方法
  • chat.send 方法
  • node.invoke 方法

6.4 错误处理与重试机制

错误码体系(源码验证):

错误码 说明
NOT_LINKED 渠道未链接
NOT_PAIRED 设备未配对
AGENT_TIMEOUT Agent 超时
INVALID_REQUEST 无效请求
UNAVAILABLE 服务不可用

6.5 源码引用说明

协议定义路径(相对于 node_modules/openclaw/dist/):

  • plugin-sdk/gateway/protocol/index.d.ts
  • plugin-sdk/gateway/protocol/schema/types.d.ts
  • plugin-sdk/gateway/protocol/schema/protocol-schemas.d.ts
  • plugin-sdk/gateway/protocol/schema/error-codes.d.ts

网关实现gateway-cli-*.js(编译哈希文件名)

第 7 章:实战案例

7.1 客户端连接示例代码

// client-example.js - OpenClaw Gateway 客户端示例
const WebSocket = require('ws');

class OpenClawClient {
  constructor(gatewayUrl, authToken) {
    this.gatewayUrl = gatewayUrl;
    this.authToken = authToken;
    this.ws = null;
    this.requestId = 0;
    this.pendingRequests = new Map();
    this.connected = false;
  }

  async connect() {
    return new Promise((resolve, reject) => {
      this.ws = new WebSocket(this.gatewayUrl);
      
      const timeout = setTimeout(() => {
        if (!this.connected) {
          this.ws.close();
          reject(new Error('连接超时'));
        }
      }, 10000);

      this.ws.on('open', () => {
        console.log('✓ WebSocket 连接已建立');
        this.sendConnect()
          .then(helloOk => {
            clearTimeout(timeout);
            this.connected = true;
            resolve(helloOk);
          })
          .catch(err => {
            clearTimeout(timeout);
            reject(err);
          });
      });

      this.ws.on('message', (data) => this.handleMessage(data));
      this.ws.on('error', (err) => { clearTimeout(timeout); reject(err); });
      this.ws.on('close', () => { this.connected = false; });
    });
  }

  async sendConnect() {
    return this.sendRequest('connect', {
      minProtocol: 3,
      maxProtocol: 3,
      client: { id: 'cli', version: '1.0.0', platform: 'node' },
      auth: { token: this.authToken }
    });
  }

  sendRequest(method, params, timeoutMs = 30000) {
    return new Promise((resolve, reject) => {
      const id = `req-${++this.requestId}`;
      this.pendingRequests.set(id, { resolve, reject });
      this.ws.send(JSON.stringify({ id, type: 'req', method, params }));
      
      setTimeout(() => {
        if (this.pendingRequests.has(id)) {
          this.pendingRequests.delete(id);
          reject(new Error(`请求超时:${method}`));
        }
      }, timeoutMs);
    });
  }

  handleMessage(data) {
    const frame = JSON.parse(data.toString());
    if (frame.type === 'res') {
      const pending = this.pendingRequests.get(frame.id);
      if (pending) {
        this.pendingRequests.delete(frame.id);
        frame.ok ? pending.resolve(frame.payload || frame) 
                 : pending.reject(new Error(frame.error?.message));
      }
    } else if (frame.type === 'event') {
      console.log(`[事件] ${frame.event}`);
    }
  }

  async subscribe(events) {
    return this.sendRequest('subscribe', { events });
  }

  close() { if (this.ws) this.ws.close(); }
}

// 使用示例
async function main() {
  const client = new OpenClawClient('ws://localhost:8080/ws', 'your-token');
  try {
    const helloOk = await client.connect();
    console.log('✓ 认证成功,connId:', helloOk.server.connId);
    await client.subscribe(['agent', 'chat', 'presence']);
    console.log('✓ 客户端就绪');
  } catch (error) {
    console.error('✗ 错误:', error.message);
  } finally {
    client.close();
  }
}

main();

7.2 消息发送完整流程

  1. 建立 WebSocket 连接
  2. 发送 connect 请求(含认证信息)
  3. 接收 hello-ok 响应
  4. 订阅事件类型
  5. 发送业务请求
  6. 接收响应或事件

7.3 事件监听

事件类型 说明
agent Agent 运行状态变更
chat 聊天消息
presence 在线状态更新
tick 心跳响应

第 8 章:总结与展望

8.1 架构设计亮点总结

  • 统一控制平面架构:Gateway 作为唯一入口,简化客户端实现
  • WebSocket 实时通信:全双工通信,支持长时间连接
  • JSON Schema 验证:85+ 验证函数,保证数据合法性
  • 完善的连接管理:connect 握手、tick 心跳、断线重连
  • 事件驱动架构:多种事件类型,灵活的分发体系

8.2 性能优化方向

  • 连接池与多 Gateway 部署
  • 消息压缩与批量处理
  • 缓存层优化

8.3 未来演进路线

  • 协议增强(WebTransport)
  • 安全性增强(RBAC)
  • 生态扩展(多语言 SDK)
  • 可观测性提升

OpenClaw Gateway 的设计理念是"简单、稳定、可扩展",将成为连接 AI 代理与现实世界的重要桥梁。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐