一、OpenClaw 整体架构
OpenClaw 采用经典的分层架构,从下到上分为:
体验AI代码助手 代码解读 复制代码 ┌─────────────────────────────────────┐ │ 应用层(Web UI / API) │ ├─────────────────────────────────────┤ │ 业务层(工作流引擎 / 对话管理) │ ├─────────────────────────────────────┤ │ 服务层(模型调度 / 工具执行) │ ├─────────────────────────────────────┤ │ 数据层(PostgreSQL / Redis) │ └─────────────────────────────────────┘
核心模块:
工作流引擎:编排节点、执行流程、状态管理 - 模型调度器:统一多模型接口、负载均衡、重试容错 - 工具系统:函数注册、参数校验、沙箱执行 - 对话管理:历史存储、上下文窗口、多轮对话 - 集成层:飞书、钉钉、企微等第三方平台接入
二、工作流引擎
2.1 节点类型
OpenClaw 的工作流由节点(Node)组成,每个节点是一个独立的处理单元:
| 节点类型 | 作用 | 示例 |
|---|---|---|
| Start | 流程入口 | 接收用户输入 |
| LLM | 调用大模型 | GPT-4 生成回复 |
| Tool | 执行工具函数 | 搜索、计算、查数据库 |
| Condition | 条件分支 | 根据结果走不同路径 |
| Loop | 循环执行 | 批量处理数据 |
| End | 流程结束 | 返回最终结果 |
2.2 节点定义
每个节点是一个 JSON 对象:
json
体验AI代码助手
代码解读
复制代码{
"id": "node_1",
"type": "llm",
"config": {
"model": "gpt-4",
"prompt": "你是一个助手,回答用户问题:{{input}}",
"temperature": 0.7,
"max_tokens": 1000
},
"inputs": ["start"],
"outputs": ["node_2", "node_3"]}关键字段:
id:唯一标识 -type:节点类型 -config:配置参数(模型、提示词等) -inputs:上游节点 ID 列表 -outputs:下游节点 ID 列表
2.3 执行流程
工作流引擎的执行逻辑:
javascript
体验AI代码助手
代码解读
复制代码class WorkflowEngine { async execute(workflow, input) { const context = { input, variables: {} }; const queue = [workflow.startNode]; const visited = new Set(); while (queue.length > 0) { const nodeId = queue.shift(); if (visited.has(nodeId)) continue;
visited.add(nodeId); const node = workflow.nodes[nodeId];
// 执行节点
const result = await this.executeNode(node, context);
context.variables[nodeId] = result; // 根据结果决定下游节点
const nextNodes = this.getNextNodes(node, result);
queue.push(...nextNodes);
} return context.variables[workflow.endNode];
} async executeNode(node, context) { switch (node.type) { case 'llm': return this.executeLLM(node, context); case 'tool': return this.executeTool(node, context); case 'condition': return this.executeCondition(node, context); default: throw new Error(`Unknown node type: ${node.type}`);
}
}
}核心机制:
队列调度:用队列管理待执行节点,支持并行 2. 上下文传递:
context对象存储中间结果,节点间共享 3. 变量替换:提示词中的{{variable}}会被替换为实际值 4. 循环检测:用visited集合防止死循环
2.4 并行执行
当多个节点没有依赖关系时,可以并行执行:
javascript
体验AI代码助手
代码解读
复制代码async executeParallel(nodes, context) { const promises = nodes.map(node => this.executeNode(node, context)); const results = await Promise.all(promises); return results;
}示例场景:同时调用多个模型,取最优结果。
三、模型调度器
3.1 统一接口
OpenClaw 抽象了一个统一的模型接口,屏蔽不同厂商的差异:
javascript
体验AI代码助手
代码解读
复制代码class ModelProvider { async chat(messages, options) { throw new Error('Not implemented');
}
}class OpenAIProvider extends ModelProvider { async chat(messages, options) { const response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Authorization': `Bearer ${this.apiKey}`, 'Content-Type': 'application/json'
}, body: JSON.stringify({ model: options.model || 'gpt-3.5-turbo',
messages, temperature: options.temperature || 0.7, max_tokens: options.max_tokens
})
}); const data = await response.json(); return data.choices[0].message.content;
}
}class ZhipuProvider extends ModelProvider { async chat(messages, options) { // 智谱 API 调用逻辑
// ...
}
}3.2 模型注册
在配置文件中注册多个模型:
javascript
体验AI代码助手
代码解读
复制代码const modelRegistry = { 'gpt-4': new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }), 'gpt-3.5-turbo': new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }), 'glm-4': new ZhipuProvider({ apiKey: process.env.ZHIPU_API_KEY }), 'qwen-max': new QwenProvider({ apiKey: process.env.QWEN_API_KEY })
};3.3 负载均衡
当同一模型有多个 API Key 时,轮询或随机选择:
javascript
体验AI代码助手
代码解读
复制代码class LoadBalancer { constructor(providers) { this.providers = providers; this.index = 0;
}
getProvider() { const provider = this.providers[this.index]; this.index = (this.index + 1) % this.providers.length; return provider;
}
}// 使用const balancer = new LoadBalancer([
new OpenAIProvider({ apiKey: 'key1' }),
new OpenAIProvider({ apiKey: 'key2' })
]);const provider = balancer.getProvider();const result = await provider.chat(messages, options);3.4 重试与容错
模型调用可能失败(限流、超时等),需要重试机制:
javascript
体验AI代码助手
代码解读
复制代码async function callWithRetry(fn, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn();
} catch (error) { if (i === maxRetries - 1) throw error;
// 指数退避
const delay = Math.pow(2, i) * 1000; await new Promise(resolve => setTimeout(resolve, delay));
}
}
}// 使用const result = await callWithRetry(() =>
provider.chat(messages, options)
);3.5 流式输出
支持 SSE(Server-Sent Events)实现打字机效果:
javascript
体验AI代码助手
代码解读
复制代码async *chatStream(messages, options) { const response = await fetch(url, { method: 'POST', headers: { /* ... */ }, body: JSON.stringify({ ...options, stream: true })
}); const reader = response.body.getReader(); const decoder = new TextDecoder(); while (true) { const { done, value } = await reader.read(); if (done) break; const chunk = decoder.decode(value); const lines = chunk.split('\n').filter(line => line.trim()); for (const line of lines) { if (line.startsWith('data: ')) { const data = JSON.parse(line.slice(6)); yield data.choices[0].delta.content;
}
}
}
}// 使用for await (const chunk of provider.chatStream(messages, options)) {
process.stdout.write(chunk);
}四、工具系统
4.1 工具定义
工具是一个带元数据的函数:
javascript
体验AI代码助手
代码解读
复制代码const weatherTool = { name: 'get_weather', description: '获取指定城市的天气信息', parameters: { type: 'object', properties: { city: { type: 'string', description: '城市名称,如"北京"'
}, unit: { type: 'string', enum: ['celsius', 'fahrenheit'], default: 'celsius'
}
}, required: ['city']
}, async execute({ city, unit }) { const response = await fetch(`https://api.weather.com?city=${city}&unit=${unit}`); return response.json();
}
};4.2 工具注册
全局注册工具,供工作流调用:
javascript
体验AI代码助手
代码解读
复制代码class ToolRegistry { constructor() { this.tools = new Map();
} register(tool) { this.tools.set(tool.name, tool);
} get(name) { return this.tools.get(name);
} list() { return Array.from(this.tools.values()).map(tool => ({ name: tool.name, description: tool.description, parameters: tool.parameters
}));
}
}const registry = new ToolRegistry();
registry.register(weatherTool);
registry.register(searchTool);4.3 Function Calling
模型决定调用哪个工具:
javascript
体验AI代码助手
代码解读
复制代码
async function chatWithTools(messages, tools) {
// 第一次调用:模型决定是否用工具
const response1 = await provider.chat(messages, {
tools: tools.map(t => ({
type: 'function',
function: {
name: t.name,
description: t.description,
parameters: t.parameters
}
}))
});
// 如果模型要求调用工具
if (response1.tool_calls) {
const toolResults = [];
for (const call of response1.tool_calls) {
const tool = registry.get(call.function.name);
const args = JSON.parse(call.function.arguments);
const result = await tool.execute(args);
toolResults.push({
tool_call_id: call.id,
role: 'tool',
content: JSON.stringify(result)
});
}
// 第二次调用:把工具结果给模型
messages.push(response1);
messages.push(...toolResults);
const response2 = await provider.chat(messages);
return response2.content;
}
return response1.content;}4.4 沙箱执行
用 VM 或 Worker 隔离工具代码,防止恶意操作:
javascript
体验AI代码助手
代码解读
复制代码const { VM } = require('vm2');function executeTool(code, args) { const vm = new VM({ timeout: 5000, sandbox: {
args, fetch: safeFetch, // 限制网络访问 console: safeConsole
}
}); return vm.run(`
(async function() {
${code} return execute(args);
})()
`);
}五、对话管理
5.1 历史存储
每轮对话存入数据库:
sql 体验AI代码助手 代码解读 复制代码CREATE TABLE conversations ( id UUID PRIMARY KEY, user_id VARCHAR(255), created_at TIMESTAMP, updated_at TIMESTAMP);CREATE TABLE messages ( id UUID PRIMARY KEY, conversation_id UUID REFERENCES conversations(id), role VARCHAR(20), -- user / assistant / system content TEXT, created_at TIMESTAMP);
5.2 上下文窗口
限制历史消息数量,避免超出模型 token 限制:
javascript
体验AI代码助手
代码解读
复制代码function getContextMessages(conversationId, maxTokens = 4000) { const messages = db.query( 'SELECT * FROM messages WHERE conversation_id = ? ORDER BY created_at DESC',
[conversationId]
); const result = []; let totalTokens = 0; for (const msg of messages) { const tokens = estimateTokens(msg.content); if (totalTokens + tokens > maxTokens) break;
result.unshift(msg);
totalTokens += tokens;
} return result;
}function estimateTokens(text) { // 简单估算:1 token ≈ 4 字符
return Math.ceil(text.length / 4);
}5.3 多轮对话
保持上下文连贯:
javascript
体验AI代码助手
代码解读
复制代码
async function chat(conversationId, userMessage) { // 获取历史消息
const history = getContextMessages(conversationId);
// 添加用户消息
const messages = [
{ role: 'system', content: '你是一个助手' },
...history,
{ role: 'user', content: userMessage }
]; // 调用模型
const reply = await provider.chat(messages); // 存储对话
db.insert('messages', { conversation_id: conversationId, role: 'user', content: userMessage
});
db.insert('messages', { conversation_id: conversationId, role: 'assistant', content: reply
}); return reply;
}六、集成层
6.1 飞书机器人
接收飞书消息,转发给工作流:
javascript
体验AI代码助手
代码解读
复制代码
app.post('/api/feishu/webhook', async (req, res) => { const { header, event } = req.body; // 验证签名
if (!verifySignature(req.headers, req.body)) { return res.status(401).send('Invalid signature');
} // 处理消息事件
if (event.type === 'im.message.receive_v1') { const { message, sender } = event; const userId = sender.sender_id.user_id; const text = JSON.parse(message.content).text; // 调用工作流
const reply = await workflowEngine.execute('default', { input: text, userId }); // 回复消息
await feishuClient.sendMessage({
receive_id: userId,
msg_type: 'text',
content: JSON.stringify({ text: reply })
});
}
res.send({ code: 0 });
});6.2 钉钉机器人
类似逻辑,适配钉钉 API:
javascript
体验AI代码助手
代码解读
复制代码
app.post('/api/dingtalk/webhook', async (req, res) => { const { text, senderStaffId } = req.body; const reply = await workflowEngine.execute('default', { input: text.content });
await dingtalkClient.send({ chatId: req.body.conversationId, msgtype: 'text', text: { content: reply }
});
res.send({ success: true });
});七、数据流转
一次完整的对话流程:
sql 体验AI代码助手 代码解读 复制代码 用户输入 ↓ 飞书 Webhook ↓ 集成层解析消息 ↓ 对话管理加载历史 ↓ 工作流引擎执行 ├─ LLM 节点调用模型 ├─ Tool 节点执行工具 └─ Condition 节点判断分支 ↓ 返回结果 ↓ 对话管理存储历史 ↓ 集成层发送回复 ↓ 用户收到消息
八、性能优化
8.1 缓存
对相同输入缓存结果: https://infogram.com/pdf-1h984wvw0w78z2p https://infogram.com/pdf-1h984wvw0wrlz2p https://infogram.com/pdf-1h1749w0x0g1l2z https://infogram.com/pdf-1h0r6rzo3oypl4e https://infogram.com/pdf-1h0r6rzo3oyow4e https://infogram.com/pdf-1hnq41oy9y8gk23 https://infogram.com/pdf-1h9j6q7oyokxv4g https://infogram.com/pdf-1hnp27e050ypy4g https://infogram.com/pdf-1hnp27e050ywn4g https://infogram.com/pdf-1h984wvw0wkod2p https://infogram.com/pdf-1hxj48m070kd52v https://infogram.com/pdf-1h0r6rzo3on5w4e https://infogram.com/pdf-1hnq41oy9y7ok23 https://infogram.com/pdf-1h984wvw0w9qd2p https://infogram.com/pdf-1h0n25o0m059l4p https://infogram.com/pdf-1hnp27e050wgy4g https://infogram.com/pdf-1h984wvw0w9dz2p https://infogram.com/pdf-1h1749w0x0p5l2z https://infogram.com/pdf-1h9j6q7oyqvv54g https://infogram.com/pdf-1h984wvw0g3zd2p https://infogram.com/pdf-1h984wvw0g3kz2p https://infogram.com/pdf-1hmr6g8mw3d5z2n https://infogram.com/pdf-1h0r6rzo3qprl4e https://infogram.com/pdf-1hnq41oy9j0ep23 https://infogram.com/pdf-1hxj48m07jpl52v https://infogram.com/pdf-1hmr6g8mw37qz2n https://infogram.com/pdf-1h0n25o0mjoyz4p https://infogram.com/pdf-1hxj48m07jm1q2v https://infogram.com/pdf-1h9j6q7oyq7rv4g https://infogram.com/pdf-1h0n25o0mjkoz4p https://infogram.com/pdf-1hnp27e05jk7y4g https://infogram.com/pdf-1h7v4pdv9q9p84k https://infogram.com/pdf-1hnp27e05j5xn4g https://infogram.com/pdf-1h9j6q7oyqy9v4g https://infogram.com/pdf-1hnp27e05j5ly4g https://infogram.com/pdf-1hmr6g8mw317z2n https://infogram.com/pdf-1h9j6q7oyqpp54g https://infogram.com/pdf-1hnp27e05jo1n4g https://infogram.com/pdf-1h984wvw0gqld2p https://infogram.com/pdf-1h0n25o0mj3vl4p https://infogram.com/pdf-1hnq41oy9jnlk23 https://infogram.com/pdf-1hxj48m07jvwq2v https://infogram.com/pdf-1h0n25o0mjzql4p https://infogram.com/pdf-1h7v4pdv9qj1j4k https://infogram.com/pdf-1hmr6g8mw3kez2n https://infogram.com/pdf-1hnq41oy9jq1k23 https://infogram.com/pdf-1hxj48m07j1qq2v https://infogram.com/pdf-1hmr6g8mw3kro2n https://infogram.com/pdf-1h0n25o0mjdll4p https://infogram.com/pdf-1hmr6g8mw3ywz2n https://infogram.com/pdf-1h1749w0xj7nl2z https://infogram.com/pdf-1h1749w0xj8dl2z https://infogram.com/pdf-1h7v4pdv9qkr84k https://infogram.com/pdf-1hnq41oy9j1yk23 https://infogram.com/pdf-1hxj48m07j8zq2v https://infogram.com/pdf-1hmr6g8mw39vo2n https://infogram.com/pdf-1h7v4pdv9qrnj4k https://infogram.com/pdf-1h0r6rzo3qgvw4e https://infogram.com/pdf-1h9j6q7oyqdd54g https://infogram.com/pdf-1hxj48m07jwdq2v https://infogram.com/pdf-1h7v4pdv9q0wj4k https://infogram.com/pdf-1h984wvw0g1zz2p https://infogram.com/pdf-1h1749w0xjq8l2z https://infogram.com/pdf-1h9j6q7oyq5554g https://infogram.com/pdf-1hxj48m07jqgq2v https://infogram.com/pdf-1hmr6g8mw3j5o2n https://infogram.com/pdf-1hnq41oy9jy5p23 https://infogram.com/pdf-1hnp27e05j05y4g https://infogram.com/pdf-1h0r6rzo3qo8w4e https://infogram.com/pdf-1h984wvw0gwkd2p https://infogram.com/pdf-1hxj48m07jj152v https://infogram.com/pdf-1h1749w0xjjql2z https://infogram.com/pdf-1h9j6q7oyqqq54g https://infogram.com/pdf-1hxj48m07jjlq2v https://infogram.com/pdf-1hmr6g8mw33po2n https://infogram.com/pdf-1h9j6q7oyqr0v4g https://infogram.com/pdf-1hnp27e05jgny4g https://infogram.com/pdf-1hmr6g8mw3ngz2n https://infogram.com/pdf-1h0n25o0mjrjz4p https://infogram.com/pdf-1h7v4pdv9q5y84k https://infogram.com/pdf-1h9j6q7oyqee54g https://infogram.com/pdf-1hnq41oy9jerk23 https://infogram.com/pdf-1h7v4pdv9qljj4k https://infogram.com/pdf-1hxj48m07jg852v https://infogram.com/pdf-1h9j6q7oyq9954g https://infogram.com/pdf-1hnp27e05jd9n4g https://infogram.com/pdf-1h0n25o0mjlml4p https://infogram.com/pdf-1h9j6q7oyqkjv4g https://infogram.com/pdf-1hnq41oy9jzxp23 https://infogram.com/pdf-1h0r6rzo3q5ow4e https://infogram.com/pdf-1hnq41oy9jzgk23 https://infogram.com/pdf-1hxj48m07jexq2v https://infogram.com/pdf-1h1749w0xj9xq2z https://infogram.com/pdf-1hnq41oy9jrlp23 https://infogram.com/pdf-1h0r6rzo3q9qw4e https://infogram.com/pdf-1h9j6q7oyqll54g https://infogram.com/pdf-1hmr6g8mw30wo2n https://infogram.com/pdf-1h984wvw0gmgz2p https://infogram.com/pdf-1h0n25o0mjn1z4p https://infogram.com/pdf-1h1749w0xje3q2z
javascript
体验AI代码助手
代码解读
复制代码const cache = new Map();async function cachedChat(messages, options) { const key = JSON.stringify({ messages, options });
if (cache.has(key)) { return cache.get(key);
} const result = await provider.chat(messages, options);
cache.set(key, result);
return result;
}8.2 队列
用 Redis 队列处理高并发:
javascript
体验AI代码助手
代码解读
复制代码const queue = new Bull('chat', { redis: redisConfig });
queue.process(async (job) => { const { conversationId, message } = job.data; const reply = await chat(conversationId, message); return reply;
});// 添加任务await queue.add({ conversationId, message });8.3 数据库索引
sql 体验AI代码助手 代码解读 复制代码 CREATE INDEX idx_messages_conversation ON messages(conversation_id, created_at); CREATE INDEX idx_conversations_user ON conversations(user_id, updated_at);
九、安全机制
9.1 权限控制
基于角色的访问控制(RBAC):
javascript
体验AI代码助手
代码解读
复制代码
const permissions = {
admin: ['read', 'write', 'delete', 'manage'],
user: ['read', 'write'],
guest: ['read']
};
function checkPermission(userId, action) {
const role = getUserRole(userId);
return permissions[role].includes(action);
}9.2 输入校验
防止注入攻击:
javascript
体验AI代码助手
代码解读
复制代码function sanitizeInput(text) { // 移除危险字符
return text.replace(/<script>/gi, '')
.replace(/javascript:/gi, '')
.trim();
}9.3 速率限制
防止滥用:
javascript
体验AI代码助手
代码解读
复制代码const rateLimit = require('express-rate-limit');const limiter = rateLimit({ windowMs: 60 * 1000, // 1 分钟 max: 10, // 最多 10 次请求 message: '请求过于频繁,请稍后再试'});
app.use('/api/chat', limiter);十、监控与日志
10.1 日志记录
javascript
体验AI代码助手
代码解读
复制代码const winston = require('winston');const logger = winston.createLogger({ level: 'info', format: winston.format.json(), transports: [ new winston.transports.File({ filename: 'error.log', level: 'error' }), new winston.transports.File({ filename: 'combined.log' })
]
});
logger.info('Workflow executed', { workflowId, duration, result });10.2 性能监控
javascript
体验AI代码助手
代码解读
复制代码async function executeWithMetrics(fn, name) { const start = Date.now();
try { const result = await fn(); const duration = Date.now() - start;
metrics.record(name, { duration, status: 'success' });
return result;
} catch (error) {
metrics.record(name, { duration: Date.now() - start, status: 'error' });
throw error;
}
}总结
OpenClaw 的核心架构:
工作流引擎:节点编排、队列调度、上下文传递 - 模型调度器:统一接口、负载均衡、重试容错、流式输出 - 工具系统:函数注册、参数校验、Function Calling、沙箱执行 - 对话管理:历史存储、上下文窗口、多轮对话 - 集成层:飞书/钉钉等平台适配
关键设计:
分层架构,职责清晰 - 插件化工具系统,易扩展 - 统一模型接口,支持多厂商 - 队列 + 缓存优化性能 - RBAC + 速率限制保障安全
理解这些原理,你就能定制自己的 AI 工作流平台。

随时随地看视频