生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~250k tokens,输出 ~6k tokens(本节)
一台运行 OpenClaw Gateway 的电脑,能力是有限的——它可以执行 Shell 命令、读写文件、控制浏览器,但它看不到手机摄像头、无法推送系统通知到 iPad、也不能调用远程服务器上的 GPU 集群。OpenClaw 的节点系统(Node System)就是为了解决这个问题:让 Agent 可以跨设备调用能力,就像在本地执行一样自然。
本节介绍节点系统的核心概念:什么是节点、节点有哪些角色、以及节点命令的命名空间与分类。
19.1.1 什么是节点:设备能力的远程暴露
在 OpenClaw 的术语中,节点(Node) 是指通过 WebSocket 连接到 Gateway 的一个远程设备或进程。节点的核心职责是将自身的硬件和软件能力暴露(expose) 给 Gateway,使得 Agent 可以像调用本地工具一样远程使用这些能力。
衍生解释:能力暴露(Capability Exposure)
"能力暴露"是分布式系统中的一个常见模式。类似于操作系统中的设备驱动将硬件能力抽象为文件操作(Unix 的"一切皆文件"理念),节点系统将远程设备的能力抽象为命令调用。Agent 发出 camera.snap 命令,不需要知道摄像头连接在哪台设备上——Gateway 会自动路由到拥有摄像头的节点。
每个连接到 Gateway 的节点都由 NodeSession 类型描述:
// src/gateway/node-registry.ts
export type NodeSession = {
nodeId: string; // 节点唯一标识(设备 ID 或客户端 ID)
connId: string; // 当前 WebSocket 连接 ID
client: GatewayWsClient; // WebSocket 客户端实例
displayName?: string; // 人类可读名称,如 "MacBook Pro"
platform?: string; // 操作系统标识,如 "ios"、"darwin"、"android"
version?: string; // 客户端版本号
coreVersion?: string; // OpenClaw 核心版本
uiVersion?: string; // UI 版本(仅原生客户端)
deviceFamily?: string; // 设备系列,如 "iPhone"、"iPad"
modelIdentifier?: string;// 设备型号,如 "iPhone15,2"
remoteIp?: string; // 远程 IP 地址
caps: string[]; // 能力列表,如 ["system", "browser"]
commands: string[]; // 声明支持的命令列表
permissions?: Record<string, boolean>; // 权限状态
pathEnv?: string; // PATH 环境变量
connectedAtMs: number; // 连接时间戳
};
这个类型揭示了节点系统的设计哲学:节点是自描述的。连接时,节点向 Gateway 报告自己的身份(nodeId、platform)、能力(caps、commands)和元数据(version、deviceFamily),Gateway 据此决定可以向该节点下发哪些命令。
节点与 Gateway 之间的连接拓扑是经典的星型结构(Star Topology):
所有节点都连接到同一个 Gateway,形成中心化的管理模式。这种架构的优势在于:
Gateway 知道所有在线节点,可以选择最合适的目标
19.1.2 节点角色:macOS / iOS / Android / 无头
并非所有节点都提供相同的能力。一台 iPhone 有摄像头但没有 Shell 环境;一台 Linux 服务器可以执行任意命令但没有 GUI。OpenClaw 通过平台标识来区分不同角色的节点,并为每个平台预设允许的命令集。
平台识别由 normalizePlatformId 函数完成:
这个函数采用两级回退策略:先看 platform 字符串前缀,如果无法识别再根据 deviceFamily 推断。这保证了即使节点报告了非标准的平台字符串,也能正确分类。
根据平台和用途,节点通常分为以下四类:
Shell 执行、浏览器代理、Canvas、摄像头
每种角色的默认命令允许集在 PLATFORM_DEFAULTS 中硬编码:
注意 unknown 平台被赋予了最宽松的权限——所有命令类型的并集。这看起来反直觉,但它确保未知设备类型的功能不会被意外屏蔽。实际的安全控制依赖于节点的 commands 声明和配置层面的 allowCommands / denyCommands。
Gateway 在某些场景下需要知道是否有移动设备在线(例如,决定是否提供拍照工具)。这由一个简洁的辅助函数实现:
19.1.3 节点命令:命名空间与分类
节点命令采用点分命名空间(dot-separated namespace) 组织,类似于 Java 的包名或 DNS 域名。每个命名空间对应一类设备能力:
canvas.present, canvas.hide, canvas.navigate, canvas.eval, canvas.snapshot, canvas.a2ui.push, canvas.a2ui.pushJSONL, canvas.a2ui.reset
camera.list, camera.snap, camera.clip
system.run, system.which, system.notify, system.execApprovals.get, system.execApprovals.set
这种命名约定使得权限控制非常灵活——可以按命名空间整体授权(如允许所有 canvas.*),也可以精确到单个命令。
一个命令能否被成功执行,需要通过三层检查:
这个设计实现了双向约束:
Gateway 侧约束:即使节点声称支持某个命令,如果 Gateway 配置不允许,该命令也无法执行。
节点侧约束:即使 Gateway 允许某个命令,如果节点没有声明支持,也会被拒绝。
具体实现在 isNodeCommandAllowed 函数中:
而 allowlist 的构建由 resolveNodeCommandAllowlist 完成:
衍生解释:白名单(Allowlist)模式
安全领域有两种基本策略:黑名单(Blocklist,默认允许,列出禁止项)和白名单(Allowlist,默认禁止,列出允许项)。节点命令系统采用白名单模式——先从平台默认集合出发,然后通过 allowCommands 追加、denyCommands 移除,最终得到精确的允许集合。白名单模式在安全上更加保守,因为遗漏一个规则只会导致功能不可用(安全但不便),而非功能泄露(危险但方便)。
当 Agent 需要调用一个节点命令时(例如 camera.snap),完整的时序如下:
这个时序展示了 Gateway 作为中间人的角色:它不仅负责消息路由,还在路由之前进行安全检查。Node Host 收到请求后执行实际操作,然后通过 node.invoke.result 将结果返回。
节点是远程能力的代理——通过 WebSocket 连接到 Gateway,将设备的硬件和软件能力暴露给 Agent 使用。
NodeSession 是节点的运行时快照——包含身份标识、平台信息、能力列表和声明的命令集。
星型拓扑简化了管理——所有节点连接到同一个 Gateway,路由、权限、状态管理都集中在 Gateway 侧。
平台决定默认角色——iOS/Android 侧重移动感知能力(摄像头、定位),macOS/Linux 侧重系统执行能力(Shell、浏览器代理)。
三层命令控制保证安全——平台默认集 + 配置调整 → allowlist → 节点声明双向校验,白名单模式确保了最小权限原则。
点分命名空间组织命令——canvas.*、camera.*、system.* 等清晰划分能力域,便于精细化权限管理。