为了账号安全,请及时绑定邮箱和手机立即绑定

OpenClaw 的架构设计与运行原理

标签:
JavaScript

一、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}`);
    }
  }
}

核心机制:

  1. 队列调度:用队列管理待执行节点,支持并行 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 工作流平台。


点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消