第1节 引言:多 Agent 隔离机制概述
1.1 什么是多 Agent 隔离
多 Agent 隔离(Multi-Agent Isolation) 是指在同一个 AI 助手框架内,让多个 Agent 实例各自拥有独立的运行环境,彼此之间不会相互干扰的技术机制。
在 OpenClaw 的架构中,多 Agent 隔离通过三个维度实现:
┌─────────────────────────────────────────────────────────┐
│ OpenClaw Gateway │
│ (单一控制平面, ws:18789) │
├─────────────┬─────────────┬─────────────┬───────────────┤
│ Agent: main│ Agent: work │ Agent: dev │ Agent: ops │
│ │ │ │ │
│ workspace │ workspace │ workspace │ workspace │
│ sessions │ sessions │ sessions │ sessions │
│ skills │ skills │ skills │ skills │
│ memory │ memory │ memory │ memory │
│ config │ config │ config │ config │
└─────────────┴─────────────┴─────────────┴───────────────┘
↑ ↑ ↑ ↑
独立文件 独立会话 独立工具 独立记忆
系统目录 存储目录 配置集 索引
每个 Agent 在系统中拥有以下独立的资源域:
| 隔离维度 | 存储位置 | 说明 |
|---|---|---|
| 工作空间 | ~/.openclaw/workspace-<agentId>/ |
Agent 的文件系统 cwd,存放 AGENTS.md、SOUL.md、TOOLS.md、IDENTITY.md、USER.md 等配置文件 |
| 状态目录 | ~/.openclaw/agents/<agentId>/agent/ |
per-agent 配置(models.json、config.json 等) |
| 会话存储 | ~/.openclaw/agents/<agentId>/sessions/ |
聊天历史(sessions.json)和会话记录(JSONL 格式) |
| 技能目录 | ~/.openclaw/workspace-<agentId>/skills/ |
Agent 专属技能文件夹 |
这种隔离确保了:Agent A 修改的文件不会影响 Agent B;Agent A 的对话历史与 Agent B 完全分离;每个 Agent 可以拥有独立的人格定义、工具权限和技能集。
1.2 为什么需要隔离:应用场景
多 Agent 隔离机制并非理论设计,而是由实际使用场景驱动的必要架构。以下是 OpenClaw 中隔离机制的典型应用场景:
场景一:生活与工作分离
用户可能希望在个人 WhatsApp 号上运行的 Agent(处理私人事务)与工作 WhatsApp 号上的 Agent(处理工作事务)完全隔离。两个 Agent 使用不同的工作空间、不同的记忆文件、甚至可能使用不同的模型。
{
agents: {
list: [
{ id: "personal", workspace: "~/.openclaw/workspace-personal" },
{ id: "work", workspace: "~/.openclaw/workspace-work" }
]
}
}
场景二:多渠道差异化服务
同一用户可能同时使用飞书、Discord、WhatsApp 等多个渠道,每个渠道承载不同的使用目的。例如飞书用于团队协作、Discord 用于社区管理、WhatsApp 用于私人通讯。通过隔离,不同渠道的 Agent 可以有不同的人格和能力。
场景三:安全沙箱
在多用户环境中,OpenClaw 支持 Docker 沙箱隔离。非主会话可以在隔离容器中运行,限制文件系统访问和网络 egress。这对于不受信任的用户输入或第三方集成至关重要。
{
agents: {
defaults: {
sandbox: {
mode: "non-main",
workspaceRoot: "~/.openclaw/sandbox",
allow: ["read", "write", "exec"],
deny: ["browser", "canvas", "nodes"]
}
}
}
}
场景四:专业化 Agent 分工
OpenClaw 实际部署中可以看到多个专业 Agent:lobster-master(任务管理)、shrimp-t800(质量检查)、data-researcher(资料搜集)、art-designer(美术设计)、sys-ops(系统运维)等。每个 Agent 专注于特定领域,拥有独立的技能集和工具配置,互不干扰。
1.3 OpenClaw 的隔离哲学
OpenClaw 的隔离设计遵循三条核心理念:
1.3.1 本地优先(Local-First)
所有隔离资源都存储在本地文件系统中,而非云端数据库。这意味着:
- 用户对数据拥有完全控制权
- 隔离边界由文件系统权限自然保障
- 无需依赖外部服务即可实现完整的隔离效果
正如 OpenClaw 架构分析文档所述:"OpenClaw 是一个运行在用户自有设备上的个人 AI 助手框架"。本地优先的设计理念贯穿整个隔离机制。
1.3.2 声明式配置(Declarative Configuration)
隔离关系通过 openclaw.json 配置文件声明式定义,而非硬编码。用户可以随时添加新的 Agent、调整绑定规则、修改工作空间路径,无需修改任何核心代码。
// 配置即文档:每个 Agent 的隔离边界一目了然
{
agents: {
list: [
{
id: "lobster-master",
workspace: "/home/admin/openclaw/workspace-agents/lobster-master",
agentDir: "/home/admin/.openclaw/agents/lobster-master/agent",
model: "generic/qwen3.6-plus",
identity: { name: "龙虾场主", emoji: "🦞" }
}
]
}
}
1.3.3 确定性路由(Deterministic Routing)
OpenClaw 采用确定性、最具体优先的路由算法,确保每条消息都能被精确路由到目标 Agent。8 级路由优先级(从精确的 peer 匹配到默认回退)保证了路由行为的可预测性和可调试性。这是隔离机制能够有效运行的基础------如果消息路由不确定,隔离就会失效。
1.3.4 最小权限原则(Least Privilege)
每个 Agent 默认只拥有完成其职责所需的最小权限。工具策略(tools.allow/deny)、沙箱模式、技能门控(Skill Gating)等多层控制确保 Agent 不会越权访问不属于自己的资源。
消息进入 → 路由匹配(binding → agentId) → 工具策略过滤 → 沙箱执行 → 结果返回
↑ ↑ ↑ ↑
隔离维度1 隔离维度2 隔离维度3 隔离维度4
(消息路由) (工作空间) (工具权限) (执行环境)
1.4 本文结构
本文将围绕 OpenClaw 多 Agent 隔离的三个核心支柱展开:
- 工作空间隔离:每个 Agent 如何拥有独立的文件系统、技能目录和记忆体系
- 状态隔离:会话管理、认证配置和 per-agent 设置如何独立维护
- 绑定路由:Bindings 机制如何实现精确的消息路由,以及 8 级优先级算法的确定性保证
通过深入剖析这三个维度,读者将全面理解 OpenClaw 如何在单一 Gateway 进程中实现安全、可靠的多 Agent 运行环境。
第2节 四个维度:工作空间、状态、会话与配置隔离
OpenClaw 的多 Agent 隔离机制不是一个单一维度的设计,而是从 工作空间(Workspace)、状态(State)、会话(Session)、配置(Configuration) 四个维度共同构建的立体隔离体系。这四个维度相互独立又互为补充,确保每个 Agent 在同一个 Gateway 进程中运行时,既能享受共享基础设施带来的效率,又能保持彼此间的严格边界。
本节将逐一拆解这四个隔离维度,揭示 OpenClaw 如何实现"一个 Gateway,多个互不干扰的 Agent"。
2.1 工作空间隔离(Workspace Isolation)
工作空间隔离是多 Agent 架构的第一道防线。每个 Agent 在文件系统中拥有完全独立的工作区域,从根目录到技能目录,再到启动注入文件,层层隔离。
独立文件系统
在 OpenClaw 的配置中,每个 Agent 通过 workspace 字段指定专属的工作目录,通过 agentDir 字段指定状态存储目录(存放会话数据等)。如果未指定 agentDir,系统根据 Agent ID 自动生成默认路径。
{
agents: {
list: [
{
id: "personal",
workspace: "~/.openclaw/workspace-personal",
agentDir: "~/.openclaw/agents/personal",
},
{
id: "work",
workspace: "~/.openclaw/workspace-work",
agentDir: "~/.openclaw/agents/work",
},
{
id: "dev",
workspace: "~/.openclaw/workspace-dev",
agentDir: "~/.openclaw/agents/dev",
},
],
},
}
Agent 的所有文件操作(read、write、edit 等工具调用)都以该 workspace 目录为 当前工作目录(cwd) 。这意味着 personal Agent 写入的 ~/memory/2026-04-10.md 和 work Agent 写入的 ~/memory/2026-04-10.md 实际上分别位于不同的物理路径,永远不会冲突。
~/.openclaw/
├── workspace-personal/ ← personal Agent 的专属空间
│ ├── AGENTS.md
│ ├── SOUL.md
│ ├── MEMORY.md
│ ├── memory/
│ │ └── 2026-04-10.md
│ └── skills/
├── workspace-work/ ← work Agent 的专属空间
│ ├── AGENTS.md
│ ├── SOUL.md
│ ├── MEMORY.md
│ ├── memory/
│ │ └── 2026-04-10.md
│ └── skills/
└── workspace-dev/ ← dev Agent 的专属空间
├── AGENTS.md
├── SOUL.md
└── ...
技能目录隔离
技能目录是工作空间隔离的重要延伸。OpenClaw 从三个位置加载技能,其中优先级最高的是 工作区技能:
~/.openclaw/workspace-<agentId>/skills/ ← 优先级最高
~/.openclaw/skills/ ← 共享技能
<安装路径>/skills/ ← 捆绑技能(优先级最低)
这意味着每个 Agent 不仅可以拥有完全不同的工作区文件,还可以加载完全不同的技能集。personal Agent 可以安装 weather 和 stock-watcher 技能,而 work Agent 则安装 feishu-doc 和 healthcheck 技能,互不干扰。
当技能名称冲突时,工作区技能优先于共享技能,共享技能优先于捆绑技能。这为 Agent 级别的技能定制提供了精细的控制能力。
启动文件注入机制
每次新会话启动时,OpenClaw 会将工作区中的以下启动文件内容直接注入到 Agent 的系统提示中:
| 文件 | 用途 |
|---|---|
AGENTS.md |
操作指令和记忆管理指南 |
SOUL.md |
Agent 的人设、边界和语调 |
TOOLS.md |
用户维护的工具备忘录 |
IDENTITY.md |
Agent 的名称、风格和 emoji |
USER.md |
用户画像和偏好设置 |
BOOTSTRAP.md |
一次性初始化脚本(首次运行后自动删除) |
这些文件定义了 Agent 的行为准则。由于每个 Agent 的工作区独立,它们的行为准则也天然隔离------personal Agent 可以是轻松幽默的"龙虾场主",而 work Agent 可以是严谨专业的"商务助理"。
┌─────────────────────────────────────────────────┐
│ Gateway(单一进程) │
├─────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌──────────────────────┐ │
│ │ personal Agent │ │ work Agent │ │
│ │ │ │ │ │
│ │ AGENTS.md ──┐ │ │ AGENTS.md ────┐ │ │
│ │ SOUL.md ──┤ │ │ SOUL.md ────┤ │ │
│ │ TOOLS.md ──┤ │ │ TOOLS.md ────┤ │ │
│ │ IDENTITY ──┤ │ │ IDENTITY ────┤ │ │
│ │ USER.md ──┤ │ │ USER.md ────┤ │ │
│ │ BOOTSTRAP───┘ │ │ BOOTSTRAP ────┘ │ │
│ │ │ │ │ │
│ │ skills/ ──────┤ │ skills/ ──────────┤ │ │
│ │ weather │ │ feishu-doc │ │ │
│ │ stock-watcher│ │ healthcheck │ │ │
│ │ │ │ │ │
│ │ memory/ │ │ memory/ │ │
│ │ (独立日志) │ │ (独立日志) │ │
│ └─────────────────┘ └──────────────────────┘ │
│ │
└─────────────────────────────────────────────────┘
沙箱模式(Docker 隔离)
对于需要更高安全级别的场景,OpenClaw 提供 Docker 沙箱模式:
{
agents: {
defaults: {
sandbox: {
mode: "non-main", // off | non-main | all
scope: "agent", // session | agent | shared
workspaceRoot: "~/.openclaw/sandbox",
allow: ["read", "write", "exec", "process", "sessions_*"],
deny: ["browser", "canvas", "nodes", "cron", "gateway"],
},
},
},
}
- mode :
off(无沙箱)、non-main(非主会话在容器中运行)、all(所有会话沙箱化) - scope :
session(每会话一个容器)、agent(每 Agent 一个容器)、shared(所有会话共享容器)
在沙箱模式下,Agent 的 exec 等命令在 Docker 容器内执行,文件系统访问受限,网络出口可配置,浏览器、节点控制等敏感工具默认禁用。这为多用户环境或不受信任的工作负载提供了操作系统级别的隔离保障。
2.2 状态隔离(State Isolation)
如果说工作空间隔离保证了文件系统的独立性,状态隔离则确保了每个 Agent 的运行上下文互不干扰。
认证配置分离
每个 Agent 拥有独立的状态目录,路径为 ~/.openclaw/agents/<agentId>/。这意味着 personal Agent 和 work Agent 即使连接同一个 LLM 提供商(如 Anthropic),它们各自的 API Key 和认证状态也是完全分离的。一个 Agent 的认证失效不会影响另一个 Agent。
模型注册表独立
模型注册表信息存储在各自的状态目录中。不同 Agent 可以使用完全不同的模型配置------personal 使用 generic/qwen3.6-plus 作为主模型,work 使用 generic/MiniMax-M2.5,dev 使用本地 Ollama 模型。每个 Agent 的模型解析、fallback 链和认证配置均独立管理。
Per-Agent 配置
OpenClaw 支持在 agents.list 中为每个 Agent 指定个性化配置:
每个 Agent 的配置项包括:id(Agent 标识)、workspace(工作空间路径)、agentDir(状态存储路径,可选)、model(默认模型)、tools(工具策略)、identity(可选的 Agent 身份标识,如名称和 emoji)等。
{
agents: {
list: [
{
id: "personal",
workspace: "~/.openclaw/workspace-personal",
model: "generic/qwen3.6-plus",
default: true,
},
{
id: "work",
workspace: "~/.openclaw/workspace-work",
model: "generic/MiniMax-M2.5",
sandbox: {
mode: "all",
scope: "agent",
},
tools: {
allow: ["read", "exec"],
deny: ["write", "edit", "browser"],
},
},
],
},
}
每个 Agent 可以拥有独立的:
- 主模型和 fallback 模型
- 沙箱策略
- 工具策略
- 内存搜索配置
- 上下文压缩参数
会话存储路径
每个 Agent 的会话数据存储在专属路径下:
~/.openclaw/agents/<agentId>/sessions/
├── sessions.json ← 会话元数据索引
├── <SessionId_1>.jsonl ← 会话记录 1
├── <SessionId_2>.jsonl ← 会话记录 2
└── ...
personal Agent 的会话记录位于 ~/.openclaw/agents/personal/sessions/,work Agent 的会话记录位于 ~/.openclaw/agents/work/sessions/,物理路径完全不同,确保会话历史的严格隔离。
会话元数据文件 sessions.json 记录了所有活跃和最近会话的键、状态和时间戳。当文件超过 rotateBytes 限制(默认 10MB)时会自动轮转,超过 pruneAfter 天数(默认 30 天)的条目会自动清理。
2.3 会话隔离(Session Isolation)
会话隔离是多 Agent 架构中最精细的维度,它决定了"谁在跟谁说话"以及"对话的上下文如何保持"。
会话键格式
OpenClaw 使用结构化的会话键来唯一标识每个会话:
| 场景 | 会话键格式 | 示例 |
|---|---|---|
| 直接聊天(DM) | agent:<agentId>:<mainKey> |
agent:personal:main |
| 群组聊天 | agent:<agentId>:<channel>:group:<id> |
agent:work:discord:group:987654 |
| 定时任务(Cron) | cron:<job.id> |
cron:daily-report |
| Webhook | hook:<uuid> |
hook:a1b2c3d4-e5f6 |
| 子 Agent | agent:<agentId>:subagent:<uuid> |
agent:personal:subagent:abc123 |
会话键是会话隔离的基础------不同的会话键意味着不同的对话历史和上下文状态。
会话作用域模型
DM 消息的会话隔离由 dmScope 配置控制,支持四种模式(详见第5节):
{
session: {
dmScope: "per-channel-peer", // main | per-peer | per-channel-peer | per-account-channel-peer
},
}
不同的作用域模式决定了同一发送者通过不同渠道发送消息时是否共享对话上下文。
会话生命周期管理
OpenClaw 提供了灵活的会话生命周期管理机制:
- 每日重置:默认每天凌晨 4:00(网关主机本地时间)自动创建新会话,旧的对话上下文归档但保留在 JSONL 文件中
- 空闲重置 :可配置
idleMinutes,超过设定时间无交互后自动开启新会话 - 手动重置 :用户随时可以通过
/new或/reset命令手动开启新会话
这种设计确保了 Agent 不会因为无限增长的上下文而性能下降,同时又保留了历史对话的可追溯性。
会话状态存储结构
每个会话的完整状态包括:
注:此为概念性展示,实际会话数据以 JSONL 格式逐行存储,详见第7节 7.2。
{
"sessionKey": "agent:personal:main",
"sessionId": "sess-abc123",
"agentId": "personal",
"channel": "webchat",
"peerId": "user-123",
"created": 1712736000000,
"lastActive": 1712822400000,
"compactCount": 3,
"history": [
{ "role": "user", "content": "今天天气如何?" },
{ "role": "assistant", "content": "让我帮你查一下..." }
],
"compactions": [
{ "summary": "用户询问了天气情况..." }
]
}
会话记录以 JSONL(JSON Lines)格式追加写入,支持高效的顺序读写和流式回放。
2.4 配置隔离(Configuration Isolation)
配置隔离确保每个 Agent 拥有独立的工具策略、模型配置和内存环境。
独立模型配置
每个 Agent 可以配置完全不同的模型栈:
{
agents: {
list: [
{
id: "personal",
model: "generic/qwen3.6-plus",
models: {
"generic/qwen3.6-plus": { alias: "Sonnet" },
"generic/MiniMax-M2.5": { alias: "GPT" },
},
},
{
id: "dev",
model: "ollama/llama3.3:70b",
// 完全使用本地模型,零 API 成本
},
],
},
}
这不仅仅是模型选择的不同------每个 Agent 的模型解析逻辑、认证配置文件、rate limit 管理和 fallback 策略都是独立的。
工具策略独立
工具策略(tools.allow / tools.deny)可以在每个 Agent 级别单独配置:
{
agents: {
list: [
{
id: "personal",
tools: {
allow: ["group:fs", "group:runtime", "group:memory", "browser", "image"],
},
},
{
id: "work",
tools: {
profile: "minimal",
allow: ["session_status", "message"],
},
},
],
},
}
personal Agent 拥有完整的工具集(包括浏览器和文件操作),而 work Agent 被限制为最小权限,只能查询状态和发送消息。即使两个 Agent 运行在同一台机器上,work Agent 也无法访问文件系统或浏览器。
此外,工具策略支持按供应商限制(tools.byProvider),可以为不同模型供应商配置不同的工具集。
内存文件隔离
内存(Memory)文件存储在各 Agent 的工作区中,天然隔离:
~/.openclaw/workspace-personal/
├── MEMORY.md ← personal Agent 的长期记忆
├── memory/
│ └── 2026-04-10.md ← personal Agent 的日志
└── ...
~/.openclaw/workspace-work/
├── MEMORY.md ← work Agent 的长期记忆
├── memory/
│ └── 2026-04-10.md ← work Agent 的日志
└── ...
更关键的是,MEMORY.md 仅在主会话(私人对话)中加载,永远不会在群组上下文中加载。这确保了每个 Agent 的长期记忆不会意外泄露到不安全的场景中。
向量记忆搜索的索引也是按工作区构建的,不同 Agent 的记忆搜索结果互不影响。
总结:四维隔离全景图
┌──────────────────────────────────────────────────────────────────────┐
│ Gateway(单一控制平面) │
│ │
│ ┌──────────────────────────┐ ┌──────────────────────────────────┐ │
│ │ personal Agent │ │ work Agent │ │
│ │ │ │ │ │
│ │ ① Workspace Isolation │ │ ① Workspace Isolation │ │
│ │ ~/.openclaw/workspace- │ │ ~/.openclaw/workspace-work/ │ │
│ │ personal/ │ │ │ │
│ │ ├── AGENTS.md │ │ ├── AGENTS.md │ │
│ │ ├── SOUL.md │ │ ├── SOUL.md │ │
│ │ ├── skills/ │ │ ├── skills/ │ │
│ │ └── memory/ │ │ └── memory/ │ │
│ │ │ │ │ │
│ │ ② State Isolation │ │ ② State Isolation │ │
│ │ ~/.openclaw/agents/ │ │ ~/.openclaw/agents/ │ │
│ │ personal/sessions/ │ │ work/sessions/ │ │
│ │ │ │ │ │
│ │ ③ Session Isolation │ │ ③ Session Isolation │ │
│ │ agent:personal:main │ │ agent:work:main │ │
│ │ agent:personal:wa: │ │ agent:work:tg:group:xyz │ │
│ │ group:123 │ │ │ │
│ │ │ │ │ │
│ │ ④ Configuration │ │ ④ Configuration │ │
│ │ model: generic/qwen3.6-plus │ │ model: generic/MiniMax-M2.5 │ │
│ │ tools: full │ │ tools: minimal │ │
│ │ sandbox: off │ │ sandbox: all │ │
│ └──────────────────────────┘ └──────────────────────────────────┘ │
│ │
│ ←──── 路由:bindings(最具体优先匹配) ────→ │
│ 精确匹配 > 线程继承 > Discord角色 > Discord服务器 > Slack团队 │
│ > 账户匹配 > 渠道级匹配 > 默认回退 │
└──────────────────────────────────────────────────────────────────────┘
四个隔离维度共同构建了一个完整的防护体系:工作空间 隔离了文件和技能,状态 隔离了认证和会话存储,会话 隔离了对话上下文,配置 隔离了模型和工具策略。通过 bindings 路由机制,来自不同渠道、不同发送者、不同群组的消息被精确分发到对应的 Agent,确保每个 Agent 在自己的"沙箱"中安全运行。
第3节 绑定路由(Bindings):消息如何找到正确的 Agent
3.1 什么是 Bindings
Bindings(绑定) 是 OpenClaw 中用于将入站消息路由到特定 Agent 的配置规则。它是多 Agent 隔离机制的"交通指挥系统"------当消息从 WhatsApp、Telegram、Discord、飞书等渠道进入 Gateway 时,Bindings 决定了这条消息应该由哪个 Agent 来处理。
如果没有 Bindings,所有消息都会回退到默认 Agent(通常是 main)。有了 Bindings,用户可以实现精细化的消息路由控制,让不同来源的消息自动分配给最合适的 Agent。
入站消息流:
┌──────────┐ ┌──────────────┐ ┌──────────────────┐ ┌──────────┐
│ WhatsApp │───▶│ │───▶│ Agent: personal │ │ │
│ Msg A │ │ Bindings │ │ (工作空间 A) │ │ │
│ │ │ 路由引擎 │ │ │ │ │
├──────────┤ │ │ ├──────────────────┤ │ Gateway │
│ Discord │───▶│ │───▶│ Agent: work │ │ │
│ Msg B │ │ match{ │ │ (工作空间 B) │ │ │
│ │ │ channel, │ │ │ │ │
├──────────┤ │ accountId, │ ├──────────────────┤ │ │
│ 飞书消息 │───▶│ peer, │───▶│ Agent: main │ │ │
│ Msg C │ │ guildId, │ │ (默认) │ │ │
│ │ │ ... } │ │ │ │ │
└──────────┘ └──────────────┘ └──────────────────┘ └──────────┘
3.2 绑定配置语法
Bindings 在 openclaw.json 配置文件中以数组形式定义,每个绑定规则包含两个核心字段:
agentId:目标 Agent 的 ID,对应agents.list中定义的某个 Agentmatch:匹配条件对象,定义什么来源的消息适用此规则
基本配置结构
{
// 定义可用的 Agent 列表
agents: {
list: [
{ id: "main", workspace: "~/.openclaw/workspace" },
{ id: "personal", workspace: "~/.openclaw/workspace-personal" },
{ id: "work", workspace: "~/.openclaw/workspace-work" }
]
},
// 定义路由绑定规则
bindings: [
{ agentId: "personal", match: { channel: "whatsapp", accountId: "personal-number" } },
{ agentId: "work", match: { channel: "whatsapp", accountId: "biz-number" } },
{ agentId: "main", match: { channel: "feishu", accountId: "default" } }
]
}
真实配置示例
以下是当前 OpenClaw 实例中实际使用的绑定配置:
{
"bindings": [
{
"agentId": "main",
"match": {
"channel": "feishu",
"accountId": "default"
}
},
{
"agentId": "lobster-master",
"match": {
"channel": "feishu",
"accountId": "ou_181af55d1b5696b2dd9dea7e52731ec5"
}
}
]
}
这个配置的含义是:
- 来自飞书
default账号的消息 → 路由到mainAgent - 来自飞书
ou_181af55d1b5696b2dd9dea7e52731ec5账号的消息 → 路由到lobster-masterAgent
复杂绑定示例
{
bindings: [
// 规则1:Discord 特定频道路由到 work Agent
{
agentId: "work",
match: {
channel: "discord",
peer: { kind: "channel", id: "123456789" }
}
},
// 规则2:Discord 特定服务器中的所有消息路由到 community Agent
{
agentId: "community",
match: {
channel: "discord",
guildId: "987654321"
}
},
// 规则3:Slack 特定团队路由到 slack-agent
{
agentId: "slack-agent",
match: {
channel: "slack",
teamId: "T01ABCDEF"
}
},
// 规则4:Discord 角色路由------管理员角色消息路由到 admin-agent
{
agentId: "admin-agent",
match: {
channel: "discord",
guildId: "987654321",
roles: ["admin", "moderator"]
}
},
// 规则5:特定用户(peer)的私聊路由到 personal Agent
{
agentId: "personal",
match: {
channel: "telegram",
peer: { kind: "user", id: "12345678" }
}
},
// 规则6:WhatsApp 特定账号路由
{
agentId: "biz-agent",
match: {
channel: "whatsapp",
accountId: "work-number"
}
}
]
}
3.3 匹配条件详解
Bindings 的 match 对象支持多种匹配字段,每个字段对应消息的一个属性维度:
3.3.1 channel(渠道)
匹配消息来源的渠道类型。这是最基础的匹配维度。
| 值 | 说明 |
|---|---|
"whatsapp" |
WhatsApp 消息 |
"telegram" |
Telegram 消息 |
"discord" |
Discord 消息 |
"slack" |
Slack 消息 |
"feishu" |
飞书消息 |
"signal" |
Signal 消息 |
"wecom" |
企业微信消息 |
"webchat" |
WebChat 消息 |
"qqbot" |
QQ 机器人消息 |
"dingtalk" |
钉钉消息 |
{
agentId: "work",
match: { channel: "discord" } // 所有 Discord 消息
}
3.3.2 peer(对等体)
匹配具体的发送者或群组/频道 ID。peer 是一个对象,包含两个字段:
-
kind:对等体类型,可选值包括"user"(私聊用户)、"group"(群组)、"channel"(频道) -
id:对等体的唯一标识符{
agentId: "personal",
match: {
channel: "telegram",
peer: { kind: "user", id: "987654321" } // 特定用户的私聊
}
}{
agentId: "community",
match: {
channel: "discord",
peer: { kind: "channel", id: "111222333444" } // 特定 Discord 频道
}
}
3.3.3 accountId(账户 ID)
匹配渠道的账户标识。在支持多账户的渠道中(如多个 WhatsApp 号码、多个飞书应用),accountId 用于区分不同账户。
{
agentId: "biz-agent",
match: {
channel: "whatsapp",
accountId: "biz-number" // 工作 WhatsApp 号
}
}
{
agentId: "lobster-master",
match: {
channel: "feishu",
accountId: "ou_181af55d1b5696b2dd9dea7e52731ec5" // 特定飞书应用
}
}
3.3.4 guildId(Discord 服务器 ID)
仅适用于 Discord 渠道,匹配特定的 Discord 服务器(Guild)。
{
agentId: "community",
match: {
channel: "discord",
guildId: "555666777888" // 特定的 Discord 服务器
}
}
3.3.5 roles(Discord 角色列表)
仅适用于 Discord 渠道,匹配发送者拥有的角色。当消息发送者拥有指定角色列表中的任意角色时,匹配成功。
{
agentId: "admin-agent",
match: {
channel: "discord",
guildId: "555666777888",
roles: ["admin", "moderator"] // 拥有 admin 或 moderator 角色的用户
}
}
3.3.6 teamId(Slack 团队 ID)
仅适用于 Slack 渠道,匹配特定的 Slack 工作区(Team)。
{
agentId: "work",
match: {
channel: "slack",
teamId: "T01ABCDEF" // 特定的 Slack 工作区
}
}
3.3.7 parentPeer(线程继承)
匹配父级对等体,用于线程消息的路由。当一条消息是某个群组或频道中的线程回复时,parentPeer 可用于将线程消息路由到与父消息相同的 Agent。
{
agentId: "support",
match: {
channel: "discord",
parentPeer: { kind: "channel", id: "111222333" }
}
}
3.4 多绑定场景处理
当配置了多条绑定规则时,OpenClaw 按照最具体优先的原则进行匹配。这意味着更精确的匹配条件会覆盖更宽泛的条件。
优先级排序原则
精确匹配 (peer/group/channel ID) → 最具体,优先级最高
↓
线程继承 (parentPeer)
↓
角色匹配 (guildId + roles)
↓
服务器匹配 (guildId)
↓
团队匹配 (teamId)
↓
账户匹配 (accountId)
↓
渠道级匹配 (accountId: "*")
↓
默认 Agent 回退 → 最宽泛,优先级最低
冲突解决示例
{
agents: {
list: [
{ id: "main", workspace: "~/.openclaw/workspace" },
{ id: "vip", workspace: "~/.openclaw/workspace-vip" },
{ id: "support", workspace: "~/.openclaw/workspace-support" }
]
},
bindings: [
// 规则A:所有 Discord 消息 → main
{ agentId: "main", match: { channel: "discord" } },
// 规则B:特定 Discord 服务器 → support
{ agentId: "support", match: { channel: "discord", guildId: "123" } },
// 规则C:特定服务器中特定频道的消息 → vip
{ agentId: "vip", match: { channel: "discord", peer: { kind: "channel", id: "456" } } }
]
}
在这个例子中:
- 来自 Discord 服务器
123中频道456的消息 → 匹配规则 C(最具体)→ vip - 来自 Discord 服务器
123中其他频道的消息 → 匹配规则 B → support - 来自其他 Discord 服务器的消息 → 匹配规则 A → main
绑定评估流程图
消息进入 Gateway
│
▼
┌─────────────────────────┐
│ 提取消息属性 │
│ channel, peer, guildId, │
│ accountId, teamId, roles │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 遍历所有 bindings 规则 │
│ 按最具体优先排序 │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 找到最佳匹配? │
│ 是 → 路由到对应 Agent │
│ 否 → 使用默认 Agent │
└─────────────────────────┘
3.5 绑定与 Agent 列表的关系
Bindings 和 agents.list 是两个独立但紧密关联的配置部分:
职责分工
| 配置项 | 职责 | 必选/可选 |
|---|---|---|
agents.list |
定义系统中有哪些 Agent 可用,以及每个 Agent 的工作空间、模型、工具等配置 | 必选 |
bindings |
定义消息如何路由到这些 Agent | 可选(不配置则全部回退到默认 Agent) |
约束关系
agentId必须存在于agents.list中 :binding 中引用的agentId必须在agents.list中有对应定义,否则路由无效- 一个 Agent 可以被多条绑定引用:同一个 Agent 可以处理来自多个渠道/账户的消息
- 默认 Agent :
agents.list中第一个 Agent 或标记为default: true的 Agent 作为默认回退目标 - 未匹配的消息:如果没有任何 binding 匹配,消息将路由到默认 Agent
一对多关系示意
agents.list 定义: bindings 路由:
┌──────────────┐ whatsapp:personal ──────┐
│ id: main │◀────────────────── feishu:default ──────┤
└──────────────┘ │
├──▶ main Agent
┌──────────────┐ │
│ id: personal │◀────────────────── telegram:user123 ──────┤
└──────────────┘ whatsapp:biz ──────┼──▶ personal Agent
│
┌──────────────┐ discord:guild1 ──────┤
│ id: work │◀────────────────── slack:team1 ──────┘
└──────────────┘
实际配置分析
以当前实例的配置为例:
{
agents: {
list: [
{ id: "main", model: "generic/MiniMax-M2.5", identity: { name: "领主", emoji: "🦞" } },
{ id: "lobster-master", model: "generic/qwen3.6-plus", identity: { name: "龙虾场主", emoji: "🦞" } }
// ... 其他 Agent
]
},
bindings: [
{ agentId: "main", match: { channel: "feishu", accountId: "default" } },
{ agentId: "lobster-master", match: { channel: "feishu", accountId: "ou_181af55d1b5696b2dd9dea7e52731ec5" } }
]
}
这是一个典型的双 Agent 飞书渠道隔离配置:
mainAgent(领主)处理默认飞书账户的消息lobster-masterAgent(龙虾场主)处理特定飞书账户(ou_181af55d1b5696b2dd9dea7e52731ec5)的消息- 两个 Agent 各自拥有独立的工作空间、模型配置和身份定义
- 通过
accountId的精确匹配,实现了同一渠道(飞书)下不同账户的完全隔离
这种配置模式是 OpenClaw 多 Agent 隔离机制的典型应用------通过 Bindings 在渠道层面实现 Agent 分流,每个 Agent 在各自的工作空间内独立运行,互不干扰。
第4节 路由优先级:8 级确定性路由算法
4.1 概述
OpenClaw 的多 Agent 路由采用确定性、最具体优先的算法。当入站消息到达 Gateway 时,系统会按照预定义的 8 级优先级顺序,从最精确的匹配条件开始逐级检查,直到找到最佳匹配为止。
确定性路由 = 相同输入 → 相同输出 → 可预测、可调试
这种设计确保了路由行为的可预测性:相同的消息来源总是路由到同一个 Agent,不会因为配置加载顺序或其他随机因素而产生歧义。
4.2 8 级路由优先级详解
以下是 OpenClaw 路由算法的完整 8 级优先级表(从最高到最低):
┌─────┬──────────────────────────┬──────────────────────────────────────┐
│ 级别 │ 匹配类型 │ 说明 │
├─────┼──────────────────────────┼──────────────────────────────────────┤
│ 1 │ peer 精确匹配 │ 匹配 DM/群组/频道的精确 ID │
│ 2 │ parentPeer 线程继承 │ 匹配线程的父级对等体 │
│ 3 │ guildId + roles │ Discord 服务器 + 角色组合匹配 │
│ 4 │ guildId │ Discord 服务器匹配 │
│ 5 │ teamId │ Slack 工作区匹配 │
│ 6 │ accountId 匹配 │ 渠道账户 ID 匹配 │
│ 7 │ 渠道级匹配 │ accountId: "*" 通配 │
│ 8 │ 默认 Agent 回退 │ 无匹配时的兜底规则 │
└─────┴──────────────────────────┴──────────────────────────────────────┘
第1级:Peer 精确匹配
匹配条件 :match.peer.kind + match.peer.id
这是最精确的匹配级别。peer 对象包含 kind(对等体类型)和 id(唯一标识符)两个字段,可以精确到某个特定用户、群组或频道。
{
agentId: "vip-agent",
match: {
channel: "discord",
peer: { kind: "channel", id: "999888777666" }
}
}
{
agentId: "personal",
match: {
channel: "telegram",
peer: { kind: "user", id: "12345678" }
}
}
优先级判断逻辑 :当消息的 peer.kind 和 peer.id 与 binding 中的 match.peer 完全一致时,立即匹配成功,不再检查更低级别。
典型场景:
- 将特定 VIP 用户的私聊路由到专属 Agent
- 将关键业务频道(如
#alerts)的消息路由到运维 Agent - 将重要客户群组的消息路由到客服 Agent
第2级:ParentPeer 线程继承
匹配条件 :match.parentPeer.kind + match.parentPeer.id
当消息是某个群组或频道中的线程(Thread)回复时,parentPeer 匹配会将线程消息路由到与父级上下文关联的 Agent。
{
agentId: "support-thread",
match: {
channel: "discord",
parentPeer: { kind: "channel", id: "111222333" }
}
}
优先级判断逻辑 :如果消息是一个线程回复,检查其父级 peer 是否匹配 match.parentPeer。这保证了线程中的后续对话不会脱离原始 Agent 的上下文。
典型场景:
- Discord 线程消息继承父频道的 Agent 路由
- Telegram 论坛话题中子消息的路由一致性
第3级:guildId + roles 组合匹配
匹配条件 :match.guildId + match.roles
这是 Discord 特有的角色路由机制。只有当消息来自指定服务器(guildId)且发送者拥有指定角色列表中的任意角色时,才会匹配。
{
agentId: "admin-agent",
match: {
channel: "discord",
guildId: "555666777",
roles: ["admin", "moderator"]
}
}
优先级判断逻辑:
- 首先检查
guildId是否匹配 - 然后检查发送者的角色是否与
roles数组有交集 - 两者都满足才匹配成功
典型场景:
- 管理员/版主消息路由到管理专用 Agent
- 开发团队成员消息路由到开发 Agent
第4级:guildId 服务器匹配
匹配条件 :match.guildId
匹配来自特定 Discord 服务器的所有消息,不考虑角色限制。
{
agentId: "community",
match: {
channel: "discord",
guildId: "555666777"
}
}
优先级判断逻辑 :只要消息来自指定的 guildId,即匹配成功。这是比角色匹配更宽泛的条件,因此优先级更低。
第5级:teamId 团队匹配
匹配条件 :match.teamId
这是 Slack 特有的匹配维度。teamId 对应 Slack 工作区(Workspace/Team)的唯一标识。
{
agentId: "work-agent",
match: {
channel: "slack",
teamId: "T01ABCDEF"
}
}
优先级判断逻辑 :当消息来自 Slack 渠道且 teamId 匹配时成功。
第6级:accountId 精确匹配
匹配条件 :match.accountId(精确值,非通配符)
匹配特定渠道账户 ID。在支持多账户的渠道中,accountId 可以区分同一渠道下的不同账户实例。
{
agentId: "work",
match: {
channel: "whatsapp",
accountId: "biz-number"
}
}
这正是当前实例实际使用的路由方式:
{
agentId: "lobster-master",
match: {
channel: "feishu",
accountId: "ou_181af55d1b5696b2dd9dea7e52731ec5"
}
}
典型场景:
- 个人 WhatsApp vs 工作 WhatsApp 的 Agent 隔离
- 多个飞书应用的独立 Agent 路由
第7级:渠道级通配匹配
匹配条件 :match.accountId: "*" 或仅有 match.channel
这是渠道级别的宽泛匹配,覆盖该渠道下的所有账户和所有消息。
{
agentId: "telegram-agent",
match: {
channel: "telegram",
accountId: "*"
}
}
{
agentId: "discord-agent",
match: {
channel: "discord"
}
}
优先级判断逻辑 :只要消息的 channel 与 binding 中的 match.channel 匹配,即视为匹配成功。accountId: "*" 是显式通配,省略 accountId 也属于渠道级匹配。
第8级:默认 Agent 回退
匹配条件:无(无条件匹配)
当所有 binding 规则都不匹配时,消息回退到默认 Agent。默认 Agent 通常是 agents.list 中第一个定义的 Agent,或设置了 default: true 的 Agent。
优先级判断逻辑:仅当上述 7 级匹配全部失败时才触发。这是最后的兜底规则,确保每条消息都有一个明确的归属。
4.3 确定性路由算法解析
OpenClaw 的路由算法是确定性的,这意味着:
4.3.1 算法特性
| 特性 | 说明 |
|---|---|
| 确定性 | 相同的输入(消息属性 + 配置)总是产生相同的输出(目标 Agent) |
| 最具体优先 | 更精确的匹配条件优先于宽泛条件 |
| 无随机性 | 不依赖随机因素、时间戳或加载顺序 |
| 可调试 | 给定配置和消息,可以手动推导路由结果 |
4.3.2 路由决策流程
同级匹配规则 :当同一级别有多条规则满足匹配条件时,取
bindings数组中最先出现的规则。例如两条 Level 1 的 peer 匹配规则都能匹配消息,系统会选择配置文件中排在前面的那条。 因此建议在配置时,将更具体的规则放在前面,宽泛规则放在后面,确保路由行为可预测。
flowchart TD
A[入站消息] --> B{提取消息属性}
B --> C[channel, peer, guildId, accountId, teamId, roles]
C --> D[Level 1: peer 精确匹配?]
D -->|是| E[路由到对应 Agent ✅]
D -->|否| F[Level 2: parentPeer 线程继承?]
F -->|是| E
F -->|否| G[Level 3: guildId + roles 组合?]
G -->|是| E
G -->|否| H[Level 4: guildId 服务器匹配?]
H -->|是| E
H -->|否| I[Level 5: teamId 团队匹配?]
I -->|是| E
I -->|否| J[Level 6: accountId 精确匹配?]
J -->|是| E
J -->|否| K[Level 7: 渠道级通配?]
K -->|是| E
K -->|否| L[Level 8: 默认 Agent 回退]
L --> E
4.3.3 算法伪代码
function resolveAgent(message, bindings, defaultAgent):
attrs = extractMessageAttrs(message)
matchers = [
// Level 1: peer 精确匹配
() => find(b => b.match.peer?.kind == attrs.peerKind
&& b.match.peer?.id == attrs.peerId
&& b.match.channel == attrs.channel),
// Level 2: parentPeer 线程继承
() => find(b => b.match.parentPeer?.kind == attrs.parentPeerKind
&& b.match.parentPeer?.id == attrs.parentPeerId
&& b.match.channel == attrs.channel),
// Level 3: guildId + roles 组合
() => find(b => b.match.guildId == attrs.guildId
&& b.match.roles
&& intersects(b.match.roles, attrs.roles)
&& b.match.channel == attrs.channel),
// Level 4: guildId(无 roles 限制)
() => find(b => b.match.guildId == attrs.guildId
&& !b.match.roles
&& b.match.channel == attrs.channel),
// Level 5: teamId
() => find(b => b.match.teamId == attrs.teamId
&& b.match.channel == attrs.channel),
// Level 6: accountId 精确匹配(非通配)
() => find(b => b.match.accountId == attrs.accountId
&& b.match.accountId != "*"
&& b.match.channel == attrs.channel),
// Level 7: 渠道级通配
() => find(b => (b.match.accountId == "*" || !b.match.accountId)
&& b.match.channel == attrs.channel)
]
for matcher in matchers:
result = matcher()
if result: return lookupAgent(result.agentId)
return defaultAgent // Level 8: 兜底
注 :
match: {}(空匹配对象)不作为 binding 规则参与 Level 1-7 的匹配,仅作为 Level 8 的默认 Agent 回退。例如{ agentId: "personal", match: {} }表示"所有未匹配的消息都路由到 personal Agent"。
4.4 实际场景中的路由决策流程
场景一:飞书多渠道 Agent 分流
以当前 OpenClaw 实例的实际配置为例:
{
agents: {
list: [
{ id: "main", model: "generic/MiniMax-M2.5" },
{ id: "lobster-master", model: "generic/qwen3.6-plus" }
]
},
bindings: [
{ agentId: "main", match: { channel: "feishu", accountId: "default" } },
{ agentId: "lobster-master", match: { channel: "feishu", accountId: "ou_181af55d1b5696b2dd9dea7e52731ec5" } }
]
}
消息路由决策表:
| 消息来源 | 匹配过程 | 目标 Agent | 匹配级别 |
|---|---|---|---|
| 飞书 default 账号消息 | Level 1-5: 无 peer/guildId/teamId → 跳过;Level 6: accountId="default" 精确匹配 | main | Level 6 |
| 飞书 ou_181af55d... 账号消息 | Level 1-5: 跳过;Level 6: accountId 精确匹配 | lobster-master | Level 6 |
| QQ 机器人消息 | Level 1-7: 无匹配 channel → Level 8: 默认 Agent | main(默认) | Level 8 |
| 企业微信消息 | Level 1-7: 无匹配 channel → Level 8: 默认 Agent | main(默认) | Level 8 |
场景二:Discord 多层级路由
假设配置了以下 bindings:
{
bindings: [
{ agentId: "admin", match: { channel: "discord", guildId: "G1", roles: ["admin"] } },
{ agentId: "dev", match: { channel: "discord", peer: { kind: "channel", id: "C1" } } },
{ agentId: "community", match: { channel: "discord", guildId: "G1" } },
{ agentId: "main", match: { channel: "discord" } }
]
}
路由决策追踪:
消息A: Discord 服务器 G1, 频道 C1, 用户拥有 admin 角色
→ Level 1: peer 精确匹配 C1 → ✅ 匹配 "dev"
→ 路由到: dev
消息B: Discord 服务器 G1, 频道 C2, 用户拥有 admin 角色
→ Level 1: peer 不匹配 → ❌
→ Level 2: parentPeer 不匹配 → ❌
→ Level 3: guildId=G1 AND roles 含 admin → ✅ 匹配 "admin"
→ 路由到: admin
消息C: Discord 服务器 G1, 频道 C2, 普通用户(无特殊角色)
→ Level 1-2: 不匹配 → ❌
→ Level 3: guildId=G1 但 roles 不匹配 → ❌
→ Level 4: guildId=G1 → ✅ 匹配 "community"
→ 路由到: community
消息D: Discord 服务器 G2(未配置的其他服务器)
→ Level 1-4: 不匹配 → ❌
→ Level 5-6: 不匹配 → ❌
→ Level 7: channel=discord → ✅ 匹配 "main"
→ 路由到: main
这个场景清晰展示了优先级叠加效应:
- 消息A 虽然有 admin 角色,但因为 peer 精确匹配(Level 1)优先级高于角色匹配(Level 3),所以路由到
dev而非admin - 消息C 没有特殊角色,所以跳过了 Level 3 的角色匹配,落入 Level 4 的服务器匹配
场景三:跨渠道路由
{
bindings: [
{ agentId: "work", match: { channel: "whatsapp", accountId: "biz" } },
{ agentId: "personal", match: { channel: "whatsapp", accountId: "home" } },
{ agentId: "main", match: { channel: "feishu" } }
]
}
WhatsApp biz 号消息 → Level 6: accountId="biz" → work
WhatsApp home 号消息 → Level 6: accountId="home" → personal
飞书消息 → Level 6: 无 accountId → 降级 → Level 7: channel=feishu → main
Telegram 消息 → Level 1-7: 无匹配 → Level 8: 默认 → work(list 第一个)
4.5 路由确定性的工程意义
可预测性
在运维场景中,确定性路由意味着管理员可以预知每条消息的去向。这对于故障排查、审计和合规性至关重要。如果路由是非确定性的,同一用户的消息可能在不同时间被路由到不同的 Agent,导致上下文丢失和行为不一致。
可调试性
确定性路由支持离线验证------给定一组 bindings 配置和一条消息的属性,任何人都可以手动推导出路由结果,无需实际运行系统。这在配置变更的 Code Review 中非常有用。
可扩展性
8 级优先级的设计预留了充足的扩展空间。当前已有 peer、parentPeer、guildId、roles、teamId、accountId、channel 七个维度的匹配条件,未来可以在此基础上继续扩展(如消息类型匹配、标签匹配等),而不需要改变算法的核心逻辑。
隔离保障
路由确定性是多 Agent 隔离的第一道防线。只有当每条消息都被精确路由到正确的 Agent,后续的"工作空间隔离"和"状态隔离"才有意义。如果路由出现偏差,消息被错误地路由到非目标 Agent,隔离机制就会失效。
第5节 会话作用域模型
会话作用域模型(Session Scope Model)是 OpenClaw 会话隔离机制的核心控制点。它决定了:当同一个用户通过不同渠道发送消息时,这些对话是共享上下文还是各自独立?
这个配置项名为 dmScope,位于 session 配置块下,支持四种模式。理解它们的差异,是构建多 Agent 系统的必修课。
5.1 main 模式(所有 DM 共享)
{
session: {
dmScope: "main", // 默认模式
},
}
在 main 模式下,该 Agent 收到的所有直接消息(DM)共享同一个会话上下文。无论用户是从 WhatsApp、Telegram 还是 WebChat 发送消息,它们都会汇聚到同一个对话历史中。
WhatsApp: "今天有什么会议?" ──┐
Telegram: "帮我查下邮件" ──┤──→ agent:main:main (同一个会话)
WebChat: "下午记得提醒我" ──┘
优点:
- 对话连续性最佳,用户在任何渠道都能看到完整的上下文
- 适合单用户场景,一个人用多个渠道与同一个 Agent 对话
缺点:
- 不同渠道的消息混在一起,可能产生上下文混淆
- 不适合多用户场景------不同用户的对话会互相干扰
适用场景: 个人使用,一个用户通过多个渠道(如手机上用 WhatsApp,电脑上用 WebChat)与同一个 Agent 交互。
5.2 per-peer 模式(按发送者隔离)
{
session: {
dmScope: "per-peer",
},
}
在 per-peer 模式下,会话按发送者 ID 隔离。同一个用户无论通过什么渠道发消息,都使用同一个会话;但不同用户的消息会被隔离到不同的会话中。
用户 Alice (WhatsApp): "今天天气如何?" ──→ agent:main:peer:alice
用户 Alice (Telegram): "谢谢!" ──→ agent:main:peer:alice (同一会话)
用户 Bob (WhatsApp): "帮我查下邮件" ──→ agent:main:peer:bob (独立会话)
优点:
- 支持多用户,每个用户有独立的对话上下文
- 同一用户跨渠道保持连续性
缺点:
- 如果同一个用户在 WhatsApp 和 Telegram 上有不同身份需求,无法区分
适用场景: 家庭或小团队使用,每个成员有独立对话,但同一个成员希望跨设备保持对话连续性。
5.3 per-channel-peer 模式(渠道 + 发送者)
{
session: {
dmScope: "per-channel-peer",
},
}
在 per-channel-peer 模式下,会话按渠道 + 发送者组合隔离。同一用户通过不同渠道发送的消息属于不同的会话。
用户 Alice (WhatsApp): "今天天气如何?" ──→ agent:main:whatsapp:alice (会话 A)
用户 Alice (Telegram): "帮我查下邮件" ──→ agent:main:telegram:alice (会话 B)
用户 Bob (WhatsApp): "下午提醒我" ──→ agent:main:whatsapp:bob (会话 C)
优点:
- 最精细的多用户隔离
- 不同渠道的对话完全独立,互不干扰
- 适合正式的多用户部署
缺点:
- 同一用户在不同渠道的对话不连续
适用场景: 企业部署、多人聊天机器人、需要严格区分渠道上下文的场景。这是多用户场景的推荐配置。
5.4 per-account-channel-peer 模式(账户 + 渠道 + 发送者)
{
session: {
dmScope: "per-account-channel-peer",
},
}
这是最细粒度的隔离模式,会话按账户 + 渠道 + 发送者三重维度隔离。当同一个 Gateway 管理了多个 WhatsApp 账号或多个 Telegram Bot 时,这种模式能确保每个账户的对话完全独立。
个人 WhatsApp (Alice): "今天日程" ──→ agent:main:wa-personal:alice (会话 A)
工作 WhatsApp (Alice): "会议纪要" ──→ agent:main:wa-work:alice (会话 B)
个人 WhatsApp (Bob): "帮忙订餐" ──→ agent:main:wa-personal:bob (会话 C)
工作 WhatsApp (Bob): "代码审查" ──→ agent:main:wa-work:bob (会话 D)
优点:
- 最严格的隔离级别
- 多账户 + 多用户场景的完美解决方案
缺点:
- 隔离粒度最细,会话碎片化程度最高
- 同一用户在不同账户下的对话完全不连续
适用场景: 多账户管理场景(如同时管理个人和工作 WhatsApp 账号),或需要为不同客户群体提供隔离服务的商业部署。
5.5 模式选择建议
| 场景 | 推荐模式 | 原因 |
|---|---|---|
| 个人使用,多渠道 | main |
保持跨渠道对话连续 |
| 家庭/小团队 | per-peer |
每人独立,跨渠道连续 |
| 企业多用户 | per-channel-peer ⭐ |
渠道+用户双重隔离,推荐默认 |
| 多账户运营 | per-account-channel-peer |
账户+渠道+用户三重隔离 |
| 公共聊天机器人 | per-channel-peer |
防止不同用户上下文泄露 |
与会话生命周期的关系
无论选择哪种作用域模式,会话生命周期管理(每日重置、空闲重置、手动重置)的行为都是一致的。区别仅在于"什么算一个会话"的判定标准不同。
例如,在 per-channel-peer 模式下,/new 命令只会重置当前渠道+当前用户的会话,不会影响其他渠道或其他用户的会话。
群组消息的会话隔离
需要注意的是,dmScope 仅影响 直接消息(DM) 的作用域。群组消息的会话隔离由群组 ID 自然决定------不同群组天然就是不同的会话键(agent:<agentId>:<channel>:group:<id>),不受 dmScope 影响。
选择合适的会话作用域模式,是多 Agent 架构设计的第一步。它决定了信息流动的边界,直接影响用户体验和系统安全性。对于大多数生产环境,per-channel-peer 是推荐的默认选择。
第6节 实战配置示例
工具组速查表
OpenClaw 支持工具组(Tool Groups)简写,以下为完整映射关系:
| 工具组 | 包含工具 |
|---|---|
group:runtime |
exec, bash, process |
group:fs |
read, write, edit, apply_patch |
group:sessions |
sessions_list, sessions_history, sessions_send, sessions_spawn, session_status |
group:memory |
memory_search, memory_get |
group:web |
web_search, web_fetch |
group:ui |
browser, canvas |
group:automation |
cron, gateway |
group:messaging |
message |
group:nodes |
nodes |
group:openclaw |
所有内置 OpenClaw 工具 |
本节提供多 Agent 隔离机制的完整配置示例,所有配置均基于 OpenClaw 的真实能力边界编写,可直接用于生产环境。
6.1 双 Agent 配置(个人 + 工作)
场景描述
在单台 Gateway 主机上同时运行两个完全隔离的 Agent:
- personal --- 个人助手,处理日常事务、日程管理、智能家居控制
- work --- 工作助手,处理代码审查、项目管理、企业通讯
两个 Agent 拥有独立的工作空间、技能目录、会话状态和模型配置。
目录结构
~/.openclaw/
├── openclaw.json # 主配置文件
├── agents/
│ ├── personal/
│ │ └── sessions/
│ │ ├── sessions.json # 个人 Agent 会话索引
│ │ └── <sessionId>.jsonl # 个人 Agent 会话记录
│ └── work/
│ └── sessions/
│ ├── sessions.json # 工作 Agent 会话索引
│ └── <sessionId>.jsonl # 工作 Agent 会话记录
├── workspace-personal/ # 个人工作空间
│ ├── AGENTS.md
│ ├── SOUL.md
│ ├── USER.md
│ ├── IDENTITY.md
│ ├── TOOLS.md
│ ├── MEMORY.md
│ ├── memory/
│ └── skills/
└── workspace-work/ # 工作工作空间
├── AGENTS.md
├── SOUL.md
├── USER.md
├── IDENTITY.md
├── TOOLS.md
├── MEMORY.md
├── memory/
└── skills/
完整配置示例
{
// ===== Agent 列表定义 =====
agents: {
// 默认 Agent 配置(未单独指定时使用)
defaults: {
// 每日会话重置时间(Gateway 主机本地时区)
resetHour: 4,
// 会话维护策略
sessionPrune: {
pruneAfter: 30, // 30 天后过期
maxEntries: 500, // 最多 500 条会话记录
maxDiskBytes: 100_000_000, // 100MB 磁盘配额
rotateBytes: 10_000_000, // sessions.json 超过 10MB 时轮转
},
// 工具策略:默认开放
tools: {
allow: ["group:openclaw"],
},
// 上下文压缩(注:扩展配置项 reserveTokensFloor/memoryFlush 需验证版本兼容性)
compaction: { mode: "safeguard" },
},
// 具体 Agent 实例
list: [
{
// 个人 Agent
id: "personal",
// 工作空间路径
workspace: "~/.openclaw/workspace-personal",
agentDir: "~/.openclaw/agents/personal", // 状态存储目录(可选,不指定则自动生成)
// 使用 Claude Sonnet 4.5
model: "generic/qwen3.6-plus",
// 设为默认 Agent(无匹配绑定时使用)
default: true,
// 人格配置通过 workspace 中的 SOUL.md 定义
},
{
// 工作 Agent
id: "work",
// 独立工作空间
workspace: "~/.openclaw/workspace-work",
agentDir: "~/.openclaw/agents/work", // 状态存储目录(可选)
// 使用 GPT-5.2 处理代码相关任务
model: "generic/MiniMax-M2.5",
// 启用沙箱隔离:所有会话在 Docker 容器中运行
sandbox: {
mode: "all",
scope: "agent",
workspaceRoot: "~/.openclaw/sandbox/work",
// 允许的工具
allow: ["read", "write", "edit", "exec", "process",
"sessions_list", "sessions_spawn", "session_status"],
// 禁止的危险工具
deny: ["browser", "canvas", "nodes", "cron", "gateway"],
},
// 限制工具范围:仅允许文件系统、运行时、会话工具
tools: {
allow: ["group:fs", "group:runtime", "group:sessions", "group:memory"],
},
// 工作 Agent 的独立会话隔离策略
session: {
dmScope: "per-channel-peer", // 按渠道+发送者隔离
},
},
],
},
// ===== 绑定路由 =====
bindings: [
// WhatsApp 工作号码 → work Agent
{
agentId: "work",
match: {
channel: "whatsapp",
accountId: "work-number",
},
},
// WhatsApp 个人号码 → personal Agent
{
agentId: "personal",
match: {
channel: "whatsapp",
accountId: "personal-number",
},
},
// Telegram 个人 bot → personal Agent
{
agentId: "personal",
match: {
channel: "telegram",
accountId: "personal-bot",
},
},
// 所有未匹配的消息 → personal Agent(default: true 已覆盖,此处显式声明)
{
agentId: "personal",
match: {}, // 空匹配 = catch-all
},
],
// ===== 渠道配置 =====
channels: {
whatsapp: {
enabled: true,
dmPolicy: "pairing", // 未知用户需要配对
// 多账户配置
accounts: {
"personal-number": {
phone: "+8613800000001",
},
"work-number": {
phone: "+8613800000002",
},
},
},
telegram: {
enabled: true,
dmPolicy: "pairing",
accounts: {
"personal-bot": {
botToken: "YOUR_TELEGRAM_BOT_TOKEN",
},
},
},
},
}
配置说明
| 配置项 | 作用 | 隔离效果 |
|---|---|---|
agents.list[].workspace |
每个 Agent 的独立工作空间 | 文件系统隔离,技能/记忆不共享 |
agents.list[].model |
独立模型配置 | 可针对不同场景选择最优模型 |
sandbox.mode |
沙箱开关 | 代码执行在容器中运行 |
bindings[] |
消息路由规则 | 渠道/账户级别的消息分流 |
session.dmScope |
会话作用域策略 | 控制会话粒度 |
6.2 Discord 多频道路由配置
场景描述
在同一个 Discord 服务器(Guild)中,将不同频道(Channel)的消息路由到不同的 Agent:
- #dev-chat → 编程助手 Agent(代码审查、技术问答)
- #ops-alerts → 运维助手 Agent(日志分析、故障排查)
- #general → 通用助手 Agent(日常聊天、日程管理)
路由流程图
Discord 消息到达 Gateway
│
▼
┌──────────────────────┐
│ 提取消息元数据 │
│ - guildId │
│ - channelId │
│ - authorId │
│ - thread.parentId │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 匹配规则 1: 精确 │
│ channelId 匹配? │
└──────┬───────────┬───┘
│ 匹配 │ 不匹配
▼ ▼
路由到指定 ┌──────────────────────┐
Agent │ 匹配规则 2: 角色路由 │
│ 检查 author roles │
└──────┬───────────┬───┘
│ 匹配 │ 不匹配
▼ ▼
路由到指定 ┌──────────────────────┐
Agent │ 匹配规则 3: guildId │
│ │ 整个服务器默认路由 │
│ └──────┬───────────┬───┘
│ │ 匹配 │ 不匹配
▼ ▼ ▼
DONE 路由到指定 进入下一条
Agent binding
完整配置示例
{
agents: {
list: [
{
id: "dev-helper",
workspace: "~/.openclaw/workspace-dev-helper",
model: "generic/qwen3.6-plus",
// 编程场景需要完整工具集
tools: {
allow: ["group:fs", "group:runtime", "group:sessions",
"group:memory", "group:web", "image"],
},
},
{
id: "ops-helper",
workspace: "~/.openclaw/workspace-ops-helper",
model: "generic/MiniMax-M2.5",
// 运维场景需要系统命令执行
tools: {
allow: ["group:fs", "group:runtime", "group:sessions",
"group:memory", "group:web"],
},
},
{
id: "main",
workspace: "~/.openclaw/workspace",
model: "generic/qwen3.6-plus",
default: true,
},
],
},
bindings: [
// === 精确频道匹配 ===
// #dev-chat 频道 → dev-helper
// 通过 peer 字段精确匹配 channel ID
{
agentId: "dev-helper",
match: {
channel: "discord",
peer: {
kind: "channel",
// 替换为实际的 Discord 频道 ID
id: "1234567890123456789",
},
},
},
// #ops-alerts 频道 → ops-helper
{
agentId: "ops-helper",
match: {
channel: "discord",
peer: {
kind: "channel",
id: "9876543210987654321",
},
},
},
// === 线程继承 ===
// 在 #dev-chat 中创建的线程自动继承父频道路由
// OpenClaw 通过 parentPeer 字段自动匹配:
// 如果线程的父频道已绑定到 dev-helper,则线程也路由到 dev-helper
// === 角色路由 ===
// 拥有 "admin" 角色的用户在任意频道由 main Agent 响应
{
agentId: "main",
match: {
channel: "discord",
guildId: "1111111111111111111", // 服务器 ID
roles: ["admin"], // Discord 角色 ID 列表
},
},
// === 服务器级默认路由 ===
// 整个服务器的未匹配消息 → main Agent
{
agentId: "main",
match: {
channel: "discord",
guildId: "1111111111111111111",
},
},
],
channels: {
discord: {
enabled: true,
token: "YOUR_DISCORD_BOT_TOKEN",
dmPolicy: "pairing",
// 群组(Guild)配置
groups: {
// 所有群组要求 @mention
"*": {
requireMention: true,
},
// 特定频道的独立配置
"1234567890123456789": {
requireMention: false, // #dev-chat 不需要 @mention
sessionMode: "per-peer", // 按用户隔离会话
},
},
},
},
}
配置说明
peer.kind: "channel"匹配 Discord 文本频道(TextChannel)peer.kind: "group"匹配 Discord 语音频道或直接消息roles数组中的值为 Discord 角色 ID(非角色名称)- 线程继承是自动的:如果父频道绑定到某 Agent,该频道的线程自动继承绑定
requireMention控制是否需要在消息中 @Bot 才能触发
6.3 WhatsApp 多账户路由配置
场景描述
通过 Baileys 库在同一个 Gateway 进程中运行多个 WhatsApp 账户,每个账户路由到不同的 Agent:
- 主号码 → 个人助手
- 工作号码 → 工作助手
- 客服号码 → 客服 Agent
路由流程图
WhatsApp 消息到达
│
▼
┌─────────────────────────┐
│ 提取消息元数据 │
│ - accountId (BAILEYS) │
│ - peer (发送者 JID) │
│ - isGroup │
└──────────┬──────────────┘
│
▼
┌─────────────────────────┐
│ binding 匹配(按优先级) │
│ │
│ 1. peer 精确匹配? │
│ 2. accountId 匹配? │
│ 3. accountId: "*" 匹配? │
│ 4. 默认 Agent 回退 │
└──────────┬──────────────┘
│
▼
路由到对应 Agent
完整配置示例
{
agents: {
list: [
{
id: "personal",
workspace: "~/.openclaw/workspace-personal",
agentDir: "~/.openclaw/agents/personal", // 状态存储目录(可选,不指定则自动生成)
model: "generic/qwen3.6-plus",
default: true,
},
{
id: "work",
workspace: "~/.openclaw/workspace-work",
agentDir: "~/.openclaw/agents/work", // 状态存储目录(可选)
model: "generic/qwen3.6-plus",
sandbox: {
mode: "non-main", // 仅非主会话沙箱化
scope: "session", // 每个会话独立容器
},
},
{
id: "support",
workspace: "~/.openclaw/workspace-support",
model: "generic/MiniMax-M2.5",
// 客服 Agent 使用严格的会话隔离
session: {
dmScope: "per-account-channel-peer", // 最细粒度隔离
},
},
],
},
bindings: [
// === 客服号码:按发送者精确路由 ===
// VIP 客户由专用 Agent 响应
{
agentId: "support",
match: {
channel: "whatsapp",
accountId: "support-line",
peer: {
kind: "user",
id: "85291234567@s.whatsapp.net", // VIP 客户的 JID
},
},
},
// === 客服号码:普通客户 → support Agent ===
// accountId 匹配,不指定 peer = 该账户所有消息
{
agentId: "support",
match: {
channel: "whatsapp",
accountId: "support-line",
},
},
// === 工作号码 → work Agent ===
{
agentId: "work",
match: {
channel: "whatsapp",
accountId: "work-line",
},
},
// === 个人号码 → personal Agent ===
{
agentId: "personal",
match: {
channel: "whatsapp",
accountId: "personal-line",
},
},
// === 通配符匹配 ===
// 任何未明确绑定的 WhatsApp 消息 → personal Agent
{
agentId: "personal",
match: {
channel: "whatsapp",
accountId: "*", // 通配符:匹配所有未明确指定的账户
},
},
],
channels: {
whatsapp: {
enabled: true,
dmPolicy: "pairing",
// 多账户定义
// 每个 accountId 对应一个独立的 Baileys 会话
accounts: {
"personal-line": {
// 通过配对码或 QR 码完成认证
// 凭证存储在 ~/.openclaw/agents/personal/auth/
},
"work-line": {
// 凭证存储在 ~/.openclaw/agents/work/auth/
},
"support-line": {
// 凭证存储在 ~/.openclaw/agents/support/auth/
},
},
},
},
}
配置说明
- Baileys 认证隔离 :每个
accountId的 WhatsApp 会话凭证(creds.json、预密钥等)存储在其对应 Agent 的状态目录中,确保认证信息物理隔离 per-account-channel-peer是最细粒度的会话隔离策略:即使同一个人在不同账户下发送消息,也会被视为不同的会话- 通配符
accountId: "*"作为 fallback,匹配所有未在上方 binding 中明确指定的 WhatsApp 账户
6.4 企业级多 Agent 部署方案
场景描述
企业环境下的多 Agent 部署方案,满足以下需求:
- 研发 Agent --- 代码生成、PR 审查、技术文档
- 运维 Agent --- 日志分析、故障排查、基础设施管理
- 客服 Agent --- 客户支持、工单处理
- 管理 Agent --- 日程管理、会议安排、报告生成
每个 Agent 运行在 Docker 沙箱中,拥有严格的工具权限控制。
完整配置示例
{
// ===== Agent 定义 =====
agents: {
defaults: {
resetHour: 4,
// 企业级会话维护
sessionPrune: {
pruneAfter: 90, // 保留 90 天
maxEntries: 2000, // 最多 2000 条
maxDiskBytes: 500_000_000, // 500MB 磁盘配额
rotateBytes: 50_000_000, // 50MB 轮转
},
// 上下文压缩(注:扩展配置项需验证版本兼容性)
compaction: { mode: "safeguard" },
// 消息队列策略
messages: {
queue: {
mode: "collect",
debounceMs: 1000,
cap: 20,
drop: "summarize",
},
},
},
list: [
// ---- 研发 Agent ----
{
id: "dev",
workspace: "~/.openclaw/workspace-dev",
model: "generic/qwen3.6-plus",
// 开发场景需要完整工具集,但仍限制浏览器和节点控制
tools: {
allow: ["group:fs", "group:runtime", "group:sessions",
"group:memory", "group:web", "image"],
deny: ["browser", "nodes", "cron"],
},
sandbox: {
mode: "all",
scope: "agent",
workspaceRoot: "~/.openclaw/sandbox/dev",
},
},
// ---- 运维 Agent ----
{
id: "ops",
workspace: "~/.openclaw/workspace-ops",
model: "generic/MiniMax-M2.5",
// 运维需要完整的运行时工具(含 exec)
tools: {
allow: ["group:fs", "group:runtime", "group:sessions",
"group:memory", "group:web"],
},
sandbox: {
mode: "all",
scope: "session",
workspaceRoot: "~/.openclaw/sandbox/ops",
},
},
// ---- 客服 Agent ----
{
id: "support",
workspace: "~/.openclaw/workspace-support",
model: "generic/qwen3.6-plus",
// 客服仅需要消息和会话工具
tools: {
allow: ["group:sessions", "group:memory", "group:messaging"],
deny: ["exec", "write", "edit", "browser", "canvas", "nodes"],
},
session: {
dmScope: "per-account-channel-peer",
},
},
// ---- 管理 Agent(默认)----
{
id: "admin",
workspace: "~/.openclaw/workspace-admin",
model: "generic/qwen3.6-plus",
default: true,
tools: {
allow: ["group:openclaw"],
},
},
],
},
// ===== 绑定路由 =====
bindings: [
// Slack #engineering → dev Agent
{
agentId: "dev",
match: {
channel: "slack",
teamId: "T0ABCDEF123",
peer: { kind: "channel", id: "C0ENG123456" },
},
},
// Slack #ops-alerts → ops Agent
{
agentId: "ops",
match: {
channel: "slack",
teamId: "T0ABCDEF123",
peer: { kind: "channel", id: "C0OPS123456" },
},
},
// WhatsApp 客服线 → support Agent
{
agentId: "support",
match: {
channel: "whatsapp",
accountId: "support-main",
},
},
// 飞书工作群 → dev Agent
{
agentId: "dev",
match: {
channel: "feishu",
peer: { kind: "group", id: "oc_dev_group_chat_id" },
},
},
// 飞书运维群 → ops Agent
{
agentId: "ops",
match: {
channel: "feishu",
peer: { kind: "group", id: "oc_ops_group_chat_id" },
},
},
// 飞书客服群 → support Agent
{
agentId: "support",
match: {
channel: "feishu",
peer: { kind: "group", id: "oc_support_group_chat_id" },
},
},
],
// ===== 渠道配置 =====
channels: {
slack: {
enabled: true,
botToken: "xoxb-YOUR-BOT-TOKEN",
appToken: "xapp-YOUR-APP-TOKEN",
dmPolicy: "allowlist",
allowFrom: ["slack:U0ADMIN123"], // 仅管理员可 DM
groups: {
"*": { requireMention: true },
},
},
whatsapp: {
enabled: true,
dmPolicy: "open",
accounts: {
"support-main": {},
},
},
feishu: {
enabled: true,
appId: "cli_aXXXXXXXX",
appSecret: "YOUR_FEISHU_APP_SECRET",
dmPolicy: "allowlist",
allowFrom: ["feishu:ou_admin123"],
groups: {
"*": { requireMention: true },
},
},
},
}
企业级部署要点
- 沙箱隔离 :研发(dev)和运维(ops)Agent 启用了
sandbox.mode: "all",客服(support)和管理(admin)Agent 未启用沙箱(可根据需要添加)。 - 工具最小权限:每个 Agent 仅获得完成其职责所需的工具集
- 会话独立维护 :每个 Agent 有独立的
sessionPrune策略和会话存储 - 并发控制 :
maxConcurrent: 10限制 Gateway 整体并发 Agent 运行数 - 消息队列 :
collect模式合并排队消息,避免重复响应
6.5 沙箱隔离配置详解
沙箱模式概览
OpenClaw 通过 Docker 容器实现沙箱隔离,防止 Agent 的文件系统和进程执行影响主机环境。
┌─────────────────────────────────────────────┐
│ Gateway 主机 │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ 主会话 (非沙箱) │ │
│ │ 完整权限:fs/exec/browser/nodes/... │ │
│ └───────────────────────────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Docker │ │ Docker │ │ Docker │ │
│ │ 容器 A │ │ 容器 B │ │ 容器 C │ │
│ │ (Agent X)│ │ (Agent Y)│ │ (Agent Z)│ │
│ │ 受限fs │ │ 受限fs │ │ 受限fs │ │
│ │ 受限net │ │ 受限net │ │ 受限net │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────┘
沙箱配置参数
| 参数 | 类型 | 说明 |
|---|---|---|
mode |
string | 沙箱模式:off(关闭)、non-main(仅非主会话)、all(全部) |
scope |
string | 容器粒度:session(每会话)、agent(每 Agent)、shared(共享) |
workspaceRoot |
string | 沙箱内工作空间根目录 |
allow |
string[] | 沙箱内允许的工具列表 |
deny |
string[] | 沙箱内禁止的工具列表 |
配置示例 1:渐进式沙箱
{
agents: {
defaults: {
sandbox: {
// 主会话不沙箱(保留完整能力)
// 所有子 Agent / 非主会话自动沙箱化
mode: "non-main",
// 每个会话一个独立容器
scope: "session",
// 沙箱内的工作空间路径
workspaceRoot: "~/.openclaw/sandbox",
// 沙箱内的工具白名单
allow: [
"read", "write", "edit",
"exec", "process",
"session_status",
"sessions_list", "sessions_spawn",
"web_fetch",
],
// 沙箱内禁止的工具
deny: [
"browser", // 无法控制主机浏览器
"canvas", // 无法访问画布
"nodes", // 无法操作设备节点
"cron", // 无法创建定时任务
"gateway", // 无法控制 Gateway
"voice_call", // 无法发起语音通话
],
},
},
list: [
{
id: "main",
workspace: "~/.openclaw/workspace",
default: true,
},
],
},
}
配置示例 2:Agent 级共享沙箱
{
agents: {
list: [
{
id: "dev",
workspace: "~/.openclaw/workspace-dev",
sandbox: {
mode: "all",
// 整个 Agent 共享一个容器
// 适合需要持久化状态的开发场景
scope: "agent",
workspaceRoot: "~/.openclaw/sandbox/dev",
allow: ["group:fs", "group:runtime", "group:sessions", "group:web"],
},
},
{
id: "testing",
workspace: "~/.openclaw/workspace-testing",
sandbox: {
mode: "all",
// 每个会话独立容器
// 适合测试场景,确保会话间无状态泄漏
scope: "session",
workspaceRoot: "~/.openclaw/sandbox/testing",
allow: ["group:fs", "group:runtime", "group:sessions"],
deny: ["web_fetch"], // 测试 Agent 禁止网络访问
},
},
],
},
}
沙箱内 exec 行为
在沙箱模式下,exec 和 process 工具的行为发生以下变化:
- 命令执行环境 :
exec在 Docker 容器内执行,而非主机 shell - 文件系统访问:仅能访问容器内挂载的工作空间目录
- 网络访问:默认情况下容器有网络访问权限,可通过 Docker 网络策略限制
- 进程隔离:容器内进程与主机进程完全隔离
- 工具代理:沙箱内的工具调用通过 Gateway 的 WebSocket 接口代理回主机
安全建议
- 生产环境 :推荐使用
mode: "all"+scope: "session",确保最大隔离 - 开发调试 :可使用
mode: "non-main",主会话保留完整能力用于调试 - 敏感数据 :在
deny中明确列出browser、nodes、gateway等可能暴露主机状态的工具 - 网络限制 :结合 Docker 网络配置(如
--network none)进一步限制容器网络访问
本节完。所有配置示例均基于 OpenClaw 实际支持的配置字段编写,可直接用于生产部署。
第7节 内部实现机制
本节深入剖析 OpenClaw 多 Agent 隔离机制的内部实现,包括路由解析算法、会话状态存储结构、会话维护策略以及并发控制机制。所有技术描述均基于实际文件验证。
7.1 路由解析算法
OpenClaw 的路由解析是一个确定性最具体优先 的匹配过程。当一条消息到达 Gateway 时,系统需要从 bindings 数组中选出最匹配的条目,将消息路由到对应的 Agent。
路由解析完整流程
入站消息(含 channel、peer、guildId、accountId 等元数据)
│
▼
┌───────────────────────┐
│ 遍历 bindings[] │ 按配置文件中定义顺序
│ 计算每个 binding │ 从上到下逐一匹配
│ 的匹配条件 │
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ 最具体优先排序 │ 按 8 级优先级排序
│ (非分数制) │ 同级取首个匹配
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ 选中最佳 binding │ 确定目标 Agent
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ 查找 Agent 定义 │ 在 agents.list 中查找
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ 计算会话键 │ 基于 dmScope 规则
└───────────┬───────────┘
│
▼
路由完成
三步详解
步骤 1:消息元数据提取
Gateway 收到消息后,从消息中提取路由所需的元数据字段:
channel--- 消息来源渠道(whatsapp、telegram、discord 等)peer--- 发送者或群组标识(包含 kind 和 id)accountId--- 渠道账户 IDguildId--- Discord 服务器 IDroles--- Discord 角色列表teamId--- Slack 团队 IDparentPeer--- 父级会话(用于线程继承)
说明:以上字段名是概念性描述,实际内部数据结构(如 TypeScript 接口定义)未在公开文档中详细披露。
步骤 2:会话键计算
根据 dmScope 配置计算会话键(sessionKey):
| dmScope | 会话键格式示例 |
|---|---|
main |
agent:lobster-master:main |
per-peer |
agent:lobster-master:webchat:peer:alice |
per-channel-peer |
agent:lobster-master:discord:peer:alice |
per-account-channel-peer |
agent:lobster-master:personal:discord:peer:alice |
群组聊天的会话键格式:agent:lobster-master:discord:group:123456789
步骤 3:Agent 实例化
根据匹配的 binding 找到 agentId,从 agents.list 中加载对应的 Agent 配置(工作空间、模型、工具策略等),实例化会话并执行。
匹配规则说明
OpenClaw 官方文档确认的路由排序原则是**"最具体优先"**,即匹配条件越具体的 binding 优先级越高。具体的排序实现细节(如是否采用分数制加权计算)未在公开文档中明确披露。
已确认的 8 级优先级排序(从高到低):
- 精确匹配(peer/group/channel ID)--- 匹配特定频道或群组
- 线程继承(parentPeer)--- 线程继承父会话的路由
- Discord 角色路由(guildId + roles)--- 按用户角色分发
- Discord 服务器(guildId)--- 按服务器整体路由
- Slack 团队(teamId)--- 按 Slack workspace 路由
- 账户匹配(accountId)--- 按账户路由
- 通道级匹配(accountId: "*")--- 渠道级别通配
- 默认 Agent 回退 --- 无匹配时的兜底
重要说明:关于"匹配分数体系"的具体数值权重,本文不作推测性描述。OpenClaw 采用确定性路由算法,相同输入始终产生相同输出,但具体实现方式(排序算法、是否使用分数)未在公开文档中明确。
7.2 会话状态存储结构
OpenClaw 的会话状态存储在 Gateway 所在主机的 ~/.openclaw/agents/<agentId>/sessions/ 目录下,采用两层数据结构。
sessions.json 格式
sessions.json 是会话索引文件,使用 sessionKey 作为键 的对象结构:
{
"agent:lobster-master:main": {
"sessionId": "7f0861b0-523a-422e-b7b4-d5c0274d97ee",
"updatedAt": 1775797535477,
"systemSent": true,
"abortedLastRun": false,
"model": "qwen3.6-plus",
"modelProvider": "generic",
"origin": {
"provider": "webchat",
"surface": "webchat",
"chatType": "direct"
},
"lastChannel": "webchat",
"skillsSnapshot": {
"prompt": "...",
"skills": [
{ "name": "acpx" },
{ "name": "acp-router" },
{ "name": "weather" }
]
}
},
"agent:lobster-master:cron:d4b938a6": {
"sessionId": "...",
"updatedAt": 1775797260000,
"systemSent": false,
"abortedLastRun": false,
"model": "qwen3.6-plus",
"modelProvider": "generic",
"origin": {
"provider": "cron",
"surface": "cron",
"chatType": "direct"
},
"lastChannel": "cron",
"skillsSnapshot": { "prompt": "...", "skills": [] }
}
}
字段说明表:
| 字段 | 类型 | 说明 |
|---|---|---|
sessionId |
string | 会话唯一标识符(UUID) |
updatedAt |
number | 最后活动时间戳(毫秒) |
systemSent |
boolean | 是否已发送系统消息 |
abortedLastRun |
boolean | 上次运行是否被中止 |
model |
string | 当前使用的模型名称 |
modelProvider |
string | 模型提供商 |
origin |
object | 消息来源信息 |
origin.provider |
string | 来源提供者(webchat/discord/cron 等) |
origin.surface |
string | 交互界面类型 |
origin.chatType |
string | 聊天类型(direct/group) |
lastChannel |
string | 最后活跃的渠道名称 |
skillsSnapshot |
object | 会话启动时加载的技能快照 |
说明:以上格式基于当前运行实例的实际文件内容验证。不同版本的 OpenClaw 可能存在字段差异。
JSONL 会话记录格式
每个会话的完整对话历史以 JSONL(JSON Lines)格式存储,每条记录占一行。
实际记录类型(经验证当前实例的 .jsonl 文件):
| 记录类型 (type) | 说明 | 关键字段 |
|---|---|---|
session |
会话初始化 | id, version, cwd, timestamp |
model_change |
模型切换 | id, parentId, provider, modelId |
thinking_level_change |
思考级别变更 | id, parentId, thinkingLevel |
custom |
自定义事件 | id, customType, data |
message |
用户或助手消息 | id, parentId, message.role, message.content |
compaction |
上下文压缩 | summary, entries |
实际 JSONL 记录示例(来自运行中的实例):
{"type":"session","version":3,"id":"00445d32-cd48-40b9-a9ee-9baf1226c761","timestamp":"2026-04-10T02:25:44.389Z","cwd":"/home/admin/openclaw/workspace-agents/lobster-master"}
{"type":"model_change","id":"59cadbd5","parentId":null,"timestamp":"2026-04-10T02:25:44.399Z","provider":"generic","modelId":"qwen3.6-plus"}
{"type":"thinking_level_change","id":"3a13b17c","parentId":"59cadbd5","timestamp":"2026-04-10T02:25:44.399Z","thinkingLevel":"off"}
{"type":"custom","customType":"model-snapshot","data":{"timestamp":1775787944415,"provider":"generic","modelApi":"openai-completions","modelId":"qwen3.6-plus"},"id":"04b6d5c2","parentId":"3a13b17c","timestamp":"2026-04-10T02:25:44.416Z"}
{"type":"message","id":"76ff0298","parentId":"04b6d5c2","timestamp":"2026-04-10T02:25:44.429Z","message":{"role":"user","content":[{"type":"text","text":"[cron:xxx] 请执行以下操作..."}],"timestamp":1775787944421}}
记录结构说明:
- 每条记录都有
type、id、timestamp字段 - 大部分记录有
parentId字段,用于构建事件树 message类型记录的role字段区分user(用户消息)和assistant(助手回复)message.content是数组格式,支持多模态内容(文本、图片等)- 工具调用和工具结果通过
message中的结构化内容体现,不是独立的记录类型
存储结构全景图
~/.openclaw/agents/<agentId>/sessions/
├── sessions.json ← 会话索引(sessionKey → 元数据)
├── 7f0861b0-...jsonl ← main 会话历史
├── c562da39-...jsonl ← 群组会话历史
├── 015f4cc3-...jsonl ← 子 Agent 会话历史
└── ... ← 每个会话一个独立的 JSONL 文件
每个 .jsonl 文件从会话创建开始,按时间顺序记录所有事件。文件的大小反映了会话的活跃程度和对话深度。
7.3 会话维护策略
OpenClaw 提供自动化的会话清理机制(配置路径因版本而异,以下以研究文档中的 agents.defaults.sessionPrune 为例),防止磁盘空间无限增长。维护策略包含四个维度:
pruneAfter(时间过期)
删除超过指定天数的旧会话。
{
agents: {
defaults: {
sessionPrune: {
pruneAfter: 30, // 30 天
}
}
}
}
注 :
sessionPrune配置路径在不同 OpenClaw 版本中可能有所不同。当前运行实例的agents.defaults中未显式配置 sessionPrune,以上配置基于架构研究文档。实际使用时请以openclaw.json的实际配置路径为准。
工作机制:
- Gateway 定期检查所有会话的
updatedAt时间戳 - 超过
pruneAfter的会话及其 JSONL 文件被删除 - 默认值为 30 天,可根据需要调整
maxEntries(最大条目数)
限制 sessions.json 中的最大会话条目数。
{
agents: {
defaults: {
sessionPrune: {
maxEntries: 500,
}
}
}
}
工作机制:
- 当会话条目数超过上限时触发清理
- 优先删除最久未活跃的会话
- 确保 sessions.json 文件不会无限膨胀
maxDiskBytes(磁盘配额)
限制会话存储的总磁盘占用。
{
agents: {
defaults: {
sessionPrune: {
maxDiskBytes: 500 * 1024 * 1024, // 500 MB
}
}
}
}
工作机制:
- 计算所有 JSONL 文件和 sessions.json 的总大小
- 超过配额时按时间从旧到新删除会话
- 具体清理阈值未在官方文档中明确说明
rotateBytes(轮转策略)
控制 sessions.json 文件本身的轮转大小。
{
agents: {
defaults: {
sessionPrune: {
rotateBytes: 10 * 1024 * 1024, // 10 MB
}
}
}
}
工作机制:
- 当 sessions.json 文件大小超过
rotateBytes时触发轮转 - 旧数据归档,保留最近的会话索引
- 防止 sessions.json 自身成为性能瓶颈
典型场景配置建议
| 场景 | pruneAfter | maxEntries | maxDiskBytes |
|---|---|---|---|
| 个人单用户 | 30 天 | 200 | 200 MB |
| 多用户家庭 | 14 天 | 500 | 500 MB |
| 企业团队 | 7 天 | 1000 | 1 GB |
7.4 并发控制与序列化
会话键序列化
OpenClaw 采用按会话键序列化的运行机制:
规则:同一 sessionKey 的请求按顺序执行
效果:保证同一会话内的对话上下文一致性
这意味着:
- 同一会话的多条消息不会并行处理
- 后到的消息需要等待前一条消息处理完成
- 不同会话的请求可以并行执行
全局并发限制
{
agents: {
defaults: {
maxConcurrent: 10, // 全局最大并发 Agent 运行数
}
}
}
工作机制:
- 限制同时运行的 Agent 总数
- 超过限制的新请求进入排队队列
- 防止 LLM API 调用过多导致速率限制
子 Agent 独立队列
通过 sessions_spawn 创建的子 Agent 拥有独立的执行队列:
主会话 ──→ 主队列(按 sessionKey 序列化)
子 Agent ──→ 独立队列(不阻塞主会话)
子 Agent 的运行不会阻塞主会话或其他子 Agent,实现真正的并发处理。
消息队列模式
OpenClaw 支持多种消息队列处理模式:
{
messages: {
queue: {
mode: "collect", // 收集模式(默认)
debounceMs: 1000, // 防抖时间 1 秒
cap: 20, // 最大排队数
drop: "summarize", // 丢弃策略
}
}
}
| 模式 | 说明 | 适用场景 |
|---|---|---|
collect |
合并排队消息为单次运行 | 默认推荐 |
steer |
立即注入当前运行 | 紧急插队 |
followup |
等当前完成后排队执行 | 顺序处理 |
steer-backlog |
立即引导 + 保留后续 | 复杂交互 |
四层并发控制总结
┌──────────────────────────────────────────────────────────────┐
│ 四层并发控制架构 │
├──────────────────────────────────────────────────────────────┤
│ L1: 会话键序列化 │
│ 同一会话的请求按序执行,保证上下文一致性 │
├──────────────────────────────────────────────────────────────┤
│ L2: 全局并发限制(maxConcurrent) │
│ 限制同时运行的主 Agent 总数(当前实例:10) │
├──────────────────────────────────────────────────────────────┤
│ L3: 子 Agent 并发限制(subagents.maxConcurrent) │
│ 限制子 Agent 独立并发数(当前实例:50) │
│ 子 Agent 队列独立于主 Agent,不占用 maxConcurrent 配额 │
├──────────────────────────────────────────────────────────────┤
│ L4: 消息队列管理(queue.mode) │
│ 控制多条消息的处理策略,避免重复执行 │
│ • collect:合并排队消息(默认) │
│ • debounceMs:防抖时间(1000ms) │
│ • cap:最大排队数(20),超限后按 drop 策略处理 │
└──────────────────────────────────────────────────────────────┘
并发超限时行为:
- 主 Agent 达到
maxConcurrent上限时,新请求进入排队队列等待,不会被拒绝 - 子 Agent 达到
subagents.maxConcurrent上限时,新的sessions_spawn请求排队等待 - 排队队列无超时限制,等待前面的请求完成后依次执行
- 可通过
/status命令查看当前并发状态
本节所有格式示例均基于实际运行实例的文件验证,确保技术描述的准确性。
第8节 最佳实践与常见陷阱
多 Agent 隔离机制赋予了 OpenClaw 强大的灵活性,但"能用"不等于"该用"。本节总结在实际使用中积累的最佳实践,帮助你在复杂度与收益之间找到最佳平衡点。
8.1 何时需要多 Agent
并非每个场景都需要多 Agent。在决定引入多 Agent 之前,先问自己几个问题:
需要多 Agent 的信号 ✅
- 不同的身份/人格需求:需要 Agent 在不同场景下表现出完全不同的人设(如"工作助手"需要专业严谨,"生活助手"需要轻松幽默)
- 敏感信息隔离:工作相关的对话数据不应与个人数据混合存储
- 不同的工具权限:某些场景需要完整的工具集,另一些场景需要严格限制
- 多渠道多账户管理:同时管理多个 WhatsApp 账号、多个 Telegram Bot
- 团队协作:多人共享同一个 Gateway,但每人需要独立的对话上下文和记忆
不需要多 Agent 的场景 ❌
- 只有一个人使用,即使有多个渠道,
dmScope: "main"配合单 Agent 就足够了 - 只需要按渠道区分群组消息(群组消息天然按群组 ID 隔离)
- 只需要不同的模型选择(可以在单个 Agent 中配置 fallback 模型链)
经验法则
从简单开始,按需扩展。 先用一个 Agent + 合适的
dmScope满足需求,只有当确实遇到隔离冲突时,再引入第二个 Agent。
8.2 隔离粒度选择
隔离粒度的选择需要在安全性和便利性之间权衡。过度隔离会增加维护成本,隔离不足则可能导致信息泄露。
推荐的隔离层次
层级 1(必须):工作空间隔离
→ 每个 Agent 独立 workspace
层级 2(推荐):会话作用域隔离
→ 多用户场景使用 per-channel-peer
层级 3(按需):工具策略隔离
→ 为不同 Agent 配置不同的工具权限
层级 4(高阶):沙箱隔离
→ 多用户/不受信任场景使用 Docker 沙箱
Agent 数量建议
| 团队规模 | 建议 Agent 数量 | 说明 |
|---|---|---|
| 个人 | 1 个 | 配合 dmScope: "main" 或 "per-peer" |
| 2-3 人 | 1-2 个 | 按用途区分(如个人 + 工作) |
| 小团队(5-10 人) | 2-4 个 | 按角色/渠道/账户划分 |
| 企业级(10+ 人) | 按需 | 建议配合 Docker 沙箱 |
8.3 安全注意事项
最小权限原则
每个 Agent 只应该拥有完成其任务所需的最小权限:
{
agents: {
list: [
{
id: "public-bot",
tools: {
// 公共机器人只允许读取和查询
allow: ["read", "web_fetch", "session_status"],
deny: ["write", "edit", "exec", "browser"],
},
},
{
id: "admin",
tools: {
// 管理员拥有完整权限
profile: "full",
},
},
],
},
}
敏感数据保护
MEMORY.md安全 :确保MEMORY.md仅在主会话中加载,绝不会在群组上下文中泄露- API Key 管理:不同 Agent 使用不同的 API Key,避免一个 Agent 的 Key 泄露影响所有 Agent
- BOOTSTRAP.md 清理 :初始化完成后确认
BOOTSTRAP.md已被删除,防止敏感初始化数据残留
沙箱加固
对于面向公众的 Agent,务必启用沙箱:
{
agents: {
list: [
{
id: "public-bot",
sandbox: {
mode: "all",
scope: "session",
allow: ["read", "web_fetch"],
deny: ["write", "edit", "exec", "process", "browser", "cron"],
},
},
],
},
}
8.4 性能影响分析
多 Agent 架构对系统性能的影响主要体现在以下几个方面:
内存消耗
每个 Agent 的工作区文件和会话数据会占用磁盘空间。一个活跃 Agent 的会话数据(JSONL 格式)每天可能产生几 KB 到几十 KB 的数据。
优化建议:
- 合理设置
pruneAfter(默认 30 天)清理过期会话 - 配置
rotateBytes(默认 10MB)控制sessions.json大小 - 设置
maxEntries(默认 500)限制最大会话数
CPU 和模型调用
多个 Agent 意味着更多的模型 API 调用。每个 Agent 的上下文压缩、记忆搜索、向量嵌入都是独立的计算开销。
优化建议:
- 为不同 Agent 选择性价比合适的模型(如
personal用高级模型,dev用本地模型) - 启用嵌入缓存(
memorySearch.cache.enabled: true)避免重复嵌入 - 配置
maxConcurrent限制并发运行数,防止资源耗尽
启动延迟
新会话启动时,OpenClaw 需要加载工作区文件、技能快照和会话历史。技能目录越大,启动越慢。
优化建议:
- 定期清理不再使用的技能
- 使用
skill-gating的requires条件按需加载技能 - 避免在 workspace 技能目录中放置大型文件
8.5 故障排查指南
常见问题与解决方案
问题 1:消息路由到了错误的 Agent
症状:发送给 work Agent 的消息被 personal Agent 回复
排查:
1. 检查 bindings 配置的匹配顺序(最具体优先)
2. 使用 /status 查看当前会话的 agentId
3. 确认 accountId/channel 配置是否正确
问题 2:Agent 找不到预期的技能
症状:Agent 报告工具不可用
排查:
1. 检查技能目录路径 ~/.openclaw/workspace-<agentId>/skills/
2. 确认 SKILL.md 格式正确(YAML front matter + 内容)
3. 检查 skill-gating 条件是否满足(bins/env/config)
4. 查看 Gateway 日志中的技能加载信息
问题 3:会话上下文不连续
症状:Agent "忘记"了之前的对话
排查:
1. 检查 dmScope 配置是否符合预期
2. 确认是否触发了每日重置(凌晨 4:00)
3. 检查 idleMinutes 是否设置过短
4. 确认会话键格式是否正确
问题 4:沙箱中命令执行失败
症状:exec 命令在沙箱中报错
排查:
1. 确认 Docker 服务正常运行(docker ps)
2. 检查 sandbox.allow/deny 配置
3. 确认命令所需的二进制文件在容器中可用
4. 查看 Docker 容器日志
诊断命令
# 查看 Gateway 状态
openclaw gateway status
# 查看当前活跃的 Agent 会话
# 在 WebChat 或任何渠道中发送
/status
# 手动重置当前会话
/new
# 查看日志
journalctl -u openclaw -f # systemd 管理
# 或
tail -f ~/.openclaw/logs/gateway.log # 直接查看日志(实际路径因部署方式而异)
日志分析技巧
OpenClaw 的 Gateway 日志包含丰富的诊断信息:
- 技能加载 :查找
skill关键字,确认哪些技能被成功加载/跳过 - 会话创建 :查找
session关键字,确认会话键和作用域 - 路由匹配 :查找
binding关键字,确认消息路由到了哪个 Agent - 错误信息 :查找
error关键字,快速定位问题
8.6 常见陷阱
在实际部署和维护多 Agent 隔离系统时,以下错误配置场景经常出现。了解这些陷阱,可以帮助你少走弯路。
陷阱一:Bindings 顺序不当导致路由错乱
错误场景:将宽泛的渠道级匹配规则放在精确匹配规则之前。
// ❌ 错误示例:宽泛规则在前
bindings: [
{ agentId: "main", match: { channel: "discord" } }, // 先匹配,截获所有 Discord 消息
{ agentId: "dev", match: { channel: "discord", peer: { kind: "channel", id: "123" } } } // 永远不会被执行
]
后果 :所有 Discord 消息都被路由到 main Agent,精确匹配规则永远不会触发。
正确做法:将精确匹配规则放在前面,宽泛规则放在后面。
// ✅ 正确示例:精确规则在前
bindings: [
{ agentId: "dev", match: { channel: "discord", peer: { kind: "channel", id: "123" } } }, // 先匹配
{ agentId: "main", match: { channel: "discord" } } // 兜底
]
陷阱二:agentId 引用了未在 agents.list 中定义的 Agent
错误场景 :在 bindings 中引用了一个未在 agents.list 中定义的 agentId。
agents: {
list: [
{ id: "main", workspace: "~/.openclaw/workspace" }
// 没有定义 "ops" Agent
]
},
bindings: [
{ agentId: "ops", match: { channel: "slack" } } // ❌ ops 不存在!
]
后果:匹配到该 binding 时路由失败,消息可能被丢弃或回退到默认 Agent,具体行为取决于实现版本。
正确做法 :确保每个 binding 中的 agentId 都在 agents.list 中有对应定义。在配置变更后使用 /status 命令验证路由。
陷阱三:会话作用域模式与使用场景不匹配
错误场景 :在多用户企业部署中使用了 dmScope: "main"。
session: {
dmScope: "main" // ❌ 所有用户的 DM 共享同一个会话
}
后果:不同用户的对话上下文混在一起,用户 A 可以看到用户 B 的对话历史,造成严重的信息泄露风险。
正确做法 :多用户场景使用 per-channel-peer(推荐)或 per-account-channel-peer(多账户场景)。
session: {
dmScope: "per-channel-peer" // ✅ 按渠道+发送者隔离
}
陷阱四:沙箱模式配置错误导致权限过大或功能不足
错误场景 A --- 权限过大:面向公众的客服 Agent 没有启用沙箱,拥有完整的文件系统访问权限。
// ❌ 客服 Agent 不应拥有完整 exec 权限
{
id: "support",
workspace: "~/.openclaw/workspace-support",
// 没有 sandbox 配置
tools: { allow: ["group:openclaw"] } // 全部工具开放
}
错误场景 B --- 功能不足 :开发 Agent 在沙箱中禁用了 exec,无法执行任何命令。
// ❌ 开发 Agent 需要 exec 能力
{
id: "dev",
sandbox: {
mode: "all",
deny: ["exec", "process"] // 开发 Agent 不能执行命令?
}
}
正确做法:根据 Agent 的职责精确配置沙箱和工具策略。
// ✅ 客服 Agent:最小权限 + 沙箱
{
id: "support",
sandbox: { mode: "all", scope: "session" },
tools: { allow: ["group:sessions", "group:messaging"] }
}
// ✅ 开发 Agent:完整工具 + 沙箱保护
{
id: "dev",
sandbox: { mode: "all", scope: "agent" },
tools: { allow: ["group:fs", "group:runtime", "group:sessions", "group:web"] }
}
核心原则:简单优先,安全至上。 多 Agent 是强大的工具,但每个新增的 Agent 都增加了系统的复杂度。只在确实需要隔离时才引入多 Agent,并为每个 Agent 配置最小权限。
第9节 总结
9.1 三大支柱回顾
本文围绕 OpenClaw 多 Agent 隔离机制的三大核心支柱进行了系统性的剖析:
第一支柱:隔离机制。 从工作空间、状态、会话到配置,四个维度的隔离共同构建了立体防护体系。每个 Agent 拥有独立的文件系统、会话存储、技能目录和模型配置,确保"一个 Gateway,多个互不干扰的 Agent"的架构愿景得以实现。沙箱模式更进一步,在操作系统层面提供了容器级的隔离保障。
第二支柱:绑定路由。 Bindings 是多 Agent 架构的"交通指挥系统"。8 级确定性路由算法------从 peer 精确匹配到默认 Agent 回退------确保每条消息都能被精确、可预测地分发到目标 Agent。确定性路由不仅是功能需求,更是安全底线:路由的不确定性将直接导致隔离机制失效。
第三支柱:会话管理。 dmScope 会话作用域模型决定了对话上下文的边界。从 main 模式的完全共享到 per-account-channel-peer 模式的极致隔离,四种模式覆盖了从个人单用户到企业多账户运营的各类场景。配合每日重置、空闲重置和自动清理策略,会话管理在上下文连续性与资源效率之间取得了平衡。
9.2 核心价值
OpenClaw 多 Agent 隔离机制的核心价值可以概括为三个关键词:
- 安全:文件系统级隔离 + 工具策略 + 沙箱模式,多层防御确保数据和权限不会越界
- 灵活:声明式配置让用户无需修改核心代码即可调整隔离边界,适配从个人到企业的各类场景
- 可控:确定性路由 + 会话生命周期管理 + 并发控制,让系统的行为完全可预测、可调试
这套机制的本质,是在单一进程中模拟多个独立 AI 助手的效果,同时保持了共享基础设施的效率优势。
9.3 未来展望
随着 OpenClaw 架构的持续演进,多 Agent 隔离机制还有广阔的优化空间:
- 更细粒度的权限控制:未来可能引入基于角色的访问控制(RBAC),实现工具级别的精细化权限管理
- 动态隔离策略:根据消息内容、发送者信任度等上下文因素动态调整隔离级别,在安全性和便利性之间实现智能平衡
- 跨节点隔离:当前隔离主要在同一 Gateway 主机内实现,未来可能扩展到多节点分布式部署场景
- 可观测性增强:更完善的隔离状态监控和审计日志,帮助管理员实时掌握各 Agent 的隔离边界和资源使用情况
- AI 辅助配置:利用 AI 分析使用模式,自动推荐最优的隔离粒度和绑定路由配置
OpenClaw 的隔离设计体现了"本地优先、声明式配置、确定性路由"的核心哲学。随着社区的发展和实际应用场景的不断丰富,这一机制将持续演进,为多 Agent 协作提供更坚实、更智能的基础设施保障。