27 KiB
OpenClaw 系统架构设计文档
项目:https://github.com/openclaw/openclaw 文档版本:1.0 创建日期:2026-02-06
目录
- 1. 概述
- 2. 项目整体结构
- 3. 核心架构设计
- 4. 关键设计模式
- 5. 插件扩展机制
- 6. 路与会话管理
- 7. 模块间关系
- 8. 通信协议
- 9. 认证与安全
- 10. 测试策略
- 11. 构建与部署
- 12. 编码规范
- 13. 附录:代码示例
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/Format:Oxlint + 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/zalousernostr/mattermostnextcloud-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.md 和 docs/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.md 和 docs/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);
}
参考资料
文档结束