457 lines
15 KiB
Markdown
457 lines
15 KiB
Markdown
# 给龙虾做了个 CT:43 万行代码的 OpenClaw 架构全拆解
|
||
|
||
> 分析日期:2026-03-11
|
||
> 源码版本:基于 GitHub 最新主分支
|
||
> 分析工具:Claude Opus 4.6
|
||
> 代码规模:约 43 万行 TypeScript,monorepo 架构
|
||
|
||
---
|
||
|
||
## 一、项目总览
|
||
|
||
OpenClaw 是一个**多通道 AI 智能体网关系统**——它不是一个简单的聊天机器人框架,而是一个完整的「AI 员工」运行时平台。其核心能力是:让大语言模型通过多种消息渠道(Slack、Telegram、Discord、WhatsApp 等 30+ 平台)接收指令、自主执行任务、并将结果回传。
|
||
|
||
### 1.1 Monorepo 结构
|
||
|
||
```
|
||
openclaw/
|
||
├── src/ # 核心运行时源码(主体)
|
||
│ ├── gateway/ # WebSocket 网关服务器
|
||
│ ├── acp/ # Agent Client Protocol 协议层
|
||
│ ├── agents/ # Agent 运行时、模型集成、工具系统
|
||
│ ├── memory/ # 向量检索 + 全文搜索记忆系统
|
||
│ ├── plugins/ # 插件加载、注册、Hook 执行
|
||
│ ├── channels/ # 通道管理器
|
||
│ ├── routing/ # 消息路由与会话键解析
|
||
│ ├── auto-reply/ # 心跳机制与自动回复
|
||
│ ├── config/ # 配置加载与会话持久化
|
||
│ ├── security/ # 安全审计与策略执行
|
||
│ ├── infra/ # 基础设施(设备身份、TLS、投递)
|
||
│ ├── cli/ # CLI 命令行界面
|
||
│ ├── web/ # Web/WhatsApp Webhook 处理
|
||
│ ├── terminal/ # 终端 TUI 组件
|
||
│ └── media-understanding/# 多媒体理解(图片/音频)
|
||
├── extensions/ # 34 个通道/功能插件
|
||
├── packages/ # 兼容包(clawdbot、moltbot 旧名)
|
||
├── apps/ # 原生客户端(macOS/iOS/Android)
|
||
├── ui/ # React Web 管理界面
|
||
├── skills/ # 内置技能
|
||
├── docs/ # 文档
|
||
├── test/ # 测试套件
|
||
└── vendor/ # 第三方依赖(a2ui 等)
|
||
```
|
||
|
||
### 1.2 技术栈
|
||
|
||
| 层面 | 技术选型 |
|
||
|------|---------|
|
||
| 语言 | TypeScript (ESM),Node.js 22+ |
|
||
| 构建 | tsdown (基于 Rolldown) + Vite (UI) |
|
||
| 包管理 | pnpm workspace (monorepo) |
|
||
| 协议 | WebSocket + ACP (Agent Client Protocol) |
|
||
| 存储 | SQLite (sqlite-vec + FTS5) + JSON 文件 |
|
||
| 验证 | AJV Schema Validation |
|
||
| 测试 | Vitest + V8 Coverage |
|
||
| 容器 | Docker / Podman 多阶段构建 |
|
||
| 桌面 | SwiftUI (macOS) / React Native (移动端) |
|
||
|
||
---
|
||
|
||
## 二、核心架构全景
|
||
|
||

|
||
|
||
---
|
||
|
||
## 三、六大核心子系统详解
|
||
|
||
### 3.1 Gateway(通信网关)
|
||
|
||
Gateway 是整个系统的**中枢神经**,负责接收所有外部连接、认证设备、路由消息。
|
||
|
||

|
||
|
||
**核心文件:**
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `src/gateway/server.impl.ts` | 网关启动入口 `startGatewayServer()` |
|
||
| `src/gateway/client.ts` | WebSocket 客户端,含重连与退避策略 |
|
||
| `src/gateway/server-chat.ts` | 聊天消息处理器 |
|
||
| `src/gateway/protocol/index.ts` | 协议帧定义与 AJV 校验 |
|
||
| `src/gateway/auth.ts` | 认证中间件 |
|
||
| `src/gateway/auth-rate-limit.ts` | 速率限制策略 |
|
||
| `src/gateway/server-channels.ts` | 通道生命周期管理 |
|
||
|
||
**Gateway 启动序列:**
|
||
|
||

|
||
|
||
**协议帧类型:**
|
||
|
||
| 帧类型 | 方向 | 用途 |
|
||
|--------|------|------|
|
||
| `RequestFrame` | Client → Server | chat.send, config.get, sessions.list 等 |
|
||
| `ResponseFrame` | Server → Client | 请求响应数据 |
|
||
| `EventFrame` | Server → Client | agent_message, tool_call, usage_update 等 |
|
||
| `HelloOk` | Server → Client | 握手响应,含协议版本和能力声明 |
|
||
|
||
**安全特性:**
|
||
- **CWE-319 防护**:`isSecureWebSocketUrl()` 禁止非回环地址使用明文 `ws://`
|
||
- **设备身份**:Ed25519 密钥对存储于 `~/.openclaw/credentials/`
|
||
- **TLS 指纹**:支持证书指纹验证(Certificate Pinning)
|
||
- **连接序列号**:检测消息间隙,防止重放攻击
|
||
|
||
---
|
||
|
||
### 3.2 ACP(Agent Client Protocol 协议层)
|
||
|
||
ACP 是 OpenClaw 定义的**标准化 Agent 通信协议**,作为 Gateway 与 Agent 运行时之间的翻译层。
|
||
|
||

|
||
|
||
**AcpGatewayAgent 核心职责:**
|
||
- 翻译 ACP 协议 ↔ Gateway 协议
|
||
- 管理会话生命周期(initialize → prompt → response)
|
||
- 速率限制(默认 120 请求 / 10 秒窗口)
|
||
- 追踪待处理的 prompt 和 tool call
|
||
|
||
**AcpSessionManager 核心职责:**
|
||
- 所有 ACP 运行时会话的单例管理器
|
||
- 运行时缓存(空闲 TTL 驱逐)
|
||
- 活跃回合与延迟统计
|
||
- **Actor 队列**:防止对同一会话的并发写入
|
||
|
||
**会话键格式:**
|
||
|
||
```
|
||
@main → 默认主会话
|
||
@jane → 名为 "jane" 的 Agent 会话
|
||
$subagent-id:child-key → 子 Agent 会话
|
||
thread:123 → 线程绑定会话
|
||
acp:uuid → ACP/IDE 会话
|
||
```
|
||
|
||
---
|
||
|
||
### 3.3 Agent Runtime(Agent 运行时)
|
||
|
||
Agent 运行时是系统的**大脑**,负责 LLM 推理、工具调用、子 Agent 调度。
|
||
|
||

|
||
|
||
**支持的 LLM 提供商(10+):**
|
||
|
||
| 提供商 | 说明 |
|
||
|--------|------|
|
||
| Anthropic | Claude Opus / Sonnet / Haiku |
|
||
| OpenAI | GPT 系列 |
|
||
| Google | Gemini 系列 |
|
||
| Qwen | 通义千问(阿里) |
|
||
| Minimax | 国产大模型 |
|
||
| Ollama | 本地部署任意开源模型 |
|
||
| Groq | 高速推理 |
|
||
| Grok | xAI |
|
||
| Azure | Azure OpenAI Service |
|
||
| Volc | 火山引擎(字节) |
|
||
|
||
**模型降级链(Fallback Chains):** 当主模型不可用时,自动切换到备用模型,保证服务连续性。
|
||
|
||
**工具审批机制:**
|
||
|
||

|
||
|
||
---
|
||
|
||
### 3.4 Plugin System(插件系统)
|
||
|
||
插件系统是 OpenClaw 可扩展性的核心——所有通道集成、记忆后端、诊断工具都以插件形式存在。
|
||
|
||

|
||
|
||
**已包含的 34 个通道插件:**
|
||
|
||
| 类别 | 插件 |
|
||
|------|------|
|
||
| 即时通讯 | Telegram, WhatsApp, Signal, iMessage, Line, Zalo |
|
||
| 团队协作 | Slack, Discord, MS Teams, Mattermost, Google Chat, 飞书 |
|
||
| 社交/社区 | Matrix, IRC, Nostr, Twitch, Tlon |
|
||
| 企业通讯 | Synology Chat, Nextcloud Talk, BlueBubbles |
|
||
| 语音 | voice-call |
|
||
| 开发/集成 | acpx, copilot-proxy, lobster |
|
||
|
||
**Plugin Runtime API:**
|
||
|
||
```typescript
|
||
PluginRuntime = {
|
||
subagent: {
|
||
run(), // 运行子 Agent
|
||
waitForRun(), // 等待运行完成
|
||
getSessionMessages(),
|
||
deleteSession()
|
||
},
|
||
channel: {
|
||
list(), // 列出通道
|
||
inspect(), // 检查通道状态
|
||
sendMessage() // 发送消息
|
||
},
|
||
core: {
|
||
config, // 全局配置
|
||
workspaceDir, // 工作区目录
|
||
agentId // 当前 Agent ID
|
||
}
|
||
}
|
||
```
|
||
|
||
**Hook 系统:**
|
||
|
||
| Hook | 触发时机 |
|
||
|------|---------|
|
||
| `gateway.startup()` | 网关启动时 |
|
||
| `gateway.shutdown()` | 优雅关闭时 |
|
||
| `channel.ready()` | 通道连接就绪 |
|
||
| `channel.message()` | 收到消息时 |
|
||
| `session.start()` | 会话开始 |
|
||
| `session.prompt()` | LLM 推理前 |
|
||
| `session.response()` | LLM 响应后 |
|
||
|
||
---
|
||
|
||
### 3.5 Memory System(记忆系统)
|
||
|
||
记忆系统实现了**向量检索 + BM25 全文搜索**的混合搜索架构,是 Agent 长期记忆的基础。
|
||
|
||

|
||
|
||
**MemoryIndexManager 是单例模式**,每个 Agent + Workspace 一个实例:
|
||
|
||
```typescript
|
||
// 获取或创建记忆管理器
|
||
const memory = await MemoryIndexManager.get({
|
||
cfg: config,
|
||
agentId: "main",
|
||
purpose: "chat"
|
||
});
|
||
|
||
// 混合搜索
|
||
const results = await memory.search({
|
||
query: "用户上周提到的跑步习惯",
|
||
limit: 10,
|
||
threshold: 0.7,
|
||
hybrid: { weight: 0.6 } // 向量权重 60%, BM25 权重 40%
|
||
});
|
||
```
|
||
|
||
**关键特性:**
|
||
- **时间衰减**:近期记忆权重更高
|
||
- **批量嵌入**:失败自动恢复
|
||
- **查询缓存**:TTL 控制的 embedding 缓存层
|
||
- **额外记忆路径**:可引入外部文档目录
|
||
|
||
---
|
||
|
||
### 3.6 Heartbeat(心跳机制)
|
||
|
||
心跳是 OpenClaw 最具争议也最核心的设计——让 AI **主动醒来执行任务**,而不是被动等待指令。
|
||
|
||

|
||
|
||
**HEARTBEAT.md 示例:**
|
||
|
||
```markdown
|
||
## 每日任务
|
||
|
||
- 每天早上 9:00 检查未读邮件,分类后发送摘要到 Slack #daily
|
||
- 监控竞品价格变动,降幅超过 10% 立即通知
|
||
- 每周五下午生成本周工作总结
|
||
|
||
## 触发条件
|
||
|
||
- 仅在工作日执行
|
||
- 静默模式:无变化时不发送消息
|
||
```
|
||
|
||
**可见性控制:**
|
||
|
||
| 配置项 | 说明 | 默认值 |
|
||
|--------|------|--------|
|
||
| `heartbeat.every` | 心跳间隔 | 30m |
|
||
| `heartbeat.enabled` | 是否启用 | true |
|
||
| `heartbeat.ackMaxChars` | ACK 最大字符数 | 300 |
|
||
| `SILENT_REPLY_TOKEN` | 静默回复标记 | #SILENT_ACK |
|
||
| `HEARTBEAT_OK` | 无需操作标记 | HEARTBEAT_OK |
|
||
|
||
---
|
||
|
||
## 四、数据流全链路
|
||
|
||
一条消息从外部平台进入到最终响应,经过的完整链路:
|
||
|
||

|
||
|
||
---
|
||
|
||
## 五、持久化与存储架构
|
||
|
||

|
||
|
||
**会话存储细节:**
|
||
|
||
| 存储项 | 格式 | 说明 |
|
||
|--------|------|------|
|
||
| 会话元数据 | JSON | 模型、Token 用量、思考级别等 |
|
||
| 会话转录 | JSONL (追加写入) | 不可变的消息日志,按大小/数量自动轮转 |
|
||
| 记忆索引 | SQLite | 向量表 + FTS 表 + 缓存表 |
|
||
| 设备身份 | JSON | Ed25519 公私钥对 |
|
||
| 配置 | JSON | 全局配置,含 Secret 引用 |
|
||
|
||
**Secrets 引用机制:**
|
||
|
||
```json
|
||
{
|
||
"providers": {
|
||
"anthropic": {
|
||
"apiKey": "${file://~/.openclaw/secrets/anthropic.key}"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
支持 `${file://path}` 和 `${env://VAR_NAME}` 两种引用方式。
|
||
|
||
---
|
||
|
||
## 六、安全架构
|
||
|
||

|
||
|
||
**操作域(Scopes)细粒度控制:**
|
||
|
||
| Scope | 权限 |
|
||
|-------|------|
|
||
| `gateway:full` | 网关完全控制 |
|
||
| `gateway:read` | 只读访问 |
|
||
| `channels:read` | 读取通道信息 |
|
||
| `messages:send` | 发送消息 |
|
||
| `config:write` | 修改配置 |
|
||
| `agents:manage` | Agent 管理 |
|
||
|
||
**沙箱策略:**
|
||
|
||
| 策略 | 说明 |
|
||
|------|------|
|
||
| `inherit` | 继承父会话沙箱模式 |
|
||
| `require` | 强制更严格的沙箱 |
|
||
| `forbidden` | 禁止子 Agent 派生 |
|
||
|
||
**安全审计(`src/security/`):**
|
||
- `dangerous-tools.ts` — 危险工具扫描器
|
||
- `dangerous-config-flags.ts` — 危险配置标记检测
|
||
- `audit.ts` — 审计日志记录器
|
||
- 临时路径防护、外部内容策略
|
||
|
||
---
|
||
|
||
## 七、通道集成架构
|
||
|
||

|
||
|
||
**通道插件必须实现的接口:**
|
||
|
||
```typescript
|
||
interface ChannelPlugin {
|
||
// 配置 Schema 定义
|
||
configSchema: JSONSchema;
|
||
|
||
// 生命周期
|
||
initialize(config: ChannelConfig): Promise<void>;
|
||
shutdown(): Promise<void>;
|
||
|
||
// 消息处理
|
||
onMessage(handler: MessageHandler): void;
|
||
sendMessage(target: Target, message: Message): Promise<void>;
|
||
|
||
// 状态
|
||
getStatus(): ChannelStatus;
|
||
getAccounts(): AccountInfo[];
|
||
}
|
||
```
|
||
|
||
**消息标准化:** 所有通道的消息都会被标准化为统一格式,包括:
|
||
- 文本内容
|
||
- 附件(图片/文件/音频)
|
||
- 发送者身份
|
||
- 线程/回复关系
|
||
- 通道特定元数据
|
||
|
||
---
|
||
|
||
## 八、构建与部署
|
||
|
||
### 8.1 Docker 部署架构
|
||
|
||

|
||
|
||
### 8.2 发布通道
|
||
|
||
| 通道 | 版本格式 | npm dist-tag |
|
||
|------|---------|--------------|
|
||
| Stable | vYYYY.M.D | `latest` |
|
||
| Beta | vYYYY.M.D-beta.N | `beta` |
|
||
| Dev | main 分支 | 无 tag |
|
||
|
||
### 8.3 客户端矩阵
|
||
|
||
| 平台 | 技术栈 | 位置 |
|
||
|------|--------|------|
|
||
| CLI | Commander.js + Clack | `src/cli/` |
|
||
| Web UI | React + Vite | `ui/` |
|
||
| macOS | SwiftUI + XPC Bridge | `apps/macos/` |
|
||
| iOS | React Native | `apps/ios/` |
|
||
| Android | React Native | `apps/android/` |
|
||
|
||
---
|
||
|
||
## 九、关键设计模式总结
|
||
|
||
### 9.1 架构模式
|
||
|
||

|
||
|
||
### 9.2 核心设计决策
|
||
|
||
| 决策 | 选择 | 理由 |
|
||
|------|------|------|
|
||
| 协议 | WebSocket + 自定义协议 | 双向实时通信,低延迟 |
|
||
| 存储 | 文件系统 + SQLite | 零外部依赖,本地优先 |
|
||
| 插件加载 | jiti 动态导入 | 支持 TypeScript 直接加载,无需预编译 |
|
||
| 并发控制 | Actor 队列 | 避免锁竞争,每会话串行保证一致性 |
|
||
| 记忆检索 | 向量 + BM25 混合 | 语义理解 + 精确匹配,互补短板 |
|
||
| 安全模型 | 设备身份 + Scopes | 零信任架构,最小权限原则 |
|
||
| 心跳 | 文件驱动 (HEARTBEAT.md) | 无需额外调度基础设施,用户可直接编辑 |
|
||
|
||
### 9.3 值得关注的工程亮点
|
||
|
||
1. **协议翻译器模式(ACP Translator)**:将外部标准协议与内部网关协议解耦,允许独立演进
|
||
2. **运行时缓存 + 空闲驱逐**:会话不用时自动回收资源,用时自动恢复
|
||
3. **Secret 引用而非内联**:配置文件中不存储明文密钥,而是引用外部文件或环境变量
|
||
4. **会话转录追加写入**:不可变日志,天然支持故障恢复和审计
|
||
5. **嵌入提供商可替换**:同一套记忆系统可无缝切换 OpenAI、Gemini、本地 Ollama 等后端
|
||
|
||
---
|
||
|
||
## 十、架构风险与局限
|
||
|
||
| 风险点 | 说明 | 影响 |
|
||
|--------|------|------|
|
||
| **明文 Markdown 存储** | HEARTBEAT.md、MEMORY.md 等以明文存储 | API Key 泄露风险 |
|
||
| **Root 级终端权限** | `system.run` 工具可执行任意命令 | 需依赖审批机制,但默认可绕过 |
|
||
| **心跳无人值守** | Agent 可在用户不知情时自主行动 | MoltMatch 等事件的根因 |
|
||
| **第三方 Skill 生态** | ClawHub 26% 插件含漏洞/恶意代码 | 供应链攻击面 |
|
||
| **单体网关** | Gateway 是单点,承载所有通道 | 高可用需额外架构 |
|
||
| **文件系统依赖** | 会话存储依赖本地文件系统 | 不原生支持分布式部署 |
|
||
|
||
---
|
||
|
||
> **总结**:OpenClaw 的架构本质上是一个**面向消息的分布式系统**——Gateway 是交换机,Agent 是 LLM 驱动的任务执行器,Channel 是双向传输管道。记忆、安全和可扩展性是一等公民,而非事后补丁。但其"本地优先"的设计哲学也带来了明文存储和单点依赖的固有风险。
|