1. 为什么 OpenClaw Gateway 要用 WebSocket 长连接OpenClaw Gateway 是整个 Agent 框架的神经中枢它对外暴露的核心接口就是一条 WebSocket 长连接。你可以把它理解成一个“总机”macOS 桌面端、命令行工具、手机节点、Web 管理页全都拨同一个号码进来由 Gateway 负责把消息分发给正确的对象。它适合正在搭 AI Agent 后端、需要多端实时同步状态的开发者也适合想把本地工具接进统一通信层的同学。我一开始也疑惑都 2025 年了为什么不用 REST 或者 SSE实测下来AI Agent 这个场景有三个硬需求REST 很难优雅满足。第一是流式输出大模型回复是逐 Token 生成的REST 要靠 SSE 才能推而 SSE 是单向的客户端没法在同一条通道里回话。第二是服务端主动推送新消息到达、心跳、节点上下线这些事件必须由 Gateway 主动告诉客户端REST 只能靠轮询延迟和开销都难看。第三是多路复用一个客户端可能同时关注多个会话的状态REST 得开多条连接或者长轮询。WebSocket 是全双工长连接一条连接就能双向收发天然支持服务端推送和流式传输。握手阶段走一次 HTTP Upgrade之后就是持续的 JSON 帧交换。对需要实时性的 AI 助手来说这是更贴合的选择。下面这张对照表可以先建立直觉维度RESTSSEWebSocket通信方向单向请求响应服务端单向推送全双工双向流式输出需额外方案支持原生支持服务端主动推送轮询支持支持多路复用多连接/长轮询单通道单连接多会话适用场景简单 CRUD单向通知实时 Agent 控制面理解了“为什么”接下来就是“怎么配”。这篇会从 config.toml 骨架讲到 settings.json 关键项再演示多端消息互通的验证动作让你能直接复制落地。2. TaoToken 前置把模型通道先打通Gateway 负责的是连接层但 Agent 真正干活时要调用大模型。如果你还没准备好模型侧的访问凭证建议先把这一步做掉否则后面验证多端通信时Agent 回复会因为拿不到模型而卡住。TaoToken 在这里扮演的是统一的模型接入入口。你可以在官网了解整体能力然后到控制台创建 API Key。整个流程不复杂注册后进入控制台新建一个 Key复制出来保存好。这个 Key 后面会写进 Gateway 的模型配置里供 Agent 运行时调用。需要区分两个地址官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 注意 API 地址后面不加任何查询参数。配置时把 base_url 指向 API 地址Key 填你刚创建的那串字符即可。如果你更想先在网页里试试模型对话效果可以直接打开模型对话页面确认通道可用之后再回到 Gateway 配置里填参数。这样能避免“到底是连接层问题还是模型层问题”的排查混乱。提示Key 属于敏感凭证不要提交到 Git 仓库建议放在环境变量或本地未跟踪的配置文件里。3. 可复制配置config.toml 骨架与 settings.json 关键项这一节是全文的核心给你可以直接抄的配置。OpenClaw Gateway 的主配置放在 config.toml客户端侧的关键项放在 settings.json。3.1 config.toml 骨架先看 Gateway 侧的骨架。下面这份配置定义了监听端口、心跳、认证和模型通道字段名按常见约定给出你可以按自己版本微调[gateway] # WebSocket 监听地址与端口 host 0.0.0.0 port 18790 # 单条连接空闲超时秒超时未收到心跳则关闭 idle_timeout 90 # 心跳发送间隔秒 heartbeat_interval 30 # 心跳响应超时秒超时判定连接失效 heartbeat_timeout 10 [gateway.auth] # 是否允许本地回环地址免配对 allow_loopback true # 配对码有效期秒 pairing_ttl 300 # Token 校验开关 require_token true [gateway.limits] # 单设备最大并发连接数超出则关闭最旧连接 max_connections_per_device 3 # 全局最大连接数 max_connections 256 [model] # 模型通道基址注意不加查询参数 base_url https://taotoken.net/api # 从环境变量读取避免明文写进仓库 api_key ${TAOTOKEN_API_KEY} # 默认模型标识 default_model claude-sonnet [agent] # 流式分块按时间窗口毫秒批量推送 stream_flush_ms 50 # 流式分块按字符数批量推送 stream_flush_chars 20几个参数值得单独说。heartbeat_interval 设成 30 秒是比较稳的折中太短会增加无谓流量太长则断线发现不及时。max_connections_per_device 设成 3是为了防止 App 崩溃重启后旧连接没清理干净导致“幽灵连接”堆积。stream_flush_ms 和 stream_flush_chars 是流式输出的分块策略后面验证时会看到效果。3.2 settings.json 关键项客户端侧的 settings.json 决定它怎么连、以什么身份连、断线怎么重连{ gateway: { url: ws://127.0.0.1:18790, deviceId: macbook-pro-m3, role: client, token: ${GATEWAY_TOKEN}, reconnect: { enabled: true, baseDelayMs: 1000, maxDelayMs: 30000, factor: 2, jitter: true }, heartbeat: { enabled: true, intervalMs: 30000 } }, session: { defaultKey: local:default, subscribe: [agent.stream, agent.done, session.update, node.status] } }role 字段很关键它决定这条连接的身份。role 为 client 的是普通客户端比如桌面 App、CLI、Web 管理页可以查询状态、发消息、管配置。role 为 node 的是边缘节点比如手机它暴露摄像头、GPS、屏幕等硬件能力供 Agent 工具调用。同一个 Gateway 可以同时接这两种角色。reconnect 里的指数退避参数baseDelayMs 是首次重连等待factor 是倍数maxDelayMs 是上限。断线后按 1s、2s、4s、8s 递增加上 jitter 抖动避免大量客户端在同一瞬间重连把 Gateway 冲垮。注意url 里的 127.0.0.1 只适合本机调试。跨设备接入时改成 Gateway 所在机器的局域网 IP并确保防火墙放行 18790 端口。3.3 多端接入参数对照不同客户端接入时主要差异在 deviceId、role 和订阅事件上。下面这张表帮你快速对齐客户端deviceId 示例role主要订阅事件macOS Appmacbook-pro-m3clientagent.stream, agent.doneCLI 工具cli-dev-01clientsession.update手机节点iphone-15-nodenodenode.statusWeb Adminweb-admin-01clientsession.update, node.statusdeviceId 要保证唯一重复连接时 Gateway 会自动关闭旧连接、保留新连接这正是前面 max_connections_per_device 要配合的地方。4. 验证请求多端消息互通的实操动作配置写完必须验证。这一节给你一套可跟做的验证流程从单端连通到多端互通。4.1 启动 Gateway 并确认监听先在 Gateway 所在机器启动服务然后确认端口在监听# 启动 Gateway按你的实际启动方式调整 openclaw gateway --config ./config.toml # 另开一个终端确认 18790 在监听 ss -lntp | grep 18790如果看到 LISTEN 状态说明 Gateway 已经起来了。如果没看到先检查 config.toml 里的 host 和 port 是否被其他进程占用。4.2 用 CLI 建立第一条连接用命令行工具发起连接观察握手和认证过程# 以 client 身份连接token 从环境变量读取 openclaw connect \ --url ws://127.0.0.1:18790 \ --device-id cli-dev-01 \ --role client \ --token $GATEWAY_TOKEN连接成功后你会看到认证帧被接受连接进入活跃状态。此时可以手动发一条消息帧格式是带类型标记的 JSON{ type: agent.message, sessionKey: local:default, content: 帮我查一下明天的天气, ts: 1709452800000 }Gateway 收到后会触发 Agent 运行时处理并把流式结果推回来。你会看到一串 agent.stream 帧最后跟一个 done 为 true 的结束帧。4.3 多端同时接入并验证互通现在开第二个终端用不同的 deviceId 再连一条openclaw connect \ --url ws://127.0.0.1:18790 \ --device-id web-admin-01 \ --role client \ --token $GATEWAY_TOKEN两条连接都建立后在第一条连接里发消息观察第二条连接是否收到 agent.stream 推送。如果第二条也实时刷出了同样的流式片段说明 Gateway 的广播路由生效了多端互通验证通过。再进一步把手机节点也接进来role 设为 node订阅 node.status。当节点上线或下线时client 侧应该能收到状态变更事件。这一步验证的是不同角色之间的消息分发是否正确。4.4 观察流式分块效果回到 config.toml 里的 stream_flush_ms 和 stream_flush_chars。你可以把 stream_flush_ms 改成 200 再重启对比一下推送频率。数值越大帧越少但实时感越弱数值越小帧越密但开销越高。实测下来50ms 配 20 字符是个比较舒服的平衡点首字延迟低推送也不至于太碎。5. 本篇常见错排查配置和验证过程中最容易踩的坑集中在连接、认证和路由三块。下面按现象给出排查路径。5.1 连接被立即关闭现象是握手成功后马上收到 Close 帧。最常见原因是认证帧没发或发晚了。Gateway 在连接建立后会等一个很短的窗口如果客户端没有及时发送 auth 帧连接会被强制关闭。检查你的客户端是否在 onopen 回调里第一时间发了认证帧token 是否正确。另一个原因是 token 过期或被吊销。到控制台确认 Key 状态必要时重新生成。5.2 心跳超时导致频繁断线如果连接每隔一段时间就断先看 heartbeat_interval 和 heartbeat_timeout 的配合。timeout 必须小于 interval否则每次心跳还没等到回应就被判失效。网络抖动大的环境可以适当放宽 timeout但不要超过 interval 的一半。5.3 多端收不到广播一条连接发消息另一条收不到通常是订阅关系没对上。检查 settings.json 里的 subscribe 数组是否包含对应事件类型。另外Gateway 的广播是按事件类型和订阅关系路由的如果第二条连接没订阅 agent.stream自然收不到流式片段。5.4 同一设备重复连接导致旧连接被踢这是预期行为不是 bug。Gateway 检测到相同 deviceId 的新连接时会主动关闭旧连接避免幽灵连接堆积。如果你确实需要同一设备多连接把 deviceId 区分开或者调大 max_connections_per_device。5.5 跨设备连不上本机 127.0.0.1 能连换成局域网 IP 就连不上多半是防火墙没放行 18790或者 Gateway 的 host 还绑在回环地址上。把 host 改成 0.0.0.0并在系统防火墙里放行对应端口。提示排查时优先看 Gateway 侧日志认证失败、心跳超时、连接被踢这些事件通常都有明确记录比在客户端猜要快得多。6. 把连接层用起来下一步怎么走连接打通之后你可以做几件更有价值的事。第一把 CLI 和桌面端同时接上日常调试时一边发指令一边看流式输出效率比单端高不少。第二把手机节点接进来让 Agent 能调用摄像头、GPS 这类硬件能力多端协同的场景就打开了。第三如果你打算长期跑编码类 Agent可以了解 Coding Plan把模型调用和连接层一起纳入稳定通道。需要再确认模型通道是否正常随时回到模型对话页面发一条测试消息。要管理或新建凭证去 API Keys 页面操作。接入细节和字段说明接入文档里有完整对照遇到拿不准的帧格式先去那里查。最后留一个实用习惯把 config.toml 和 settings.json 都纳入版本管理但 token 和 api_key 用环境变量注入。这样换机器、换环境时配置能直接复用凭证也不会泄露。连接层的稳定性往往就藏在这些不起眼的工程细节里。