openclaw/OPENCLAW_SYSTEM_ARCHITECTUR...

27 KiB
Raw Permalink Blame History

OpenClaw 系统架构设计文档

项目:https://github.com/openclaw/openclaw 文档版本1.0 创建日期2026-02-06


目录


1. 概述

OpenClaw 是一个多平台消息聚合与 AI Agent 平台,支持 WhatsApp、Telegram、Discord、Slack、Signal、iMessage 等多个消息通道,以及多种 AI 模型提供者。

1.1 核心特性

  • 多通道支持:通过插件化架构支持十多种消息平台
  • Gateway 架构:集中式的 WebSocket 网关服务所有客户端
  • 插件系统:可扩展的插件机制(通道、模型提供者、内存等)
  • 灵活路由:基于绑定的智能消息路由
  • 会话管理:持久化的会话存储和历史记录
  • 媒体处理:完整的媒体上传、存储和处理管道

1.2 技术栈

  • 语言TypeScript (ESM)
  • 运行时Node 22+,支持 Bun
  • 包管理pnpm保持 npm 兼容性)
  • 测试Vitest + V8 覆盖率
  • Lint/FormatOxlint + Oxfmt
  • 协议WebSocket (JSON)HTTP (REST + OpenAI 兼容)

2. 项目整体结构

2.1 主要目录

openclaw/
├── src/
│   ├── cli/                  # CLI 入口和命令系统
│   ├── commands/             # 命令实现
│   ├── gateway/              # Gateway 服务器
│   ├── channels/             # 通道系统
│   ├── providers/            # AI 模型提供者
│   ├── agents/               # Agent 运行时
│   ├── media/                # 媒体管道
│   ├── infra/                # 基础设施
│   ├── config/               # 配置系统
│   ├── plugins/              # 插件系统
│   ├── plugin-sdk/           # 插件开发 SDK
│   ├── routing/              # 路由系统
│   ├── acp/                  # Agent Client Protocol
│   ├── pairing/              # 设备配对
│   ├── hooks/                # 生命周期钩子
│   ├── terminal/             # 终端输出工具
│   ├── logging/              # 日志系统
│   └── ...
├── extensions/               # 扩展插件(工作区包)
├── apps/                     # 移动应用和 macOS 应用
├── ui/                       # Web UI (dien)
├── docs/                     # 文档
├── skills/                   # 内置技能
└── openclaw.mjs             # CLI 入口点

2.2 程序入口

openclaw.mjs (编译缓存入口)
    └─> src/index.ts
          └─> buildProgram()
                ├─> createProgramContext()
                └─> registerProgramCommands()

2.3 包导出

{
  "exports": {
    ".": "./dist/index.js",
    "./plugin-sdk": "./dist/plugin-sdk/index.js",
    "./cli-entry": "./openclaw.mjs"
  }
}

3. 核心架构设计

3.1 CLI 命令系统

3.1.1 命令注册表模式

CLI 基于 commander,采用注册表模式进行命令注册:

// src/cli/program/command-registry.ts
export const commandRegistry: CommandRegistration[] = [
  { id: "setup", register: ({ program }) => registerSetupCommand(program) },
  { id: "onboard", register: ({ program }) => registerOnboardCommand(program) },
  { id: "config", register: ({ program }) => registerConfigCli(program) },
  { id: "memory", register: ({ program }) => registerMemoryCli(program) },
  { id: "agent", register: ({ program, ctx }) => registerAgentCommands(program, ctx) },
  // ... 更多命令
];

3.1.2 命令分类

类别 模块 示例命令
核心命令 src/commands/ agent, send, message
配置命令 src/config/ config set/get/apply
通道命令 Sub CLI channels status/login/logout
Gateway Sub CLI gateway run/stop
Daemon Sub CLI daemon start/stop
节点 Sub CLI nodes list/status

3.1.3 路由机制

// src/cli/program/routing.ts
export type RouteSpec = {
  match: (path: string[]) => boolean;
  loadPlugins?: boolean; // 是否加载插件以解析命令
  run: (argv: string[]) => Promise<boolean>;
};

路由机制允许快速解析某些命令路径,例如网关模式下直接启动而无需加载所有插件。


3.2 网关架构

3.2.1 网关启动入口

src/gateway/server.impl.ts
  └─> startGatewayServer(port, opts): Promise<GatewayServer>

3.2.2 核心子系统

子系统 实现路径 职责
协议验证 src/gateway/protocol/ Ajv 验证所有 JSON 帧
方法处理器 src/gateway/server-methods/ 各个 gateway 方法实现
运行时状态 src/gateway/server-runtime-state.ts 服务器状态、缓冲区
通道管理 src/gateway/server-channels.ts 通道启停
事件处理 src/gateway/server-chat.ts Agent 事件和广播
WebSocket src/gateway/server-ws-runtime.ts WS 连接和帧分发
配置重载 src/gateway/config-reload.ts 监听配置变更
启动/停止 src/gateway/server-close.ts 优雅关闭
协议定义 src/gateway/protocol/ 请求/事件帧模式

3.2.3 网关启动流程

startGatewayServer()
  ├─> 加载配置 (loadConfig)
  ├─> 加载插件 (loadGatewayPlugins)
  │     ├─> 注册插件钩子
  │     ├─> 注册通道插件
  │     └─> 注册自定义 Gateway 方法
  ├─> 创建运行时状态 (createGatewayRuntimeState)
  │     ├─> HTTP 服务器
  │     ├─> WebSocket 服务器
  │     ├─> Canvas Host (a2ui, 端口 18793)
  │     └─> 协议验证 (AJV)
  ├─> 注册状态恢复
  ├─> 注册方法处理器 (coreGatewayHandlers + plugin 处理器)
  ├─> 启动通道 (startChannels)
  ├─> 启动 Cron 服务 (buildGatewayCronService)
  ├─> 配置重载监听 (startGatewayConfigReloader)
  └─> 返回 GatewayServer 实例

3.2.4 HTTP 端点

默认端口:18789

端点 方法 用途
/ws WebSocket 控制和事件流
/v1/gateway/* POST 增量 API 方法
/v1/chat/completions POST OpenAI 兼容
/v1/responses POST OpenResponses 兼容
/media/* GET/PUT 媒体服务

3.3 消息通道系统

3.3.1 通道插件化

所有通道必须实现 ChannelPlugin 接口:

export type ChannelPlugin<ResolvedAccount, Probe, Audit> = {
  id: ChannelId;
  meta: ChannelMeta;
  capabilities: ChannelCapabilities;
  config: ChannelConfigAdapter<ResolvedAccount>;
  configSchema?: ChannelConfigSchema;
  setup?: ChannelSetupAdapter;
  pairing?: ChannelPairingAdapter;
  security?: ChannelSecurityAdapter<ResolvedAccount>;
  groups?: ChannelGroupAdapter;
  mentions?: ChannelMentionAdapter;
  outbound?: ChannelOutboundAdapter;
  status?: ChannelStatusAdapter<ResolvedAccount, Probe, Audit>;
  gatewayMethods?: string[];
  gateway?: ChannelGatewayAdapter<ResolvedAccount>;
  auth?: ChannelAuthAdapter;
  elevated?: ChannelElevatedAdapter;
  commands?: ChannelCommandAdapter;
  streaming?: ChannelStreamingAdapter;
  threading?: ChannelThreadingAdapter;
  messaging?: ChannelMessagingAdapter;
  agentPrompt?: ChannelAgentPromptAdapter;
  directory?: ChannelDirectoryAdapter;
  resolver?: ChannelResolverAdapter;
  actions?: ChannelMessageActionAdapter;
  heartbeat?: ChannelHeartbeatAdapter;
  agentTools?: ChannelAgentToolFactory | ChannelAgentTool[];
};

3.3.2 核心适配器

适配器 接口 职责
ChannelConfigAdapter listAccountIds, resolveAccount 配置解析
ChannelOutboundAdapter sendText, sendMedia 消息发送
ChannelGatewayAdapter startAccount, stopAccount 网关启停
ChannelStatusAdapter snapshots, probe, audit 状态探查
ChannelGroupAdapter resolveGroup 群组上下文
ChannelSecurityAdapter resolveDMPolicy 安全策略
ChannelDirectoryAdapter listGroups, listPeers 用户目录
ChannelAuthAdapter login 登录流程

3.3.3 内置通道

通道 实现目录
WhatsApp Web src/web/, src/whatsapp/
Telegram src/telegram/
Discord src/discord/
Slack src/slack/
Signal src/signal/
iMessage src/imessage/
LINE src/line/
Google Chat src/googlechat/
MS Teams src/msteams/

3.3.4 扩展通道

位于 extensions/*/

  • bluebubbles / matrix / msteams (extension)
  • tton / zalo / zalouser
  • nostr / mattermost
  • nextcloud-talk / feishu

3.4 媒体管道

3.4.1 核心组件

文件 职责
mime.ts MIME 类型检测magic number + content type
parse.ts 消息媒介提取(文本、图片、音频等)
store.ts 磁盘存储,文件命名 {original}---{uuid}.ext
fetch.ts HTTP/HTTPS 远程获取
host.ts HTTP 服务,鉴权和 Headers
image-ops.ts 图片调整大小 (JPEG)
audio.ts 音频转换、兼容性检查
server.ts HTTP 服务配置

3.4.2 存储结构

~/.openclaw/media/
├── inbound/    # 接收的媒体
└── outbound/   # 发送的媒体

3.4.3 媒体处理流程

入站:
  消息媒介提取
      ↓
  MIME 检测 (magic number)
      ↓
  保存到磁盘 (store.ts)
      ↓
  生成内部 URL

出站:
  媒体上传/处理
      ↓
  MIME 检测
      ↓
  压缩/转换 (可选)
      ↓
  保存到磁盘
      ↓
  通过 HTTP 端点服务

3.5 基础设施层

3.5.1 端口管理

src/infra/ports.ts

功能 说明
checkPortAvailability 检查端口是否可用
killPortOccupyingProcess 杀死占用端口的进程
autoDetectAvailablePort 自动检测可用端口
DEFAULT_PORT 默认端口 18789

3.5.2 SSRF 防护

src/infra/net/ssrf.ts

解析主机名并验证是否为安全的内部地址。

3.5.3 事件系统

表件 事件类型
diagnostic-events.ts 诊断事件
heartbeat-events.ts 心跳事件
system-events.ts 系统事件队列
channel-activity.ts 通道活动跟踪

3.5.4 出站传送

src/infra/outbound/deliver.ts

支持三种传送模式:

  • single - 单通道
  • gateway - 通过网关
  • mixed - 混合模式

4. 关键设计模式

4.1 依赖注入

4.1.1 CLI 依赖

// src/cli/deps.ts
export type CliDeps = {
  sendMessageWhatsApp: typeof sendMessageWhatsApp;
  sendMessageTelegram: typeof sendMessageTelegram;
  sendMessageDiscord: typeof sendMessageDiscord;
  sendMessageSlack: typeof sendMessageSlack;
  sendMessageSignal: typeof sendMessageSignal;
  sendMessageIMessage: typeof sendMessageIMessage;
};

export function createDefaultDeps(): CliDeps {
  return {
    sendMessageWhatsApp,
    sendMessageTelegram,
    sendMessageDiscord,
    sendMessageSlack,
    sendMessageSignal,
    sendMessageIMessage,
  };
}

4.1.2 插件运行时依赖

// src/plugins/runtime/types.ts
export type PluginRuntime = {
  version: string;
  config: { loadConfig, writeConfigFile };
  system: { enqueueSystemEvent, runCommandWithTimeout };
  media: { loadWebMedia, detectMime, mediaKindFromMime, ... };
  tts: { textToSpeechTelephony };
  tools: { createMemoryGetTool, createMemorySearchTool, ... };
  channel: {
    text: { chunkByNewline, chunkMarkdownText, ... };
    reply: { dispatchReplyWithBufferedBlockDispatcher, ... };
    routing: { resolveAgentRoute };
    pairing: { buildPairingReply, ... };
    network: { fetchRemoteMedia, saveMediaBuffer };
    activity: { record, get };
    session: { resolveStorePath, ... };
    // 各通道特定函数...
  };
  logging: { shouldLogVerbose, getChildLogger };
  state: { resolveStateDir };
};

4.2 状态管理

4.2.1 配置状态

// 配置加载流程
loadConfig()  parseConfigJson5()  validateConfigObject()  migrateLegacyConfig()

配置文件位置:~/.openclaw/config.json5

4.2.2 配置监听和重载

src/gateway/config-reload.ts

监听配置文件变更,触发网关状态更新。

4.2.3 通道状态

// src/gateway/server-channels.ts
type ChannelRuntime = {
  id: string;
  accountId: string;
  status: Snapshot;
  stop?: () => Promise<void>;
  // ...
};

4.2.4 会话状态

会话存储位置:~/.openclaw/sessions/{channel}/{accountId}/{session}.jsonl

会话键格式:session/{agentId}/{channel}/{accountId}/{peer}


4.3 消息路由机制

4.3.1 路由解析

// src/routing/resolve-route.ts
export type ResolveAgentRouteInput = {
  cfg: OpenClawConfig;
  channel: string;
  accountId?: string | null;
  peer?: RoutePeer | null;
  parentPeer?: RoutePeer | null;
  guildId?: string | null;
  teamId?: string | null;
};

export type ResolvedAgentRoute = {
  agentId: string;
  channel: string;
  accountId: string;
  sessionKey: string;
  mainSessionKey: string;
  matchedBy:
    | "binding.peer"
    | "binding.peer.parent"
    | "binding.guild"
    | "binding.team"
    | "binding.account"
    | "binding.channel"
    | "default";
};

4.3.2 路由匹配优先级

1. peer (具体用户/组)
2. thread parent peer (继承)
3. guildId (Discord 服务器)
4. teamId (Slack/Teams)
5. account (非通配符)
6. account (通配符)
7. default (默认代理)

4.3.3 会话键构建

// src/routing/session-key.ts
export function buildAgentSessionKey(params: {
  agentId: string;
  channel: string;
  accountId?: string | null;
  peer?: RoutePeer | null;
  dmScope?: "main" | "per-peer" | "per-channel-peer" | "per-account-channel-peer";
  identityLinks?: Record<string, string[]>;
}): string;

4.4 配置系统

4.4.1 配置模块

src/config/
├── types.agent-defaults.ts
├── types.agents.ts
├── types.auth.ts
├── types.base.ts
├── types.browser.ts
├── types.channels.ts
├── types.openclaw.ts
├── types.cron.ts
├── types.sandbox.ts
├── types.memory.ts
├── types.models.ts
├── types.node-host.ts
├── types.tts.ts
├── types.tools.ts
├── types.whatsapp.ts
├── types.imessage.ts
├── types.slack.ts
├── ... (更多通道配置)
├── config.ts (主导出)
└── ...

4.4.2 验证机制

使用 Zod 进行模式验证:

validateConfigObject(config): ValidationResult
validateConfigObjectWithPlugins(config, plugins): ValidationResult

4.4.3 配置迁移

migrateLegacyConfig() - 处理旧配置版本的自动迁移。


4.5 钩子系统

4.5.1 钩子类型

// src/hooks/types.ts
export type HookEntry = {
  name: string;
  handler: HookHandler;
  priority?: number;
};

export type HookEvent =
  | "before_agent_start"
  | "after_agent_start"
  | "before_message_send"
  | "after_message_send"
  | "message_received"
  | "tool_called"
  | "config_changed"
  // ... 更多钩子
};

4.5.2 钩子注册方式

  • 插件通过 api.registerHook() 注册
  • 优先级按 priority 数值排序

5. 插件扩展机制

5.1 插件类型

类型 说明 示例
memory 内存/向量存储插件 LanceDB
channel 通道插件 Matrix, Zalo
provider 模型提供者插件 自定义 OpenAI 兼容 API

5.2 插件 API

// src/plugins/types.ts
export type OpenClawPluginDefinition = {
  id?: string;
  name?: string;
  description?: string;
  version?: string;
  kind?: PluginKind; // "channel" | "memory" | "provider" | ...
  configSchema?: OpenClawPluginConfigSchema;
  register?: (api: OpenClawPluginApi) => void | Promise<void>;
  activate?: (api: OpenClawPluginApi) => void | Promise<void>;
};

5.3 通道插件

参见 3.3.1 节

5.4 插件运行时

插件通过 OpenClawPluginApi.runtime 访问运行时 API参见 4.1.2 节


6. 路由与会话管理

6.1 路由解析

详见 4.3.1 节

6.2 会话结构

~/.openclaw/sessions/
└── {channel}/
    └── {accountId}/
        └── {session}.jsonl (JSONL 格式)

每行包含:

  • role: "user" | "assistant"
  • content: 消息内容
  • timestamp: 时间戳
  • meta: 元数据

6.3 会话 API

loadSessionStore(sessionPath): Promise<Session>
saveSessionStore(sessionPath, session): Promise<void>
updateLastRoute(channel, accountId, route): Promise<void>

7. 模块间关系

7.1 CLI 层

openclaw.mjs
  └─> src/index.ts
        ├─> createDefaultDeps()
        ├─> buildProgram()
        │     ├─> createProgramContext()
        │     └─> registerProgramCommands()
        │           ├─> registerSetupCommand()
        │           ├─> registerOnboardCommand()
        │           ├─> registerConfigCli()
        │           ├─> registerAgentCommands()
        │           ├─> registerSubCliCommands()
        │           └─> ...
        └─> 程序解析 → 各命令处理器

7.2 Gateway 层

startGatewayServer()
  ├─> 配置加载 (loadConfig)
  ├─> 插件加载 (loadGatewayPlugins)
  │     ├─> 插件注册表
  │     └─> 通道插件 (listChannelPlugins)
  ├─> 运行时状态 (createGatewayRuntimeState)
  │     ├─> HTTP 服务器
  │     ├─> WebSocket 服务器
  │     ├─> Canvas Host (a2ui)
  │     └─> 协议验证 (AJV)
  ├─> 方法处理器
  ├─> 事件广播
  ├─> 通道管理器
  ├─> Cron 服务
  ├─> 节点注册
  └─> 配置重载

7.3 消息流转

入站:
  平台消息 → 通道适配器 → Gateway 事件 → 路由解析 → Agent 执行 → 出站

出站:
  CLI/Web/App → Gateway 方法 → 根据路由分发 → 通道适配器 → 平台

8. 通信协议

8.1 Gateway Protocol

详见 docs/concepts/architecture.mddocs/gateway/protocol.md

核心帧类型:

export type GatewayFrame =
  | RequestFrame // {type:"req", id, method, params}
  | ResponseFrame // {type:"res", id, ok, payload|error}
  | EventFrame; // {type:"event", event, payload, seq?, stateVersion?}

事件类型

  • agent - Agent 执行事件
  • chat - 聊天更新
  • presence - 在线状态
  • health - 健康状态
  • heartbeat - 心跳
  • cron - Cron 任务
  • tick - 定时脉冲

常用 Gateway 方法

方法 功能
health 健康检查
status 状态查询
send 发送消息
agent 启动 Agent
channels.list 列出通道账户
channels.status 通道状态
channels.login 通道登录

8.2 ACP (Agent Client Protocol)

位于 src/acp/,用于 Agent 与客户端的通信。


9. 认证与安全

9.1 设备配对

新建设备 ID 需要配对批准:

  • 本地连接:自动批准
  • 远程连接:需要显式批准
  • 挑战签名:防止劫持

设备令牌存储在 ~/.openclaw/device-tokens.json

9.2 Gateway 认证

// src/config/auth.ts
export type GatewayAuth = {
  token?: string; // Bearer Token 检查
  allowed?: string[]; // 允许的设备 ID
};

9.3 SSRF 防护

src/infra/net/ssrf.ts - 防止服务器端请求伪造。


10. 测试策略

10.1 测试框架

  • 框架Vitest
  • 覆盖率V8
  • 阈值70% (线/分/函数/语句)

10.2 测试类型

类型 后缀 说明
单元测试 *.test.ts 功能单元测试
E2E 测试 *.e2e.test.ts 端到端测试

10.3 测试命令

pnpm test                 # 运行所有测试
pnpm test:coverage        # 运行测试并生成覆盖率报告
pnpm test:live            # 运行 Live 测试 (需要真实凭证)

11. 构建与部署

11.1 构建命令

pnpm build        # 完整构建
pnpm tsgo         # TypeScript 类型检查
pnpm check        # Lint + Format

11.2 macOS 应用打包

scripts/package-mac-app.sh

11.3 发布流程

详解见 docs/platforms/mac/release.mddocs/reference/RELEASING.md

发布通道:

  • stable: 版本标签 (v2026.2.4) + npm tag latest
  • beta: 预发布标签 (v2026.2.4-beta.N) + npm tag beta
  • dev: main 分支头部 (无标签)

12. 编码规范

12.1 语言与风格

  • 语言TypeScript (ESM)
  • 严格类型:避免 any
  • 格式化Oxlint + Oxfmt
  • 文件大小:目标 < ~700 LOC

12.2 命名规范

  • 产品/文档标题OpenClaw (大写)
  • CLI 命令openclaw (小写)
  • 包/二进制名openclaw (小写)
  • 配置键openclaw (小写)

12.3 代码注释

为复杂或非显而易见的逻辑添加简短注释。

12.4 终端输出

  • 进度条src/cli/progress.ts (osc-progress + @clack/prompts)
  • 表格src/terminal/table.ts (ANSI 安全换行)

12.5 多 Agent 安全

  • 不创建/应用/删除 git stash 除非明确要求
  • 不删除/修改 git worktree 除非明确要求
  • 尊重其他 Agent 的工作

13. 附录:代码示例

13.1 注册插件钩子

export default function register(api: OpenClawPluginApi) {
  api.on("before_agent_start", async (event, ctx) => {
    console.log("Agent starting:", ctx.agentId);
    return {
      systemPrompt: "Custom system prompt...",
      prependContext: "Extended context...\n",
    };
  });

  api.on("message_received", async (event, ctx) => {
    console.log("Received:", event.content);
  });
}

13.2 注册自定义命令

api.registerCommand({
  name: "tts",
  description: "Text to speech",
  acceptsArgs: true,
  requireAuth: true,
  handler: async (ctx) => {
    const text = ctx.args || "";
    // ... 处理 tts 并回复
    return { text: `Speaking: ${text}` };
  },
});

13.3 注册通道

api.registerChannel({
  id: "mychannel" as ChannelId,
  meta: {
    id: "mychannel" as ChannelId,
    label: "My Channel",
    selectionLabel: "My Channel",
    docsPath: "/channels/mychannel",
    blurb: "My custom channel implementation",
  },
  capabilities: {
    chatTypes: ["dm", "group"],
    media: true,
    reactions: true,
    reply: true,
  },
  config: {
    listAccountIds: (cfg) => Object.keys(cfg.mychannel?.accounts ?? {}),
    resolveAccount: (cfg, accountId) => cfg.mychannel?.accounts?.[accountId] ?? {},
    defaultAccountId: (cfg) => "default",
  },
  outbound: {
    deliveryMode: "gateway",
    sendText: async (ctx) => {
      // 发送文本到平台
      return { ok: true };
    },
  },
  gatewayMethods: ["mychannel.send"],
  gateway: {
    startAccount: async (ctx) => {
      // 启动通道监听器
    },
    stopAccount: async (ctx) => {
      // 停止通道监听器
    },
  },
});

13.4 使用插件 SDK

import {
  registerTool,
  resolveAgentRoute,
  loadConfig,
  dispatchReplyWithBufferedBlockDispatcher,
} from 'openclaw/plugin-sdk';

export default function register(api: OpenClawPluginApi) {
  const tool = {
    type: 'function',
    name: 'mytool',
    description: 'My custom tool',
    parameters: {
      type: 'object',
      properties: {},
      additionalProperties: false,
    },
    handler: async ({ accountId, messageChannel, agentId, ... }) => {
      // 处理工具
      return {
        success: true,
        content: [],
        data: undefined,
      };
    },
  };
  api.registerTool(tool);
}

参考资料


文档结束