OpenClaw 实现原理详解(六):WebSocket Gateway 详解

6.1 Gateway 的角色:消息中枢

WebSocket Gateway 是 OpenClaw 的消息中枢,负责:

  • 维护平台连接:管理 WhatsApp、Telegram、Discord 等渠道的长连接
  • 客户端通信:为 UI 客户端、CLI、远程节点提供 WebSocket API
  • 会话管理:维护多渠道、多用户的会话状态
  • 认证授权:验证客户端身份,控制访问权限
objectivec 复制代码
┌─────────────────────────────────────────────────────────────┐
│                      WebSocket Gateway                       │
│                                                             │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐         │
│  │WhatsApp │  │Telegram │  │Discord  │  │  微信   │  ...    │
│  │ Provider│  │ Provider│  │ Provider│  │ Provider│         │
│  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘         │
│       │            │            │            │              │
│       └────────────┴─────┬──────┴────────────┘              │
│                          │                                   │
│                    ┌─────▼─────┐                             │
│                    │  Router   │  消息路由                   │
│                    └─────┬─────┘                             │
│                          │                                   │
│       ┌──────────────────┼──────────────────┐               │
│       │                  │                  │               │
│  ┌────▼────┐       ┌─────▼─────┐      ┌─────▼─────┐         │
│  │   CLI   │       │ WebChat   │      │ macOS App │  ...    │
│  └─────────┘       └───────────┘      └───────────┘         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

6.2 协议设计

消息帧格式

所有 WebSocket 通信使用 JSON 格式,分为三种帧类型:

typescript 复制代码
// 请求帧
interface Request {
  type: "req";
  id: string;        // 唯一标识,用于匹配响应
  method: string;    // 方法名
  params: object;    // 参数
}

// 响应帧
interface Response {
  type: "res";
  id: string;        // 对应请求的 id
  ok: boolean;       // 是否成功
  payload?: object;  // 成功时的数据
  error?: string;    // 失败时的错误信息
}

// 事件帧
interface Event {
  type: "event";
  event: string;     // 事件名
  payload: object;   // 事件数据
  seq?: number;      // 序列号(可选)
}

示例交互

arduino 复制代码
Client                          Gateway
  │                                │
  │──── req:connect ──────────────>│  首帧必须是 connect
  │<──── res (ok) ─────────────────│  或 res error + close
  │                                │
  │<──── event:tick ───────────────│  心跳
  │<──── event:presence ───────────│  状态同步
  │                                │
  │──── req:agent ────────────────>│  发起 AI 请求
  │<──── res:agent ────────────────│  确认接受
  │<──── event:agent ──────────────│  流式输出
  │<──── res:agent ────────────────│  完成
  │                                │

6.3 连接生命周期

1. 连接建立

客户端连接 Gateway 时,首帧必须是 connect 请求:

json 复制代码
{
  "type": "req",
  "id": "conn_001",
  "method": "connect",
  "params": {
    "token": "your-gateway-token",
    "clientId": "my-client",
    "version": "1.0.0"
  }
}

2. 认证

Gateway 验证 token:

json 复制代码
// 成功
{
  "type": "res",
  "id": "conn_001",
  "ok": true,
  "payload": {
    "serverVersion": "1.2.3",
    "agents": ["main"]
  }
}

// 失败
{
  "type": "res",
  "id": "conn_001",
  "ok": false,
  "error": "Invalid token"
}

3. 心跳

Gateway 定期发送 tick 事件:

json 复制代码
{
  "type": "event",
  "event": "tick",
  "payload": {
    "ts": 1704067200000
  }
}

4. 断开连接

客户端或服务器可以随时关闭连接。Gateway 会:

  • 清理会话状态
  • 通知其他客户端(如果需要)
  • 释放资源

6.4 认证与授权

Token 认证

Gateway 使用 token 进行认证:

json5 复制代码
{
  gateway: {
    token: "your-secret-token",  // 或从环境变量读取
  }
}
bash 复制代码
# 环境变量
OPENCLAW_GATEWAY_TOKEN=your-secret-token

设备配对

远程节点需要先配对:

bash 复制代码
# 生成配对码
openclaw pair generate

# 输出
Pairing code: ABCD-EFGH
Expires in: 5 minutes

客户端使用配对码连接:

json 复制代码
{
  "type": "req",
  "method": "connect",
  "params": {
    "pairCode": "ABCD-EFGH"
  }
}

6.5 常用 RPC 方法

agent

调用 Agent 进行推理:

json 复制代码
{
  "type": "req",
  "id": "agent_001",
  "method": "agent",
  "params": {
    "sessionKey": "agent:main:main",
    "message": "帮我整理文件",
    "model": "claude-3-5-sonnet"
  }
}

send

发送消息到渠道:

json 复制代码
{
  "type": "req",
  "id": "send_001",
  "method": "send",
  "params": {
    "channel": "telegram",
    "target": "123456789",
    "message": {
      "text": "你好!"
    }
  }
}

health

健康检查:

json 复制代码
{
  "type": "req",
  "id": "health_001",
  "method": "health",
  "params": {}
}

status

获取状态:

json 复制代码
{
  "type": "req",
  "id": "status_001",
  "method": "status",
  "params": {}
}

6.6 常用事件

tick

心跳事件,定期发送。

agent

Agent 状态变更:

json 复制代码
{
  "type": "event",
  "event": "agent",
  "payload": {
    "stream": "assistant",
    "delta": "你好!有什么可以帮你的?"
  }
}

presence

用户在线状态变更:

json 复制代码
{
  "type": "event",
  "event": "presence",
  "payload": {
    "channel": "whatsapp",
    "userId": "123456789",
    "status": "online"
  }
}

chat

收到新消息:

json 复制代码
{
  "type": "event",
  "event": "chat",
  "payload": {
    "channel": "telegram",
    "sender": {
      "id": "123456789",
      "name": "Alice"
    },
    "message": {
      "text": "你好"
    }
  }
}

shutdown

Gateway 即将关闭:

json 复制代码
{
  "type": "event",
  "event": "shutdown",
  "payload": {
    "reason": "maintenance",
    "gracePeriodMs": 30000
  }
}

6.7 连接管理

多客户端

Gateway 支持多个客户端同时连接:

markdown 复制代码
┌─────────────┐
│   Gateway   │
└──────┬──────┘
       │
  ┌────┼────┬────────┐
  │    │    │        │
  ▼    ▼    ▼        ▼
CLI  Web  macOS   iOS App

竞争处理

当多个客户端同时操作同一会话时:

  1. 请求排队:请求按到达顺序处理
  2. 状态同步:变更通过事件广播给所有客户端
  3. 乐观锁:某些操作使用版本号防止冲突

6.8 Gateway 配置

基本配置

json5 复制代码
{
  gateway: {
    // 监听地址
    bind: "loopback",  // 只监听本地
    // bind: "0.0.0.0",  // 监听所有接口
    
    port: 19000,
    
    // 认证
    token: "your-token",
    
    // 远程访问
    remote: {
      enabled: true,
      url: "https://your-gateway.example.com"
    },
    
    // Tailscale
    tailscale: {
      enabled: true,
      hostname: "openclaw-gateway"
    }
  }
}

安全配置

json5 复制代码
{
  gateway: {
    // 只允许可信来源
    cors: {
      origins: ["https://your-app.example.com"]
    },
    
    // 速率限制
    rateLimit: {
      windowMs: 60000,
      maxRequests: 100
    },
    
    // 连接超时
    connectionTimeout: 300000,  // 5 分钟
  }
}

6.9 客户端实现示例

JavaScript/TypeScript

typescript 复制代码
import WebSocket from 'ws';

const ws = new WebSocket('ws://localhost:19000');

ws.on('open', () => {
  // 发送连接请求
  ws.send(JSON.stringify({
    type: 'req',
    id: 'conn_001',
    method: 'connect',
    params: { token: 'your-token' }
  }));
});

ws.on('message', (data) => {
  const frame = JSON.parse(data.toString());
  
  if (frame.type === 'res') {
    console.log('Response:', frame);
  } else if (frame.type === 'event') {
    console.log('Event:', frame.event, frame.payload);
  }
});

// 调用 Agent
function callAgent(message: string) {
  ws.send(JSON.stringify({
    type: 'req',
    id: `agent_${Date.now()}`,
    method: 'agent',
    params: {
      sessionKey: 'agent:main:main',
      message
    }
  }));
}

总结

WebSocket Gateway 是 OpenClaw 的核心枢纽:

组件 职责
连接管理 维护客户端和渠道连接
协议处理 解析和生成消息帧
认证授权 验证身份,控制权限
消息路由 将消息分发到正确的目标
状态同步 广播状态变更给客户端
会话管理 维护会话状态和持久化

🦞 下一章预告:我们将深入 Skills 技能系统,了解如何扩展 Agent 的能力。

相关推荐
楚国的小隐士2 小时前
“你用AI,那我也会用AI,我还要你干什么?”
ai·大模型·编程·ai编程·哲学·氛围编程·辩证唯物主义·马列主义·唯物论
左耳咚2 小时前
Claude Code 中的 SubAgent
前端·ai编程·claude
Jackson__3 小时前
OpenSpec:AI 写代码,先立规矩再动手
前端·ai编程
恋猫de小郭4 小时前
为什么中转渠道的顶级模型会不好用?这是一个技术问题
前端·人工智能·ai编程
workflower4 小时前
需求-什么时候才算完成
人工智能·机器人·集成测试·ai编程·软件需求
NI_chunz5 小时前
Cursor使用frontend-design 让AI生成出来的前端界面更有风格
ai编程
柯儿的天空6 小时前
【OpenClaw 全面解析:从零到精通】第 019 篇:GoClaw 企业版——从开源到商业化的演进之路
gpt·开源·aigc·copilot·ai编程·ai写作·agi
卡尔AI工坊6 小时前
copilot更新:本地、背景、云;Claude、Codex
人工智能·经验分享·chatgpt·软件工程·copilot·ai编程
JaydenAI6 小时前
[LangChain智能体本质论]中间件装饰器是如何将函数转换成AgentMiddleware的?
python·langchain·ai编程