OpenClaw 运行原理
1. 系统架构
OpenClaw 采用模块化、可扩展的架构设计,基于 Node.js 平台构建,主要由以下核心组件组成:
1.1 核心组件
| 组件 | 描述 | 位置 | 关键文件 |
|---|---|---|---|
| 网关服务 (Gateway) | 中央协调器,处理所有请求和响应,管理 WebSocket 连接 | src/gateway/ |
src/gateway/server.ts, src/gateway/auth.ts |
| 技能系统 (Skills) | 提供模块化功能扩展,支持自定义技能 | skills/ |
src/agents/skills.ts, src/agents/skills/workspace.ts |
| 命令行界面 (CLI) | 用户交互入口,提供各种命令 | src/cli/ |
src/cli/program.ts, src/cli/route.ts |
| 消息通道 (Channels) | 与外部服务的通信接口 | src/telegram/, src/discord/, src/slack/ 等 |
src/telegram/bot.ts, src/discord/client.ts |
| 配置系统 | 管理系统配置,支持多层配置 | src/config/ |
src/config/config.ts, src/config/io.ts |
| 插件系统 | 扩展核心功能,支持第三方插件 | src/plugins/ |
src/plugins/loader.ts, src/plugins/runtime.ts |
| 媒体处理 | 处理图像、视频等媒体内容 | src/media/ |
src/media/host.ts, src/media/image-ops.ts |
| 安全系统 | 提供访问控制和安全防护 | src/security/ |
src/security/audit.ts, src/security/fix.ts |
| 内存管理 | 管理会话和上下文内存 | src/memory/ |
src/memory/manager.ts, src/memory/hybrid.ts |
1.2 数据流架构
1.3 技术栈
| 技术 | 用途 | 来源 |
|---|---|---|
| TypeScript | 主要开发语言 | tsconfig.json |
| Node.js | 运行环境 | package.json |
| Express | Web 服务器 | src/gateway/server.ts |
| WebSocket | 实时通信 | src/gateway/ws.ts |
| YAML/JSON | 配置文件 | src/config/io.ts |
| Git | 版本控制 | .gitignore |
| Docker | 容器化部署 | Dockerfile |
2. 启动流程
2.1 网关启动流程
-
初始化配置:
- 加载
~/.openclaw/openclaw.json主配置文件 - 合并环境变量覆盖配置
- 验证配置有效性
- 加载
-
启动 Web 服务器:
- 在配置的端口(默认 18789)启动 HTTP/WebSocket 服务器
- 注册路由和中间件
- 配置 CORS 和安全头
-
初始化技能系统:
- 扫描技能目录
- 加载技能元数据
- 验证技能完整性
- 构建技能索引
-
连接消息通道:
- 初始化配置的消息通道(如 Telegram、Discord 等)
- 建立与外部服务的连接
- 注册消息处理器
-
启动后台服务:
- 启动定时任务服务
- 初始化媒体服务
- 启动健康检查服务
-
进入监听状态:
- 等待客户端连接
- 处理 incoming 请求
- 维护系统状态
2.2 命令执行流程
-
命令接收:
- 从 CLI、Web 界面或消息平台接收命令
- 解析命令来源和上下文
- 验证命令格式
-
命令解析:
- 提取命令名称和参数
- 验证参数有效性
- 构建命令执行上下文
-
技能匹配:
- 根据命令内容和上下文匹配技能
- 计算技能匹配度
- 选择最佳匹配技能
-
技能执行:
- 加载技能代码和资源
- 执行技能逻辑
- 处理技能执行结果
-
结果处理:
- 格式化执行结果
- 应用输出模板
- 处理错误和异常
-
结果返回:
- 将结果返回给命令来源
- 记录执行日志
- 更新系统状态
2.3 代码示例:网关启动
typescript
// src/gateway/boot.ts
import { loadConfig } from '../config/config.js';
import { createServer } from './server.js';
import { loadWorkspaceSkillEntries } from '../agents/skills/workspace.js';
import { resolveDefaultAgentId } from '../agents/agent-scope.js';
import { resolveAgentWorkspaceDir } from '../agents/agent-scope.js';
async function bootGateway() {
// 加载配置
const config = loadConfig();
// 初始化技能系统
const agentId = resolveDefaultAgentId(config);
const workspaceDir = resolveAgentWorkspaceDir(config, agentId);
const skills = loadWorkspaceSkillEntries(workspaceDir, { config });
// 创建服务器
const server = createServer({ config, skills });
// 启动服务器
const port = config.gateway?.port || 18789;
server.listen(port, () => {
console.log(`Gateway listening on port ${port}`);
});
}
export { bootGateway };
3. 技能系统
3.1 技能结构
每个技能由以下部分组成:
skill-name/
├── SKILL.md (必需) # 技能主文件
│ ├── YAML frontmatter 元数据 # 技能元数据
│ │ ├── name: (必需) # 技能名称
│ │ ├── description: (必需) # 技能描述
│ │ └── metadata: (可选) # 额外元数据
│ └── Markdown 说明文档 # 技能使用说明
├── scripts/ (可选) # 可执行脚本
│ ├── script1.py # Python 脚本
│ └── script2.sh # Shell 脚本
├── references/ (可选) # 参考文档
│ ├── api-docs.md # API 文档
│ └── workflows.md # 工作流程文档
└── assets/ (可选) # 资源文件
├── template.txt # 模板文件
└── logo.png # 图像资源
3.2 技能加载机制
-
技能发现:
- 内置技能:
skills/目录 - 管理技能:
~/.openclaw/skills/目录 - 工作区技能:
workspace/skills/目录 - 插件技能:
extensions/*/skills/目录 - 个人代理技能:
~/.agents/skills/目录 - 项目代理技能:
workspace/.agents/skills/目录
- 内置技能:
-
技能优先级:
- 工作区技能 > 项目代理技能 > 个人代理技能 > 管理技能 > 内置技能 > 额外技能
-
技能过滤:
- 根据配置过滤技能
- 根据环境条件过滤技能
- 根据权限过滤技能
-
技能缓存:
- 缓存技能元数据
- 缓存技能执行结果
- 缓存技能依赖状态
3.3 技能执行机制
-
技能触发:
- 命令匹配触发
- 事件触发
- 定时触发
-
技能执行:
- 加载技能上下文
- 执行技能逻辑
- 处理技能输出
-
技能依赖管理:
- 检查技能依赖
- 安装缺失依赖
- 验证依赖版本
3.4 代码示例:技能加载
typescript
// src/agents/skills/workspace.ts
export function loadSkillEntries(
workspaceDir: string,
opts?: {
config?: OpenClawConfig;
managedSkillsDir?: string;
bundledSkillsDir?: string;
},
): SkillEntry[] {
const limits = resolveSkillsLimits(opts?.config);
const loadSkills = (params: { dir: string; source: string }): Skill[] => {
const resolved = resolveNestedSkillsRoot(params.dir, {
maxEntriesToScan: limits.maxCandidatesPerRoot,
});
const baseDir = resolved.baseDir;
// 检查根目录是否为技能
const rootSkillMd = path.join(baseDir, "SKILL.md");
if (fs.existsSync(rootSkillMd)) {
try {
const size = fs.statSync(rootSkillMd).size;
if (size > limits.maxSkillFileBytes) {
skillsLogger.warn("Skipping skills root due to oversized SKILL.md.", {
dir: baseDir,
filePath: rootSkillMd,
size,
maxSkillFileBytes: limits.maxSkillFileBytes,
});
return [];
}
} catch {
return [];
}
const loaded = loadSkillsFromDir({ dir: baseDir, source: params.source });
return unwrapLoadedSkills(loaded);
}
// 扫描子目录
const childDirs = listChildDirectories(baseDir);
const suspicious = childDirs.length > limits.maxCandidatesPerRoot;
const maxCandidates = Math.max(0, limits.maxSkillsLoadedPerSource);
const limitedChildren = childDirs.slice().sort().slice(0, maxCandidates);
// 加载技能
const loadedSkills: Skill[] = [];
for (const name of limitedChildren) {
const skillDir = path.join(baseDir, name);
const skillMd = path.join(skillDir, "SKILL.md");
if (!fs.existsSync(skillMd)) {
continue;
}
// 检查文件大小
try {
const size = fs.statSync(skillMd).size;
if (size > limits.maxSkillFileBytes) {
skillsLogger.warn("Skipping skill due to oversized SKILL.md.", {
skill: name,
filePath: skillMd,
size,
maxSkillFileBytes: limits.maxSkillFileBytes,
});
continue;
}
} catch {
continue;
}
const loaded = loadSkillsFromDir({ dir: skillDir, source: params.source });
loadedSkills.push(...unwrapLoadedSkills(loaded));
if (loadedSkills.length >= limits.maxSkillsLoadedPerSource) {
break;
}
}
return loadedSkills;
};
// 加载各种来源的技能
const managedSkillsDir = opts?.managedSkillsDir ?? path.join(CONFIG_DIR, "skills");
const workspaceSkillsDir = path.resolve(workspaceDir, "skills");
const bundledSkillsDir = opts?.bundledSkillsDir ?? resolveBundledSkillsDir();
const bundledSkills = bundledSkillsDir
? loadSkills({
dir: bundledSkillsDir,
source: "openclaw-bundled",
})
: [];
const managedSkills = loadSkills({
dir: managedSkillsDir,
source: "openclaw-managed",
});
// 合并技能
const merged = new Map<string, Skill>();
// 按优先级合并
for (const skill of bundledSkills) merged.set(skill.name, skill);
for (const skill of managedSkills) merged.set(skill.name, skill);
// 构建技能条目
const skillEntries: SkillEntry[] = Array.from(merged.values()).map((skill) => {
let frontmatter: ParsedSkillFrontmatter = {};
try {
const raw = fs.readFileSync(skill.filePath, "utf-8");
frontmatter = parseFrontmatter(raw);
} catch {
// ignore malformed skills
}
return {
skill,
frontmatter,
metadata: resolveOpenClawMetadata(frontmatter),
invocation: resolveSkillInvocationPolicy(frontmatter),
};
});
return skillEntries;
}
4. 消息处理
4.1 消息通道
OpenClaw 支持多种消息通道:
| 通道 | 实现方式 | 特点 | 配置文件 |
|---|---|---|---|
| Telegram | Telegram Bot API | 支持命令和消息 | src/telegram/bot.ts |
| Discord | Discord Bot API | 支持丰富的消息格式 | src/discord/client.ts |
| Slack | Slack API | 企业级消息平台 | src/slack/client.ts |
| Signal | Signal Protocol | 端到端加密 | src/signal/client.ts |
| iMessage | Apple Script | 仅 macOS 支持 | src/imessage/client.ts |
| Web | WebSocket/HTTP | 浏览器界面 | src/web/accounts.ts |
| WhatsApp Web | 聊天和媒体支持 | src/web/outbound.ts |
4.2 消息路由
-
消息接收:
- 从各通道接收消息
- 解析消息格式
- 验证消息来源
-
消息预处理:
- 提取命令和参数
- 清理消息内容
- 标准化消息格式
-
技能匹配:
- 根据消息内容匹配技能
- 考虑消息上下文
- 计算匹配分数
-
技能执行:
- 加载匹配的技能
- 执行技能逻辑
- 处理技能输出
-
结果发送:
- 格式化执行结果
- 根据通道特性调整输出
- 将结果发送回原通道
4.3 消息处理流程
外部服务 执行引擎 技能系统 网关服务 消息通道 用户 外部服务 执行引擎 技能系统 网关服务 消息通道 用户 发送消息/命令 转发消息 匹配技能 执行技能 调用外部服务 返回结果 处理结果 返回技能执行结果 格式化输出 显示结果
5. 配置管理
5.1 配置文件
| 配置文件 | 描述 | 位置 | 用途 |
|---|---|---|---|
| openclaw.json | 主配置文件 | ~/.openclaw/openclaw.json |
全局系统配置 |
| auth-profiles.json | 认证配置 | ~/.openclaw/agents/<agent-id>/auth-profiles.json |
API 密钥和认证信息 |
| models.json | 模型配置 | ~/.openclaw/agents/<agent-id>/models.json |
AI 模型配置 |
| agent.json | 代理配置 | ~/.openclaw/agents/<agent-id>/agent.json |
代理特定配置 |
5.2 配置层次
- 默认配置:内置默认值,硬编码在代码中
- 全局配置 :
openclaw.json,覆盖默认配置 - 代理配置:特定代理的配置,覆盖全局配置
- 环境变量:环境变量设置,覆盖配置文件
- 命令行参数:运行时命令行参数,覆盖所有其他配置
5.3 配置示例
openclaw.json 示例:
json
{
"gateway": {
"mode": "local",
"port": 18789,
"bind": "loopback"
},
"skills": {
"install": {
"preferBrew": true,
"nodeManager": "pnpm"
},
"limits": {
"maxSkillsInPrompt": 150,
"maxSkillsPromptChars": 30000
}
},
"channels": {
"telegram": {
"token": "YOUR_TELEGRAM_TOKEN"
},
"discord": {
"token": "YOUR_DISCORD_TOKEN"
}
},
"models": {
"default": "volcengine/deepseek-v3-2-251201"
}
}
auth-profiles.json 示例:
json
{
"volcengine": {
"apiKey": "YOUR_VOLCENGINE_API_KEY",
"apiSecret": "YOUR_VOLCENGINE_API_SECRET"
},
"openai": {
"apiKey": "YOUR_OPENAI_API_KEY"
}
}
6. 插件系统
6.1 插件结构
extension-name/
├── package.json # 插件配置和依赖
├── index.ts # 插件入口文件
├── skills/ (可选) # 插件提供的技能
│ └── skill-name/ # 技能目录
├── src/ (可选) # 插件源代码
│ ├── commands.ts # 插件命令
│ └── utils.ts # 插件工具函数
└── README.md # 插件说明文档
6.2 插件加载
-
插件发现:
- 扫描
extensions/目录 - 读取插件
package.json - 验证插件结构
- 扫描
-
插件初始化:
- 加载插件模块
- 执行插件初始化函数
- 注册插件提供的功能
-
插件生命周期:
- 加载:插件被发现和加载
- 初始化:插件执行初始化逻辑
- 运行:插件提供功能
- 卸载:插件被移除或禁用
6.3 插件 API
typescript
// 插件入口示例
import type { OpenClawPlugin } from 'openclaw/plugin-sdk';
export const plugin: OpenClawPlugin = {
name: 'my-plugin',
version: '1.0.0',
description: 'My custom plugin',
async initialize() {
// 插件初始化逻辑
console.log('My plugin initialized');
},
async shutdown() {
// 插件关闭逻辑
console.log('My plugin shutdown');
},
commands: {
'my-command': {
description: 'My custom command',
async handler(args) {
// 命令处理逻辑
return 'Command executed successfully';
}
}
},
skills: {
// 插件提供的技能
}
};
7. 安全机制
7.1 沙箱环境
-
文件系统限制:
- 限制文件操作范围
- 防止路径遍历攻击
- 验证文件权限
-
网络限制:
- 防止 SSRF 攻击
- 限制网络访问范围
- 验证网络请求目标
-
命令执行限制:
- 限制可执行命令
- 验证命令参数
- 监控命令执行
-
资源限制:
- CPU 使用率限制
- 内存使用限制
- 磁盘空间限制
7.2 认证与授权
-
API 密钥管理:
- 安全存储 API 密钥
- 密钥轮换机制
- 密钥权限控制
-
权限控制:
- 基于角色的访问控制
- 命令权限管理
- 资源访问控制
-
会话管理:
- 安全的会话处理
- 会话超时机制
- 会话验证
-
审计日志:
- 记录安全事件
- 监控异常行为
- 安全事件告警
7.3 安全代码示例
typescript
// src/infra/fs-safe.ts
import fs from 'node:fs';
import path from 'node:path';
export function readFileWithinRoot(filePath: string, root: string): string {
// 解析路径
const resolved = path.resolve(root, filePath);
// 验证路径是否在根目录内
if (!resolved.startsWith(root)) {
throw new Error('Path outside root directory');
}
// 验证文件存在
if (!fs.existsSync(resolved)) {
throw new Error('File not found');
}
// 验证文件类型
const stats = fs.statSync(resolved);
if (!stats.isFile()) {
throw new Error('Path is not a file');
}
// 读取文件
return fs.readFileSync(resolved, 'utf-8');
}
8. 扩展性
8.1 技能扩展
-
创建自定义技能:
- 使用 skill-creator 工具
- 遵循技能结构规范
- 测试技能功能
-
发布技能:
- 通过 ClawHub 发布
- 版本控制和更新
- 技能文档和示例
-
技能版本管理:
- 语义化版本控制
- 版本兼容性管理
- 技能依赖管理
8.2 通道扩展
-
创建自定义通道:
- 实现通道接口
- 处理消息格式
- 管理通道状态
-
通道配置:
- 灵活的配置选项
- 通道认证管理
- 通道性能优化
8.3 插件扩展
-
创建自定义插件:
- 遵循插件结构
- 实现插件 API
- 测试插件功能
-
插件依赖管理:
- 独立的依赖管理
- 依赖版本控制
- 依赖冲突解决
-
插件生态系统:
- 插件发现和安装
- 插件评分和评价
- 插件更新和维护
9. 性能优化
9.1 技能加载优化
-
懒加载:
- 按需加载技能
- 延迟加载非关键技能
- 技能预加载策略
-
缓存机制:
- 缓存技能元数据
- 缓存技能执行结果
- 缓存技能依赖状态
-
并行加载:
- 并行处理技能加载
- 异步技能初始化
- 技能加载队列
9.2 消息处理优化
-
队列机制:
- 消息队列处理
- 优先级队列
- 消息批处理
-
批处理:
- 批量处理相似请求
- 合并重复操作
- 批量 API 调用
-
异步执行:
- 非阻塞执行模式
- 异步 I/O 操作
- 后台任务处理
-
资源池:
- 连接池管理
- 线程池管理
- 内存池管理
9.3 代码示例:技能缓存
typescript
// 技能缓存实现
import { LRU } from 'lru-cache';
class SkillCache {
private cache: LRU<string, SkillEntry>;
constructor() {
this.cache = new LRU({
max: 100,
ttl: 1000 * 60 * 5, // 5分钟
});
}
get(key: string): SkillEntry | undefined {
return this.cache.get(key);
}
set(key: string, skill: SkillEntry): void {
this.cache.set(key, skill);
}
has(key: string): boolean {
return this.cache.has(key);
}
clear(): void {
this.cache.clear();
}
}
export const skillCache = new SkillCache();
10. 故障处理
10.1 错误处理
-
错误捕获:
- 全局错误捕获
- 局部错误处理
- 异步错误处理
-
错误日志:
- 详细的错误日志
- 错误分类和优先级
- 错误上下文信息
-
错误恢复:
- 自动错误恢复机制
- 故障转移策略
- 服务重启机制
-
错误通知:
- 错误告警系统
- 错误报告机制
- 错误统计分析
10.2 监控与诊断
-
健康检查:
- 定期健康状态检查
- 系统组件健康监控
- 外部服务健康检查
-
性能监控:
- 系统性能监控
- 资源使用监控
- 响应时间监控
-
日志分析:
- 详细的日志记录
- 日志聚合和分析
- 日志可视化
-
诊断工具:
- 系统诊断命令
- 性能分析工具
- 故障排查指南
10.3 代码示例:错误处理
typescript
// src/infra/errors.ts
export class OpenClawError extends Error {
public code: string;
public metadata: Record<string, unknown>;
constructor(message: string, code: string, metadata?: Record<string, unknown>) {
super(message);
this.name = 'OpenClawError';
this.code = code;
this.metadata = metadata || {};
}
}
export function handleError(error: unknown): void {
if (error instanceof OpenClawError) {
// 处理已知错误
console.error(`[${error.code}] ${error.message}`, error.metadata);
} else if (error instanceof Error) {
// 处理未知错误
console.error(`[UNKNOWN] ${error.message}`, { stack: error.stack });
} else {
// 处理非错误对象
console.error(`[UNKNOWN] ${String(error)}`);
}
}
11. 部署模式
11.1 本地部署
-
单机部署:
- 在本地机器上运行
- 适合个人使用
- 简单配置和管理
-
开发模式:
- 支持热重载和调试
- 详细的日志输出
- 开发工具集成
-
生产模式:
- 优化性能和稳定性
- 最小化资源使用
- 安全加固
11.2 远程部署
-
服务器部署:
- 在远程服务器上运行
- 适合团队或企业使用
- 支持多用户访问
-
容器化部署:
- 支持 Docker 容器
- 标准化部署流程
- 环境一致性
-
云服务部署:
- 支持各种云服务平台
- 弹性伸缩能力
- 高可用性
11.3 部署配置示例
Docker 部署示例:
dockerfile
FROM node:22-alpine
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
EXPOSE 18789
CMD ["pnpm", "openclaw", "gateway", "run", "--bind", "0.0.0.0", "--port", "18789"]
Docker Compose 示例:
yaml
version: '3.8'
services:
openclaw:
build: .
ports:
- "18789:18789"
volumes:
- ~/.openclaw:/root/.openclaw
environment:
- NODE_ENV=production
restart: unless-stopped
12. 总结
OpenClaw 是一个高度模块化、可扩展的 AI 助手系统,通过以下核心特性实现其功能:
- 模块化架构:清晰的组件分离和职责划分,便于维护和扩展
- 技能系统:可扩展的功能模块,支持自定义技能和第三方技能
- 多通道支持:与各种消息平台集成,提供多渠道访问
- 安全机制:多层安全防护,保障系统和数据安全
- 可扩展性:支持插件和自定义技能,适应不同使用场景
- 性能优化:高效的系统设计,优化资源使用和响应速度
- 故障处理:完善的错误处理和监控机制,提高系统可靠性
- 灵活部署:支持多种部署模式,适应不同环境需求
这种架构设计使得 OpenClaw 能够适应各种使用场景,从个人助手到企业级应用,都能提供稳定、高效的服务。通过不断的扩展和优化,OpenClaw 可以成为一个功能强大、安全可靠的 AI 助手平台。
13. 术语表
| 术语 | 解释 |
|---|---|
| Gateway | 网关服务,OpenClaw 的中央协调器,处理所有请求和响应 |
| Skill | 技能,提供特定功能的模块化组件,是 OpenClaw 的功能扩展单元 |
| Channel | 通道,与外部服务的通信接口,如 Telegram、Discord 等 |
| Plugin | 插件,扩展 OpenClaw 核心功能的模块,可添加新功能和集成 |
| Agent | 代理,OpenClaw 的运行实例,每个代理有独立的配置和技能 |
| ClawHub | 技能 marketplace,用于分享和获取技能的平台 |
| ACP | 访问控制策略,管理系统权限和访问控制 |
| Runtime | 运行时环境,提供 OpenClaw 运行所需的基础服务 |
| Workspace | 工作区,存储技能和配置的目录 |
| Config | 配置,控制 OpenClaw 行为的设置 |
| Metadata | 元数据,描述技能和插件的信息 |
| Frontmatter | 前置 matter,技能文件中的 YAML 元数据部分 |
| Sandbox | 沙箱,限制技能和插件的执行环境,提高安全性 |