先认清真实 API 边界

OpenClaw 不是一组围绕消息、记忆和“动态注册 Python 函数”设计的 REST 资源。它的核心集成边界是长期运行的 Gateway:Gateway 持有消息渠道连接、会话状态、Agent 运行、审批流程和节点状态,并通过 WebSocket 暴露带类型约束的请求、响应与事件。

因此,生产接入需要解决的不是“拼出一个 HTTP 请求”,而是完整客户端生命周期:

  • 建立并维护有状态连接;
  • 生成设备身份并完成配对;
  • 按功能申请 Operator 权限;
  • 区分“请求已接受”和“任务已完成”;
  • 在断线后恢复订阅并核对权威状态;
  • 同时锁定客户端包版本与 Wire 协议版本。

截至 2026 年 10 月 3 日,官方客户端开发文档给出的已验证稳定包是 @openclaw/[email protected] 和 @openclaw/[email protected],对应 Wire v4。包版本与 Wire 版本是两个不同的兼容维度,不能只锁其中一个。

如果还不了解 Gateway、会话、记忆与工具之间的关系,可先阅读 OpenClaw AI Agent 完全指南。本文只回答一个更具体的问题:业务系统如何按照官方合约可靠地接入 OpenClaw。

两种集成面如何选择

OpenClaw 当前有两类语义明显不同的入口。

集成面 适用场景 调用方必须负责
Gateway WebSocket/RPC 聊天客户端、控制台、会话列表、审批、节点管理、流式 Agent 运行 连接生命周期、设备身份、配对、权限、事件顺序与断线恢复
POST /tools/invoke 可信服务调用少量经过审核的工具 可信网络入口、共享令牌保护、业务授权、工具白名单、审计与超时

不要把 /tools/invoke 包装成一套“OpenClaw REST API”。它默认拒绝 Shell、进程执行和文件系统变更等危险工具,设计目标就是受限调用。反过来,如果需求只是内网服务触发一个明确动作,也不必为了“统一”而模拟完整聊天客户端。

选择依据应是交互语义:

  1. 需要会话、流式事件、订阅、审批或持久设备身份时,使用 Gateway 协议。
  2. 一个可信服务只需要调用极小工具面时,评估 /tools/invoke。
  3. 最终用户或不同租户权限不同时,在 OpenClaw 前增加业务自有 API 和授权层。

Gateway 协议的核心模型

官方 Gateway 架构文档定义了三类顶层 WebSocket 文本帧:

json
{"type":"req","id":"req-17","method":"chat.send","params":{"sessionKey":"main","message":"总结本次事故"}}
{"type":"res","id":"req-17","ok":true,"payload":{"runId":"run-92","status":"accepted"}}
{"type":"event","event":"agent","payload":{"runId":"run-92","phase":"completed"},"seq":481,"stateVersion":73}

客户端的第一帧必须是 connect。握手成功后,Gateway 返回 hello-ok,其中包含协商结果、初始快照和能力元数据。hello-ok.features.methods 可用于发现方法,但不能证明调用权限;最终还要同时满足角色、已批准 Scope、设备配对、工具策略和方法自身规则。

接受请求不等于任务完成

agent 或 chat.send 返回 accepted,只代表 Gateway 接受了工作,不能证明:

  • 模型已经完成响应;
  • 所有工具都执行成功;
  • 消息渠道已经投递;
  • 对应业务动作已经生效。

应用必须用返回的 runId 关联后续事件,并查询会话或任务的权威状态。建议在业务状态机中明确区分:

text
requested -> accepted -> running -> terminal
                                -> waiting_for_approval
                                -> failed
                                -> cancelled

如果收到 RPC ACK 就把订单、通知或工单标成成功,断线与异步失败会直接制造错误数据。

用版本化结构建模协议帧

Go 服务即使不使用官方 TypeScript 客户端,也应保留相同的结构和语义:

go
package main

import (
	"encoding/json"
	"fmt"
)

type RequestFrame struct {
	Type   string `json:"type"`
	ID     string `json:"id"`
	Method string `json:"method"`
	Params any    `json:"params"`
}

type AgentParams struct {
	SessionKey     string `json:"sessionKey"`
	Message        string `json:"message"`
	IdempotencyKey string `json:"idempotencyKey"`
}

func main() {
	frame := RequestFrame{
		Type:   "req",
		ID:     "req-17",
		Method: "agent",
		Params: AgentParams{
			SessionKey:     "incident-review",
			Message:        "基于已审批的事故证据生成摘要。",
			IdempotencyKey: "incident-2026-10-03-v1",
		},
	}

	payload, err := json.Marshal(frame)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(payload))
}

实际传输层应使用成熟的 WebSocket 库,并完成四件事:按锁定版本的 Schema 校验入站帧、拒绝不兼容 Wire 版本、限制消息大小、保留 Gateway 结构化错误。把所有错误压成一段字符串,会丢失“需要配对、缺少 Scope、可以重试、必须终止”等关键决策信息。

鉴权、设备配对与 Scope

引导鉴权解决“谁可以开始连接”,设备配对绑定长期设备身份,Scope 约束已配对操作者可以调用什么。三者不是同一个控制点。

官方客户端流程可以归纳为:

  1. 生成并持久化 Ed25519 设备身份。
  2. 接收 connect.challenge,对包含 Challenge 的设备载荷签名。
  3. 发送 connect,携带角色、请求的 Scope,以及配置好的 Gateway Token 或密码。
  4. 收到 PAIRING_REQUIRED 时,向用户展示请求 ID,并停止特权操作。
  5. 操作者核对并批准这一个明确请求。
  6. 重新连接,保存 Gateway 签发且绑定角色与 Scope 的设备 Token。

角色或 Scope 扩大时会产生新的待审批请求。仅轮换 Token 不会扩大权限。

按用户动作申请最小权限

客户端能力 对应的最小相关 Scope
查看历史、会话、模型状态 operator.read
发送聊天、修改普通会话 operator.write
展示或处理执行/插件审批 operator.approvals
回答 Agent 的交互式问题 operator.questions
管理已配对设备或节点 operator.pairing
修改管理配置 operator.admin

只读大屏不应持有审批或管理权限;无法完整展示审批对象和参数的聊天端,也不应申请批准能力。为了开发方便一次申请全部 Scope,会让配对审核失去意义。

节点还有第二层边界:设备配对允许节点建立连接,节点能力审批决定它能暴露哪些命令。已经配对的节点新增命令后,仍需重新审批,并继续受 Gateway 命令策略约束。

断线恢复与副作用去重

网络可能在任意两个观测点之间中断。客户端发出请求后断线,没有看到 ACK,并不代表 Gateway 没有接受该请求。

可靠恢复流程是:

  1. 发送前持久化客户端请求 ID、幂等键、会话键和最后看到的序列号或状态版本;
  2. 使用同一个设备身份和设备 Token 重连;
  3. 恢复事件订阅;
  4. 获取权威会话历史或任务状态;
  5. 先核对已有 Run,再决定是否重试;
  6. 重试副作用请求时复用同一个幂等键。

Gateway 要求 send、agent 等副作用方法携带幂等键,并维护短期去重缓存。短期缓存不是永久业务账本。发送账单、发布公告、修改外部对象等动作,仍需由业务系统保存长期 Operation ID,并在下游实现幂等。

事件也不应假定“严格只到一次”。存在 seq 或 stateVersion 时,应检测缺口与陈旧更新;发现缺口后重新拉取权威状态,而不是自行猜测丢失事件。

安全使用 /tools/invoke

受限 HTTP 端点适合可信内网服务触发明确动作:

bash
curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer ${OPENCLAW_GATEWAY_TOKEN}" \
  --header "Content-Type: application/json" \
  --data '{
    "tool": "message",
    "action": "send",
    "idempotencyKey": "maintenance-2026-10-03-v1",
    "args": {
      "channel": "telegram",
      "target": "ops-room",
      "message": "已审批的维护窗口开始。"
    }
  }' \
  "http://127.0.0.1:18789/tools/invoke"

应根据锁定版本再次核对字段,且绝不能因为存在这个端点就把 18789 端口暴露到公网。共享 Gateway Bearer 代表较宽的操作者权限,应将端点限制在 Loopback、私网、认证服务网格或业务代理之后,并由代理继续执行:

  • 调用方与租户身份校验;
  • 精确到工具和 Action 的白名单;
  • 有界参数 Schema;
  • 速率与并发限制;
  • 出站网络约束;
  • 审计 ID 与日志脱敏;
  • 高影响动作的人工确认。

OpenClaw 的工具限制是纵深防御,不能替代业务系统对“哪个用户能向哪个频道发送什么”的授权判断。

升级前必须验证什么

一套可维护的集成至少记录四个版本:

版本 影响范围
Gateway Release 服务端行为与方法集合
Gateway Client Package 重连、设备身份与宿主集成
Protocol Package / Wire Version 帧结构与兼容规则
业务合约版本 产品真正依赖的方法、事件、Scope 与错误类型

每次升级前,至少回放以下兼容性用例:

  1. 新设备配对与第二次无感重连;
  2. 只读客户端无法执行写操作;
  3. Agent 请求从 Accepted 走到终态;
  4. ACK 丢失后的幂等恢复;
  5. 需要审批的动作;
  6. 被撤销的设备 Token;
  7. 未知方法或不兼容帧;
  8. 事件缺口后的权威状态恢复。

生产环境应固定精确版本。浮动 latest 或宽松依赖范围,会把协议升级变成未经评审的线上变更。

生产检查清单

  • Gateway 只监听 Loopback 或可信私网;远程管理通过 SSH 或 VPN。
  • 设备私钥与 Token 存入系统钥匙串或 Secret Manager。
  • 读、写、审批、配对与管理客户端按职责拆分。
  • 限制帧大小、队列深度、重连频率与事件保留量。
  • 保留结构化错误码、请求 ID 与 Run ID。
  • 消息正文和工具参数进入可观测系统前完成脱敏。
  • 测试撤销、断线和状态恢复,不只验证首次握手。
  • 接入业务系统前阅读 AI Agent 工具安全指南。
  • 定时与多步骤任务参见 OpenClaw 自动化工作流指南。
  • 容器化运维参见 OpenClaw Docker 部署指南。

一手资料

总结

可靠的 OpenClaw 接入应从 Gateway 的有状态协议出发,而不是围绕不存在的 REST 资源开发。设备要配对,客户端只申请最小 Scope,ACK 与完成事件必须分开,断线后先核对权威状态,所有副作用都要具备业务级幂等。/tools/invoke 只适合作为可信服务之间的窄入口,并由业务授权层继续收紧权限。这样才能让 AI Agent 成为可测试的系统组件,而不是一个无边界控制面。