返回博客

OpenClaw 源码解读(3): Workspaces 与多智能体路由

2026年3月7日

深入 OpenClaw Gateway 源码,解析这个唯一控制平面如何通过 WebSocket 网络、会话隔离、沙箱机制与 Pi RPC 运行时,实现对多设备、多会话的安全调度与流式传输。


在上一篇文章中,我们拆解了 OpenClaw 万物互联的中枢——Gateway 控制平面。了解了系统如何收发消息后,一个核心问题浮出水面:当四面八方的消息涌入网关时,OpenClaw 是如何决定由哪个"大脑"来处理的?

如果是个人私聊,我们需要一个全知全能的私人助理;如果是群组接入,我们可能只需要一个特定领域的客服或观察者。为了解决这个场景冲突,OpenClaw 引入了非常优雅的 Workspaces(工作区)多智能体路由(Multi-agent routing) 机制。

img1

今天,老金就带大家深入 OpenClaw 的源码,扒一扒这个"多重宇宙"是如何运转的。


会话隔离模型

在很多初级 AI 应用中,所有的对话往往共享同一个全局上下文,这在多渠道接入时会导致灾难性的隐私泄露或幻觉。OpenClaw 在架构设计之初,就严格定义了会话隔离模型。

在源码的类型定义中,核心被划分为两类:Main session(单人直聊)Non-main sessions(群组/频道)

img2

// src/core/session/types.ts 

export enum SessionType {
  MAIN = 'MAIN_DIRECT',       // 主人的超级会话
  NON_MAIN = 'NON_MAIN_GROUP' // 群组、公共频道或受限访客
}

export interface SessionContext {
  sessionId: string;
  type: SessionType;
  workspaceId: string; // 绑定的 Agent 工作区
  permissions: PermissionFlags;
}

  • Main session(主会话): 通常绑定管理员的直接通讯渠道(如你的专属 飞书 账号)。在这里,Agent 拥有最高权限,可以调用核心敏感工具(如操作宿主机本地命令、管理其他会话等)。
  • Non-main sessions(非主会话): 针对群聊、公开频道等。这类会话会被严格降级,放入沙箱环境。它们只能访问被明确授权的只读工具或受限回复能力,防止恶意群友通过 Prompt 注入(Prompt Injection)控制你的电脑。

路由分发

当一个外部请求(无论是 飞书 还是 企业微信)打到 Gateway 时,它是如何找到对应的 Agent 的呢?

OpenClaw 采用了一种多维度的路由解析策略。它会提取入站请求的 Channel (渠道)、Account (账户) 或 Peer Node (对等节点) 的标识,然后映射到预设的 Workspace 中。

我们可以看看核心的路由调度器是如何实现的:

// src/core/router/AgentRouter.ts

export class AgentRouter {
  // 路由分发核心入口
  public async dispatchInboundMessage(message: InboundMessage): Promise<void> {
    // 1. 解析来源上下文
    const { channelId, senderId, isGroup } = message.metadata;

    // 2. 匹配对应的工作区 (Workspace)
    const workspaceId = await this.resolveWorkspace(channelId, senderId, isGroup);

    // 3. 实例化或唤醒对应的 Agent Runtime
    const agent = await AgentManager.getOrSpawnAgent(workspaceId);

    // 4. 将消息推入该 Agent 的处理队列
    await agent.process(message);
  }

  private async resolveWorkspace(channelId: string, senderId: string, isGroup: boolean): Promise<string> {
    // 默认回退到通用工作区
    let targetWorkspace = 'default_workspace';

    // 优先匹配群组专属 Agent
    if (isGroup) {
      const groupRule = await ConfigManager.getGroupRoutingRule(channelId);
      if (groupRule) return groupRule.workspaceId;
    }

    // 匹配特定私聊对象的专属 Agent
    const userRule = await ConfigManager.getUserRoutingRule(senderId);
    if (userRule) return userRule.workspaceId;

    return targetWorkspace;
  }
}

通过这种设计,你可以轻松实现:把报警频道交给"运维 Agent",把某个群交给"摸鱼聊天 Agent",而你自己的私聊则永远路由给"超级助理 Agent"。

img3


上下文注入机制

找到了对应的 Agent,下一步就是告诉大模型"你是谁、你能干什么"。

不同于将 Prompt 硬编码在数据库里,OpenClaw 采用了基于文件系统的目录结构来管理 Agent 的上下文。所有的配置都存在 ~/.openclaw/workspace 目录下。

一个标准的工作区目录通常包含:

  • SOUL.md:核心性格与底层指令(比如:你是一只叫 Molty 的龙虾,说话要带点幽默)。
  • AGENTS.md:当前角色的具体任务定义。
  • TOOLS.md:该工作区允许使用的工具列表(通过 Markdown 列表动态挂载)。

在发起 LLM 请求前,OpenClaw 会动态读取这些文件,组装成最终的 System Prompt:

// src/core/agent/ContextBuilder.ts

import * as fs from 'fs';
import * as path from 'path';

export class ContextBuilder {
  public static buildSystemPrompt(workspacePath: string): string {
    const parts: string[] = [];

    // 1. 注入灵魂 (核心设定,优先级最高)
    const soulPath = path.join(workspacePath, 'SOUL.md');
    if (fs.existsSync(soulPath)) {
      parts.push('### CORE IDENTITY ###\n' + fs.readFileSync(soulPath, 'utf-8'));
    }

    // 2. 注入角色任务
    const agentPath = path.join(workspacePath, 'AGENTS.md');
    if (fs.existsSync(agentPath)) {
      parts.push('### CURRENT DIRECTIVES ###\n' + fs.readFileSync(agentPath, 'utf-8'));
    }

    // 3. 注入工具白名单与可用技能
    const toolsPath = path.join(workspacePath, 'TOOLS.md');
    if (fs.existsSync(toolsPath)) {
      parts.push('### AVAILABLE TOOLS ###\n' + fs.readFileSync(toolsPath, 'utf-8'));
    }

    // 最终拼接发送给 LLM
    return parts.join('\n\n');
  }
}

这种基于 Markdown 的文本拼接方式非常适合本地优先(Local-first)的理念。作为开发者,你甚至不需要写前端面板,直接用 VS Code 打开目录修改 Markdown 文件,保存的瞬间,下一个对话的 Agent 灵魂就已经变了。配合 Git 进行版本控制,体验非常丝滑。


总结

OpenClaw 通过 区分主次会话 保障了系统的底层安全,通过 多维路由分发 实现了对 20+ 渠道的有条不紊的管理,最后用极简的 文件系统注入 完成了 Agent 灵魂的组装。

这套"多重宇宙"机制,是 OpenClaw 能够从一个简单的聊天机器人,跃升为全平台 AI 管家的核心基石。

下一篇,我们将进入实战环节《OpenClaw 源码解读(4):多渠道接入(Channels)源码实战》,看看这些千奇百怪的第三方平台协议,是如何被 OpenClaw 抹平差异的。