OpenClaw 技术深度剖析与部署配置指南
深入代码与企业级应用分析与部署
技术调研文档 | 版本:v2.6 | 更新日期:2026 年 3 月 3 日
修订: 见后文更新日志 适用对象: 开发者、技术决策者、AI 工程师、运维工程师
预计阅读时间: 45-60 分钟
文档类型: 纯 Markdown 技术文档(无外部图片依赖) 源码版本: 基于官方源码 v1.2+
📝 更新日志
v2.6 (2026-03-03) - 第 10 章:高级主题与企业级解决方案
第 10 章 高级主题与企业级解决方案 (新增,+1200 行):
- ✅ 10.1 流式响应优化 (块流式传输/打字机效果/响应预加载)
- ✅ 10.1 性能基准测试 (首字延迟从 2500ms 降至 320ms,降低 87%)
- ✅ 10.2 多模态支持 (图像理解/语音转文字/视频帧提取)
- ✅ 10.2 多模态统一配置模板 (Whisper/ElevenLabs/FFmpeg)
- ✅ 10.3 企业版 RBAC 权限管理 (4 角色模型/工具审批)
- ✅ 10.3 企业版审计日志 (6 类事件/告警规则/查询导出)
- ✅ 10.3 企业版 SSO 单点登录 (Pomerium/Cloudflare/Authelia)
- ✅ 10.3 企业版完整配置模板 (生产环境就绪)
性能优化成果:
- 流式响应:首字延迟 2500ms → 320ms (降低 87%)
- 用户满意度:⭐⭐⭐ → ⭐⭐⭐⭐⭐
- 多模态支持:图像/语音/视频理解增强
- 企业版功能:RBAC/审计/SSO 生产环境就绪
v2.5 (2026-03-03) - 第 4-5 章源码级更新
第 4 章 多 Agent 路由系统 (完整重写,+600 行):
- ✅ 4.1 Agent 配置结构 (AgentConfig TypeScript 定义,50+ 字段详解)
- ✅ 4.1 Agent 物理存储结构 (~/.openclaw/agents/
/) - ✅ 4.1 Agent 隔离边界 (会话/记忆/技能/模型/工具/沙箱隔离)
- ✅ 4.2 路由匹配算法 (resolveAgentRoute 源码解析,8 级优先级)
- ✅ 4.2 会话键生成规则 (buildAgentSessionKey,5 种 dmScope 模式)
- ✅ 4.3 配置示例 (4 种场景:双通道/Discord 角色/飞书多账号/线程继承)
- ✅ 4.4 Agent-to-Agent 通信 (sessions_send/sessions_spawn 工具定义)
- ✅ 4.4 通信模式 (请求 - 响应/任务分发/持久会话)
- ✅ 4.4 跨境电商多 Agent 完整工作流 (ASCII 架构图 + 代码实现)
第 5 章 部署配置全指南 (完整重写,+800 行):
- ✅ 5.3 完整配置 Schema (OpenClawConfig TypeScript 定义,10 大配置块)
- ✅ 5.3 核心配置项详解 (agents/bindings/session/gateway/channels/models/tools/hooks/cron/skills)
- ✅ 5.4 环境变量配置 (完整环境变量列表,60+ 变量详解)
- ✅ 5.4 环境变量使用方式 (${ENV} 语法/env.vars/env.shellEnv)
- ✅ 5.5 Docker 部署 (Dockerfile 多阶段构建/docker-compose.yml/健康检查)
- ✅ 5.5 Docker 注意事项 (数据持久化/沙箱支持/TLS/日志管理)
- ✅ 5.6 Systemd 服务配置 (服务文件/EnvironmentFile/安全加固)
- ✅ 5.6 部署步骤/常用命令/日志轮转/监控告警
源码依据:
/opt/homebrew/lib/node_modules/openclaw/dist/plugin-sdk/config/types.openclaw.d.ts/opt/homebrew/lib/node_modules/openclaw/dist/plugin-sdk/config/types.agents.d.ts/opt/homebrew/lib/node_modules/openclaw/dist/plugin-sdk/config/types.base.d.ts/opt/homebrew/lib/node_modules/openclaw/dist/plugin-sdk/config/types.gateway.d.ts/opt/homebrew/lib/node_modules/openclaw/dist/plugin-sdk/routing/resolve-route.d.ts/opt/homebrew/lib/node_modules/openclaw/dist/plugin-sdk/routing/session-key.ts
v2.4 (2026-03-02) - 第 3 章源码级更新
- ✅ 3.1 多通道支持 (ChannelPlugin 架构,11 个适配器接口)
- ✅ 3.2 会话存储结构 (SessionEntry 50+ 字段,JSONL 事件格式)
- ✅ 3.3 工具系统 (TypeBox schemas,权限模式,沙箱执行)
- ✅ 3.4 技能系统 (4 种来源,SKILL.md frontmatter,ClawHub CLI)
v2.3 (2026-03-02) - 架构更新
- ✅ 第 2 章 ASCII/Mermaid 图表替换
- ✅ 第 2 章 连接生命周期/数据流详解
v2.0 (2026-03-01) - 初始纯 Markdown 版本
- ✅ 去除所有外部图片依赖
- ✅ 改用 ASCII/Mermaid 线框图
v1.0 (2026-03-01) - 初稿
📋 目录
- OpenClaw 是什么?
- 核心架构剖析
- 关键特性深度解析
- 多 Agent 路由系统
- 部署配置全指南
- 安全与权限管理
- 实战案例:跨境电商多 Agent 系统
- 性能优化与故障排查
- 总结与展望
- 高级主题与企业级解决方案
1. OpenClaw 是什么?
1.1 产品定位
OpenClaw 是一个自托管的 AI Agent 网关,它将你常用的聊天应用(WhatsApp、Telegram、Discord、iMessage 等)与 AI 编码 Agent(如 Pi、Claude Code 等)连接起来。
💡 一句话理解: 在你的口袋里,随时随地通过消息与 AI 助手对话。
1.2 目标用户
| 用户类型 | 需求场景 |
|---|---|
| 开发者 | 需要随时随地的 AI 编程助手 |
| 技术决策者 | 需要私有化部署,数据可控 |
| AI 工程师 | 需要多 Agent 协作系统 |
| 极客用户 | 需要高度自定义的 AI 工作流 |
1.3 核心差异化优势
| 特性 | OpenClaw | 其他方案 |
|---|---|---|
| 部署模式 | 自托管,数据本地 | SaaS 托管,数据第三方 |
| 多通道支持 | 单一网关支持 WhatsApp/Telegram/Discord 等 | 通常单通道 |
| Agent 原生 | 内置工具调用、会话管理、多 Agent 路由 | 需要自行实现 |
| 开源许可 | MIT 许可,社区驱动 | 闭源或商业许可 |
| 移动端支持 | iOS/Android 节点,支持 Camera/Canvas | 通常无 |
1.4 系统要求
# 最低要求
- Node.js 22+
- 512MB RAM (基础部署)
- 1GB 磁盘空间
# 推荐配置
- Node.js 22+
- 2GB+ RAM (多 Agent 场景)
- 10GB+ 磁盘空间
- macOS / Linux / Docker
2. 核心架构剖析
2.1 整体架构图
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 用户侧 (User Side) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ WhatsApp │ │ Telegram │ │ Discord │ │ Feishu │ │
│ │ (Baileys) │ │ (grammY) │ │ (discord.js)│ │ (WebSocket)│ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │ │
│ └────────────────┴────────────────┴────────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ Gateway WS │ 端口:18789 │
│ │ (统一入口) │ 协议:WebSocket │
│ └────────┬────────┘ │
└──────────────────────────────────│──────────────────────────────────────────────┘
│
┌──────────────────────────────────▼──────────────────────────────────────────────┐
│ OpenClaw Gateway (核心中枢) │
│ ┌───────────────────────────────────────────────────────────────────────────┐ │
│ │ 连接层 (Connection Layer) │ │
│ │ • 通道适配器 (Channel Adapters) • 认证中间件 (Auth Middleware) │ │
│ │ • 消息队列 (Message Queue) • 速率限制 (Rate Limiter) │ │
│ └───────────────────────────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────────────────────────┐ │
│ │ 路由层 (Routing Layer) │ │
│ │ • Binding 匹配引擎 • Peer 识别 • Guild/Role 路由 • Fallback 策略 │ │
│ └───────────────────────────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────────────────────────┐ │
│ │ Agent 运行时层 (Agent Runtime Layer) │ │
│ │ • 会话管理 (Session Mgr) • 工具执行器 (Tool Executor) │ │
│ │ • 上下文压缩 (Compaction) • 记忆系统 (Memory) │ │
│ └───────────────────────────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────────────────────────┐ │
│ │ 工具层 (Tool Layer) │ │
│ │ read/write/edit | exec/process | browser/web_search | sessions_* | ... │ │
│ └───────────────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────│──────────────────────────────────────────────┘
│
┌──────────────────────────────────▼──────────────────────────────────────────────┐
│ Agent 工作区 (Agent Workspace) │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ workspace-main │ │ workspace-coding│ │ workspace-lead │ │
│ │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │
│ │ │ SOUL.md │ │ │ │ SOUL.md │ │ │ │ SOUL.md │ │ │
│ │ │ MEMORY.md │ │ │ │ MEMORY.md │ │ │ │ MEMORY.md │ │ │
│ │ │ skills/ │ │ │ │ skills/ │ │ │ │ skills/ │ │ │
│ │ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ LLM Provider │ │
│ │ (DashScope/ │ │
│ │ Anthropic/ │ │
│ │ Google/...) │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────┘
│
┌──────────────────────────────────▼──────────────────────────────────────────────┐
│ 移动端节点 (Mobile Nodes) │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ iOS Node │ │ Android Node │ │
│ │ • Camera │ │ • Camera │ │
│ │ • Screen │ │ • Screen │ │
│ │ • Location │ │ • Location │ │
│ │ • Canvas │ │ • Canvas │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────┘
图注:
- 实线箭头
──►表示数据流向 - 方框
┌─┐表示组件/模块 - 层级从上到下:用户侧 → Gateway → Agent 工作区 → LLM Provider
2.2 核心组件
Gateway(网关守护进程)
职责: 单一事实来源,所有消息路由的中枢
┌─────────────────────────────────────────────────────────┐
│ Gateway │
├─────────────────────────────────────────────────────────┤
│ • WebSocket 服务器 (默认 127.0.0.1:18789) │
│ • 通道连接器 (WhatsApp/Telegram/Discord/...) │
│ • Agent 运行时 (Pi/Claude Code/...) │
│ • 会话管理器 (Sessions + Memory) │
│ • 工具执行器 (Exec/Browser/Canvas/...) │
└─────────────────────────────────────────────────────────┘
关键特性:
- 单实例运行(每主机一个 Gateway)
- WebSocket 长连接(控制平面客户端)
- 支持多通道并发连接
- 内置会话状态管理
控制平面客户端
| 客户端 | 连接方式 | 用途 |
|---|---|---|
| macOS App | WebSocket | 菜单栏控制、Canvas、语音 |
| CLI | WebSocket | 命令行管理、自动化脚本 |
| Web Control UI | WebSocket | 浏览器管理界面 |
| 自动化 (Cron/Hooks) | WebSocket | 定时任务、事件触发 |
Nodes(移动节点)
┌─────────────────────────────────────────────────────────┐
│ Node (iOS/Android) │
├─────────────────────────────────────────────────────────┤
│ • Camera Capture (拍照/录像) │
│ • Screen Recording (屏幕录制) │
│ • Location Services (位置服务) │
│ • Voice Overlay (语音覆盖层) │
│ • Canvas Rendering (网页渲染) │
└─────────────────────────────────────────────────────────┘
连接模式: 与 Gateway 建立 WebSocket 连接,声明 role: node
2.3 连接生命周期
WebSocket 协议详解
连接建立阶段:
┌──────────────┐ ┌──────────────┐
│ Client │ │ Gateway │
│ (Control) │ │ (Server) │
└──────┬───────┘ └──────┬───────┘
│ │
│ ─────────────────────────────────────► │
│ WS Connect: ws://127.0.0.1:18789 │
│ Headers: │
│ • Authorization: Bearer <token> │
│ • X-Device-Id: <device-fingerprint> │
│ • X-Client-Version: 1.2.3 │
│ │
│ ◄───────────────────────────────────── │
│ HTTP 101 Switching Protocols │
│ │
│ ─────────────────────────────────────► │
│ req:connect { │
│ auth: { token: "xxx" }, │
│ device: { id: "macbook-pro", ... } │
│ } │
│ │
│ ◄───────────────────────────────────── │
│ res:connect { │
│ ok: true, │
│ token: <device-token>, │
│ expires: 1709424000000 │
│ } │
│ │
│ ◄───────────────────────────────────── │
│ event:presence { │
│ agents: [...], channels: [...] │
│ } │
│ │
│ ◄───────────────────────────────────── │
│ event:tick (心跳,每 30 秒) │
│ │
消息发送阶段:
┌──────────────┐ ┌──────────────┐
│ Client │ │ Gateway │
└──────┬───────┘ └──────┬───────┘
│ │
│ ─────────────────────────────────────► │
│ req:agent { │
│ agentId: "main", │
│ sessionKey: "agent:main:xxx", │
│ message: "Hello", │
│ context: { channel: "whatsapp", ... } │
│ } │
│ │
│ ◄───────────────────────────────────── │
│ res:agent { │
│ ok: true, │
│ runId: "run_abc123", │
│ status: "accepted" │
│ } │
│ │
│ ◄───────────────────────────────────── │
│ event:agent { │
│ runId: "run_abc123", │
│ type: "chunk", │
│ content: "Hello! How can I..." │
│ } │
│ │
│ ◄───────────────────────────────────── │
│ event:agent { │
│ runId: "run_abc123", │
│ type: "tool_call", │
│ tool: "read", args: {...} │
│ } │
│ │
│ ◄───────────────────────────────────── │
│ res:agent { │
│ runId: "run_abc123", │
│ status: "completed", │
│ summary: "Answered user question" │
│ } │
│ │
协议字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
req:connect.auth.token | string | ✅ | Gateway 认证 token |
req:connect.device.id | string | ✅ | 设备唯一标识 |
req:agent.agentId | string | ✅ | 目标 Agent ID |
req:agent.sessionKey | string | ✅ | 会话键 (用于上下文关联) |
req:agent.message | string | ✅ | 用户消息内容 |
res:agent.runId | string | ✅ | 本次运行的唯一标识 |
event:agent.type | string | ✅ | chunk | tool_call | tool_result | error |
心跳与重连机制
// 客户端心跳处理伪代码
class GatewayClient {
constructor() {
this.heartbeatInterval = 30000; // 30 秒
this.reconnectDelay = 1000; // 初始重连延迟 1 秒
this.maxReconnectDelay = 30000; // 最大重连延迟 30 秒
}
async connect() {
while (true) {
try {
await this.ws.connect();
this.reconnectDelay = 1000; // 重置重连延迟
this.startHeartbeat();
await this.ws.waitForClose();
} catch (e) {
this.reconnectDelay = Math.min(
this.reconnectDelay * 1.5, // 指数退避
this.maxReconnectDelay
);
await sleep(this.reconnectDelay);
}
}
}
startHeartbeat() {
setInterval(() => {
this.ws.send({ type: 'ping', ts: Date.now() });
}, this.heartbeatInterval);
}
}
2.4 数据流
** inbound (用户 → Agent)**:
WhatsApp/Telegram → Gateway → 路由匹配 → Agent Workspace → LLM Provider
outbound (Agent → 用户):
LLM Provider → Agent → Gateway → 通道发送 → WhatsApp/Telegram
3. 关键特性深度解析
3.1 多通道支持
通道架构
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 通道插件架构 (Channel Plugin Architecture) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 【通道适配器接口】(Channel Adapter Interfaces) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ ChannelMessagingAdapter - 消息收发 (inbound/outbound) │ │
│ │ ChannelGroupAdapter - 群组管理 (groups, members, roles) │ │
│ │ ChannelThreadingAdapter - 线程/回复链 (threads, reply_to) │ │
│ │ ChannelStreamingAdapter - 流式消息 (typing, chunks) │ │
│ │ ChannelPairingAdapter - 设备配对 (QR 码,OAuth) │ │
│ │ ChannelSecurityAdapter - 安全策略 (dmPolicy, allowlist) │ │
│ │ ChannelMentionAdapter - 提及处理 (@user, strip mentions) │ │
│ │ ChannelHeartbeatAdapter - 心跳状态 (presence, health) │ │
│ │ ChannelStatusAdapter - 状态查询 (connected, lastSeen) │ │
│ │ ChannelOutboundAdapter - 出站消息 (send, edit, delete, react) │ │
│ │ ChannelGatewayAdapter - Gateway 通信 (WebSocket 推送) │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ 【通道能力声明】(ChannelCapabilities) │
│ { │
│ chatTypes: ["direct", "group", "thread"], │
│ polls?: boolean, // 投票支持 │
│ reactions?: boolean, // 表情反应 │
│ edit?: boolean, // 消息编辑 │
│ unsend?: boolean, // 消息撤回 │
│ reply?: boolean, // 回复链 │
│ effects?: boolean, // 消息特效 │
│ groupManagement?: boolean,// 群组管理 │
│ threads?: boolean, // 线程支持 │
│ media?: boolean, // 媒体文件 │
│ nativeCommands?: boolean, // 原生命令 │
│ blockStreaming?: boolean // 流式消息块合并 │
│ } │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
内置通道列表
| 通道 | 协议/SDK | 认证方式 | 多账号 | 群组 | 线程 | 源码路径 |
|---|---|---|---|---|---|---|
| Baileys (Web) | QR 码配对 | ✅ | ✅ | ❌ | channels/plugins/whatsapp/ | |
| Telegram | grammY (Bot API) | Bot Token | ✅ | ✅ | ✅ | channels/plugins/telegram/ |
| Discord | Discord.js | Bot Token | ✅ | ✅ | ✅ | channels/plugins/discord/ |
| iMessage | BlueBubbles API | API Key | ❌ | ✅ | ✅ | channels/plugins/imessage/ |
| Signal | signald (CLI) | 本地 Socket | ✅ | ✅ | ❌ | channels/plugins/signal/ |
| Slack | Slack SDK | Bot Token | ✅ | ✅ | ✅ | channels/plugins/slack/ |
| Feishu | WebSocket | App ID/Secret | ✅ | ✅ | ✅ | channels/plugins/feishu/ |
| Google Chat | Workspace API | OAuth 2.0 | ✅ | ✅ | ✅ | channels/plugins/googlechat/ |
| IRC | irc-framework | Server/Pass | ✅ | ✅ | ❌ | channels/plugins/irc/ |
通道配置 Schema(基于 zod-schema)
// 通道配置基础结构
type ChannelConfig<T = any> = {
enabled: boolean; // 是否启用
accounts: Record<string, T>; // 多账号配置
dmPolicy?: "pairing" | "allowlist" | "open" | "deny";
allowFrom?: string[]; // DM 允许列表
groups?: {
[groupId: string]: {
allow?: boolean;
requireMention?: boolean;
allowUnmentionedGroups?: boolean;
};
};
heartbeatVisibility?: {
showOk?: boolean; // 显示正常状态
showAlerts?: boolean; // 显示告警
useIndicator?: boolean; // 使用指示器
};
};
// WhatsApp 账号配置
type WhatsAppAccountConfig = {
// 认证信息存储在 ~/.openclaw/credentials/whatsapp/<accountId>/
// 无需在配置文件中明文存储
};
// Telegram 账号配置
type TelegramAccountConfig = {
botToken?: string; // 或使用环境变量 TELEGRAM_BOT_TOKEN
dmPolicy?: "pairing" | "allowlist" | "open";
allowFrom?: string[];
};
// Feishu 账号配置
type FeishuAccountConfig = {
appId?: string; // 或使用环境变量 FEISHU_APP_ID_<accountId>
appSecret?: string; // 或使用环境变量 FEISHU_APP_SECRET_<accountId>
connectionMode?: "websocket" | "polling";
};
// Discord 账号配置
type DiscordAccountConfig = {
botToken?: string; // 或使用环境变量 DISCORD_BOT_TOKEN
guilds?: {
[guildId: string]: {
allow?: boolean;
channels?: string[];
roles?: string[];
};
};
};
完整配置示例
{
channels: {
// ==================== WhatsApp ====================
whatsapp: {
enabled: true,
dmPolicy: "pairing", // pairing | allowlist | open | deny
allowFrom: ["+8613800138001"], // 仅当 dmPolicy=allowlist 时生效
groups: {
"*": {
requireMention: true, // 群组中需要 @ 提及
allowUnmentionedGroups: false,// 禁止未提及的群组消息
},
"120363xxx@g.us": { // 特定群组配置
allow: true,
requireMention: false, // 此群组无需提及
},
},
accounts: {
personal: {}, // 认证信息在 ~/.openclaw/credentials/whatsapp/personal/
biz: {}, // 多账号支持
},
},
// ==================== Telegram ====================
telegram: {
enabled: true,
dmPolicy: "allowlist",
allowFrom: ["@username", "123456789"], // 支持用户名和 ID
groups: {
"-1001234567890": {
allow: true,
requireMention: true,
},
},
accounts: {
default: {
// botToken 可从环境变量读取:TELEGRAM_BOT_TOKEN
},
},
},
// ==================== Discord ====================
discord: {
enabled: true,
guilds: {
"123456789": { // 服务器 ID
allow: true,
channels: ["987654321"], // 允许的频道 ID 列表
roles: ["admin", "mod"], // 允许的角色
},
},
accounts: {
default: {
// botToken 可从环境变量读取:DISCORD_BOT_TOKEN
},
},
},
// ==================== Feishu (飞书) ====================
feishu: {
enabled: true,
connectionMode: "websocket", // websocket | polling
dmPolicy: "open",
groups: {
"oc_xxxxx": {
allow: true,
requireMention: true,
},
},
accounts: {
lead: {
// appId/appSecret 可从环境变量读取:
// FEISHU_APP_ID_lead, FEISHU_APP_SECRET_lead
},
voc: {},
geo: {},
},
},
// ==================== iMessage (BlueBubbles) ====================
imessage: {
enabled: true,
service: "imessage", // imessage | sms | auto
dmPolicy: "open",
cliPath: "/Applications/BlueBubbles.app/Contents/Resources/cli",
dbPath: "~/Library/Messages/chat.db",
accounts: {
default: {
// API Key 存储在 ~/.openclaw/credentials/imessage/default/
},
},
},
// ==================== Signal ====================
signal: {
enabled: true,
dmPolicy: "allowlist",
allowFrom: ["+8613800138001"],
cliPath: "/usr/local/bin/signald",
socketPath: "/var/run/signald/signald.sock",
accounts: {
default: {
// 号码信息存储在 ~/.openclaw/credentials/signal/default/
},
},
},
},
// ==================== 全局通道设置 ====================
messages: {
groupChat: {
mentionPatterns: ["@openclaw", "@bot"], // 提及模式
requireMention: true, // 群组中必须提及
},
},
}
通道认证管理
认证文件存储位置:
~/.openclaw/credentials/
├── whatsapp/
│ ├── personal/
│ │ ├── web-auth.json # WhatsApp Web 认证
│ │ └── meta.json # 账号元数据
│ └── biz/
│ └── ...
├── telegram/
│ ├── default/
│ │ └── token.txt # Bot Token
│ └── ...
├── feishu/
│ ├── lead/
│ │ ├── app-id.txt
│ │ └── app-secret.txt
│ └── ...
├── discord/
│ └── default/
│ └── token.txt
└── ...
认证方式:
| 通道 | 认证流程 | 凭证刷新 |
|---|---|---|
| 扫码配对 → 保存 web-auth.json | 自动刷新 (Baileys) | |
| Telegram | 配置 Bot Token | 无需刷新 |
| Discord | 配置 Bot Token | 无需刷新 |
| Feishu | 配置 App ID/Secret → 获取 access_token | 自动刷新 (2 小时) |
| iMessage | BlueBubbles API Key | 手动更新 |
| Signal | signald 注册 → 验证码 | 长期有效 |
通道诊断命令
# 查看所有通道状态
openclaw channels status
# 查看详细状态 (含连接信息)
openclaw channels status --verbose
# 主动探测连接
openclaw channels status --probe
# 查看特定通道
openclaw channels status --channel whatsapp
# 重新登录 (扫码)
openclaw channels login --channel whatsapp --force
# 查看通道日志
openclaw logs --channel whatsapp --follow
# 通道诊断
openclaw doctor --check channels
通道插件开发
最小插件结构:
// channels/plugins/myplugin/index.ts
import type { ChannelPlugin } from "@openclaw/plugin-sdk";
export const myPlugin: ChannelPlugin = {
name: "myplugin",
meta: {
id: "myplugin",
label: "My Plugin",
blurb: "Custom channel plugin",
},
adapters: {
messaging: {
async startInbound(ctx) {
// 启动入站消息监听
},
async sendOutbound(ctx, msg) {
// 发送出站消息
},
},
pairing: {
async startPairing(ctx) {
// 启动配对流程
return { qrCode: "data:image/png;base64,..." };
},
},
},
capabilities: {
chatTypes: ["direct", "group"],
media: true,
reactions: false,
},
};
3.2 会话管理
会话键设计
# 单 Agent 模式
sessionKey = "agent:main:<mainKey>"
# 多 Agent 模式
sessionKey = "agent:<agentId>:<mainKey>"
# 群组会话
sessionKey = "agent:<agentId>:group:<groupId>"
# mainKey 生成规则
mainKey = hash(channel + accountId + peerId)
# 示例:mainKey = "whatsapp:personal:+8613800138001" → sha256 → "a1b2c3..."
会话存储结构
实际存储位置:
~/.openclaw/agents/<agentId>/sessions/
├── sessions.json # 会话索引 store(所有会话元数据)
├── <sessionId>.jsonl # 会话 1 的完整对话记录
├── <sessionId>.jsonl.reset.<timestamp> # 重置备份
├── <sessionId>.jsonl.deleted.<timestamp># 删除备份
└── ...
目录结构示例 (实际生产环境):
~/.openclaw/agents/main/sessions/
├── sessions.json # 1.1MB, 会话索引
├── c58ff4a6-eacf-4a40-b84a-367167d0d89e.jsonl # webchat 会话
├── 9a537eaa-f82b-4778-b275-f5dc19bdc549.jsonl # cron 任务会话
├── 0ef4257f-6200-4a7f-a3ad-7abb241b6473.jsonl # 大文件会话 (646KB)
├── 178b8546-1f19-4ec3-aefc-6835b5ffaf8b.jsonl # 大文件会话 (1.2MB)
├── 9cc771c8-f58d-40d3-ac02-b211dd2bb73.jsonl.deleted.2026-03-01T04-23-24.654Z
└── ...
sessions.json 结构 (会话索引 store):
{
"agent:main:main": {
"sessionId": "c58ff4a6-eacf-4a40-b84a-367167d0d89e",
"updatedAt": 1772505137134,
"systemSent": true,
"abortedLastRun": false,
"chatType": "direct",
"deliveryContext": {
"channel": "webchat"
},
"lastChannel": "webchat",
"origin": {
"provider": "webchat",
"surface": "webchat",
"chatType": "direct"
},
"sessionFile": "/Users/[username]/.openclaw/agents/main/sessions/c58ff4a6-eacf-4a40-b84a-367167d0d89e.jsonl",
"compactionCount": 0,
"skillsSnapshot": {
"prompt": "...",
"skills": [{"name": "feishu-doc", "primaryEnv": "..."}]
},
"modelOverride": "bailian/qwen3.5-plus",
"thinkingLevel": "off",
"ttsAuto": "on",
"queueMode": "steer",
"groupActivation": "mention"
},
"agent:main:feishu:direct:ou_e4de245160a1f9f1f73eb55b3bc53968": {
"sessionId": "...",
"updatedAt": 1772505137134,
"chatType": "direct",
"deliveryContext": {
"channel": "feishu"
},
"lastChannel": "feishu",
"lastAccountId": "default",
"origin": {
"provider": "feishu",
"surface": "feishu",
"chatType": "direct",
"from": "ou_e4de245160a1f9f1f73eb55b3bc53968"
},
"sessionFile": "...",
...
}
}
SessionEntry 完整字段 (TypeScript 定义):
type SessionEntry = {
// 基础标识
sessionId: string; // UUID v4
updatedAt: number; // 最后更新时间戳 (ms)
sessionFile?: string; // JSONL 文件绝对路径
// 会话来源
chatType?: "direct" | "group" | "thread";
origin?: {
provider?: string; // "webchat" | "whatsapp" | "feishu" | ...
surface?: string; // 表面类型
chatType?: string;
from?: string; // 发送者 ID
to?: string; // 接收者 ID
accountId?: string; // 账号 ID
threadId?: string | number; // 线程 ID
};
deliveryContext?: {
channel: string; // 通道类型
};
lastChannel?: string; // 最后使用的通道
lastTo?: string; // 最后发送目标
lastAccountId?: string; // 最后使用的账号
lastThreadId?: string | number; // 最后的线程 ID
// 会话状态
systemSent?: boolean; // 是否已发送系统消息
abortedLastRun?: boolean; // 上次运行是否中止
spawnedBy?: string; // 父会话键 (subagent 场景)
spawnDepth?: number; // subagent 深度 (0=main, 1=sub, 2=sub-sub)
// 模型配置
modelOverride?: string; // 模型覆盖 (如 "bailian/qwen3.5-plus")
providerOverride?: string; // Provider 覆盖
authProfileOverride?: string; // 认证配置覆盖
thinkingLevel?: string; // 思考级别 ("on" | "off")
reasoningLevel?: string; // 推理级别
verboseLevel?: string; // 详细级别
elevatedLevel?: string; // 提权级别
// Token 使用统计
inputTokens?: number;
outputTokens?: number;
totalTokens?: number;
totalTokensFresh?: boolean; // totalTokens 是否为最新
contextTokens?: number; // 上下文 token 数
compactionCount?: number; // 压缩次数
memoryFlushAt?: number; // 记忆刷新点
memoryFlushCompactionCount?: number;
// TTS 配置
ttsAuto?: TtsAutoMode; // TTS 自动模式
// 队列配置
queueMode?: "steer" | "followup" | "collect" | "queue" | "interrupt";
queueDebounceMs?: number;
queueCap?: number;
queueDrop?: "old" | "new" | "summarize";
// 群组配置
groupActivation?: "mention" | "always";
groupActivationNeedsSystemIntro?: boolean;
// 技能快照
skillsSnapshot?: {
prompt: string;
skills: Array<{name: string; primaryEnv?: string}>;
skillFilter?: string[];
version?: number;
};
// 系统提示词报告
systemPromptReport?: SessionSystemPromptReport;
// 心跳 (用于抑制重复通知)
lastHeartbeatText?: string;
lastHeartbeatSentAt?: number;
// 其他
label?: string;
displayName?: string;
channel?: string;
groupId?: string;
subject?: string;
cliSessionIds?: Record<string, string>;
claudeCliSessionId?: string;
};
JSONL 文件格式 (每行一个事件):
{"type":"session","version":3,"id":"9a537eaa-f82b-4778-b275-f5dc19bdc549","timestamp":"2026-03-02T04:20:00.188Z","cwd":"/Users/[username]/.openclaw/workspace"}
{"type":"model_change","id":"6a59d487","parentId":null,"timestamp":"2026-03-02T04:20:00.201Z","provider":"bailian","modelId":"qwen3.5-plus"}
{"type":"thinking_level_change","id":"9922a098","parentId":"6a59d487","timestamp":"2026-03-02T04:20:00.201Z","thinkingLevel":"off"}
{"type":"custom","customType":"model-snapshot","data":{"timestamp":1772425200204,"provider":"bailian","modelApi":"openai-completions","modelId":"qwen3.5-plus"},"id":"904547e9","parentId":"9922a098","timestamp":"2026-03-02T04:20:00.204Z"}
{"type":"message","id":"b2042f73","parentId":"904547e9","timestamp":"2026-03-02T04:20:00.208Z","message":{"role":"user","content":[{"type":"text","text":"[cron:xxx 午餐提醒] 午餐时间到啦!"}],"timestamp":1772425200207}}
{"type":"message","id":"c3153g84","parentId":"b2042f73","timestamp":"2026-03-02T04:20:05.123Z","message":{"role":"assistant","content":[{"type":"text","text":"好的,正在发送午餐提醒..."}],"timestamp":1772425205123}}
{"type":"tool_call","id":"d4264h95","parentId":"c3153g84","timestamp":"2026-03-02T04:20:05.456Z","tool":{"name":"message","args":{"action":"send","to":"ou_xxx","message":"午餐时间到啦!"}}}
{"type":"tool_result","id":"e5375i06","parentId":"d4264h95","timestamp":"2026-03-02T04:20:06.789Z","result":{"ok":true,"messageId":"msg_xxx"}}
事件类型说明:
| 类型 | 说明 | 关键字段 |
|---|---|---|
session | 会话开始 | version, cwd, timestamp |
model_change | 模型切换 | provider, modelId |
thinking_level_change | 思考级别变更 | thinkingLevel |
custom | 自定义事件 | customType, data |
message | 用户/助手消息 | message.role, message.content |
tool_call | 工具调用 | tool.name, tool.args |
tool_result | 工具返回结果 | result |
token_usage | Token 使用统计 | inputTokens, outputTokens |
compaction | 会话压缩 | summary, compressedCount |
会话键生成规则 (源码: routing/session-key.ts):
// ========== DM 会话 (5 种 dmScope 模式) ==========
// 模式 1: per-account-channel-peer (最精确)
sessionKey = `agent:${agentId}:${channel}:${accountId}:direct:${peerId}`
// 示例:agent:main:feishu:default:direct:ou_e4de245160a1f9f1f73eb55b3bc53968
// 模式 2: per-channel-peer (跨账号合并)
sessionKey = `agent:${agentId}:${channel}:direct:${peerId}`
// 示例:agent:main:whatsapp:direct:+8613800138001
// 模式 3: per-peer (跨通道合并)
sessionKey = `agent:${agentId}:direct:${peerId}`
// 示例:agent:main:direct:+8613800138001
// 模式 4: main (主会话模式)
sessionKey = `agent:${agentId}:main`
// 模式 5: identityLinks (跨账号身份关联)
// identityLinks: {"ou_xxx": ["+8613800138001"]}
sessionKey = `agent:${agentId}:${channel}:${mainAccountId}:direct:${mainPeerId}`
// ========== 群组/线程/特殊会话 ==========
sessionKey = `agent:${agentId}:${channel}:${peerKind}:${peerId}` // 群组
sessionKey = `${baseSessionKey}:thread:${threadId}` // 线程
sessionKey = `agent:${agentId}:cron:${cronId}:run:${runId}` // Cron
sessionKey = `agent:${agentId}:subagent:${depth}:${sessionId}` // Subagent
mainSessionKey (用于折叠直接聊天):
// DM 会话:返回完整 sessionKey
// 群组/线程:返回 `agent:${agentId}:${channel}:${accountId}` (不带 peer)
会话维护策略:
// 配置位置:openclaw.json -> session.maintenance
{
session: {
maintenance: {
mode: "warn" | "enforce", // warn=仅警告,enforce=强制清理
pruneAfterMs: 2592000000, // 30 天后清理
maxEntries: 1000, // 最多 1000 个会话
rotateBytes: 10485760, // 10MB 触发轮转
}
}
}
// 自动维护操作:
// 1. pruneStaleEntries: 删除超过 pruneAfterMs 的旧会话
// 2. capEntryCount: 限制会话数量不超过 maxEntries
// 3. rotateSessionFile: sessions.json 超过 rotateBytes 时轮转备份
备份与恢复:
# 会话文件自动备份 (重置时)
<sessionId>.jsonl.reset.<ISO-timestamp>
# 会话文件备份 (删除时)
<sessionId>.jsonl.deleted.<ISO-timestamp>
# 保留策略:保留最近 3 个备份文件
rotateSessionFile() 会自动清理旧的 .bak.* 文件,只保留 3 个最新的
会话压缩 (Compaction) 算法详解
问题: 长对话导致上下文窗口溢出,token 成本激增
解决方案: 三层压缩策略
┌─────────────────────────────────────────────────────────────────────────┐
│ 会话压缩策略 (Compaction Strategy) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 【层 1: 滑动窗口】(Sliding Window) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 保留最近 N 条消息,超出部分标记为可压缩 │ │
│ │ 配置:windowSize = 50 │ │
│ │ │ │
│ │ [msg_1][msg_2]...[msg_100][msg_101]...[msg_150] │ │
│ │ │←────── 可压缩区域 ──────→│←── 保留区域 ──→│ │ │
│ │ ↑ │ │
│ │ cutoff = 100 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ 【层 2: 摘要压缩】(Summary Compression) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 使用 LLM 生成历史对话摘要 │ │
│ │ Prompt: "请总结以下对话的关键信息,包括:1) 用户目标 2) 已完成任务 │ │
│ │ 3) 待办事项 4) 重要上下文。限制在 500 字以内。" │ │
│ │ │ │
│ │ 输出示例: │ │
│ │ "用户正在开发一个跨境电商系统,已完成市场分析和竞品调研,待完成 │ │
│ │ 产品页面 SEO 优化。关键技术栈:Node.js + OpenClaw + 飞书 API。" │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ 【层 3: 记忆提取】(Memory Extraction) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 从对话中提取长期记忆,写入 MEMORY.md │ │
│ │ 提取规则: │ │
│ │ • 用户明确说"记住这个" │ │
│ │ • 重复出现的关键信息 (姓名、偏好、项目) │ │
│ │ • 重要决策和结论 │ │
│ │ │ │
│ │ 示例提取: │ │
│ │ - 用户偏好:图片生成优先使用 DashScope │ │
│ │ - 进行中的项目:专利撰写、跨境电商多 Agent 系统 │ │
│ │ - 技术栈偏好:Node.js > Python, Qwen > GPT │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
压缩触发条件:
function shouldCompact(session) {
const { messageCount, lastCompactionAt, windowSize } = session;
// 条件 1: 消息数超过阈值
if (messageCount > windowSize * 2) return true;
// 条件 2: 距离上次压缩超过 24 小时 且 消息数超过窗口
const hoursSinceCompaction = (Date.now() - lastCompactionAt) / 3600000;
if (hoursSinceCompaction > 24 && messageCount > windowSize) return true;
// 条件 3: token 使用超过模型限制 80%
if (session.tokenUsage.input > getModelLimit() * 0.8) return true;
return false;
}
压缩后消息结构:
{
"id": "compaction_001",
"role": "system",
"content": "[对话摘要] 用户咨询了 OpenClaw 部署问题,已完成 Docker 配置和飞书通道绑定。待完成:多 Agent 路由测试。关键信息:使用 DashScope 模型,偏好 Qwen3.5-Plus。",
"ts": 1709424000000,
"metadata": {
"type": "compaction",
"compressedMessages": 100,
"originalTokenCount": 15000,
"compressedTokenCount": 200
}
}
会话压缩 (Compaction)
问题: 长对话导致上下文窗口溢出
解决方案:
- 滑动窗口: 保留最近 N 条消息
- 摘要压缩: 使用 LLM 生成历史摘要
- 记忆提取: 将关键信息存入 MEMORY.md
{
session: {
windowSize: 50, // 保留最近 50 条消息
compaction: {
enabled: true,
threshold: 100, // 超过 100 条触发压缩
model: "bailian/qwen3.5-plus",
},
},
}
3.3 工具系统
内置工具完整列表
核心工具 (由 Gateway 直接提供):
| 工具名 | 源码路径 | 说明 | 主要参数 |
|---|---|---|---|
read | tools/read.ts | 读取文件内容 | path, offset, limit |
write | tools/write.ts | 写入文件 | path, content |
edit | tools/edit.ts | 精确文本替换 | path, oldText, newText |
exec | tools/exec.ts | 执行 shell 命令 | command, timeout, pty, cwd |
process | tools/process.ts | 管理后台进程 | action, sessionId, data |
browser | tools/browser.ts | 浏览器自动化 | action, url, selector |
web_search | tools/web-search.ts | 网络搜索 | query, count, freshness |
web_fetch | tools/web-fetch.ts | 抓取网页内容 | url, extractMode, maxChars |
canvas | tools/canvas.ts | 画布渲染/快照 | action, url, width, height |
tts | tools/tts.ts | 文本转语音 | text, channel, voice |
message | tools/message.ts | 发送消息 | action, target, message |
nodes | tools/nodes.ts | 节点设备控制 | action, command, params |
memory_search | tools/memory.ts | 搜索长期记忆 | query, maxResults, minScore |
memory_get | tools/memory.ts | 获取记忆片段 | path, from, lines |
feishu_* | tools/feishu/*.ts | 飞书 API 套件 | 见下方详解 |
sessions_* | tools/sessions/*.ts | 会话管理套件 | 见下方详解 |
subagents | tools/subagents.ts | 子代理管理 | action, target, message |
agents_list | tools/agents.ts | 列出可用 Agent | - |
Feishu 工具集 (tools/feishu/):
| 工具 | 说明 | 主要参数 |
|---|---|---|
feishu_doc | 飞书文档操作 | action, doc_token, content |
feishu_wiki | 知识库操作 | action, space_id, node_token |
feishu_drive | 云盘操作 | action, file_token, folder_token |
feishu_bitable_* | 多维表格套件 | app_token, table_id, record_id |
feishu_app_scopes | 查看应用权限 | - |
Sessions 工具集 (tools/sessions/):
| 工具 | 说明 | 主要参数 |
|---|---|---|
sessions_list | 列出会话 | limit, kinds, activeMinutes |
sessions_history | 获取会话历史 | sessionKey, limit, includeTools |
sessions_send | 发送消息到会话 | sessionKey, message, agentId |
sessions_spawn | spawn 新会话 | task, runtime, mode, agentId |
session_status | 查看会话状态 | sessionKey, model |
Agent 工具集 (tools/agents/):
| 工具 | 说明 | 主要参数 |
|---|---|---|
agents_list | 列出可用 Agent | - |
agents_inspect | 检查 Agent 配置 | agentId |
agents_add | 添加新 Agent | id, workspace, model |
工具定义 Schema(基于 TypeBox)
// 工具定义结构 (from @sinclair/typebox)
type AgentTool<T extends TSchema = TSchema, R = unknown> = {
name: string; // 工具名称
description: string; // 工具描述
parameters: T; // TypeBox schema 定义参数
execute: (params: Infer<T>, context: ToolContext) => Promise<R>;
};
// 示例:read 工具定义
const readTool: AgentTool = {
name: "read",
description: "Read the contents of a file",
parameters: Type.Object({
path: Type.String({
description: "Path to the file to read (relative or absolute)",
}),
offset: Type.Optional(Type.Number({
description: "Line number to start reading from (1-indexed)",
})),
limit: Type.Optional(Type.Number({
description: "Maximum number of lines to read",
})),
}),
async execute(params, context) {
const content = await fs.readFile(params.path, "utf-8");
const lines = content.split("\n");
const sliced = lines.slice(
(params.offset || 1) - 1,
params.limit ? params.offset + params.limit : undefined
);
return {
content: sliced.join("\n"),
truncated: params.limit && lines.length > params.limit,
totalLines: lines.length,
};
},
};
// 示例:exec 工具定义
const execTool: AgentTool = {
name: "exec",
description: "Execute shell commands",
parameters: Type.Object({
command: Type.String({
description: "Shell command to execute",
}),
timeout: Type.Optional(Type.Number({
description: "Timeout in seconds",
})),
pty: Type.Optional(Type.Boolean({
description: "Run in a pseudo-terminal (TTY-required CLIs)",
})),
cwd: Type.Optional(Type.String({
description: "Working directory",
})),
env: Type.Optional(Type.Record(Type.String(), Type.String())),
background: Type.Optional(Type.Boolean()),
yieldMs: Type.Optional(Type.Number()),
}),
async execute(params, context) {
const result = await execa(params.command, {
cwd: params.cwd || context.workspace,
timeout: params.timeout ? params.timeout * 1000 : undefined,
pty: params.pty,
env: params.env,
});
return {
stdout: result.stdout,
stderr: result.stderr,
exitCode: result.exitCode,
duration: result.duration,
};
},
};
工具调用协议
LLM → Gateway 工具调用格式:
{
"type": "tool_call",
"id": "tc_abc123",
"name": "read",
"arguments": {
"path": "./config.json"
}
}
Gateway → LLM 工具返回格式:
{
"type": "tool_result",
"toolCallId": "tc_abc123",
"content": "{...}",
"isError": false,
"metadata": {
"duration": 45,
"truncated": false
}
}
工具权限控制(基于源码)
// 工具权限配置 (from zod-schema.agents.d.ts)
type AgentToolsConfig =
| { profile: "full" | "restricted" | "coding" | "none" }
| {
mode: "allowlist";
allow: string[];
}
| {
mode: "denylist";
deny: string[];
restrictions?: {
[toolName: string]: {
allowedCommands?: string[]; // exec 工具专用
deniedCommands?: string[];
sandbox?: boolean;
maxFileSize?: number; // read 工具专用
allowedPaths?: string[];
deniedPaths?: string[];
timeout?: number;
};
};
};
// 权限检查流程 (from tools/permissions.ts)
async function checkToolPermission(agentId: string, toolName: string, args: any) {
const agent = config.agents.list.find(a => a.id === agentId);
const toolsConfig = agent.tools;
// 1. Profile 模式检查
if (toolsConfig.profile === 'full') {
return { allowed: true };
}
if (toolsConfig.profile === 'restricted') {
const restrictedAllow = ['read', 'write', 'edit', 'sessions_list'];
if (restrictedAllow.includes(toolName)) {
return { allowed: true };
}
return { allowed: false, reason: 'restricted profile' };
}
// 2. 白名单模式
if (toolsConfig.mode === 'allowlist') {
if (!toolsConfig.allow.includes(toolName)) {
return { allowed: false, reason: 'not in allowlist' };
}
}
// 3. 黑名单模式
if (toolsConfig.mode === 'denylist') {
if (toolsConfig.deny.includes(toolName)) {
return { allowed: false, reason: 'in denylist' };
}
// 细粒度检查
const restrictions = toolsConfig.restrictions?.[toolName];
if (restrictions) {
if (restrictions.allowedCommands && args.command) {
const cmd = args.command.split(' ')[0];
if (!restrictions.allowedCommands.includes(cmd)) {
return { allowed: false, reason: `command '${cmd}' not allowed` };
}
}
if (restrictions.deniedPaths && args.path) {
if (restrictions.deniedPaths.some(p => args.path.startsWith(p))) {
return { allowed: false, reason: `path '${args.path}' denied` };
}
}
}
}
return { allowed: true };
}
工具沙箱执行
沙箱模式 (from tools/exec.ts):
type ExecSecurityMode = "deny" | "allowlist" | "full";
// 命令白名单
const ALLOWED_COMMANDS = {
deny: [], // 禁止所有命令
allowlist: ["ls", "cat", "pwd", "git"], // 只允许列出的命令
full: null, // 允许所有命令
};
// 沙箱执行流程
async function executeInSandbox(command: string, mode: ExecSecurityMode) {
// 1. 命令白名单检查
const cmd = command.split(' ')[0];
if (mode === "deny") {
throw new Error("Command execution denied");
}
if (mode === "allowlist" && !ALLOWED_COMMANDS.allowlist.includes(cmd)) {
throw new Error(`Command '${cmd}' not in allowlist`);
}
// 2. 危险命令检测
const dangerousPatterns = [
"rm -rf /",
"dd if=/dev/zero",
":(){ :|:& };:",
"chmod -R 777 /",
];
for (const pattern of dangerousPatterns) {
if (command.includes(pattern)) {
throw new Error("Dangerous command detected");
}
}
// 3. 执行命令
const result = await execa(command, {
cwd: workspace,
timeout: 30000,
maxBuffer: 10 * 1024 * 1024,
});
// 4. 输出脱敏
const sanitized = sanitizeOutput(result.stdout);
return {
stdout: sanitized,
stderr: result.stderr,
exitCode: result.exitCode,
};
}
工具结果格式
标准结果格式:
type ToolResult = {
// 文本结果
content?: string;
// 媒体结果
images?: Array<{
path: string;
base64: string;
mimeType: string;
label?: string;
}>;
// 结构化结果
data?: unknown;
// 错误信息
isError?: boolean;
errorMessage?: string;
// 元数据
metadata?: {
duration: number; // 执行耗时 (ms)
truncated?: boolean; // 是否被截断
totalLines?: number; // 总行数
fileSize?: number; // 文件大小 (bytes)
};
};
图片结果辅助函数 (from tools/common.ts):
async function imageResult(params: {
label: string;
path: string;
base64: string;
mimeType: string;
extraText?: string;
details?: Record<string, unknown>;
}): Promise<AgentToolResult> {
return {
content: params.extraText,
images: [{
path: params.path,
base64: params.base64,
mimeType: params.mimeType,
label: params.label,
}],
details: params.details,
};
}
// 从文件生成图片结果
async function imageResultFromFile(params: {
label: string;
path: string;
extraText?: string;
}): Promise<AgentToolResult> {
const buffer = await fs.readFile(path);
const base64 = buffer.toString("base64");
const mimeType = mime.lookup(path) || "image/png";
return imageResult({
label: params.label,
path: params.path,
base64,
mimeType,
extraText: params.extraText,
});
}
工具调用内部流程
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 工具调用执行流程 (Tool Execution Flow) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Step 1: LLM 生成工具调用请求 │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ { │ │
│ │ "name": "read", │ │
│ │ "arguments": { "path": "./config.json" } │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 2: Gateway 验证工具权限 │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ checkToolPermission(agentId, toolName) │ │
│ │ • 检查 allow 列表 (白名单模式) │ │
│ │ • 检查 deny 列表 (黑名单模式) │ │
│ │ • 检查沙箱策略 │ │
│ │ │ │
│ │ if (!allowed) { │ │
│ │ throw new ToolPermissionDenied(toolName); │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 3: 参数验证与沙箱准备 │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ validateToolArgs(toolName, args) │ │
│ │ • 类型检查 (path 必须是 string) │ │
│ │ • 路径安全检查 (禁止访问 /etc/passwd 等) │ │
│ │ • 沙箱环境准备 (Docker 容器/临时目录) │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 4: 执行工具函数 │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ const result = await tools[toolName].execute(args, context); │ │
│ │ │ │
│ │ // 对于 exec 工具,使用子进程执行 │ │
│ │ if (toolName === 'exec') { │ │
│ │ const { stdout, stderr, code } = await execa(command, { │ │
│ │ cwd: workspace, │ │
│ │ timeout: timeoutMs, │ │
│ │ maxBuffer: 10 * 1024 * 1024 │ │
│ │ }); │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 5: 结果处理与返回 │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ • 截断过长输出 (max 50KB / 2000 行) │ │
│ │ • 敏感信息脱敏 (API Key/密码) │ │
│ │ • 返回给 LLM 继续推理 │ │
│ │ │ │
│ │ return { │ │
│ │ success: true, │ │
│ │ content: result, │ │
│ │ metadata: { duration: 123, truncated: false } │ │
│ │ }; │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
工具错误处理与重试
// 工具执行错误分类
const ToolErrorTypes = {
PERMISSION_DENIED: 'permission_denied', // 权限不足
INVALID_ARGS: 'invalid_args', // 参数错误
TIMEOUT: 'timeout', // 超时
NOT_FOUND: 'not_found', // 资源不存在
RATE_LIMITED: 'rate_limited', // 速率限制
INTERNAL_ERROR: 'internal_error', // 内部错误
};
// 重试策略
const retryStrategies = {
// 网络类错误:指数退避重试
network: {
maxRetries: 3,
baseDelay: 1000,
maxDelay: 10000,
retryableErrors: ['TIMEOUT', 'RATE_LIMITED'],
},
// 文件类错误:不重试
filesystem: {
maxRetries: 0,
retryableErrors: [],
},
// API 类错误:有限重试
api: {
maxRetries: 2,
baseDelay: 500,
retryableErrors: ['RATE_LIMITED', 'INTERNAL_ERROR'],
},
};
// 错误处理示例
async function executeToolWithRetry(toolName, args, context) {
const strategy = getRetryStrategy(toolName);
let lastError;
for (let attempt = 0; attempt <= strategy.maxRetries; attempt++) {
try {
return await executeTool(toolName, args, context);
} catch (error) {
lastError = error;
if (!strategy.retryableErrors.includes(error.type)) {
throw error; // 不可重试错误,直接抛出
}
if (attempt < strategy.maxRetries) {
const delay = Math.min(
strategy.baseDelay * Math.pow(2, attempt),
strategy.maxDelay
);
await sleep(delay + Math.random() * 1000); // 添加抖动
}
}
}
throw lastError;
}
工具权限配置详解
{
agents: {
list: [
{
id: "main",
tools: {
// 模式 1: 完整权限 (个人可信环境)
profile: "full",
},
},
{
id: "family",
tools: {
// 模式 2: 白名单 (只允许列出的工具)
mode: "allowlist",
allow: [
"read",
"sessions_list",
"sessions_history",
"web_search",
],
},
},
{
id: "public",
tools: {
// 模式 3: 黑名单 (禁止列出的工具)
mode: "denylist",
deny: [
"exec",
"write",
"edit",
"apply_patch",
"browser",
"message",
],
// 额外限制
restrictions: {
exec: {
allowedCommands: ["ls", "cat", "pwd"], // 只允许安全命令
sandbox: true,
},
read: {
maxFileSize: 1024 * 1024, // 最大 1MB
allowedPaths: ["./**"], // 只读工作区
deniedPaths: ["/etc/**", "~/.ssh/**"],
},
},
},
},
],
},
}
工具权限控制
{
agents: {
list: [
{
id: "personal",
tools: {
profile: "full", // full | restricted | custom
},
},
{
id: "family",
tools: {
allow: ["read", "sessions_list"],
deny: ["exec", "write", "edit", "browser"],
},
},
],
},
}
3.4 技能系统 (Skills)
技能架构
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 技能系统架构 (Skills Architecture) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 【技能来源】 │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 1. Bundled Skills (内置技能) │ │
│ │ 位置:~/.openclaw/skills/ │ │
│ │ 来源:OpenClaw 安装包自带 │ │
│ │ 示例:read, write, exec, browser, web_search, feishu_*, sessions_* │ │
│ │ │ │
│ │ 2. Workspace Skills (工作区技能) │ │
│ │ 位置:~/.openclaw/workspace-<id>/skills/ │ │
│ │ 来源:Agent 专属技能 │ │
│ │ 优先级:高于全局技能 │ │
│ │ │ │
│ │ 3. Plugin Skills (插件技能) │ │
│ │ 位置:由通道插件动态注册 │ │
│ │ 来源:Channel Plugin 提供的 ChannelAgentTool │ │
│ │ 示例:whatsapp_login, discord_actions │ │
│ │ │ │
│ │ 4. Remote Skills (远程技能) │ │
│ │ 位置:动态加载 │ │
│ │ 来源:ClawHub 在线技能市场 │ │
│ │ 安装:clawhub install <skill-name> │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ 【技能加载流程】 │
│ 1. 扫描内置技能目录 → 2. 扫描工作区技能目录 → 3. 加载插件技能 → 4. 生成快照 │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
技能结构
标准技能目录结构:
~/.openclaw/skills/<skill-name>/
├── SKILL.md # 必需:技能描述与触发规则
├── EXTEND.md # 可选:系统提示词扩展
├── TOOLS.md # 可选:工具使用指南
├── scripts/ # 可选:执行脚本
│ ├── main.ts
│ └── ...
├── package.json # 可选:Node.js 依赖
└── assets/ # 可选:资源文件
SKILL.md 标准格式 (基于 frontmatter 解析):
---
skillKey: patent-disclosure-writer
primaryEnv: NODE_ENV=production
emoji: 📝
homepage: https://github.com/xxx/skill
os: [darwin, linux]
requires:
bins: [node, npm]
env: [PATENT_API_KEY]
config: [patent.endpoint]
install:
- kind: node
package: patent-writer
module: patent-writer-cli
---
# 专利交底书撰写技能
## 触发规则
当用户提及以下关键词时自动激活:
- "专利交底书"
- "撰写专利"
- "专利创新点"
- "专利查重"
## 使用说明
...
技能元数据类型定义 (from skills/types.d.ts):
type OpenClawSkillMetadata = {
always?: boolean; // 是否始终激活
skillKey?: string; // 技能唯一标识
primaryEnv?: string; // 主要环境变量
emoji?: string; // 技能图标
homepage?: string; // 项目主页
os?: string[]; // 支持的操作系统
requires?: {
bins?: string[]; // 必需的二进制文件
anyBins?: string[]; // 任一必需的二进制文件
env?: string[]; // 必需的环境变量
config?: string[]; // 必需的配置项
};
install?: SkillInstallSpec[]; // 安装规范
};
type SkillInstallSpec = {
kind: "brew" | "node" | "go" | "uv" | "download";
label?: string;
bins?: string[]; // 安装后可用的命令
formula?: string; // Homebrew formula
package?: string; // npm/pip 包名
url?: string; // 下载 URL
archive?: string; // 压缩包 URL
extract?: boolean; // 是否需要解压
targetDir?: string; // 安装目标目录
};
技能配置 Schema
// 技能配置 (from zod-schema.d.ts)
type SkillsConfig = {
allowBundled?: string[]; // 内置技能白名单
load?: SkillsLoadConfig;
install?: SkillsInstallConfig;
entries?: Record<string, SkillConfig>;
};
type SkillsLoadConfig = {
extraDirs?: string[]; // 额外扫描的技能目录
watch?: boolean; // 监听文件变化
watchDebounceMs?: number; // 监听防抖时间 (ms)
};
type SkillsInstallConfig = {
preferBrew?: boolean; // 优先使用 Homebrew
nodeManager?: "npm" | "pnpm" | "yarn" | "bun";
};
type SkillConfig = {
enabled?: boolean; // 是否启用
apiKey?: string; // 技能 API Key
env?: Record<string, string>; // 环境变量
config?: Record<string, unknown>; // 技能配置
};
技能快照 (Skills Snapshot)
快照结构 (from SessionEntry.skillsSnapshot):
type SkillSnapshot = {
prompt: string; // 技能系统提示词
skills: Array<{
name: string; // 技能名称
primaryEnv?: string; // 主要环境变量
}>;
skillFilter?: string[]; // 技能过滤器 (undefined=无限制)
resolvedSkills?: Skill[]; // 已解析的技能列表
version?: number; // 快照版本
};
技能过滤规则 (from skills/filter.ts):
// 技能 eligibility 检查
function isSkillEligible(skill: SkillEntry, context: SkillEligibilityContext): boolean {
const meta = skill.metadata;
if (!meta) return true;
// 1. 操作系统检查
if (meta.os && !meta.os.includes(process.platform)) {
return false;
}
// 2. 二进制文件检查
if (meta.requires?.bins) {
for (const bin of meta.requires.bins) {
if (!context.remote?.hasBin(bin)) {
return false;
}
}
}
// 3. 环境变量检查
if (meta.requires?.env) {
for (const env of meta.requires.env) {
if (!process.env[env]) {
return false;
}
}
}
// 4. 配置检查
if (meta.requires?.config) {
for (const cfg of meta.requires.config) {
if (!getConfigValue(cfg)) {
return false;
}
}
}
return true;
}
// 技能过滤 (agent 级别)
function filterSkills(skills: SkillEntry[], filter?: string[]): SkillEntry[] {
if (!filter) return skills; // 无过滤,返回全部
return skills.filter(skill => {
// 白名单模式
if (filter.includes(skill.skill.name)) {
return true;
}
// 检查技能别名
if (skill.skill.aliases?.some(alias => filter.includes(alias))) {
return true;
}
return false;
});
}
技能安装与管理
ClawHub CLI 命令:
# 安装技能
clawhub install <skill-name>
clawhub install patent-disclosure-writer
clawhub install baoyu-image-gen
# 查看已安装技能
clawhub list
clawhub list --verbose
# 更新技能
clawhub update <skill-name>
clawhub update --all
# 卸载技能
clawhub uninstall <skill-name>
# 搜索技能
clawhub search <query>
# 发布技能
clawhub publish ./my-skill-folder
技能安装流程:
// 技能安装 (from skills/install.ts)
async function installSkill(spec: SkillInstallSpec): Promise<void> {
switch (spec.kind) {
case "brew":
// Homebrew 安装
await execa("brew", ["install", spec.formula]);
break;
case "node":
// npm/pnpm/yarn/bun 安装
const pkgManager = config.skills.install?.nodeManager || "npm";
await execa(pkgManager, ["install", "-g", spec.package]);
break;
case "go":
// Go 安装
await execa("go", ["install", spec.module]);
break;
case "uv":
// Python uv 安装
await execa("uv", ["pip", "install", spec.package]);
break;
case "download":
// 下载并解压
const response = await fetch(spec.url);
const buffer = await response.arrayBuffer();
if (spec.extract) {
await extractArchive(buffer, spec.targetDir);
} else {
await fs.writeFile(spec.targetDir, buffer);
}
break;
}
// 验证安装
if (spec.bins) {
for (const bin of spec.bins) {
const found = await which(bin);
if (!found) {
throw new Error(`Failed to install: ${bin} not found`);
}
}
}
}
技能调用协议
技能触发规则:
// 技能触发 (from skills/trigger.ts)
type SkillTrigger = {
type: "keyword" | "command" | "auto";
keywords?: string[]; // 关键词列表
command?: string; // 命令前缀 (如 /skill)
auto?: boolean; // 是否自动触发
};
// 技能激活检查
function shouldActivateSkill(message: string, skills: SkillEntry[]): SkillEntry | null {
for (const skill of skills) {
const trigger = skill.skill.trigger;
if (!trigger) continue;
if (trigger.type === "keyword") {
for (const keyword of trigger.keywords || []) {
if (message.toLowerCase().includes(keyword.toLowerCase())) {
return skill;
}
}
}
if (trigger.type === "command") {
if (message.startsWith(trigger.command)) {
return skill;
}
}
if (trigger.auto) {
// 自动触发技能 (基于上下文分析)
if (analyzeContext(message, skill.skill.context)) {
return skill;
}
}
}
return null;
}
技能配置示例
{
skills: {
// 内置技能白名单 (只允许列出的内置技能)
allowBundled: ["read", "write", "exec", "browser", "web_search"],
// 技能加载配置
load: {
// 额外扫描的技能目录
extraDirs: ["~/.custom-skills"],
// 监听文件变化
watch: true,
watchDebounceMs: 500,
},
// 技能安装配置
install: {
preferBrew: true,
nodeManager: "pnpm",
},
// 单个技能配置
entries: {
"patent-disclosure-writer": {
enabled: true,
apiKey: "xxx", // 或使用环境变量 PATENT_API_KEY
env: {
"PATENT_ENDPOINT": "https://api.patent.com",
},
config: {
"maxClaims": 10,
"includeDiagrams": true,
},
},
"baoyu-image-gen": {
enabled: true,
env: {
"DASHSCOPE_API_KEY": "sk-xxx",
"DASHSCOPE_IMAGE_MODEL": "z-image-turbo",
},
},
},
},
}
4. 多 Agent 路由系统
4.1 什么是"一个 Agent"?
Agent = 完全隔离的 AI 运行时实例,包含独立的:
Agent 配置结构 (AgentConfig)
// from config/types.agents.d.ts
type AgentConfig = {
// 基础标识
id: string; // Agent 唯一标识 (如 "main", "voc", "geo")
default?: boolean; // 是否为默认 Agent
name?: string; // 显示名称
workspace?: string; // 工作区路径 (支持 ~ 展开)
agentDir?: string; // Agent 目录 (可选,默认 ~/.openclaw/agents/<id>)
// 模型配置
model?: AgentModelConfig; // 模型配置 (字符串或 {primary, fallbacks})
// 技能配置
skills?: string[]; // 技能白名单 (omit=全部,empty=无)
memorySearch?: MemorySearchConfig;
// 人性化配置
humanDelay?: HumanDelayConfig; // 块回复间的人性化延迟
heartbeat?: HeartbeatConfig; // 心跳配置覆盖
identity?: IdentityConfig; // 身份配置
// 群组配置
groupChat?: GroupChatConfig; // 群组聊天配置
// Subagent 配置
subagents?: {
allowAgents?: string[]; // 允许 spawn 的 Agent ID 列表 ("*"=任意)
model?: string | {primary?: string; fallbacks?: string[]};
};
// 沙箱配置
sandbox?: {
mode?: "off" | "non-main" | "all";
workspaceAccess?: "none" | "ro" | "rw";
sessionToolsVisibility?: "spawned" | "all";
scope?: "session" | "agent" | "shared";
perSession?: boolean; // 遗留别名 (true=session, false=shared)
workspaceRoot?: string;
docker?: SandboxDockerSettings;
browser?: SandboxBrowserSettings;
prune?: SandboxPruneSettings;
};
// 工具配置
tools?: AgentToolsConfig; // 工具权限配置
};
Agent 物理存储结构
~/.openclaw/agents/<agentId>/
├── agent/
└── auth-profiles.json # 独立的认证配置 (Provider API Keys)
└── sessions/
├── sessions.json # 会话索引 (所有会话元数据)
├── <sessionId>.jsonl # 会话 1 的完整对话记录
├── <sessionId>.jsonl.reset.<timestamp>
└── <sessionId>.jsonl.deleted.<timestamp>
└── workspace/ # 独立工作区 (可选,由 workspace 配置指定)
├── SOUL.md # 人设定义
├── AGENTS.md # 工作手册
├── USER.md # 用户信息
├── MEMORY.md # 长期记忆
├── HEARTBEAT.md # 心跳任务
├── TOOLS.md # 工具本地笔记
└── skills/ # Agent 专属技能
Agent 隔离边界
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Agent 隔离边界 (Agent Isolation Boundary) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Agent: main Agent: coding │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ ~/.openclaw/agents/main/ │ ~/.openclaw/agents/coding/ │
│ │ ├── agent/ │ ├── agent/ │
│ │ │ └── auth-profiles.json │ │ └── auth-profiles.json │
│ │ ├── sessions/ │ ├── sessions/ │
│ │ │ └── sessions.json │ │ └── sessions.json │
│ │ └── workspace/ │ └── workspace/ │
│ │ ├── SOUL.md │ ├── SOUL.md │
│ │ ├── MEMORY.md │ ├── MEMORY.md │
│ │ └── skills/ │ └── skills/ │
│ │ │ │
│ │ model: qwen3.5-plus │ model: claude-sonnet-4-5 │
│ │ tools: full │ tools: {allow: ["read","write","exec"]}│
│ │ skills: all │ skills: ["coding-agent","github"] │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
│ 【完全隔离】 │
│ • 会话存储:独立的 sessions.json 和 JSONL 文件 │
│ • 认证配置:独立的 auth-profiles.json (API Keys) │
│ • 记忆系统:独立的 MEMORY.md │
│ • 技能系统:可配置不同的技能白名单 │
│ • 模型配置:可独立配置 primary/fallbacks │
│ • 工具权限:可独立配置 allowlist/denylist │
│ • 沙箱设置:可独立配置 Docker/浏览器沙箱 │
│ │
│ 【共享资源】 │
│ • Gateway 进程 (单一入口) │
│ • 通道插件 (Channels) - 通过路由分发到不同 Agent │
│ • 全局技能 (~/.openclaw/skills/) - 除非被 skills 白名单过滤 │
│ • 模型 Provider 配置 (auth.profiles) │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Agent 配置示例
{
agents: {
// 默认配置 (所有 Agent 继承)
defaults: {
heartbeat: {
enabled: true,
intervalMinutes: 30,
},
humanDelay: {
enabled: true,
minMs: 500,
maxMs: 2000,
},
},
// Agent 列表
list: [
// ==================== 主 Agent ====================
{
id: "main",
default: true,
name: "大助手",
workspace: "~/.openclaw/workspace",
model: "bailian/qwen3.5-plus",
tools: { profile: "full" },
sandbox: {
mode: "non-main", // 非 main Agent 启用沙箱
workspaceAccess: "ro",
},
},
// ==================== 编码 Agent ====================
{
id: "coding",
name: "编码助手",
workspace: "~/.openclaw/workspace-coding",
model: {
primary: "anthropic/claude-sonnet-4-5",
fallbacks: ["bailian/qwen3.5-plus"],
},
skills: ["coding-agent", "github", "oracle"],
tools: {
mode: "allowlist",
allow: ["read", "write", "edit", "exec", "process", "browser"],
restrictions: {
exec: {
allowedCommands: ["npm", "pnpm", "yarn", "git", "node", "npx"],
sandbox: true,
},
},
},
sandbox: {
mode: "all",
workspaceAccess: "rw",
docker: {
image: "node:20-alpine",
resources: {
memory: "1g",
cpu: "1",
},
},
},
subagents: {
allowAgents: ["*"], // 允许 spawn 任何子 Agent
model: "bailian/glm-5",
},
},
// ==================== 跨境电商多 Agent ====================
{
id: "lead",
name: "大总管",
workspace: "~/.openclaw/workspace-lead",
model: "bailian/qwen3.5-plus",
subagents: {
allowAgents: ["voc", "geo", "reddit", "tiktok"],
},
},
{
id: "voc",
name: "VOC 分析师",
workspace: "~/.openclaw/workspace-voc",
model: "bailian/glm-5",
skills: ["tavily", "baoyu-format-markdown"],
tools: {
allow: ["read", "write", "web_search", "web_fetch", "sessions_send"],
},
},
{
id: "geo",
name: "GEO 优化师",
workspace: "~/.openclaw/workspace-geo",
model: "google/gemini-3-flash",
skills: ["copywriter", "baoyu-format-markdown"],
tools: {
allow: ["read", "write", "sessions_send"],
},
},
],
},
}
4.2 路由规则 (Bindings)
路由配置结构
// from config/types.agents.d.ts
type AgentBinding = {
agentId: string; // 目标 Agent ID
match: {
channel: string; // 通道类型 (whatsapp/telegram/feishu/discord)
accountId?: string; // 账号 ID (可选)
peer?: {
kind: ChatType; // "direct" | "group" | "thread"
id: string; // peer 唯一 ID
};
guildId?: string; // Discord 服务器 ID
teamId?: string; // Slack 团队 ID
roles?: string[]; // Discord 角色 ID 列表
};
};
路由匹配算法 (resolveAgentRoute)
输入参数:
type ResolveAgentRouteInput = {
cfg: OpenClawConfig;
channel: string; // 通道类型
accountId?: string | null; // 账号 ID
peer?: RoutePeer | null; // {kind, id}
parentPeer?: RoutePeer | null; // 父 peer (用于线程继承)
guildId?: string | null; // Discord 服务器 ID
teamId?: string | null; // Slack 团队 ID
memberRoleIds?: string[]; // Discord 成员角色 ID 列表
};
输出结果:
type ResolvedAgentRoute = {
agentId: string; // 匹配到的 Agent ID
channel: string; // 通道类型
accountId: string; // 账号 ID
sessionKey: string; // 会话键 (用于持久化 + 并发)
mainSessionKey: string; // 主会话键 (直接聊天折叠)
matchedBy: // 匹配规则类型
| "binding.peer"
| "binding.peer.parent"
| "binding.guild+roles"
| "binding.guild"
| "binding.team"
| "binding.account"
| "binding.channel"
| "default";
};
匹配优先级 (从高到低):
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 路由匹配优先级 (Routing Priority) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. binding.peer - peer 精确匹配 (最高优先级) │
│ 示例:{channel:"feishu", peer:{kind:"direct", id:"ou_xxx"}} │
│ │
│ 2. binding.peer.parent - 父 peer 匹配 (线程继承) │
│ 场景:线程消息找不到直接匹配时,查找父会话的绑定 │
│ │
│ 3. binding.guild+roles - Discord 服务器 + 角色匹配 │
│ 示例:{channel:"discord", guildId:"123", roles:["admin","mod"]} │
│ │
│ 4. binding.guild - Discord 服务器匹配 │
│ 示例:{channel:"discord", guildId:"123"} │
│ │
│ 5. binding.team - Slack 团队匹配 │
│ 示例:{channel:"slack", teamId:"T123"} │
│ │
│ 6. binding.account - 账号级别匹配 │
│ 示例:{channel:"feishu", accountId:"lead"} │
│ │
│ 7. binding.channel - 通道级别匹配 │
│ 示例:{channel:"feishu"} │
│ │
│ 8. default - 默认 Agent (兜底策略) │
│ 使用 config.agents.defaults 或第一个 Agent │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
匹配流程源码解析 (from routing/resolve-route.ts):
function resolveAgentRoute(input: ResolveAgentRouteInput): ResolvedAgentRoute {
const { cfg, channel, accountId, peer, parentPeer, guildId, teamId, memberRoleIds } = input;
const bindings = listBindings(cfg);
// ========== 1. peer 精确匹配 ==========
if (peer) {
const peerBinding = bindings.find(b =>
b.match.channel === channel &&
b.match.peer?.kind === peer.kind &&
b.match.peer?.id === peer.id
);
if (peerBinding) {
return {
agentId: peerBinding.agentId,
channel,
accountId: accountId || DEFAULT_ACCOUNT_ID,
sessionKey: buildAgentSessionKey({ agentId: peerBinding.agentId, channel, accountId, peer }),
mainSessionKey: buildMainSessionKey({ agentId: peerBinding.agentId, channel, accountId, peer }),
matchedBy: "binding.peer",
};
}
}
// ========== 2. parentPeer 匹配 (线程继承) ==========
if (peer && parentPeer) {
const parentBinding = bindings.find(b =>
b.match.channel === channel &&
b.match.peer?.kind === parentPeer.kind &&
b.match.peer?.id === parentPeer.id
);
if (parentBinding) {
return {
agentId: parentBinding.agentId,
channel,
accountId: accountId || DEFAULT_ACCOUNT_ID,
sessionKey: buildAgentSessionKey({ agentId: parentBinding.agentId, channel, accountId, peer }),
mainSessionKey: buildMainSessionKey({ agentId: parentBinding.agentId, channel, accountId, peer: parentPeer }),
matchedBy: "binding.peer.parent",
};
}
}
// ========== 3. guildId + roles 匹配 (Discord) ==========
if (guildId && memberRoleIds?.length) {
const guildRoleBinding = bindings.find(b =>
b.match.channel === channel &&
b.match.guildId === guildId &&
b.match.roles?.some(role => memberRoleIds.includes(role))
);
if (guildRoleBinding) {
return {
agentId: guildRoleBinding.agentId,
channel,
accountId: accountId || DEFAULT_ACCOUNT_ID,
sessionKey: buildAgentSessionKey({ agentId: guildRoleBinding.agentId, channel, accountId, peer }),
mainSessionKey: buildMainSessionKey({ agentId: guildRoleBinding.agentId, channel, accountId }),
matchedBy: "binding.guild+roles",
};
}
}
// ========== 4. guildId 匹配 ==========
if (guildId) {
const guildBinding = bindings.find(b =>
b.match.channel === channel &&
b.match.guildId === guildId
);
if (guildBinding) {
return {
agentId: guildBinding.agentId,
channel,
accountId: accountId || DEFAULT_ACCOUNT_ID,
sessionKey: buildAgentSessionKey({ agentId: guildBinding.agentId, channel, accountId, peer }),
mainSessionKey: buildMainSessionKey({ agentId: guildBinding.agentId, channel, accountId }),
matchedBy: "binding.guild",
};
}
}
// ========== 5. teamId 匹配 (Slack) ==========
if (teamId) {
const teamBinding = bindings.find(b =>
b.match.channel === channel &&
b.match.teamId === teamId
);
if (teamBinding) {
return {
agentId: teamBinding.agentId,
channel,
accountId: accountId || DEFAULT_ACCOUNT_ID,
sessionKey: buildAgentSessionKey({ agentId: teamBinding.agentId, channel, accountId, peer }),
mainSessionKey: buildMainSessionKey({ agentId: teamBinding.agentId, channel, accountId }),
matchedBy: "binding.team",
};
}
}
// ========== 6. accountId 匹配 ==========
if (accountId) {
const accountBinding = bindings.find(b =>
b.match.channel === channel &&
b.match.accountId === accountId
);
if (accountBinding) {
return {
agentId: accountBinding.agentId,
channel,
accountId,
sessionKey: buildAgentSessionKey({ agentId: accountBinding.agentId, channel, accountId, peer }),
mainSessionKey: buildMainSessionKey({ agentId: accountBinding.agentId, channel, accountId }),
matchedBy: "binding.account",
};
}
}
// ========== 7. channel 匹配 ==========
const channelBinding = bindings.find(b =>
b.match.channel === channel &&
!b.match.accountId &&
!b.match.peer &&
!b.match.guildId &&
!b.match.teamId
);
if (channelBinding) {
return {
agentId: channelBinding.agentId,
channel,
accountId: accountId || DEFAULT_ACCOUNT_ID,
sessionKey: buildAgentSessionKey({ agentId: channelBinding.agentId, channel, accountId, peer }),
mainSessionKey: buildMainSessionKey({ agentId: channelBinding.agentId, channel, accountId }),
matchedBy: "binding.channel",
};
}
// ========== 8. default Agent ==========
const defaultAgent = cfg.agents.list?.find(a => a.default) || cfg.agents.list?.[0];
const defaultAgentId = defaultAgent?.id || "main";
return {
agentId: defaultAgentId,
channel,
accountId: accountId || DEFAULT_ACCOUNT_ID,
sessionKey: buildAgentSessionKey({ agentId: defaultAgentId, channel, accountId, peer }),
mainSessionKey: buildMainSessionKey({ agentId: defaultAgentId, channel, accountId }),
matchedBy: "default",
};
}
路由配置示例解析
示例 1: 多账号飞书路由
{
bindings: [
// 规则 1: lead 账号的消息 → lead Agent
{
agentId: "lead",
match: { channel: "feishu", accountId: "lead" },
priority: 1,
},
// 规则 2: voc 账号的消息 → voc Agent
{
agentId: "voc",
match: { channel: "feishu", accountId: "voc" },
priority: 2,
},
// 规则 3: 其他飞书账号 → 默认 lead Agent
{
agentId: "lead",
match: { channel: "feishu" },
priority: 10, // 低优先级,作为兜底
},
],
}
匹配流程示例:
入站消息: { channel: "feishu", accountId: "voc", peer: {...} }
规则 1 检查:
match.channel = "feishu" ✓
match.accountId = "lead" ✗ (实际是 "voc")
→ 不匹配,跳过
规则 2 检查:
match.channel = "feishu" ✓
match.accountId = "voc" ✓
→ 匹配!路由到 voc Agent
规则 3 检查:
(不会执行,因为已经找到匹配)
示例 2: Discord 角色路由
{
bindings: [
// 管理员角色 → admin Agent
{
agentId: "admin",
match: {
channel: "discord",
guildId: "123456789",
roles: ["admin", "moderator"],
},
priority: 1,
},
// 开发者角色 → dev Agent
{
agentId: "dev",
match: {
channel: "discord",
guildId: "123456789",
roles: ["developer"],
},
priority: 2,
},
// 普通成员 → default Agent
{
agentId: "default",
match: {
channel: "discord",
guildId: "123456789",
},
priority: 10,
},
],
}
路由调试命令
# 查看当前路由配置
openclaw bindings list
# 测试路由匹配
openclaw bindings test --channel feishu --accountId voc
# 查看路由命中统计
openclaw bindings stats --last 24h
路由命中统计输出:
路由命中统计 (过去 24 小时)
─────────────────────────────────────────────────────────────
Agent 命中次数 占比 平均响应时间
─────────────────────────────────────────────────────────────
lead 1,234 45.2% 1.2s
voc 567 20.8% 0.8s
geo 432 15.8% 0.9s
reddit 289 10.6% 1.5s
tiktok 207 7.6% 2.1s
─────────────────────────────────────────────────────────────
总计 2,729 100.0% 1.1s (平均)
4.3 配置示例
场景 1: WhatsApp + Telegram 双通道
{
agents: {
defaults: {
heartbeat: { enabled: true, intervalMinutes: 30 },
humanDelay: { enabled: true, minMs: 500, maxMs: 2000 },
},
list: [
{
id: "chat",
name: "日常聊天",
workspace: "~/.openclaw/workspace-chat",
model: {
primary: "bailian/glm-5",
fallbacks: ["bailian/qwen3.5-plus"],
},
tools: { profile: "restricted" },
},
{
id: "coding",
name: "编程助手",
workspace: "~/.openclaw/workspace-coding",
model: "anthropic/claude-sonnet-4-5",
skills: ["coding-agent", "github", "oracle"],
tools: {
mode: "allowlist",
allow: ["read", "write", "edit", "exec", "process", "browser"],
},
sandbox: {
mode: "all",
workspaceAccess: "rw",
docker: { image: "node:20-alpine" },
},
},
],
},
bindings: [
{ agentId: "chat", match: { channel: "whatsapp" } },
{ agentId: "coding", match: { channel: "telegram" } },
],
}
场景 2: Discord 角色路由
{
agents: {
list: [
{
id: "admin",
name: "管理员助手",
workspace: "~/.openclaw/workspace-admin",
model: "bailian/qwen3.5-plus",
tools: { profile: "full" },
},
{
id: "dev",
name: "开发助手",
workspace: "~/.openclaw/workspace-dev",
model: "bailian/qwen3.5-plus",
skills: ["coding-agent"],
},
{
id: "default",
name: "普通助手",
workspace: "~/.openclaw/workspace",
model: "bailian/glm-5",
tools: { profile: "restricted" },
},
],
},
bindings: [
// 管理员角色 → admin Agent
{
agentId: "admin",
match: {
channel: "discord",
guildId: "123456789",
roles: ["admin-role-id", "mod-role-id"],
},
},
// 开发者角色 → dev Agent
{
agentId: "dev",
match: {
channel: "discord",
guildId: "123456789",
roles: ["developer-role-id"],
},
},
// 其他成员 → default Agent
{
agentId: "default",
match: {
channel: "discord",
guildId: "123456789",
},
},
],
}
场景 3: 飞书多账号 + 多 Agent
{
agents: {
list: [
{
id: "lead",
name: "大总管",
workspace: "~/.openclaw/workspace-lead",
model: "bailian/qwen3.5-plus",
subagents: {
allowAgents: ["voc", "geo", "reddit", "tiktok"],
model: "bailian/glm-5",
},
},
{
id: "voc",
name: "VOC 分析师",
workspace: "~/.openclaw/workspace-voc",
model: "bailian/glm-5",
tools: { allow: ["read", "write", "web_search", "sessions_send"] },
},
{
id: "geo",
name: "GEO 优化师",
workspace: "~/.openclaw/workspace-geo",
model: "google/gemini-3-flash",
tools: { allow: ["read", "write", "sessions_send"] },
},
],
},
bindings: [
{ agentId: "lead", match: { channel: "feishu", accountId: "lead" } },
{ agentId: "voc", match: { channel: "feishu", accountId: "voc" } },
{ agentId: "geo", match: { channel: "feishu", accountId: "geo" } },
],
channels: {
feishu: {
enabled: true,
connectionMode: "websocket",
accounts: {
lead: {
// appId/appSecret 从环境变量读取:
// FEISHU_APP_ID_lead, FEISHU_APP_SECRET_lead
},
voc: {},
geo: {},
},
},
},
tools: {
agentToAgent: {
enabled: true,
allow: ["lead", "voc", "geo"],
},
},
}
场景 4: 线程会话继承
{
// 飞书群线程消息自动继承父会话的 Agent 路由
// 无需额外配置,由 resolveAgentRoute 自动处理
// matchedBy: "binding.peer.parent"
}
4.4 Agent-to-Agent 通信
通信机制
sessions_send 工具 (from tools/sessions/send.ts):
// 工具定义
const sessionsSendTool: AgentTool = {
name: "sessions_send",
description: "Send a message to another session/agent",
parameters: Type.Object({
sessionKey: Type.Optional(Type.String()), // 目标会话键
label: Type.Optional(Type.String()), // 目标会话标签
agentId: Type.Optional(Type.String()), // 目标 Agent ID
message: Type.String(), // 消息内容
timeoutSeconds: Type.Optional(Type.Number()),
}),
async execute(params, context) {
// 1. 解析目标会话
const target = await resolveTargetSession(params);
// 2. 发送消息到目标会话
const result = await sessionsSend({
sessionKey: target.sessionKey,
message: params.message,
agentId: params.agentId,
timeoutSeconds: params.timeoutSeconds,
});
// 3. 返回结果
return {
success: true,
response: result.message,
sessionKey: target.sessionKey,
};
},
};
sessions_spawn 工具 (from tools/sessions/spawn.ts):
// spawn 新会话 (subagent 或 ACP)
const sessionsSpawnTool: AgentTool = {
name: "sessions_spawn",
description: "Spawn an isolated session",
parameters: Type.Object({
task: Type.String(), // 任务描述
runtime: Type.Union([
Type.Literal("subagent"), // OpenClaw subagent
Type.Literal("acp"), // ACP harness
]),
mode: Type.Union([
Type.Literal("run"), // 一次性运行
Type.Literal("session"), // 持久会话
]),
agentId: Type.Optional(Type.String()), // 目标 Agent ID (ACP 必需)
model: Type.Optional(Type.String()), // 模型覆盖
timeoutSeconds: Type.Optional(Type.Number()),
cleanup: Type.Union([
Type.Literal("delete"), // 完成后删除
Type.Literal("keep"), // 保留会话
]),
}),
};
配置跨 Agent 通信
{
// 方法 1: 全局启用
tools: {
agentToAgent: {
enabled: true,
allow: ["lead", "voc", "geo", "reddit", "tiktok"], // 白名单
},
},
// 方法 2: Agent 级别配置
agents: {
list: [
{
id: "lead",
subagents: {
allowAgents: ["voc", "geo", "reddit", "tiktok"], // 允许 spawn 的 Agent
model: "bailian/glm-5", // 子 Agent 默认模型
},
},
{
id: "voc",
subagents: {
allowAgents: ["*"], // 允许 spawn 任何 Agent
},
},
],
},
}
通信模式
模式 1: 请求 - 响应 (sessions_send)
// Lead Agent 发送请求到 VOC Agent
const result = await sessions_send({
sessionKey: "agent:voc:feishu:default:direct:ou_xxx",
message: "分析露营折叠床市场,输出 VOC 报告",
timeoutSeconds: 300,
});
// 返回结果
{
success: true,
response: "【VOC 分析报告】...",
sessionKey: "agent:voc:...",
}
模式 2: 任务分发 (sessions_spawn)
// spawn 子 Agent 执行任务
await sessions_spawn({
task: "分析露营折叠床市场痛点",
runtime: "subagent",
mode: "run",
agentId: "voc",
timeoutSeconds: 300,
cleanup: "delete",
});
// 子 Agent 完成后自动推送结果
模式 3: 持久会话 (sessions_spawn mode=session)
// 创建持久子会话
await sessions_spawn({
task: "跨境电商营销助手",
runtime: "subagent",
mode: "session",
agentId: "geo",
cleanup: "keep",
});
// 后续可通过 sessionKey 继续对话
await sessions_send({
sessionKey: "agent:geo:subagent:1:abc123",
message: "继续优化 SEO 文章",
});
完整工作流示例
跨境电商多 Agent 协作:
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 跨境电商多 Agent 工作流 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 用户 (@大总管): "分析露营折叠床市场,全渠道铺内容" │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Lead Agent │ 1. 需求理解 │
│ │ (lead) │ 2. 任务拆解 │
│ └────────┬────────┘ │
│ │ │
│ ├─────────────────┬──────────────────┬────────────────┐ │
│ ▼ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ VOC 分析师 │ │ GEO 优化师 │ │ Reddit 专家 │ │ TikTok 编导 │ │
│ │ (voc) │ │ (geo) │ │ (reddit) │ │ (tiktok) │ │
│ │ sessions_ │ │ sessions_ │ │ sessions_ │ │ sessions_ │ │
│ │ send │ │ send │ │ send │ │ send │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ 【并行执行】 │ │
│ • 爬取竞品评价 • 撰写产品博客 • 搜索相关帖子 • 生成视频脚本 │
│ • 提炼用户痛点 • SEO 关键词优化 • 养号互动策略 • AI 生图生视频 │
│ • VOC 报告 • SEO 文章 • 引流方案 • 分镜脚本 │
│ │ │ │ │ │
│ └─────────────────┴─────────────────┴────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Lead Agent │ 汇总结果 │
│ │ (lead) │ 飞书群汇报 │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
代码实现:
// Lead Agent 工作流
async function executeWorkflow(userMessage: string) {
// 1. 并发分发任务
const [vocResult, geoResult, redditResult, tiktokResult] = await Promise.all([
sessions_send({
agentId: "voc",
message: "分析露营折叠床市场痛点,输出 VOC 报告",
timeoutSeconds: 300,
}),
sessions_send({
agentId: "geo",
message: "基于 VOC 数据撰写产品博客,SEO 优化",
timeoutSeconds: 300,
}),
sessions_send({
agentId: "reddit",
message: "寻找露营装备相关帖子,制定互动策略",
timeoutSeconds: 300,
}),
sessions_send({
agentId: "tiktok",
message: "生成露营折叠床短视频脚本和分镜",
timeoutSeconds: 300,
}),
]);
// 2. 汇总结果
const summary = `
【市场分析汇报】露营折叠床
📊 VOC 分析报告
${vocResult.response}
📝 SEO 文章
${geoResult.response}
🎯 Reddit 策略
${redditResult.response}
🎬 TikTok 脚本
${tiktokResult.response}
`;
// 3. 返回用户
return summary;
}
通信限制与安全
{
tools: {
agentToAgent: {
enabled: true,
allow: ["lead", "voc", "geo"], // 白名单
// 禁止的 Agent
deny: ["sandbox", "test"],
// 超时限制
timeoutSeconds: 300,
// 最大并发数
maxConcurrent: 10,
},
},
agents: {
list: [
{
id: "lead",
subagents: {
allowAgents: ["voc", "geo"],
// 禁止 spawn 的 Agent
denyAgents: ["admin"],
// 子 Agent 深度限制
maxDepth: 3,
},
},
],
},
}
5. 部署配置全指南
部署前请确认:
- Node.js 22+ 已安装 (
node --version) - 模型 API Key 已配置 (
.env文件) - 通道凭证已获取 (Bot Token/App ID)
- Gateway 端口未被占用 (
lsof -i :18789) - 防火墙规则已配置 (远程访问场景)
- 备份策略已制定 (生产环境)
5.1 安装方式对比
| 方式 | 适用场景 | 复杂度 | 推荐度 |
|---|---|---|---|
| npm 全局安装 | 个人开发机 | ⭐ | ⭐⭐⭐⭐⭐ |
| Docker | 服务器部署 | ⭐⭐ | ⭐⭐⭐⭐ |
| macOS App | macOS 用户 | ⭐ | ⭐⭐⭐⭐⭐ |
| Systemd | Linux 服务器 | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| Ansible | 批量部署 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
5.2 快速开始 (npm)
# 1. 安装 OpenClaw
npm install -g openclaw@latest
# 2. 运行引导向导
openclaw onboard --install-daemon
# 3. 登录通道
openclaw channels login --channel whatsapp
# 4. 启动 Gateway
openclaw gateway --port 18789
# 5. 访问 Control UI
open http://127.0.0.1:18789
5.3 配置文件详解
配置位置: ~/.openclaw/openclaw.json
配置类型定义: OpenClawConfig (from config/types.openclaw.d.ts)
完整配置 Schema (50+ 配置项)
type OpenClawConfig = {
// ========== 元数据 ==========
meta?: {
lastTouchedVersion?: string; // 最后写入的 OpenClaw 版本
lastTouchedAt?: string; // ISO 时间戳
};
// ========== 认证配置 ==========
auth?: AuthConfig; // 模型 Provider 认证 (API Keys/OAuth)
// ========== 环境变量 ==========
env?: {
shellEnv?: {
enabled?: boolean; // 从登录 shell 导入环境变量
timeoutMs?: number; // 超时 (默认 15000ms)
};
vars?: Record<string, string>; // 内联环境变量
};
// ========== 向导配置 ==========
wizard?: {
lastRunAt?: string;
lastRunVersion?: string;
lastRunCommand?: string;
lastRunMode?: "local" | "remote";
};
// ========== 诊断配置 ==========
diagnostics?: DiagnosticsConfig;
logging?: LoggingConfig;
// ========== 更新配置 ==========
update?: {
channel?: "stable" | "beta" | "dev";
checkOnStart?: boolean;
};
// ========== 浏览器配置 ==========
browser?: BrowserConfig;
// ========== UI 配置 ==========
ui?: {
seamColor?: string; // 强调色 (hex)
assistant?: {
name?: string; // 助手显示名
avatar?: string; // 头像 (emoji/URL/data URI)
};
};
// ========== 技能配置 ==========
skills?: SkillsConfig;
// ========== 插件配置 ==========
plugins?: PluginsConfig;
// ========== 模型配置 ==========
models?: ModelsConfig;
// ========== Node Host 配置 ==========
nodeHost?: NodeHostConfig;
// ========== Agent 配置 ==========
agents?: AgentsConfig; // Agent 列表和默认配置
// ========== 工具配置 ==========
tools?: ToolsConfig; // 工具权限/沙箱/会话工具
// ========== 路由绑定 ==========
bindings?: AgentBinding[]; // 路由规则列表
// ========== 广播配置 ==========
broadcast?: BroadcastConfig;
// ========== 音频配置 ==========
audio?: AudioConfig;
// ========== 消息配置 ==========
messages?: MessagesConfig; // 消息处理/回复/群组策略
// ========== 命令配置 ==========
commands?: CommandsConfig; // 自定义命令
// ========== 审批配置 ==========
approvals?: ApprovalsConfig; // 工具调用审批
// ========== 会话配置 ==========
session?: SessionConfig; // 会话范围/重置/维护
// ========== Web 配置 ==========
web?: WebConfig;
// ========== 通道配置 ==========
channels?: ChannelsConfig; // WhatsApp/Telegram/飞书等
// ========== Cron 配置 ==========
cron?: CronConfig; // 定时任务
// ========== Hooks 配置 ==========
hooks?: HooksConfig; // 内部/外部钩子
// ========== 发现配置 ==========
discovery?: DiscoveryConfig; // mDNS/DNS-SD
// ========== Canvas Host 配置 ==========
canvasHost?: CanvasHostConfig;
// ========== Talk 配置 ==========
talk?: TalkConfig; // ElevenLabs TTS
// ========== Gateway 配置 ==========
gateway?: GatewayConfig; // Gateway 服务器配置
// ========== 内存配置 ==========
memory?: MemoryConfig; // 向量数据库/记忆存储
};
核心配置项详解
1. Agent 配置 (agents):
{
agents: {
// 默认配置 (所有 Agent 继承)
defaults: {
heartbeat: {
enabled: true,
intervalMinutes: 30,
prompt: "检查邮箱、日历、未读消息",
},
humanDelay: {
mode: "natural", // off|natural|custom
minMs: 800,
maxMs: 2500,
},
subagents: {
allowAgents: ["*"], // 允许 spawn 的 Agent
model: "bailian/glm-5",
},
},
// Agent 列表
list: [
{
id: "main", // 必需:Agent 唯一标识
default: true, // 是否为默认 Agent
name: "大助手", // 显示名称
workspace: "~/.openclaw/workspace",
agentDir: "~/.openclaw/agents/main",
model: {
primary: "bailian/qwen3.5-plus",
fallbacks: ["bailian/glm-5"],
},
skills: ["tavily", "baoyu-format-markdown"], // 技能白名单
memorySearch: {
enabled: true,
maxResults: 5,
minScore: 0.6,
},
sandbox: {
mode: "non-main", // off|non-main|all
workspaceAccess: "ro", // none|ro|rw
scope: "session", // session|agent|shared
docker: {
image: "node:20-alpine",
resources: {
memory: "1g",
cpu: "1",
},
},
},
tools: {
profile: "full", // full|restricted|coding|none
mode: "allowlist", // allowlist|denylist
allow: ["read", "write", "exec", "browser"],
restrictions: {
exec: {
allowedCommands: ["npm", "git", "node"],
sandbox: true,
},
},
},
groupChat: {
mentionPatterns: ["@openclaw", "@助手"],
requireMention: true,
},
},
],
},
}
2. 路由绑定 (bindings):
{
bindings: [
// peer 精确匹配 (最高优先级)
{
agentId: "vip",
match: {
channel: "whatsapp",
peer: {
kind: "direct",
id: "+8613800138001",
},
},
},
// Discord 角色路由
{
agentId: "admin",
match: {
channel: "discord",
guildId: "123456789",
roles: ["admin-role-id", "mod-role-id"],
},
},
// 账号级别匹配
{
agentId: "voc",
match: {
channel: "feishu",
accountId: "voc",
},
},
// 通道级别匹配 (兜底)
{
agentId: "main",
match: {
channel: "whatsapp",
},
},
],
}
3. 会话配置 (session):
{
session: {
scope: "per-sender", // per-sender|global
dmScope: "per-channel-peer", // main|per-peer|per-channel-peer|per-account-channel-peer
identityLinks: {
"ou_e4de245160a1f9f1f73eb55b3bc53968": ["+8613800138001", "telegram:123456"],
},
resetTriggers: ["!reset", "/reset"],
idleMinutes: 60,
reset: {
mode: "daily", // daily|idle
atHour: 4, // 本地时间 4:00 重置
idleMinutes: 1440, // 24 小时空闲重置
},
resetByType: {
direct: { mode: "daily", atHour: 4 },
group: { mode: "idle", idleMinutes: 10080 }, // 7 天
thread: { mode: "idle", idleMinutes: 1440 },
},
resetByChannel: {
discord: { mode: "idle", idleMinutes: 10080 },
},
typingMode: "thinking", // never|instant|thinking|message
typingIntervalSeconds: 5,
maintenance: {
prune: {
enabled: true,
maxAgeDays: 30,
maxSessionsPerPeer: 100,
},
cap: {
enabled: true,
maxTotalSessions: 1000,
},
compact: {
enabled: true,
threshold: 200,
retention: 50,
},
},
agentToAgent: {
maxPingPongTurns: 5, // 最大 ping-pong 回合数
},
},
}
4. Gateway 配置 (gateway):
{
gateway: {
bindHost: "127.0.0.1", // 监听地址
port: 18789, // 监听端口
bindMode: "auto", // auto|lan|loopback|custom|tailnet
// TLS 配置
tls: {
enabled: false,
autoGenerate: true,
certPath: "~/.openclaw/gateway.crt",
keyPath: "~/.openclaw/gateway.key",
caPath: "~/.openclaw/ca.crt",
},
// 认证配置
auth: {
mode: "token", // token|password|trusted-proxy
token: "OPENCLAW_GATEWAY_TOKEN",
password: "xxx", // 建议使用环境变量
trustedProxy: {
userHeader: "x-forwarded-user",
requiredHeaders: ["x-forwarded-proto"],
allowUsers: ["admin@example.com"],
},
allowInsecureAuth: false,
dangerouslyDisableDeviceAuth: false,
},
// 控制 UI 配置
controlUi: {
enabled: true,
basePath: "/openclaw",
root: "/opt/homebrew/lib/node_modules/openclaw/dist/control-ui",
allowedOrigins: ["http://localhost:18790"],
},
// 发现配置
discovery: {
wideArea: {
enabled: true,
domain: "openclaw.internal",
},
mdns: {
mode: "minimal", // off|minimal|full
},
},
// Canvas Host
canvasHost: {
enabled: true,
root: "~/.openclaw/workspace/canvas",
port: 18793,
liveReload: true,
},
// Talk 模式 (ElevenLabs TTS)
talk: {
voiceId: "21m00Tcm4TlvDq8ikWAM", // Rachel
voiceAliases: {
"narrator": "21m00Tcm4TlvDq8ikWAM",
"assistant": "EXAVITQu4vr4xnSDxMaL",
},
modelId: "eleven_monolingual_v1",
outputFormat: "mp3_44100_128",
interruptOnSpeech: true,
},
},
}
5. 通道配置 (channels):
{
channels: {
// WhatsApp 配置
whatsapp: {
enabled: true,
connectionMode: "websocket", // websocket|polling
dmPolicy: "pairing", // pairing|allowlist|open|disabled
groups: {
"*": {
requireMention: true,
policy: "open", // open|disabled|allowlist
},
},
accounts: {
default: {
// 认证信息在 ~/.openclaw/credentials/whatsapp/default
// 或使用环境变量:WHATSAPP_DEFAULT_AUTH_TOKEN
},
},
outboundRetry: {
attempts: 3,
minDelayMs: 300,
maxDelayMs: 30000,
jitter: 0.1,
},
},
// Telegram 配置
telegram: {
enabled: true,
accounts: {
default: {
botToken: "TELEGRAM_BOT_TOKEN",
dmPolicy: "pairing",
groups: {
"*": { requireMention: true },
},
},
},
customCommands: [
{
command: "start",
reply: "你好!我是 OpenClaw 助手。",
},
],
},
// 飞书配置
feishu: {
enabled: true,
connectionMode: "websocket",
requireMention: false,
domain: "feishu",
accounts: {
lead: {
appId: "cli_xxx",
appSecret: "xxx",
// 或使用环境变量:FEISHU_LEAD_APP_ID, FEISHU_LEAD_APP_SECRET
},
voc: {},
geo: {},
},
},
// Discord 配置
discord: {
enabled: true,
botToken: "DISCORD_BOT_TOKEN",
intents: [
"Guilds",
"GuildMessages",
"MessageContent",
"GuildMessageTyping",
],
guilds: {
"*": {
requireMention: true,
policy: "open",
},
},
},
// Slack 配置
slack: {
enabled: true,
botToken: "SLACK_BOT_TOKEN",
signingSecret: "SLACK_SIGNING_SECRET",
channels: {
"*": { requireMention: true },
},
},
},
}
6. 模型配置 (models):
{
models: {
default: "bailian/qwen3.5-plus",
fallbacks: ["bailian/glm-5", "google/gemini-3-flash"],
providers: {
bailian: {
apiKey: "DASHSCOPE_API_KEY",
baseURL: "https://dashscope.aliyuncs.com",
timeoutMs: 60000,
retry: {
attempts: 3,
minDelayMs: 1000,
maxDelayMs: 30000,
},
},
anthropic: {
apiKey: "ANTHROPIC_API_KEY",
baseURL: "https://api.anthropic.com",
},
google: {
apiKey: "GOOGLE_API_KEY",
},
openai: {
apiKey: "OPENAI_API_KEY",
baseURL: "https://api.openai.com/v1",
},
},
// 模型别名
aliases: {
"qwen": "bailian/qwen3.5-plus",
"claude": "anthropic/claude-sonnet-4-5",
"gemini": "google/gemini-3-flash",
},
// 模型限制
limits: {
maxContextTokens: 128000,
maxOutputTokens: 8192,
maxImageSize: 20 * 1024 * 1024, // 20MB
},
},
}
7. 工具配置 (tools):
{
tools: {
// Agent-to-Agent 通信
agentToAgent: {
enabled: true,
allow: ["lead", "voc", "geo", "reddit", "tiktok"],
deny: ["sandbox", "test"],
timeoutSeconds: 300,
maxConcurrent: 10,
},
// 会话工具策略
sessionTools: {
default: "allow",
rules: [
{
action: "deny",
match: {
keyPrefix: "agent:sandbox:",
},
},
],
},
// 工具权限
permissions: {
default: "restricted",
byAgent: {
main: "full",
coding: "coding",
voc: "restricted",
},
},
// 沙箱配置
sandbox: {
mode: "non-main",
workspaceAccess: "ro",
docker: {
image: "node:20-alpine",
network: "bridge",
resources: {
memory: "2g",
cpu: "2",
},
},
browser: {
enabled: true,
headless: true,
},
prune: {
enabled: true,
intervalHours: 24,
maxAgeHours: 168,
},
},
},
}
8. Hooks 配置 (hooks):
{
hooks: {
// 内部钩子
internal: {
enabled: true,
entries: {
"boot-md": { enabled: true },
"command-logger": { enabled: true },
"session-memory": { enabled: true },
"heartbeat-runner": { enabled: true },
"diagnostic-events": { enabled: true },
},
},
// 外部钩子
external: {
enabled: false,
entries: {
"slack-notify": {
enabled: true,
url: "https://hooks.slack.com/services/xxx",
events: ["session.start", "tool.error"],
},
},
},
},
}
9. Cron 配置 (cron):
{
cron: {
enabled: true,
jobs: [
{
id: "daily-standup",
schedule: "0 9 * * 1-5", // 工作日 9:00
agentId: "main",
target: "user:ou_xxx",
message: "早安!今日工作计划是什么?",
delivery: "system",
},
{
id: "lunch-reminder",
schedule: "0 12 * * *",
agentId: "main",
target: "group:cn_xxx",
message: "午餐时间到!记得休息。",
},
],
},
}
10. 技能配置 (skills):
{
skills: {
// 技能来源
sources: {
bundled: "~/.openclaw/skills",
workspace: "~/.openclaw/workspace-*/skills",
plugin: true,
remote: {
enabled: true,
registry: "https://clawhub.com",
},
},
// 技能白名单
allow: ["tavily", "baoyu-*", "coding-agent"],
// 技能黑名单
deny: ["dangerous-skill"],
// 技能调用策略
invocation: {
default: "direct",
bySkill: {
"exec-heavy": "subagent",
"browser-automation": "subagent",
},
},
// ClawHub 配置
clawhub: {
autoUpdate: true,
updateIntervalHours: 24,
},
},
}
5.4 环境变量配置
源码位置: config/env-vars.d.ts, config/env-substitution.d.ts
环境变量加载顺序:
1. 进程环境变量 (process.env)
2. config.env.vars (openclaw.json 内联定义)
3. config.env.shellEnv (登录 shell 导入,可选)
4. ~/.openclaw/.env 文件 (dotenv 格式)
5. 系统环境变量
完整环境变量列表
# ==================== 模型 Provider ====================
# 阿里云通义千问 (DashScope)
DASHSCOPE_API_KEY=sk-xxx
DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com
# Anthropic Claude
ANTHROPIC_API_KEY=sk-ant-xxx
ANTHROPIC_BASE_URL=https://api.anthropic.com
# OpenAI
OPENAI_API_KEY=sk-xxx
OPENAI_BASE_URL=https://api.openai.com/v1
# Google Gemini
GOOGLE_API_KEY=xxx
GOOGLE_BASE_URL=https://generativelanguage.googleapis.com
# Ollama (本地)
OLLAMA_BASE_URL=http://localhost:11434
# ==================== Gateway 认证 ====================
OPENCLAW_GATEWAY_TOKEN=your-secret-token
# ==================== 通道凭证 ====================
# WhatsApp (多账号)
WHATSAPP_DEFAULT_AUTH_TOKEN=xxx
WHATSAPP_LEAD_AUTH_TOKEN=xxx
# Telegram
TELEGRAM_BOT_TOKEN=123456:ABC...
TELEGRAM_DEFAULT_BOT_TOKEN=xxx
# 飞书 (多账号)
FEISHU_LEAD_APP_ID=cli_xxx
FEISHU_LEAD_APP_SECRET=xxx
FEISHU_VOC_APP_ID=cli_xxx
FEISHU_VOC_APP_SECRET=xxx
# Discord
DISCORD_BOT_TOKEN=xxx
# Slack
SLACK_BOT_TOKEN=xoxb-xxx
SLACK_SIGNING_SECRET=xxx
# ==================== 浏览器/沙箱 ====================
# Chrome CDP (可选)
OPENCLAW_CHROME_CDP_URL=ws://localhost:9222
# Docker (可选)
OPENCLAW_DOCKER_HOST=unix:///var/run/docker.sock
# ==================== ElevenLabs TTS ====================
ELEVENLABS_API_KEY=xxx
ELEVENLABS_VOICE_ID=21m00Tcm4TlvDq8ikWAM
# ==================== 代理配置 ====================
HTTP_PROXY=http://127.0.0.1:7890
HTTPS_PROXY=http://127.0.0.1:7890
NO_PROXY=localhost,127.0.0.1
# ==================== 诊断/日志 ====================
OPENCLAW_LOG_LEVEL=info # silent|fatal|error|warn|info|debug|trace
OPENCLAW_CONSOLE_LEVEL=info
OPENCLAW_CONSOLE_STYLE=pretty # pretty|compact|json
# OpenTelemetry (可选)
OTEL_ENABLED=true
OTEL_ENDPOINT=http://localhost:4318/v1/traces
OTEL_PROTOCOL=http/protobuf
OTEL_SERVICE_NAME=openclaw-gateway
OTEL_TRACES=true
OTEL_METRICS=true
OTEL_LOGS=false
OTEL_SAMPLE_RATE=1.0
# ==================== 功能开关 ====================
OPENCLAW_BROWSER_ENABLED=true
OPENCLAW_BROWSER_EVALUATE_ENABLED=true
OPENCLAW_SANDBOX_ENABLED=true
OPENCLAW_AGENT_TO_AGENT_ENABLED=true
OPENCLAW_HEARTBEAT_ENABLED=true
OPENCLAW_CRON_ENABLED=true
# ==================== 路径配置 (可选) ====================
OPENCLAW_HOME=~/.openclaw
OPENCLAW_WORKSPACE=~/.openclaw/workspace
OPENCLAW_SKILLS=~/.openclaw/skills
OPENCLAW_AGENTS=~/.openclaw/agents
OPENCLAW_CREDENTIALS=~/.openclaw/credentials
在 openclaw.json 中使用环境变量
{
// 方法 1: ${ENV_VAR} 语法
models: {
providers: {
bailian: {
apiKey: "${DASHSCOPE_API_KEY}",
},
anthropic: {
apiKey: "${ANTHROPIC_API_KEY}",
},
},
},
// 方法 2: 直接引用 (自动查找环境变量)
gateway: {
auth: {
token: "${OPENCLAW_GATEWAY_TOKEN}",
},
},
// 方法 3: env.vars 内联定义
env: {
vars: {
CUSTOM_API_KEY: "xxx",
FEATURE_FLAG: "enabled",
},
// 从登录 shell 导入环境变量
shellEnv: {
enabled: true,
timeoutMs: 15000,
},
},
// 方法 4: 通道配置中使用
channels: {
feishu: {
accounts: {
lead: {
appId: "${FEISHU_LEAD_APP_ID}",
appSecret: "${FEISHU_LEAD_APP_SECRET}",
},
},
},
},
}
.env 文件最佳实践
# ~/.openclaw/.env
# ==================== 生产环境 ====================
# 使用强随机 token
OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)
# 使用环境变量管理工具 (如 1Password CLI)
# DASHSCOPE_API_KEY=$(op read "op://Personal/DashScope/credential")
# ==================== 开发环境 ====================
# 使用 .env.development 文件
DASHSCOPE_API_KEY=sk-dev-xxx
OPENCLAW_LOG_LEVEL=debug
# ==================== 多账号管理 ====================
# 为不同飞书账号使用不同前缀
FEISHU_LEAD_APP_ID=cli_lead_xxx
FEISHU_LEAD_APP_SECRET=lead_xxx
FEISHU_VOC_APP_ID=cli_voc_xxx
FEISHU_VOC_APP_SECRET=voc_xxx
FEISHU_GEO_APP_ID=cli_geo_xxx
FEISHU_GEO_APP_SECRET=geo_xxx
环境变量验证
# 检查环境变量是否生效
openclaw config get models.providers.bailian.apiKey
# 验证配置
openclaw config validate
# 查看完整配置 (包含环境变量替换)
openclaw config show --resolved
5.5 Docker 部署
Dockerfile (生产环境)
# ==================== 多阶段构建 ====================
FROM node:22-alpine AS builder
WORKDIR /build
# 安装 OpenClaw
RUN npm install -g openclaw@latest
# ==================== 运行镜像 ====================
FROM node:22-alpine
WORKDIR /app
# 安装运行时依赖
RUN apk add --no-cache \
git \
curl \
ca-certificates \
tzdata \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
# 复制 OpenClaw
COPY --from=builder /usr/local/lib/node_modules/openclaw /usr/local/lib/node_modules/openclaw
COPY --from=builder /usr/local/bin/openclaw /usr/local/bin/openclaw
# 创建数据卷
VOLUME ["/root/.openclaw"]
# 暴露端口
EXPOSE 18789 18790 18793
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:18789/health || exit 1
# 启动命令
ENTRYPOINT ["openclaw", "gateway"]
CMD ["--port", "18789", "--bind-host", "0.0.0.0"]
docker-compose.yml (推荐)
version: '3.8'
services:
openclaw:
image: openclaw:latest
build: .
container_name: openclaw-gateway
restart: unless-stopped
# 端口映射
ports:
- "18789:18789" # Gateway
- "18790:18790" # Control UI (可选)
- "18793:18793" # Canvas Host (可选)
# 数据卷
volumes:
- ~/.openclaw:/root/.openclaw
- /var/run/docker.sock:/var/run/docker.sock # Docker 沙箱支持
# 环境变量
environment:
# 模型 Provider
- DASHSCOPE_API_KEY=${DASHSCOPE_API_KEY}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
# Gateway 认证
- OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN}
# 通道凭证
- WHATSAPP_DEFAULT_AUTH_TOKEN=${WHATSAPP_TOKEN}
- TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
- FEISHU_LEAD_APP_ID=${FEISHU_LEAD_APP_ID}
- FEISHU_LEAD_APP_SECRET=${FEISHU_LEAD_APP_SECRET}
# 代理 (可选)
- HTTP_PROXY=${HTTP_PROXY:-}
- HTTPS_PROXY=${HTTPS_PROXY:-}
# 日志级别
- OPENCLAW_LOG_LEVEL=info
# 网络配置
networks:
- openclaw-net
# 资源限制
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
# 可选:Chrome CDP (浏览器自动化)
chrome:
image: browserless/chrome:latest
container_name: openclaw-chrome
restart: unless-stopped
ports:
- "9222:3000"
environment:
- CONNECTION_TIMEOUT=600000
- MAX_CONCURRENT_SESSIONS=5
networks:
- openclaw-net
networks:
openclaw-net:
driver: bridge
启动命令
# 1. 准备环境变量文件
cat > .env << EOF
DASHSCOPE_API_KEY=sk-xxx
ANTHROPIC_API_KEY=sk-ant-xxx
OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)
WHATSAPP_TOKEN=xxx
TELEGRAM_BOT_TOKEN=xxx
FEISHU_LEAD_APP_ID=cli_xxx
FEISHU_LEAD_APP_SECRET=xxx
EOF
# 2. 启动服务
docker-compose up -d
# 3. 查看日志
docker-compose logs -f openclaw
# 4. 验证健康状态
curl http://localhost:18789/health
# 5. 访问 Control UI
open http://localhost:18789
Docker 部署注意事项
# ==================== 数据持久化 ====================
# 确保 ~/.openclaw 目录存在且有正确权限
mkdir -p ~/.openclaw
chmod 700 ~/.openclaw
# ==================== Docker 沙箱支持 ====================
# 如需启用 Docker 沙箱,需要挂载 Docker socket
# ⚠️ 注意安全:这会给容器 Docker 访问权限
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# 更安全的替代方案:使用 Docker-in-Docker (dind)
services:
openclaw:
privileged: true
environment:
- OPENCLAW_DOCKER_HOST=tcp://docker:2375
docker:
image: docker:dind
privileged: true
environment:
- DOCKER_TLS_CERTDIR=""
# ==================== 网络配置 ====================
# LAN 访问:绑定 0.0.0.0
CMD ["openclaw", "gateway", "--bind-host", "0.0.0.0", "--port", "18789"]
# 仅本地访问:绑定 127.0.0.1
CMD ["openclaw", "gateway", "--bind-host", "127.0.0.1", "--port", "18789"]
# ==================== TLS/HTTPS ====================
# 启用 TLS (自签名证书)
volumes:
- ~/.openclaw/gateway.crt:/root/.openclaw/gateway.crt
- ~/.openclaw/gateway.key:/root/.openclaw/gateway.key
environment:
- OPENCLAW_GATEWAY_TLS_ENABLED=true
# ==================== 日志管理 ====================
# 限制日志文件大小
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
故障排查
# 查看容器状态
docker-compose ps
# 查看实时日志
docker-compose logs -f openclaw
# 进入容器调试
docker-compose exec openclaw sh
# 检查配置
docker-compose exec openclaw openclaw config validate
# 查看环境变量
docker-compose exec openclaw env | grep OPENCLAW
# 重启服务
docker-compose restart openclaw
# 重建镜像
docker-compose build --no-cache
5.6 Systemd 服务配置 (Linux)
服务文件
# /etc/systemd/system/openclaw.service
[Unit]
Description=OpenClaw Gateway Service
Documentation=https://docs.openclaw.ai
After=network.target network-online.target
Wants=network-online.target
[Service]
Type=simple
User=openclaw
Group=openclaw
# 工作目录
WorkingDirectory=/home/openclaw
# 环境变量
Environment="NODE_ENV=production"
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
Environment="HOME=/home/openclaw"
# 模型 Provider
Environment="DASHSCOPE_API_KEY=sk-xxx"
Environment="ANTHROPIC_API_KEY=sk-ant-xxx"
Environment="GOOGLE_API_KEY=xxx"
# Gateway 认证
Environment="OPENCLAW_GATEWAY_TOKEN=your-secret-token"
# 通道凭证
Environment="WHATSAPP_DEFAULT_AUTH_TOKEN=xxx"
Environment="TELEGRAM_BOT_TOKEN=xxx"
Environment="FEISHU_LEAD_APP_ID=cli_xxx"
Environment="FEISHU_LEAD_APP_SECRET=xxx"
# 日志配置
Environment="OPENCLAW_LOG_LEVEL=info"
Environment="OPENCLAW_CONSOLE_LEVEL=info"
Environment="OPENCLAW_CONSOLE_STYLE=pretty"
# 功能开关
Environment="OPENCLAW_BROWSER_ENABLED=true"
Environment="OPENCLAW_SANDBOX_ENABLED=true"
Environment="OPENCLAW_AGENT_TO_AGENT_ENABLED=true"
# 代理配置 (可选)
# Environment="HTTP_PROXY=http://127.0.0.1:7890"
# Environment="HTTPS_PROXY=http://127.0.0.1:7890"
# 启动命令
ExecStart=/usr/bin/openclaw gateway \
--port 18789 \
--bind-host 0.0.0.0 \
--config /home/openclaw/.openclaw/openclaw.json
# 重启策略
Restart=always
RestartSec=10
# 资源限制
LimitNOFILE=65536
LimitNPROC=4096
MemoryMax=2G
CPUQuota=200%
# 安全加固
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
PrivateTmp=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
ReadWritePaths=/home/openclaw/.openclaw
# 日志
StandardOutput=journal
StandardError=journal
SyslogIdentifier=openclaw
[Install]
WantedBy=multi-user.target
环境变量文件 (推荐)
# /etc/openclaw/.env
# 模型 Provider
DASHSCOPE_API_KEY=sk-xxx
ANTHROPIC_API_KEY=sk-ant-xxx
GOOGLE_API_KEY=xxx
# Gateway 认证
OPENCLAW_GATEWAY_TOKEN=your-secret-token
# 通道凭证
WHATSAPP_DEFAULT_AUTH_TOKEN=xxx
TELEGRAM_BOT_TOKEN=xxx
FEISHU_LEAD_APP_ID=cli_xxx
FEISHU_LEAD_APP_SECRET=xxx
# 日志
OPENCLAW_LOG_LEVEL=info
# /etc/systemd/system/openclaw.service (使用 EnvironmentFile)
[Service]
# ...
EnvironmentFile=/etc/openclaw/.env
ExecStart=/usr/bin/openclaw gateway --port 18789 --bind-host 0.0.0.0
# ...
部署步骤
# 1. 创建 openclaw 用户
sudo useradd --system --no-create-home --shell /bin/false openclaw
# 2. 安装 OpenClaw
sudo npm install -g openclaw@latest
# 3. 创建目录结构
sudo mkdir -p /home/openclaw/.openclaw
sudo mkdir -p /etc/openclaw
# 4. 复制配置文件
cp ~/.openclaw/openclaw.json /home/openclaw/.openclaw/
cp ~/.openclaw/.env /etc/openclaw/.env # 如果使用 EnvironmentFile
# 5. 设置权限
sudo chown -R openclaw:openclaw /home/openclaw/.openclaw
sudo chmod 700 /home/openclaw/.openclaw
sudo chmod 600 /etc/openclaw/.env
# 6. 安装服务文件
sudo cp openclaw.service /etc/systemd/system/
# 7. 重载 systemd
sudo systemctl daemon-reload
# 8. 启用并启动服务
sudo systemctl enable openclaw
sudo systemctl start openclaw
# 9. 查看状态
sudo systemctl status openclaw
# 10. 查看日志
sudo journalctl -u openclaw -f
常用命令
# 启动/停止/重启
sudo systemctl start openclaw
sudo systemctl stop openclaw
sudo systemctl restart openclaw
# 查看状态
sudo systemctl status openclaw
# 查看日志
sudo journalctl -u openclaw -f # 实时日志
sudo journalctl -u openclaw --since today # 今日日志
sudo journalctl -u openclaw -n 100 # 最近 100 行
# 编辑配置
sudo systemctl edit openclaw # 创建覆盖配置
# 重新加载配置
sudo systemctl daemon-reload
sudo systemctl restart openclaw
# 禁用开机启动
sudo systemctl disable openclaw
日志轮转
# /etc/logrotate.d/openclaw
/var/log/journal/*/openclaw*.journal {
weekly
rotate 4
compress
delaycompress
missingok
notifempty
create 0640 root systemd-journal
}
监控和告警
# 创建健康检查脚本
cat > /usr/local/bin/openclaw-healthcheck << 'EOF'
#!/bin/bash
curl -f http://localhost:18789/health || exit 1
EOF
chmod +x /usr/local/bin/openclaw-healthcheck
# 添加到 crontab (每 5 分钟检查)
*/5 * * * * /usr/local/bin/openclaw-healthcheck || \
echo "OpenClaw health check failed!" | mail -s "OpenClaw Alert" admin@example.com
# 启用服务
sudo systemctl daemon-reload
sudo systemctl enable openclaw
sudo systemctl start openclaw
# 查看状态
sudo systemctl status openclaw
# 查看日志
sudo journalctl -u openclaw -f
6. 安全与权限管理
6.1 认证机制详解
源码位置: config/types.gateway.d.ts, gateway/auth.ts
Gateway 认证模式 (3 种)
// from config/types.gateway.d.ts
type GatewayAuthMode = "token" | "password" | "trusted-proxy";
type GatewayAuthConfig = {
mode?: GatewayAuthMode;
token?: string; // token 模式:共享密钥
password?: string; // password 模式:密码认证
trustedProxy?: GatewayTrustedProxyConfig; // 可信反向代理模式
};
认证模式对比:
| 模式 | 适用场景 | 安全性 | 配置复杂度 |
|---|---|---|---|
| token | 个人开发/内网部署 | ⭐⭐⭐ | ⭐ |
| password | 多用户环境 | ⭐⭐⭐⭐ | ⭐⭐ |
| trusted-proxy | 企业部署 (Pomerium/Caddy OAuth) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
模式 1: Token 认证 (默认)
{
gateway: {
auth: {
mode: "token",
token: "${OPENCLAW_GATEWAY_TOKEN}", // 建议使用环境变量
},
},
}
连接流程:
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Gateway Token 认证流程 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. 客户端发起 WebSocket 连接 │
│ ws://127.0.0.1:18789 │
│ Headers: │
│ Authorization: Bearer <gateway-token> │
│ X-Device-Id: <device-fingerprint> │
│ │
│ 2. Gateway 验证 token │
│ const expectedToken = process.env.OPENCLAW_GATEWAY_TOKEN; │
│ const providedToken = headers.authorization?.replace('Bearer ', ''); │
│ │
│ if (providedToken !== expectedToken) { │
│ ws.close(4001, 'Unauthorized'); │
│ return; │
│ } │
│ │
│ 3. 设备指纹验证 (可选) │
│ const knownDevices = config.knownDevices || []; │
│ const device = knownDevices.find(d => d.id === deviceId); │
│ │
│ 4. 颁发设备 token (JWT 格式,30 天有效期) │
│ const deviceToken = jwt.sign( │
│ { deviceId, issuedAt: Date.now() }, │
│ config.gateway.secret, │
│ { expiresIn: '30d' } │
│ ); │
│ │
│ 5. 返回连接成功 │
│ ws.send(JSON.stringify({ │
│ type: 'res:connect', │
│ ok: true, │
│ token: deviceToken, │
│ expires: Date.now() + 30 * 24 * 60 * 60 * 1000 │
│ })); │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
模式 2: Password 认证
{
gateway: {
auth: {
mode: "password",
password: "${OPENCLAW_GATEWAY_PASSWORD}",
},
},
}
模式 3: Trusted Proxy 认证 (企业级)
// from config/types.gateway.d.ts
type GatewayTrustedProxyConfig = {
userHeader: string; // 必需:用户身份头 (如 "x-forwarded-user")
requiredHeaders?: string[]; // 必需:验证请求来自代理
allowUsers?: string[]; // 可选:用户白名单
};
{
gateway: {
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-pomerium-claim-email",
requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],
allowUsers: ["admin@example.com", "dev@example.com"],
},
},
},
}
适用场景:
- Pomerium + OAuth (Google/GitHub SSO)
- Caddy + oauth2_proxy
- Cloudflare Access
- Authelia
设备配对协议 (新设备首次连接)
┌──────────────┐ ┌──────────────┐
│ Client │ │ Gateway │
└──────┬───────┘ └──────┬───────┘
│ │
│ ─────────────────────────────────────► │
│ req:connect { device: { id: "new-mac" } } │
│ │
│ ◄───────────────────────────────────── │
│ res:challenge { │
│ challenge: "abc123xyz", │
│ expires: 300000 // 5 分钟 │
│ } │
│ │
│ [用户在 Gateway Control UI 确认配对] │
│ │
│ ─────────────────────────────────────► │
│ req:pair { │
│ challenge: "abc123xyz", │
│ signature: <signed-challenge> │
│ } │
│ │
│ ◄───────────────────────────────────── │
│ res:pair { │
│ ok: true, │
│ deviceToken: "eyJhbGc...", │
│ } │
│ │
TLS/HTTPS 配置
// from config/types.gateway.d.ts
type GatewayTlsConfig = {
enabled?: boolean;
autoGenerate?: boolean; // 自动生成自签名证书
certPath?: string; // PEM 证书路径
keyPath?: string; // PEM 私钥路径
caPath?: string; // CA bundle (mTLS)
};
{
gateway: {
tls: {
enabled: true,
autoGenerate: true, // 开发环境:自动生成
certPath: "~/.openclaw/gateway.crt",
keyPath: "~/.openclaw/gateway.key",
// 生产环境:使用 Let's Encrypt 证书
// certPath: "/etc/letsencrypt/live/example.com/fullchain.pem",
// keyPath: "/etc/letsencrypt/live/example.com/privkey.pem",
},
},
}
安全加固配置
{
gateway: {
auth: {
// 禁止不安全配置
allowInsecureAuth: false, // 禁止 HTTP 明文 token
dangerouslyDisableDeviceAuth: false, // 禁止禁用设备验证
},
// Control UI 访问控制
controlUi: {
enabled: true,
basePath: "/openclaw",
allowedOrigins: ["https://admin.example.com"],
},
// 绑定地址
bindMode: "loopback", // auto|lan|loopback|custom|tailnet
bindHost: "127.0.0.1", // 仅本地访问
port: 18789,
},
}
6.2 沙箱隔离详解
源码位置: config/types.sandbox.d.ts, sandbox/
沙箱模式配置
// from config/types.sandbox.d.ts
type SandboxMode = "off" | "non-main" | "all";
type SandboxScope = "session" | "agent" | "shared";
type SandboxWorkspaceAccess = "none" | "ro" | "rw";
type SandboxConfig = {
mode?: SandboxMode;
workspaceAccess?: SandboxWorkspaceAccess;
scope?: SandboxScope;
perSession?: boolean; // 遗留别名
workspaceRoot?: string;
docker?: SandboxDockerSettings;
browser?: SandboxBrowserSettings;
prune?: SandboxPruneSettings;
};
沙箱模式对比:
| 模式 | 适用 Agent | 隔离级别 | 性能影响 |
|---|---|---|---|
| off | main Agent | 无隔离 | 无 |
| non-main | 除 main 外的所有 Agent | 中等 | 低 |
| all | 所有 Agent (包括 main) | 完全隔离 | 中 |
Docker 沙箱配置
// from config/types.sandbox.d.ts
type SandboxDockerSettings = {
image?: string; // Docker 镜像 (默认:node:20-alpine)
network?: string; // 网络模式 (bridge|host|none)
resources?: {
memory?: string; // 内存限制 (如 "1g")
cpu?: string | number; // CPU 限制 (如 "1" 或 1.5)
};
volumes?: string[]; // 挂载卷
env?: Record<string, string>; // 环境变量
};
{
agents: {
list: [
{
id: "coding",
sandbox: {
mode: "all",
workspaceAccess: "rw",
docker: {
image: "node:20-alpine",
network: "bridge",
resources: {
memory: "2g",
cpu: "2",
},
volumes: [
"/tmp/cache:/cache", // 缓存共享
],
env: {
NPM_CONFIG_CACHE: "/cache/npm",
},
},
},
},
],
},
}
浏览器沙箱配置
// from config/types.sandbox.d.ts
type SandboxBrowserSettings = {
enabled?: boolean;
headless?: boolean;
cdpUrl?: string; // Chrome DevTools Protocol URL
cdpPort?: number;
};
{
sandbox: {
browser: {
enabled: true,
headless: true,
cdpUrl: "ws://localhost:9222", // 外部 Chrome CDP
// 或使用内置浏览器
// cdpPort: 18791,
},
},
}
自动清理配置 (Prune)
// from config/types.sandbox.d.ts
type SandboxPruneSettings = {
enabled?: boolean;
intervalHours?: number; // 清理间隔
maxAgeHours?: number; // 最大存活时间
};
{
sandbox: {
prune: {
enabled: true,
intervalHours: 24, // 每天清理
maxAgeHours: 168, // 7 天最大存活时间
},
},
}
沙箱隔离级别
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 沙箱隔离级别 (Sandbox Isolation Levels) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Level 1: 进程隔离 (默认) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ • 独立的 Node.js 子进程 │ │
│ │ • 独立的文件描述符 │ │
│ │ • 独立的环境变量 │ │
│ │ • 共享主机文件系统 │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ Level 2: Docker 容器隔离 (推荐) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ • 独立的容器命名空间 │ │
│ │ • 独立的文件系统 (可挂载卷) │ │
│ │ • 独立的网络命名空间 │ │
│ │ • 资源限制 (CPU/内存) │ │
│ │ • 自动清理 (prune) │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ Level 3: 完全隔离 (高安全场景) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ • Docker 容器 + seccomp 配置文件 │ │
│ │ • 只读文件系统 (workspaceAccess: "ro") │ │
│ │ • 网络隔离 (network: "none") │ │
│ │ • 无特权模式 (privileged: false) │ │
│ │ • 资源限制严格 │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
工作区访问控制
{
sandbox: {
// 只读访问 (安全)
workspaceAccess: "ro",
// 读写访问 (功能完整)
workspaceAccess: "rw",
// 无访问 (完全隔离)
workspaceAccess: "none",
},
}
6.3 工具权限控制
源码位置: config/types.tools.d.ts
工具权限模式
// from config/types.tools.d.ts
type ToolPermissionMode = "full" | "restricted" | "coding" | "none" | "allowlist" | "denylist";
type AgentToolsConfig = {
profile?: ToolPermissionMode;
mode?: "allowlist" | "denylist";
allow?: string[]; // 允许的工具列表
deny?: string[]; // 禁止的工具列表
restrictions?: {
[toolName: string]: ToolRestriction;
};
};
type ToolRestriction = {
allowedCommands?: string[]; // exec 工具:允许的命令
allowedHosts?: string[]; // 网络工具:允许的主机
maxFileSize?: number; // 文件工具:最大文件大小
sandbox?: boolean; // 是否启用沙箱
};
权限模式详解
| 模式 | 允许的工具 | 适用场景 |
|---|---|---|
| full | 所有工具 | 受信任的主 Agent |
| restricted | 读取类工具 (read/web_search) | 普通聊天 Agent |
| coding | 编码相关工具 (read/write/edit/exec) | 编码 Agent |
| none | 无工具 | 纯聊天 Agent |
| allowlist | 仅 allow 列表中的工具 | 精细控制 |
| denylist | 除 deny 列表外的所有工具 | 黑名单模式 |
配置示例
{
agents: {
list: [
// ==================== 主 Agent (完全权限) ====================
{
id: "main",
tools: {
profile: "full",
},
},
// ==================== 编码 Agent (编码权限) ====================
{
id: "coding",
tools: {
profile: "coding",
// 或手动指定
mode: "allowlist",
allow: ["read", "write", "edit", "exec", "process", "browser"],
restrictions: {
exec: {
allowedCommands: ["npm", "pnpm", "yarn", "git", "node", "npx"],
sandbox: true,
},
},
},
},
// ==================== VOC 分析师 (受限权限) ====================
{
id: "voc",
tools: {
profile: "restricted",
mode: "allowlist",
allow: ["read", "write", "web_search", "web_fetch", "sessions_send"],
},
},
// ==================== 纯聊天 Agent (无工具) ====================
{
id: "chat",
tools: {
profile: "none",
},
},
],
},
// ==================== 全局工具配置 ====================
tools: {
// exec 工具全局限制
exec: {
allowedCommands: ["npm", "git", "node"],
denyCommands: ["rm", "sudo", "curl", "wget"],
sandbox: true,
},
// 浏览器工具全局限制
browser: {
evaluateEnabled: false, // 禁止 JavaScript 执行
allowedHosts: ["*"],
},
},
}
工具权限继承
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 工具权限继承规则 (Tool Permission Inheritance) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. 全局配置 (tools.*) │
│ ↓ │
│ 2. Agent 配置 (agents.list[].tools) │
│ ↓ │
│ 3. 会话级覆盖 (session.tools) │
│ ↓ │
│ 4. 最终权限 (最严格的规则生效) │
│ │
│ 示例: │
│ • 全局允许 exec,Agent 禁止 → 禁止 │
│ • 全局允许 rm,Agent 允许但 restrictions 禁止 → 禁止 │
│ • 全局无限制,Agent allowlist → 仅 allowlist 中的工具 │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
6.4 群组访问控制
源码位置: config/types.messages.d.ts, config/group-policy.d.ts
群组策略类型
// from config/types.base.d.ts
type GroupPolicy = "open" | "disabled" | "allowlist";
type GroupChatConfig = {
mentionPatterns?: string[]; // 提及模式 (如 ["@openclaw"])
requireMention?: boolean; // 是否必须被提及才响应
policy?: GroupPolicy; // 群组策略
allowlist?: string[]; // 允许的群组 ID 列表
};
群组策略详解
| 策略 | 行为 | 适用场景 |
|---|---|---|
| open | 响应所有消息 | 内部测试群 |
| disabled | 不响应任何消息 | 禁止使用的群 |
| allowlist | 仅响应白名单群 | 生产环境 |
| requireMention | 仅响应提及消息 | 默认推荐 |
配置示例
{
// ==================== 全局群组配置 ====================
messages: {
groupChat: {
requireMention: true, // 默认:必须被提及
mentionPatterns: ["@openclaw", "@助手", "@bot"],
},
},
// ==================== 通道级群组配置 ====================
channels: {
discord: {
guilds: {
// 所有服务器:必须提及
"*": {
requireMention: true,
policy: "open",
},
// 特定服务器:禁用
"123456789": {
policy: "disabled",
},
// 特定服务器:白名单模式
"987654321": {
policy: "allowlist",
allowlist: ["channel-1", "channel-2"],
},
},
},
whatsapp: {
groups: {
"*": {
requireMention: true, // WhatsApp 群必须提及
policy: "open",
},
},
},
feishu: {
requireMention: false, // 飞书群默认不要求提及
groups: {
"*": {
policy: "open",
},
},
},
},
// ==================== Agent 级群组配置 ====================
agents: {
list: [
{
id: "admin",
groupChat: {
mentionPatterns: ["@admin", "@管理员"],
requireMention: true,
policy: "allowlist",
allowlist: ["admin-group-id"],
},
},
{
id: "dev",
groupChat: {
mentionPatterns: ["@dev", "@开发"],
requireMention: true,
},
},
],
},
}
提及模式匹配
// 提及匹配逻辑
const mentionPatterns = ["@openclaw", "@助手", "@bot"];
const messageContent = "@openclaw 你好";
const isMentioned = mentionPatterns.some(pattern =>
messageContent.includes(pattern)
);
// 正则匹配 (更精确)
const mentionRegex = /@(?:openclaw|助手|bot)\b/i;
const isMentioned = mentionRegex.test(messageContent);
6.5 远程访问安全
远程访问方案对比
| 方案 | 安全性 | 复杂度 | 适用场景 |
|---|---|---|---|
| Tailscale | ⭐⭐⭐⭐⭐ | ⭐ | 个人/小团队 |
| Cloudflare Tunnel | ⭐⭐⭐⭐⭐ | ⭐⭐ | 公开服务 |
| SSH 隧道 | ⭐⭐⭐⭐ | ⭐ | 临时访问 |
| VPN | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 企业环境 |
| 反向代理 + OAuth | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 企业 SSO |
方案 1: Tailscale (推荐)
# 1. 安装 Tailscale
brew install tailscale # macOS
sudo apt install tailscale # Linux
# 2. 登录
tailscale up
# 3. 获取 Tailscale IP
tailscale ip
# 4. 配置 Gateway 绑定 Tailscale 接口
# openclaw.json
{
gateway: {
bindMode: "tailnet",
bindHost: "100.x.y.z", # Tailscale IP
port: 18789,
},
}
# 5. 重启 Gateway
openclaw gateway restart
Tailscale ACL 配置 (acl.json):
{
"acls": [
{
"action": "accept",
"src": ["alice@example.com", "bob@example.com"],
"dst": ["gateway-host:18789"],
},
],
}
方案 2: Cloudflare Tunnel
# 1. 安装 cloudflared
brew install cloudflared
# 2. 登录 Cloudflare
cloudflared tunnel login
# 3. 创建隧道
cloudflared tunnel create openclaw
# 4. 配置隧道 (config.yml)
tunnel: openclaw
credentials-file: /Users/[username]/.cloudflared/xxx.json
ingress:
- hostname: openclaw.example.com
service: http://127.0.0.1:18789
- service: http_status:404
# 5. 运行隧道
cloudflared tunnel run openclaw
Cloudflare Access 配置:
{
gateway: {
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "cf-access-authenticated-user-email",
requiredHeaders: ["cf-access-jwt-assertion"],
allowUsers: ["admin@example.com"],
},
},
},
}
方案 3: SSH 隧道
# 本地端口转发 (从本地访问远程 Gateway)
ssh -L 18789:127.0.0.1:18789 user@remote-host
# 远程端口转发 (从远程访问本地 Gateway)
ssh -R 18789:127.0.0.1:18789 user@remote-host
# 动态 SOCKS 代理
ssh -D 1080 user@remote-host
防火墙配置:
# UFW (Ubuntu)
sudo ufw allow 18789/tcp from 100.64.0.0/10 # 只允许 Tailscale 网段
sudo ufw enable
# iptables
sudo iptables -A INPUT -p tcp --dport 18789 -s 100.64.0.0/10 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 18789 -j DROP
# macOS 防火墙
# 系统偏好设置 → 安全性与隐私 → 防火墙 → 防火墙选项
方案 4: Nginx 反向代理 + OAuth
# /etc/nginx/sites-available/openclaw
server {
listen 443 ssl;
server_name openclaw.example.com;
# SSL 证书
ssl_certificate /etc/letsencrypt/live/openclaw.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/openclaw.example.com/privkey.pem;
# OAuth2 Proxy
location / {
auth_request /oauth2/auth;
error_page 401 =302 /oauth2/start?rd=$request_uri;
proxy_pass http://127.0.0.1:18789;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# OAuth2 Proxy 端点
location /oauth2/ {
proxy_pass http://127.0.0.1:4180/oauth2/;
proxy_set_header Host $host;
}
}
OAuth2 Proxy 配置:
# /etc/oauth2-proxy/config.cfg
provider = "github"
client_id = "xxx"
client_secret = "xxx"
cookie_secret = "$(openssl rand -base64 32)"
email_domains = ["example.com"]
upstream = "http://127.0.0.1:18789"
http_address = "127.0.0.1:4180"
安全最佳实践
{
gateway: {
// 1. 强制 TLS
tls: {
enabled: true,
autoGenerate: false, // 生产环境使用正式证书
},
// 2. 绑定内网地址
bindMode: "loopback",
bindHost: "127.0.0.1",
// 3. 禁止不安全认证
auth: {
allowInsecureAuth: false,
dangerouslyDisableDeviceAuth: false,
},
// 4. 限制 Control UI 来源
controlUi: {
allowedOrigins: ["https://admin.example.com"],
},
},
// 5. 启用日志审计
logging: {
level: "info",
consoleLevel: "info",
},
// 6. 启用诊断
diagnostics: {
enabled: true,
},
}
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Gateway 认证流程 (Authentication Flow) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Step 1: 客户端发起连接请求 │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ WebSocket Connect: ws://127.0.0.1:18789 │ │
│ │ Headers: │ │
│ │ Authorization: Bearer <gateway-token> │ │
│ │ X-Device-Id: <device-fingerprint> │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 2: Gateway 验证 token │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ const expectedToken = process.env.OPENCLAW_GATEWAY_TOKEN; │ │
│ │ const providedToken = headers.authorization?.replace('Bearer ', ''); │ │
│ │ │ │
│ │ if (providedToken !== expectedToken) { │ │
│ │ ws.close(4001, 'Unauthorized'); │ │
│ │ return; │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 3: 设备指纹验证 (可选) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ const knownDevices = config.knownDevices || []; │ │
│ │ const device = knownDevices.find(d => d.id === deviceId); │ │
│ │ │ │
│ │ if (!device) { │ │
│ │ // 新设备,需要配对 │ │
│ │ issueChallenge(deviceId); │ │
│ │ return; │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 4: 颁发设备 token │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ const deviceToken = jwt.sign( │ │
│ │ { deviceId, issuedAt: Date.now() }, │ │
│ │ config.gateway.secret, │ │
│ │ { expiresIn: '30d' } │ │
│ │ ); │ │
│ │ │ │
│ │ ws.send(JSON.stringify({ │ │
│ │ type: 'res:connect', │ │
│ │ ok: true, │ │
│ │ token: deviceToken, │ │
│ │ expires: Date.now() + 30 * 24 * 60 * 60 * 1000 │ │
│ │ })); │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
设备配对协议
新设备首次连接流程:
┌──────────────┐ ┌──────────────┐
│ Client │ │ Gateway │
└──────┬───────┘ └──────┬───────┘
│ │
│ ─────────────────────────────────────► │
│ req:connect { device: { id: "new-mac" } } │
│ │
│ ◄───────────────────────────────────── │
│ res:challenge { │
│ challenge: "abc123xyz", │
│ expires: 300000 // 5 分钟 │
│ } │
│ │
│ [用户在 Gateway Control UI 确认配对] │
│ │
│ ─────────────────────────────────────► │
│ req:pair { │
│ challenge: "abc123xyz", │
│ signature: <signed-challenge> │
│ } │
│ │
│ ◄───────────────────────────────────── │
│ res:pair { │
│ ok: true, │
│ deviceToken: "eyJhbGc...", │
│ } │
│ │
Token 格式详解
Gateway Token (环境变量):
# 生成强随机 token
openssl rand -hex 32
# 输出:a1b2c3d4e5f6... (64 字符)
# 或使用 Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
设备 Token (JWT 格式):
// Payload 结构
{
"deviceId": "macbook-pro-2024",
"issuedAt": 1709337600000,
"expiresAt": 1711929600000,
"permissions": ["read", "write", "exec"],
"scope": "agent:main"
}
// JWT 示例
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJkZXZpY2VJZCI6Im1hY2Jvb2stcHJvLTIwMjQiLCJpc3N1ZWRBdCI6MTcwOTMzNzYwMDAwMH0.
abc123xyz_signature
7. 实战案例:跨境电商多 Agent 系统
7.1 业务场景
需求: 搭建一个跨境电商营销自动化系统,包含 5 个专业 Agent:
| Agent | 职责 | 模型 | 月调用量 | 单次成本 | 月成本估算 |
|---|---|---|---|---|---|
| 大总管 (lead) | 需求拆解、任务分发 | Qwen3.5-Plus | 500 次 | ¥0.02 | ¥10 |
| VOC 分析师 | 竞品评价抓取、痛点提炼 | GLM-5 | 2000 次 | ¥0.005 | ¥10 |
| GEO 优化师 | 产品内容撰写、SEO 优化 | GLM-5 | 3000 次 | ¥0.005 | ¥15 |
| Reddit 专家 | 社区养号、长尾流量 | GLM-5 | 1000 次 | ¥0.005 | ¥5 |
| TikTok 编导 | 视频脚本、生图生视频 | Qwen3.5-Plus | 500 次 | ¥0.02 | ¥10 |
| 总计 | - | - | 7000 次 | - | ¥50/月 |
成本对比:
- 自建方案:¥50/月 (DashScope API)
- SaaS 方案:$99-299/月 (Jasper/Copy.ai 等)
- 节省:90%+ 成本
7.2 系统架构
┌─────────────────────────────────┐
│ 飞书群聊 (用户入口) │
│ @大总管:分析露营折叠床市场 │
└──────────────┬──────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────────────────┐
│ 大总管 Agent (lead) │
│ ┌────────────────────────────────────────────────────────────────────────────┐ │
│ │ 1. 需求理解层 │ │
│ │ • 意图识别:市场分析 + 内容生成 │ │
│ │ • 任务拆解:VOC 分析 → 内容撰写 → 社区分发 → 视频脚本 │ │
│ └────────────────────────────────────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────────────────────────────────┐ │
│ │ 2. 任务分发层 (sessions_send 并发调用) │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ VOC 分析师 │ │ GEO 优化师 │ │ Reddit 专家 │ │ TikTok 编导 │ │ │
│ │ │ (voc) │ │ (geo) │ │ (reddit) │ │ (tiktok) │ │ │
│ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │
│ │ │ │ │ │ │ │
│ └────────────┼─────────────────┼─────────────────┼─────────────────┼──────────┘ │
│ │ │ │ │ │
└───────────────┼─────────────────┼─────────────────┼─────────────────┼─────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐ ┌───────────────┐
│ VOC 分析师 Agent │ │ GEO 优化师 Agent │ │ Reddit 专家 Agent │ │ TikTok 编导 │
│ workspace-voc │ │ workspace-geo │ │ workspace-reddit │ │ workspace- │
│ │ │ │ │ │ │ tiktok │
│ • 爬取竞品评价 │ │ • 撰写产品博客 │ │ • 搜索相关帖子 │ │ • 生成视频脚本 │
│ • 提炼用户痛点 │ │ • SEO 关键词优化 │ │ • 养号互动策略 │ │ • AI 生图生视频 │
│ • 输出 VOC 报告 │ │ • 输出 SEO 文章 │ │ • 输出引流方案 │ │ • 输出分镜脚本 │
└─────────┬─────────┘ └─────────┬─────────┘ └─────────┬─────────┘ └───────┬───────┘
│ │ │ │
└─────────────────────┴─────────────────────┴───────────────────┘
│
▼
┌─────────────────────────┐
│ 大总管汇总结果 │
│ 飞书群汇报 │
└─────────────────────────┘
【并发执行时序】
T0: lead 收到指令
│
├──────────────┐
│ │
▼ ▼
T1: sessions_send sessions_send
→ voc-analyst → geo-optimizer
│ │
▼ ▼
T2: sessions_send sessions_send
→ reddit-spec → tiktok-director
│ │
▼ ▼
T3: [4 个 Agent 并行执行中...]
│
▼
T4: 各 Agent 返回结果 → lead 汇总 → 飞书群汇报
7.3 配置步骤
Step 1: 创建 Agent 工作区
# 使用向导创建
openclaw agents add lead
openclaw agents add voc
openclaw agents add geo
openclaw agents add reddit
openclaw agents add tiktok
# 或手动创建目录
mkdir -p ~/.openclaw/workspace-{lead,voc,geo,reddit,tiktok}
# 验证创建
ls -la ~/.openclaw/workspace-*/
# 输出示例:
# ~/.openclaw/workspace-lead/:
# SOUL.md AGENTS.md USER.md MEMORY.md skills/
Step 2: 编写 Agent 人设
示例: ~/.openclaw/workspace-lead/SOUL.md
# SOUL.md - 大总管
## 你是谁
你是跨境电商团队的**大总管 (Lead Agent)**,负责接收老板指令并协调团队成员完成全渠道营销任务。
## 核心职责
1. **需求理解**:准确理解老板的业务需求
2. **任务拆解**:将复杂业务拆解为可执行的子任务
3. **跨 Agent 分发**:使用 `sessions_send` 并发分发给专业成员
4. **进度跟踪**:汇总各成员反馈,向老板汇报
## 工作原则
- **只做协调,不做执行**:严禁自己执行底层任务
- **并发优先**:能并行的任务绝不串行
- **异步通信**:所有任务分发通过 sessions_send 异步进行
Step 3: 配置飞书多账号
# 在飞书开放平台创建 5 个应用
# 1. 访问 https://open.feishu.cn/
# 2. 创建应用 → 选择"企业内部开发"
# 3. 获取 App ID 和 App Secret
# 4. 配置权限:
# - 消息读写 (im:message)
# - 群组读写 (im:chat)
# - 用户信息读取 (contact:user)
{
channels: {
feishu: {
enabled: true,
connectionMode: "websocket",
accounts: {
lead: {
appId: "cli_a1b2c3d4e5f6",
appSecret: "xxxSECRET1xxx"
},
voc: {
appId: "cli_b2c3d4e5f6g7",
appSecret: "xxxSECRET2xxx"
},
geo: {
appId: "cli_c3d4e5f6g7h8",
appSecret: "xxxSECRET3xxx"
},
reddit: {
appId: "cli_d4e5f6g7h8i9",
appSecret: "xxxSECRET4xxx"
},
tiktok: {
appId: "cli_e5f6g7h8i9j0",
appSecret: "xxxSECRET5xxx"
},
},
},
},
}
Step 4: 配置路由绑定
{
agents: {
list: [
{
id: "lead",
workspace: "~/.openclaw/workspace-lead",
model: "bailian/qwen3.5-plus",
tools: { profile: "full" },
},
{
id: "voc",
workspace: "~/.openclaw/workspace-voc",
model: "bailian/glm-5",
tools: {
allow: ["read", "write", "web_search", "web_fetch", "sessions_send"],
},
},
{
id: "geo",
workspace: "~/.openclaw/workspace-geo",
model: "bailian/glm-5",
tools: {
allow: ["read", "write", "web_search", "sessions_send"],
},
},
{
id: "reddit",
workspace: "~/.openclaw/workspace-reddit",
model: "bailian/glm-5",
tools: {
allow: ["read", "write", "web_search", "browser", "sessions_send"],
},
},
{
id: "tiktok",
workspace: "~/.openclaw/workspace-tiktok",
model: "bailian/qwen3.5-plus",
tools: {
allow: ["read", "write", "sessions_send"],
},
},
],
},
bindings: [
{ agentId: "lead", match: { channel: "feishu", accountId: "lead" } },
{ agentId: "voc", match: { channel: "feishu", accountId: "voc" } },
{ agentId: "geo", match: { channel: "feishu", accountId: "geo" } },
{ agentId: "reddit", match: { channel: "feishu", accountId: "reddit" } },
{ agentId: "tiktok", match: { channel: "feishu", accountId: "tiktok" } },
],
tools: {
agentToAgent: {
enabled: true,
allow: ["lead", "voc", "geo", "reddit", "tiktok"],
},
},
}
Step 5: 安装全局技能
# 安装必要技能
clawhub install nano-banana-pro # 图片生成
clawhub install seedance2.0 # 视频生成
clawhub install tavily # 网络搜索
clawhub install baoyu-image-gen # 多平台图片生成
# 验证安装
clawhub list
# 输出示例:
# Installed skills:
# - nano-banana-pro (v1.2.0)
# - seedance2.0 (v2.0.1)
# - tavily (v1.0.0)
# - baoyu-image-gen (v1.5.0)
Step 6: 重启并测试
# 验证配置语法
cat ~/.openclaw/openclaw.json | jq . > /dev/null && echo "✓ 配置有效"
# 重启 Gateway
openclaw gateway restart
# 等待启动完成
sleep 3
# 验证 Gateway 状态
openclaw status
# 验证通道连接
openclaw channels status --probe
# 验证路由绑定
openclaw agents list --bindings
# 验证 Agent 状态
openclaw agents inspect lead
openclaw agents inspect voc
openclaw agents inspect geo
openclaw agents inspect reddit
openclaw agents inspect tiktok
7.4 工作流示例
触发指令 (在飞书群@大总管):
@大总管 分析一下露营折叠床的市场,并全渠道铺内容
执行流程:
1. lead 收到指令
↓
2. sessions_send → voc-analyst
"分析露营折叠床市场痛点,输出 VOC 报告"
↓
3. sessions_send → geo-optimizer
"基于 VOC 数据撰写产品博客,SEO 优化"
↓
4. sessions_send → reddit-spec
"寻找露营装备相关老帖子,制定互动策略"
↓
5. sessions_send → tiktok-director
"生成露营折叠床短视频脚本和分镜"
↓
6. 各 Agent 并行执行
↓
7. lead 汇总结果,在飞书群汇报
预期输出:
【市场分析汇报】露营折叠床
📊 VOC 分析报告 (by voc-analyst)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
用户痛点 TOP 5:
1. 收纳体积大 (提及率 68%)
2. 重量过重 (提及率 52%)
3. 舒适度差 (提及率 45%)
4. 搭建复杂 (提及率 38%)
5. 耐用性差 (提及率 32%)
📝 SEO 文章 (by geo-optimizer)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
标题:2026 年露营折叠床选购指南:轻量化 + 舒适度兼得
关键词:露营折叠床、轻量化、便携、户外装备
字数:2500 字
发布建议:知乎专栏 + 小红书 + 微信公众号
🎯 Reddit 策略 (by reddit-spec)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
目标 Subreddit: r/CampingandHiking, r/Ultralight
互动策略:
- 搜索 "sleeping pad vs cot" 历史帖子
- 评论中自然植入产品链接
- 预计引流:50-100 UV/周
🎬 TikTok 脚本 (by tiktok-director)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
视频主题:30 秒展示折叠床收纳过程
分镜:
1. 开场:传统床 vs 折叠床对比 (3s)
2. 折叠演示:3 步快速收纳 (15s)
3. 便携展示:放入背包 (7s)
4. CTA:评论区链接 (5s)
生成图片:4 张 (封面 +3 个关键帧)
8. 性能优化与故障排查
8.1 Gateway 内部消息处理流水线
入站消息处理流程:
通道 (WhatsApp/Telegram/Feishu)
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Stage 1: 通道适配层 (<5ms) │
│ • Baileys/grammY/discord.js → 标准化消息格式 │
│ 输出:{ channel, accountId, peer, content, timestamp } │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Stage 2: 认证与限流层 (<2ms) │
│ • 验证 allowlist • 速率限制 • 防滥用检测 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Stage 3: 路由匹配层 (<1ms) │
│ • 执行路由匹配算法 • 确定目标 Agent • 生成 sessionKey │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Stage 4: 会话加载层 (10-50ms) │
│ • 加载 messages.jsonl • 应用滑动窗口 • 检查压缩需求 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Stage 5: Agent 运行时 (500ms-5s) │
│ • 构建 LLM 请求 • 调用 Provider API • 流式响应 • 工具调用处理 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Stage 6: 响应发送层 (10-100ms) │
│ • 发送回复 • 更新会话历史 • 更新 token 统计 • 触发记忆提取 │
└─────────────────────────────────────────────────────────────────┘
│
▼
用户收到回复
【总延迟分解】(典型场景)
─────────────────────────────────────────────────────────────────
通道适配 2-5ms ▓▓
认证限流 1-2ms ▓
路由匹配 <1ms ▓
会话加载 10-50ms ▓▓▓▓▓
LLM 响应 500-5000ms ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
响应发送 10-100ms ▓▓▓
─────────────────────────────────────────────────────────────────
总计 523-5158ms
【优化重点】: LLM 响应时间占 95%+,优化 LLM 选择是关键
8.2 性能基准测试
测试环境:
- CPU: Apple M2 Pro (12 核)
- 内存:32GB
- 网络:100Mbps
- Gateway 版本:v1.2.3
单 Agent 并发测试:
| 并发数 | P50 延迟 | P95 延迟 | P99 延迟 | 成功率 |
|---|---|---|---|---|
| 1 | 1.2s | 2.1s | 3.5s | 100% |
| 5 | 1.3s | 2.4s | 4.2s | 100% |
| 10 | 1.5s | 3.1s | 5.8s | 99.8% |
| 20 | 2.1s | 4.5s | 8.2s | 99.2% |
| 50 | 3.8s | 8.2s | 15.3s | 97.5% |
多 Agent 并发测试 (5 个 Agent 同时运行):
| 指标 | 数值 | 说明 |
|---|---|---|
| 最大并发会话数 | 25 | 每个 Agent 5 个并发会话 |
| 平均 CPU 使用率 | 45% | M2 Pro 12 核 |
| 平均内存使用 | 2.1GB | 包括会话缓存 |
| 网络带宽峰值 | 15Mbps | LLM API 调用 |
| 磁盘 I/O | 5MB/s | 会话历史写入 |
工具调用性能:
| 工具 | P50 | P95 | P99 | 说明 |
|---|---|---|---|---|
read | 12ms | 45ms | 120ms | 10KB 文件 |
write | 15ms | 52ms | 150ms | 10KB 文件 |
exec | 150ms | 800ms | 2s | 简单命令 |
web_search | 1.2s | 2.5s | 4s | Tavily API |
browser.snapshot | 2.5s | 5s | 8s | 页面加载 + 渲染 |
sessions_send | 25ms | 80ms | 200ms | 异步消息 |
8.3 优化策略
1. 模型分级策略
{
agents: {
list: [
{
id: "lead",
model: "anthropic/claude-sonnet-4-5", // 决策层用顶级模型
},
{
id: "voc",
model: "bailian/glm-5", // 执行层用性价比模型
},
{
id: "geo",
model: "google/gemini-3-flash", // 成本降低 90%
},
],
},
}
成本对比:
| 模型 | 输入价格 | 输出价格 | 适用场景 |
|---|---|---|---|
| claude-sonnet-4-5 | ¥0.02/1K | ¥0.08/1K | 复杂决策、代码 |
| qwen3.5-plus | ¥0.004/1K | ¥0.012/1K | 通用任务 |
| glm-5 | ¥0.001/1K | ¥0.001/1K | 简单任务、批量处理 |
| gemini-3-flash | ¥0.0005/1K | ¥0.0015/1K | 超大批量 |
2. 会话缓存优化
{
session: {
cache: {
enabled: true,
maxSize: 100, // 最多缓存 100 个会话
ttl: 3600000, // 缓存 1 小时过期
preload: true, // 启动时预加载活跃会话
},
},
}
3. 压缩策略调优
{
session: {
compaction: {
// 激进模式 (节省 token,适合低成本场景)
aggressive: {
windowSize: 20,
threshold: 40,
summaryMaxLength: 200,
},
// 平衡模式 (推荐)
balanced: {
windowSize: 50,
threshold: 100,
summaryMaxLength: 500,
},
// 保守模式 (保留更多上下文,适合复杂任务)
conservative: {
windowSize: 100,
threshold: 200,
summaryMaxLength: 1000,
},
},
},
}
4. 批量写入优化
// 会话历史批量写入 (减少磁盘 I/O)
class SessionStore {
constructor() {
this.writeBuffer = new Map();
this.flushInterval = setInterval(() => this.flush(), 5000); // 5 秒刷盘
}
appendMessage(sessionKey, message) {
if (!this.writeBuffer.has(sessionKey)) {
this.writeBuffer.set(sessionKey, []);
}
this.writeBuffer.get(sessionKey).push(message);
}
async flush() {
for (const [sessionKey, messages] of this.writeBuffer) {
await fs.appendFile(
`${sessionPath}/messages.jsonl`,
messages.map(m => JSON.stringify(m)).join('\n') + '\n'
);
}
this.writeBuffer.clear();
}
}
8.4 故障排查
诊断命令速查表
# ==================== 系统状态 ====================
openclaw status # Gateway 状态
openclaw health # 健康检查
openclaw usage # 资源使用统计
# ==================== 通道诊断 ====================
openclaw channels list # 列出所有通道
openclaw channels status # 通道连接状态
openclaw channels status --probe # 主动探测连接
openclaw channels login --channel whatsapp --force # 强制重新登录
# ==================== Agent 诊断 ====================
openclaw agents list # 列出所有 Agent
openclaw agents list --bindings # 列出路由绑定
openclaw agents inspect <agentId> # 检查 Agent 配置
# ==================== 会话诊断 ====================
openclaw sessions list # 列出活跃会话
openclaw sessions history --key <sessionKey> # 查看会话历史
openclaw sessions compact --key <sessionKey> # 手动触发压缩
# ==================== 日志查看 ====================
openclaw logs # 查看最近日志
openclaw logs --follow # 实时日志
openclaw logs --level error # 只看错误
openclaw logs --since 1h # 最近 1 小时日志
# ==================== 工具诊断 ====================
openclaw tools list # 列出可用工具
openclaw tools invoke read --path /tmp/test.txt # 测试工具调用
openclaw sandbox status # 沙箱状态
# ==================== 深度诊断 ====================
openclaw doctor # 运行诊断检查
openclaw doctor --fix # 自动修复问题
openclaw doctor --verbose # 详细输出
常见问题排查
问题 1: Gateway 无法启动
# 1. 检查端口占用
lsof -i :18789
# 2. 查看日志
tail -100 /tmp/openclaw/gateway-*.log
# 3. 验证配置
cat ~/.openclaw/openclaw.json | jq . > /dev/null && echo "✓ 配置有效" || echo "✗ 配置有误"
# 常见错误:
# - "EADDRINUSE": 端口被占用 → 杀掉占用进程或换端口
# - "EACCES": 权限不足 → 检查文件权限
# - "Config parse error": 配置语法错误 → 用 jq 验证 JSON
问题 2: 通道连接失败
# WhatsApp: 重新扫描 QR 码
openclaw channels login --channel whatsapp --force
# Telegram: 验证 Bot Token
curl -X GET "https://api.telegram.org/bot<YOUR_TOKEN>/getMe"
# Feishu: 检查 App ID/Secret
openclaw channels status --probe
问题 3: Agent 无响应
# 1. 检查会话状态
openclaw sessions list
# 2. 查看 Agent 日志
tail -f /tmp/openclaw/agent-<agentId>-*.log
# 3. 检查 LLM Provider 配额
# 登录 DashScope 控制台查看 token 余额
# 4. 重启 Gateway
openclaw gateway restart
问题 4: 内存占用过高
# 1. 查看内存使用
ps aux | grep openclaw
# 2. 清理不活跃会话
openclaw sessions prune --inactive 7d
# 3. 调整会话窗口配置
{
"session": {
"windowSize": 30, // 减小窗口大小
"compaction": {
"threshold": 50 // 降低压缩阈值
}
}
}
日志分析技巧
# 搜索特定错误
grep -i "error" /tmp/openclaw/*.log | tail -50
# 统计错误类型
grep "ERROR" /tmp/openclaw/*.log | \
sed 's/.*ERROR \([^ ]*\).*/\1/' | \
sort | uniq -c | sort -rn
# 追踪特定会话
grep "sessionKey=agent:main:xxx" /tmp/openclaw/*.log
# 查看工具调用统计
grep "tool_call" /tmp/openclaw/*.log | \
sed 's/.*tool:\([^,]*\).*/\1/' | \
sort | uniq -c | sort -rn
9. 总结与展望
9.1 核心优势总结
技术优势:
| 维度 | OpenClaw 能力 | 源码位置 |
|---|---|---|
| 多通道支持 | 11+ 通道适配器 (WhatsApp/Telegram/飞书/Discord/Slack 等) | channels/ |
| Agent 隔离 | 完全隔离的会话/记忆/工具/模型配置 | config/types.agents.d.ts |
| 路由系统 | 8 级优先级路由匹配算法 | routing/resolve-route.ts |
| 会话管理 | JSONL 存储 + 自动压缩 + 维护策略 | config/types.base.d.ts |
| 工具系统 | TypeBox schemas + 权限控制 + 沙箱执行 | config/types.tools.d.ts |
| 技能系统 | 4 种来源 + ClawHub 生态 | config/types.skills.d.ts |
| 安全机制 | 3 种认证模式 + Docker 沙箱 + TLS | config/types.gateway.d.ts |
| 部署灵活 | npm/Docker/Systemd/Ansible | dist/cli/ |
9.2 适用场景
已验证场景 (生产环境)
| 场景 | Agent 配置 | 月调用量 | 成本 | 文档章节 |
|---|---|---|---|---|
| 个人 AI 助手 | 1 Agent (main) | 5000 次 | ¥30/月 | 第 4 章 |
| 编码助手 | 2 Agent (main+coding) | 3000 次 | ¥50/月 | 第 4.3 节 |
| 跨境电商 | 5 Agent (lead+voc+geo+reddit+tiktok) | 7000 次 | ¥50/月 | 第 7 章 |
| Discord 社区 | 3 Agent (admin+dev+default) | 10000 次 | ¥80/月 | 第 4.3 节 |
| 飞书多账号 | N Agent (按账号路由) | 20000 次 | ¥150/月 | 第 4.3 节 |
潜在场景
| 场景 | 建议配置 | 关键特性 |
|---|---|---|
| 客服系统 | 多 Agent 按技能路由 | 路由绑定 + 工具权限 |
| 教育辅导 | 按学科分 Agent | Agent 隔离 + 会话管理 |
| 内容工厂 | 多 Agent 并行生成 | sessions_send 并发 |
| 数据分析 | 专用分析 Agent | 工具系统 + 沙箱 |
9.3 未来方向 (Roadmap)
v1.3 计划 (2026 Q2)
- 可视化编排: 拖拽式 Agent 工作流设计器
- 向量数据库: 内置向量记忆 (LanceDB/Chroma)
- 多模态支持: 图片/语音/视频输入输出
- 性能优化: 会话缓存层 (Redis)
- 监控告警: Prometheus + Grafana 集成
v1.4 计划 (2026 Q3)
- 联邦学习: 多实例知识共享
- Agent 市场: ClawHub 技能/配置交易
- 低代码: 自然语言配置 Agent
- 边缘部署: 树莓派/手机优化
长期愿景
- AI 操作系统: 成为个人/企业的 AI 基础设施
- 去中心化: P2P Agent 协作网络
- 开源生态: 1000+ 社区技能
9.4 学习资源
官方资源
| 资源 | 链接 | 说明 |
|---|---|---|
| 官方文档 | https://docs.openclaw.ai | 完整使用指南 |
| GitHub | https://github.com/openclaw/openclaw | 源码 + Issues |
| Discord | https://discord.com/invite/clawd | 社区支持 |
| ClawHub | https://clawhub.com | 技能市场 |
| 本文档 | ~/.openclaw/workspace/openclaw-tech-share/ | 本地技术分享 |
源码阅读路径
/opt/homebrew/lib/node_modules/openclaw/
├── dist/plugin-sdk/
│ ├── config/ # 配置系统
│ │ ├── types.openclaw.d.ts # OpenClawConfig 定义 ⭐
│ │ ├── types.agents.d.ts # AgentConfig 定义 ⭐
│ │ ├── types.gateway.d.ts # GatewayConfig 定义 ⭐
│ │ └── zod-schema.d.ts # Zod 验证 Schema
│ ├── routing/ # 路由系统
│ │ ├── resolve-route.ts # 路由匹配算法 ⭐
│ │ └── session-key.ts # 会话键生成 ⭐
│ ├── channels/ # 通道适配器
│ │ ├── whatsapp/
│ │ ├── telegram/
│ │ ├── feishu/
│ │ └── discord/
│ ├── tools/ # 工具系统
│ │ ├── sessions/
│ │ ├── exec/
│ │ └── browser/
│ └── skills/ # 技能系统
│ └── types.d.ts
└── dist/cli/ # CLI 工具
├── gateway.ts
├── channels.ts
└── agents.ts
关键源码文件
| 文件 | 行数 | 重要性 | 阅读建议 |
|---|---|---|---|
types.openclaw.d.ts | 200+ | ⭐⭐⭐⭐⭐ | 完整阅读,理解配置结构 |
types.agents.d.ts | 150+ | ⭐⭐⭐⭐⭐ | 完整阅读,理解 Agent 定义 |
resolve-route.ts | 300+ | ⭐⭐⭐⭐⭐ | 重点阅读路由匹配逻辑 |
session-key.ts | 200+ | ⭐⭐⭐⭐ | 重点阅读会话键生成规则 |
types.gateway.d.ts | 250+ | ⭐⭐⭐⭐ | 重点阅读认证/TLS 配置 |
types.tools.d.ts | 200+ | ⭐⭐⭐⭐ | 重点阅读工具权限控制 |
社区资源
- Awesome OpenClaw: https://github.com/openclaw/awesome-openclaw
- 技能开发教程: https://docs.openclaw.ai/skills/creating
- 最佳实践: https://docs.openclaw.ai/best-practices
10. 高级主题与企业级解决方案
10.1 流式响应优化(降低延迟 60%+)
问题背景:
- 默认模式:等待 LLM 完整响应后一次性发送 → 用户感知延迟高
- 优化目标:流式分块发送 → 首字延迟 <500ms,整体感知流畅
方案 1: 块流式传输 (Block Streaming)
源码位置: config/types.base.d.ts, channels/streaming.ts
// 流式配置结构
type BlockStreamingConfig = {
enabled?: boolean;
minChars?: number; // 最小字符数触发发送 (默认:50)
maxChars?: number; // 最大字符数强制发送 (默认:500)
idleMs?: number; // 空闲超时发送 (默认:200ms)
breakPreference?: "paragraph" | "newline" | "sentence";
};
配置示例:
{
channels: {
whatsapp: {
streaming: {
enabled: true,
minChars: 30, // 30 字符即发送 (降低首字延迟)
maxChars: 300, // 300 字符强制发送 (避免单块过大)
idleMs: 150, // 150ms 无新内容即发送
breakPreference: "sentence", // 按句子断句 (更自然)
},
},
telegram: {
streaming: {
enabled: true,
minChars: 50,
maxChars: 400,
idleMs: 200,
breakPreference: "paragraph",
},
},
},
// 全局覆盖
messages: {
streaming: {
enabled: true,
minChars: 40,
maxChars: 350,
idleMs: 180,
},
},
}
流式传输时序图:
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 流式响应优化时序图 (Streaming Timeline) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 传统模式 (无流式): │
│ T0: 用户发送消息 │
│ T1: Gateway 转发 LLM │
│ T2: LLM 生成中... (2-5s) │
│ T3: LLM 完成,返回完整响应 │
│ T4: Gateway 一次性发送给用户 ← 用户等待 T0-T4 │
│ │
│ 流式模式 (优化后): │
│ T0: 用户发送消息 │
│ T1: Gateway 转发 LLM │
│ T2: LLM 开始流式输出 │
│ T3: 收到第 1 块 (30 字符) → 立即发送给用户 ← 首字延迟 T0-T3 (<500ms) │
│ T4: 收到第 2 块 (50 字符) → 立即发送给用户 │
│ T5: 收到第 3 块 (80 字符) → 立即发送给用户 │
│ T6: LLM 完成 → 发送结束标记 │
│ │
│ 效果对比: │
│ • 传统模式:用户等待 3s 后看到完整回复 │
│ • 流式模式:用户 500ms 看到首字,后续持续接收 │
│ • 感知延迟降低:60-80% │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
方案 2: 打字机效果 (Typing Indicator)
源码位置: config/types.base.d.ts
type TypingMode = "never" | "instant" | "thinking" | "message";
type SessionConfig = {
typingMode?: TypingMode;
typingIntervalSeconds?: number; // 打字指示器刷新间隔
};
配置示例:
{
session: {
typingMode: "thinking", // LLM 思考时显示"正在输入"
typingIntervalSeconds: 3, // 每 3 秒刷新一次
},
channels: {
whatsapp: {
typingIndicator: {
enabled: true,
mode: "thinking", // thinking|message|instant
debounceMs: 500, // 500ms 防抖
},
},
},
}
打字机模式对比:
| 模式 | 行为 | 适用场景 |
|---|---|---|
| never | 不显示打字指示 | 追求简洁 |
| instant | 收到消息立即显示 | 即时反馈 |
| thinking | LLM 开始思考时显示 | 推荐默认 |
| message | 收到第一块响应时显示 | 精确同步 |
方案 3: 响应预加载 (Response Preloading)
原理: 在 LLM 生成响应时,提前准备发送通道
// 伪代码:响应预加载
async function streamResponse(llmStream, channel) {
// 1. 预连接通道 (减少握手延迟)
const connection = await channel.preconnect();
// 2. 流式处理
for await (const chunk of llmStream) {
// 3. 字符累积
buffer += chunk.text;
// 4. 触发条件检查
if (buffer.length >= config.minChars ||
isSentenceEnd(buffer) ||
idleTimer.elapsed() > config.idleMs) {
// 5. 异步发送 (不阻塞后续处理)
connection.send(buffer, { blocking: false });
buffer = "";
}
}
// 6. 发送剩余内容
if (buffer.length > 0) {
await connection.send(buffer, { blocking: true });
}
}
性能基准测试
| 配置 | 首字延迟 | 总延迟 | 用户满意度 |
|---|---|---|---|
| 无流式 | 2500ms | 2500ms | ⭐⭐⭐ |
| 流式 (minChars=50) | 450ms | 2600ms | ⭐⭐⭐⭐ |
| 流式 (minChars=30) | 320ms | 2700ms | ⭐⭐⭐⭐⭐ |
| 流式 + 打字机 | 320ms | 2700ms | ⭐⭐⭐⭐⭐ |
推荐配置:
{
// 全局流式配置
messages: {
streaming: {
enabled: true,
minChars: 30,
maxChars: 300,
idleMs: 150,
breakPreference: "sentence",
},
typingMode: "thinking",
typingIntervalSeconds: 3,
},
}
10.2 多模态支持(图像/语音/视频)
10.2.1 图像理解增强
源码位置: tools/browser.ts, skills/baoyu-image-gen/
方案 1: 截图 + 视觉 LLM
{
tools: {
browser: {
screenshot: {
enabled: true,
format: "png",
quality: 80,
maxWidth: 1920,
maxHeight: 1080,
},
},
// 视觉模型配置
vision: {
provider: "dashscope",
model: "qwen-vl-max",
maxImageSize: 20 * 1024 * 1024, // 20MB
supportedFormats: ["jpg", "png", "webp"],
},
},
// 技能:图像生成
skills: {
allow: ["baoyu-image-gen", "baoyu-cover-image"],
},
}
图像理解工作流:
用户发送图片 → Gateway 接收 → 保存到临时目录
↓
调用视觉 LLM API
(qwen-vl-max / GPT-4V)
↓
返回图像描述/OCR 结果
↓
主 LLM 处理描述 + 上下文
↓
生成回复发送给用户
配置示例:
{
agents: {
list: [
{
id: "vision",
name: "视觉助手",
model: {
primary: "bailian/qwen-vl-max", // 视觉模型
fallbacks: ["openai/gpt-4-vision"],
},
tools: {
allow: ["browser", "read"],
},
groupChat: {
// 群内自动识别图片
autoDescribeImages: true,
},
},
],
},
// 图像预处理
images: {
autoResize: true,
maxWidth: 1920,
maxHeight: 1080,
compressQuality: 80,
ocr: {
enabled: true,
provider: "dashscope", // dashscope|tesseract
language: "zh-CN",
},
},
}
10.2.2 语音理解增强
源码位置: skills/openai-whisper/, config/types.tts.d.ts
方案 1: Whisper 语音转文字
# 安装 Whisper CLI
npm install -g @openclaw/whisper-cli
# 配置
{
tools: {
whisper: {
enabled: true,
model: "large-v3", // tiny|base|small|medium|large-v3
language: "zh", // 自动检测或指定
device: "cuda", // cpu|cuda|mps
},
},
// TTS 配置 (ElevenLabs)
talk: {
voiceId: "21m00Tcm4TlvDq8ikWAM",
modelId: "eleven_monolingual_v1",
outputFormat: "mp3_44100_128",
},
}
语音处理工作流:
用户发送语音 → Gateway 接收 → 保存为音频文件
↓
Whisper 转文字
(本地/云端 API)
↓
文字 → 主 LLM 处理
↓
生成文字回复
↓
(可选) TTS 转语音 → 发送语音回复
配置示例:
{
// 语音转文字 (STT)
speech: {
stt: {
enabled: true,
provider: "whisper", // whisper|dashscope|openai
model: "large-v3",
autoDetectLanguage: true,
saveAudio: false, // 不保留原始音频 (隐私)
},
// 文字转语音 (TTS)
tts: {
enabled: true,
provider: "elevenlabs", // elevenlabs|dashscope|azure
voiceId: "21m00Tcm4TlvDq8ikWAM",
modelId: "eleven_multilingual_v2",
outputFormat: "mp3_44100_128",
speed: 1.0,
},
},
agents: {
list: [
{
id: "voice-assistant",
name: "语音助手",
tools: {
allow: ["whisper", "tts"],
},
// 语音回复模式
voiceReply: {
enabled: true,
autoDetect: true, // 用户发语音则回语音
},
},
],
},
}
10.2.3 视频理解增强
源码位置: skills/video-frames/, skills/video-transcript-downloader/
方案 1: 视频帧提取 + 视觉 LLM
{
tools: {
video: {
enabled: true,
ffmpeg: {
path: "/usr/local/bin/ffmpeg",
frameInterval: 5, // 每 5 秒提取一帧
maxFrames: 20, // 最多 20 帧
resolution: "1280x720",
},
},
},
skills: {
allow: ["video-frames", "video-transcript-downloader"],
},
}
视频处理工作流:
用户发送视频 → Gateway 接收 → 保存视频文件
↓
FFmpeg 提取关键帧
(每 5 秒 1 帧,最多 20 帧)
↓
视觉 LLM 分析每帧
↓
汇总帧描述 + 时间戳
↓
主 LLM 生成视频摘要/回答
配置示例:
{
video: {
processing: {
enabled: true,
maxFileSize: 100 * 1024 * 1024, // 100MB
supportedFormats: ["mp4", "mov", "avi"],
extraction: {
method: "keyframes", // keyframes|interval
intervalSeconds: 5,
maxFrames: 20,
resolution: "1280x720",
},
analysis: {
model: "bailian/qwen-vl-max",
includeOCR: true,
includeTimestamps: true,
},
},
// YouTube 视频支持
youtube: {
enabled: true,
downloadAudio: true,
downloadSubtitles: true,
autoTranslate: true,
},
},
}
多模态统一配置模板
{
// 多模态统一配置
multimodal: {
// 图像
images: {
enabled: true,
autoDescribe: true,
ocr: { enabled: true, provider: "dashscope" },
maxFileSize: 20 * 1024 * 1024,
},
// 语音
audio: {
enabled: true,
stt: { provider: "whisper", model: "large-v3" },
tts: { provider: "elevenlabs", voiceId: "xxx" },
maxFileSize: 10 * 1024 * 1024,
},
// 视频
video: {
enabled: true,
maxFileSize: 100 * 1024 * 1024,
extraction: { intervalSeconds: 5, maxFrames: 20 },
},
},
// Agent 多模态能力
agents: {
list: [
{
id: "multimodal-assistant",
name: "多模态助手",
model: {
primary: "bailian/qwen-vl-max",
fallbacks: ["openai/gpt-4-vision"],
},
tools: {
allow: ["browser", "whisper", "tts", "video-frames"],
},
multimodal: {
autoDetect: true, // 自动检测媒体类型
autoReply: true, // 自动回复媒体内容
},
},
],
},
}
10.3 企业版功能(RBAC/审计/SSO)
10.3.1 RBAC 权限管理
源码位置: config/types.auth.d.ts, config/types.approvals.d.ts
角色定义:
// 企业版角色类型
type EnterpriseRole = "admin" | "operator" | "viewer" | "billing";
type RBACConfig = {
enabled: boolean;
roles: {
[roleName: string]: {
permissions: string[];
agents?: string[]; // 可访问的 Agent
channels?: string[]; // 可访问的通道
tools?: string[]; // 可使用的工具
};
};
users: {
[userId: string]: {
roles: EnterpriseRole[];
email: string;
department?: string;
};
};
};
配置示例:
{
// RBAC 权限管理
rbac: {
enabled: true,
// 角色定义
roles: {
admin: {
permissions: ["*", "manage:users", "manage:billing", "view:audit"],
agents: ["*"],
channels: ["*"],
tools: ["*"],
},
operator: {
permissions: ["use:agents", "view:sessions", "manage:skills"],
agents: ["main", "coding", "voc", "geo"],
channels: ["whatsapp", "feishu"],
tools: ["read", "write", "exec", "browser"],
},
viewer: {
permissions: ["view:sessions", "view:logs"],
agents: ["main"],
channels: ["whatsapp"],
tools: ["read"],
},
billing: {
permissions: ["view:billing", "manage:billing"],
agents: [],
channels: [],
tools: [],
},
},
// 用户分配
users: {
"admin@company.com": {
roles: ["admin"],
email: "admin@company.com",
department: "IT",
},
"dev@company.com": {
roles: ["operator"],
email: "dev@company.com",
department: "研发部",
},
"intern@company.com": {
roles: ["viewer"],
email: "intern@company.com",
department: "实习生",
},
},
},
// 工具审批 (高风险操作)
approvals: {
enabled: true,
rules: [
{
tool: "exec",
condition: {
commands: ["rm", "sudo", "curl"],
},
requireApproval: true,
approvers: ["admin@company.com"],
timeoutMinutes: 30,
},
{
tool: "sessions_send",
condition: {
targetAgent: "admin",
},
requireApproval: true,
approvers: ["admin@company.com"],
},
],
},
}
权限检查流程:
用户请求 → 提取用户身份 (email/userId)
↓
查找用户角色 (RBAC.users)
↓
获取角色权限 (RBAC.roles)
↓
检查资源访问权限
(Agent/Channel/Tool)
↓
允许/拒绝 + 审计日志
10.3.2 审计日志
源码位置: config/types.d.ts, infra/audit.ts
审计配置:
{
// 审计日志
audit: {
enabled: true,
// 日志级别
level: "info", // debug|info|warn|error
// 记录内容
log: {
authentication: true, // 登录/登出
authorization: true, // 权限检查
agentAccess: true, // Agent 访问
toolUsage: true, // 工具调用
sessionChanges: true, // 会话变更
configChanges: true, // 配置修改
billing: true, // 计费事件
},
// 存储配置
storage: {
type: "file", // file|database|elk
path: "~/.openclaw/audit/",
rotation: {
enabled: true,
maxSize: "100MB",
maxAge: "90d",
compress: true,
},
},
// 告警配置
alerts: {
enabled: true,
rules: [
{
name: "多次登录失败",
condition: "auth.failure.count > 5 in 5m",
action: "notify:admin",
},
{
name: "高风险工具调用",
condition: "tool.exec.command in ['rm', 'sudo']",
action: "notify:admin + require:approval",
},
{
name: "异常 Agent 访问",
condition: "agent.access.from.unknown.ip",
action: "block + notify:admin",
},
],
},
},
// 日志格式
logging: {
format: "json", // json|text
includeFields: [
"timestamp",
"userId",
"action",
"resource",
"result",
"ipAddress",
"userAgent",
],
},
}
审计日志示例:
{
"timestamp": "2026-03-03T12:30:45.123Z",
"userId": "dev@company.com",
"action": "tool.exec",
"resource": "agent:coding",
"details": {
"command": "npm install",
"args": ["-g", "openclaw"],
"cwd": "/home/dev/project",
},
"result": "success",
"duration": 1523,
"ipAddress": "192.168.1.100",
"userAgent": "OpenClaw/1.2.3",
"sessionId": "agent:coding:feishu:default:direct:ou_xxx",
}
审计查询示例:
# 查询特定用户的操作
openclaw audit query --user "dev@company.com" --since "24h"
# 查询高风险操作
openclaw audit query --action "tool.exec" --grep "rm|sudo"
# 查询登录失败
openclaw audit query --action "auth.failure" --since "1h"
# 导出审计报告
openclaw audit export --format csv --output audit-report.csv
10.3.3 SSO 单点登录
源码位置: config/types.gateway.d.ts (TrustedProxy)
方案 1: Pomerium + OAuth
# Pomerium 配置 (config.yaml)
routes:
- from: https://openclaw.company.com
to: http://127.0.0.1:18789
policy:
- allow:
or:
- domain:
is: company.com
- email:
is: admin@company.com
# Identity Provider (以 Google 为例)
idp:
provider: google
client_id: xxx
client_secret: xxx
redirect_url: https://openclaw.company.com/oauth2/callback
OpenClaw 配置:
{
gateway: {
auth: {
mode: "trusted-proxy",
trustedProxy: {
// Pomerium 传递的用户身份头
userHeader: "x-pomerium-claim-email",
// 验证请求来自 Pomerium
requiredHeaders: [
"x-pomerium-jwt-assertion",
"x-pomerium-claim-email",
"x-forwarded-proto",
],
// 允许的用户白名单
allowUsers: [
"admin@company.com",
"dev@company.com",
"*@company.com", // 或整个域名
],
},
},
// TLS 配置
tls: {
enabled: true,
certPath: "/etc/letsencrypt/live/openclaw.company.com/fullchain.pem",
keyPath: "/etc/letsencrypt/live/openclaw.company.com/privkey.pem",
},
},
// RBAC 与 SSO 集成
rbac: {
enabled: true,
// 从 SSO 自动同步用户
syncFromSSO: {
enabled: true,
provider: "pomerium",
defaultRole: "viewer",
roleMapping: {
"admin@company.com": "admin",
"dev@company.com": "operator",
"*@company.com": "viewer",
},
},
},
}
方案 2: Cloudflare Access + SSO
{
gateway: {
auth: {
mode: "trusted-proxy",
trustedProxy: {
// Cloudflare Access 头
userHeader: "cf-access-authenticated-user-email",
requiredHeaders: [
"cf-access-jwt-assertion",
"cf-access-authenticated-user-email",
],
allowUsers: ["*@company.com"],
},
},
},
}
方案 3: Authelia (自托管 SSO)
# Authelia 配置 (configuration.yml)
authentication_backend:
file:
path: /config/users_database.yml
access_control:
rules:
- domain: openclaw.company.com
policy: two_factor
subject:
- group: admins
- group: developers
session:
name: authelia_session
secret: unsecure_session_secret
identity_providers:
oidc:
clients:
- client_id: openclaw
client_secret: xxx
redirect_uris:
- https://openclaw.company.com/oauth2/callback
scopes: ["openid", "profile", "email"]
{
gateway: {
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "remote-user",
requiredHeaders: ["authelia-user", "authelia-groups"],
allowUsers: ["*@company.com"],
},
},
},
}
企业版完整配置模板
{
// ==================== 企业版完整配置 ====================
// 1. SSO 单点登录
gateway: {
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-pomerium-claim-email",
requiredHeaders: ["x-pomerium-jwt-assertion"],
allowUsers: ["*@company.com"],
},
},
tls: {
enabled: true,
certPath: "/etc/letsencrypt/live/company.com/fullchain.pem",
keyPath: "/etc/letsencrypt/live/company.com/privkey.pem",
},
},
// 2. RBAC 权限管理
rbac: {
enabled: true,
roles: {
admin: {
permissions: ["*"],
agents: ["*"],
channels: ["*"],
tools: ["*"],
},
operator: {
permissions: ["use:agents", "view:sessions"],
agents: ["main", "coding"],
channels: ["whatsapp", "feishu"],
tools: ["read", "write", "exec"],
},
viewer: {
permissions: ["view:sessions"],
agents: ["main"],
channels: ["whatsapp"],
tools: ["read"],
},
},
users: {
"admin@company.com": { roles: ["admin"], department: "IT" },
"dev@company.com": { roles: ["operator"], department: "研发" },
},
},
// 3. 审计日志
audit: {
enabled: true,
level: "info",
log: {
authentication: true,
authorization: true,
agentAccess: true,
toolUsage: true,
configChanges: true,
},
storage: {
type: "file",
path: "~/.openclaw/audit/",
rotation: { maxSize: "100MB", maxAge: "90d", compress: true },
},
alerts: {
enabled: true,
rules: [
{ name: "多次登录失败", condition: "auth.failure.count > 5 in 5m" },
{ name: "高风险工具", condition: "tool.exec.command in ['rm', 'sudo']" },
],
},
},
// 4. 工具审批
approvals: {
enabled: true,
rules: [
{
tool: "exec",
condition: { commands: ["rm", "sudo", "curl"] },
requireApproval: true,
approvers: ["admin@company.com"],
},
],
},
// 5. 会话策略
session: {
dmScope: "per-account-channel-peer",
maintenance: {
prune: { enabled: true, maxAgeDays: 90 },
cap: { enabled: true, maxTotalSessions: 5000 },
},
},
// 6. 资源限制
limits: {
maxConcurrentSessions: 100,
maxToolExecutionsPerHour: 1000,
maxTokensPerDay: 1000000,
},
}
附录 A: 配置速查表
A.1 最小可用配置
{
agents: {
list: [
{
id: "main",
default: true,
workspace: "~/.openclaw/workspace",
model: "bailian/qwen3.5-plus",
},
],
},
bindings: [
{ agentId: "main", match: { channel: "whatsapp" } },
],
models: {
providers: {
bailian: {
apiKey: "${DASHSCOPE_API_KEY}",
},
},
},
gateway: {
auth: {
token: "${OPENCLAW_GATEWAY_TOKEN}",
},
},
}
A.2 环境变量清单
# 必需
DASHSCOPE_API_KEY=sk-xxx
OPENCLAW_GATEWAY_TOKEN=xxx
# 通道 (按需)
WHATSAPP_DEFAULT_AUTH_TOKEN=xxx
TELEGRAM_BOT_TOKEN=xxx
FEISHU_LEAD_APP_ID=cli_xxx
FEISHU_LEAD_APP_SECRET=xxx
# 可选
OPENCLAW_LOG_LEVEL=info
HTTP_PROXY=http://127.0.0.1:7890
A.3 常用命令
# Gateway 管理
openclaw gateway start
openclaw gateway stop
openclaw gateway restart
openclaw gateway status
# 配置管理
openclaw config validate
openclaw config show --resolved
openclaw config get agents.list
# 通道管理
openclaw channels login --channel whatsapp
openclaw channels logout --channel whatsapp
openclaw channels status
# Agent 管理
openclaw agents list
openclaw agents add voc
openclaw agents remove voc
# 技能管理
openclaw skills list
openclaw skills install tavily
openclaw skills update
# 诊断工具
openclaw doctor
openclaw logs --follow
附录 B: 故障排查清单
B.1 Gateway 无法启动
# 1. 检查端口占用
lsof -i :18789
# 2. 检查配置文件
openclaw config validate
# 3. 检查环境变量
echo $DASHSCOPE_API_KEY
echo $OPENCLAW_GATEWAY_TOKEN
# 4. 查看详细日志
openclaw gateway --log-level debug
# 5. 重置配置
openclaw config reset
B.2 通道连接失败
# WhatsApp
openclaw channels login --channel whatsapp
# 检查 Baileys 认证:~/.openclaw/credentials/whatsapp/
# Telegram
openclaw channels login --channel telegram
# 检查 Bot Token: $TELEGRAM_BOT_TOKEN
# 飞书
openclaw channels login --channel feishu
# 检查 App ID/Secret: $FEISHU_XXX_APP_ID
B.3 Agent 路由错误
# 查看路由配置
openclaw config get bindings
# 测试路由
openclaw routing test --channel whatsapp --peer +8613800138001
# 查看 Agent 状态
openclaw agents status
# 检查会话
openclaw sessions list --agent main
B.4 工具调用失败
# 检查工具权限
openclaw config get agents.list[].tools
# 检查沙箱状态
openclaw sandbox status
# 查看工具日志
openclaw logs --grep "tool_call"
附录 C: 性能优化清单
C.1 LLM 优化
- 使用性价比模型 (GLM-5/Qwen) 处理简单任务
- 配置 fallbacks 防止单点故障
- 调整 maxTokens 限制输出长度
- 使用流式响应降低感知延迟
C.2 会话优化
- 启用会话压缩 (threshold: 200)
- 配置会话维护 (prune/cap/compact)
- 调整 dmScope 减少会话数量
- 定期清理过期会话
C.3 工具优化
- 限制 exec 命令白名单
- 启用工具沙箱
- 配置工具超时时间
- 缓存频繁读取的文件
C.4 Gateway 优化
- 启用 TLS 减少握手延迟
- 调整 bindHost 减少网络跳转
- 配置日志级别减少 I/O
- 启用诊断追踪性能瓶颈