OpenClaw 项目分析

OpenClaw 项目分析 - 面试参考

项目概览

OpenClaw 是一个本地 AI 助手平台。用户在自己的机器上运行,支持从 20+ 个通讯渠道(Discord、Slack、Telegram、WhatsApp 等)接收消息,然后让 AI Agent 处理这些消息。

核心设计:

  • 本地优先:所有数据和处理都在用户本地
  • 多渠道支持:统一在本地网关处理,然后分发到各个渠道
  • 任务执行:AI 能够执行浏览、编码、命令等实际操作

架构设计

分层架构

Channels (Discord/Slack/Telegram/etc)
         ↓
Local Gateway (路由、会话管理、工具调度)
         ↓
Agent Runtime (LLM 推理、工具执行、状态管理)

插件系统

  • 核心框架最小化,所有功能作为插件
  • 渠道都是插件(Discord、Slack、Telegram 等)
  • 工具是插件(Browser、Canvas、Cron 等)
  • 记忆系统可插拔
  • 技能可以从 ClawHub 加载

项目结构

/src/
  agents/      - Agent 生命周期和循环逻辑
  gateway/     - 网关协议和消息路由
  channels/    - 渠道适配器(Discord、Slack 等)
  plugins/     - 插件加载和管理
  config/      - 配置解析
  cli/         - 命令行
  tools/       - 工具定义
  memory/      - 记忆存储
  security/    - 权限和隔离

/extensions/
  discord/     - Discord 渠道
  slack/       - Slack 渠道
  telegram/    - Telegram 渠道
  browser/     - 浏览器工具
  canvas/      - UI 渲染
  cron/        - 定时任务
  ...

/ui/src/
  pages/       - 页面(Dashboard、Channels、Settings 等)
  components/  - React 组件
  services/    - API 调用
  hooks/       - 自定义 Hook
  styles/      - 样式

核心设计思想

消息处理流程

外部渠道消息(如 Discord)
  ↓
Gateway 接收
  ↓
查找或创建会话
  ↓
Agent 处理(LLM 推理)
  ↓
执行工具(浏览、编码等)
  ↓
生成响应
  ↓
路由回各个渠道

关键点:

  • Gateway 是统一的消息入口,屏蔽渠道差异
  • 每个会话维护独立的上下文和权限
  • Agent 循环处理工具调用和 LLM 推理

Agent 循环

基本逻辑:

  1. 从消息队列获取用户消息
  2. 收集可用工具、历史记录、记忆等信息
  3. 调用 LLM 生成响应或工具调用
  4. 执行工具,获得结果
  5. 如果需要进一步推理,继续循环
  6. 最终生成回复发送给用户

这个循环可以重复多次,直到 Agent 决定停止(给出最终答案)。

安全设计

  • 默认安全:DM 接收需要配对码
  • 隔离:非主会话运行在沙箱(Docker 或 SSH)
  • 权限:每个工具都有细粒度的权限控制
  • 审计:所有工具调用都有记录

关键技术方案

多模型支持

  • 支持切换 LLM 提供商(OpenAI、Anthropic 等)
  • 有模型备份机制(一个模型失败自动切换)
  • 支持 prompt caching 优化 token 消耗

上下文管理

对于长会话,不能把全部历史都送给 LLM(token 太多):

  • 动态计算 token 预算
  • 自动压缩早期消息
  • 保留关键信息到记忆系统
  • 利用 prompt caching

工具系统

常用工具:

  • Browser:自动化浏览网页、抓取、交互
  • Canvas:在客户端渲染动态 UI(A2UI 协议)
  • Cron:定时任务调度
  • Session Tools:会话间通信
  • 渠道特定操作:Discord/Slack 特有功能

记忆系统

  • 短期记忆:当前会话的上下文(在内存)
  • 长期记忆:已完成任务、知识点、技能
  • 多种后端:本地 JSON、远程向量数据库(Honcho)、文件系统(QmD)

前端架构(Control UI)

技术栈

  • React + TypeScript
  • Vite(构建和开发服务器)
  • CSS modules(样式隔离)
  • WebSocket(实时通信)
  • Vitest(单元测试)

主要页面和模块

pages/
  Dashboard.tsx       - 主控制面板
  Channels.tsx       - 渠道管理
  Agents.tsx         - Agent 配置
  Settings.tsx       - 系统设置
  WebChat.tsx        - Web 聊天

components/
  MessageList        - 消息列表展示
  ChannelConfig      - 渠道配置表单
  AgentConfig        - Agent 配置
  StatusBar          - 系统状态

services/
  gateway.ts         - Gateway API 客户端
  channels.ts        - 渠道 API
  agents.ts          - Agent API

hooks/
  useWebSocket       - WebSocket 连接管理
  useAgent           - Agent 状态管理
  useChannels        - 渠道状态管理

前端数据流

用户交互(点击、输入)
  ↓
React 状态更新
  ↓
调用 API(HTTP 或 WebSocket)
  ↓
Gateway 处理
  ↓
响应返回
  ↓
更新 UI
  ↓
WebSocket 推送实时更新

实际工作流程

用户在 Discord 发送消息的完整流程

1. 用户在 Discord 频道输入消息
   ↓
2. Discord 插件接收(通过 webhook 或 polling)
   ↓
3. Gateway 的 inbound 处理
   - 消息标准化
   - 创建或查找会话
   ↓
4. 消息入队到会话的队列
   ↓
5. Agent Worker 从队列弹出消息
   ↓
6. 收集可用工具、历史记录、记忆等
   ↓
7. 调用 LLM API(如 OpenAI)
   ↓
8. LLM 返回响应或工具调用请求
   ↓
9. 如果是工具调用:
   - 执行工具(如 Browser 访问网页)
   - 获取结果(截图、文本等)
   - 将结果加入上下文
   - 回到第 7 步继续推理
   ↓
10. 如果是最终回复:
    生成要发送给用户的消息
    ↓
11. Gateway 的 outbound 处理
    - 可以发到多个渠道(Discord、Slack、Telegram 等)
    ↓
12. 用户在各自的渠道接收回复

工具执行的例子(Browser)

假设 Agent 想要访问网页:

  1. LLM 生成工具调用请求:

    navigate("https://github.com")
    
  2. Gateway 检查权限(该会话是否允许 browser 工具)

  3. 创建浏览器上下文(Puppeteer/Playwright)

  4. 执行操作:

    • 打开 URL
    • 等待加载
    • 截图
    • 提取文本内容
  5. 返回结果给 Agent:

    {
      success: true,
      screenshot: "base64...",
      text: "extracted text content",
      url: "https://github.com"
    }
    
  6. Agent 看到结果,继续推理(可能需要更多交互)


常见技术问题

Q1:如何处理多个渠道的一致性?

关键:Gateway 是统一入口

  • 所有消息先标准化为统一格式
  • Agent 处理的都是标准化消息
  • 输出时再适配到各个渠道的格式

好处是 Agent 代码不用关心渠道细节,新增渠道也很容易。

Q2:如何管理多个并发会话?

关键:队列 + 优先级 + Worker 池

  • 每个会话有独立的消息队列
  • 优先级队列避免某个会话阻塞其他
  • 多个 Agent Worker 并行处理
  • Token 预算有全局限制和限流

Q3:长会话怎么处理 token 超限?

方案

  • 计算每个会话的 token 预算
  • 超过预算就压缩历史(把早期消息合并或删除)
  • 重要信息保存到记忆系统
  • 使用 prompt caching 减少重复 token

Q4:如何添加新工具?

实现工具接口:

export const myTool = {
  id: "my_tool",
  name: "My Tool",
  description: "What it does",
  
  input: z.object({
    param1: z.string(),
    param2: z.number()
  }),
  
  execute: async (args, context) => {
    // context 包含: session, agent, gateway
    return { result: "..." };
  }
};

Q5:如何支持新渠道?

实现渠道接口:

export class NewChannel implements ChannelPlugin {
  async connect() { /* 初始化连接 */ }
  
  async handleInbound(event) {
    // 将渠道消息转换为标准格式
    return {
      id: event.messageId,
      senderId: event.from.id,
      text: event.text,
      timestamp: event.date
    };
  }
  
  async sendMessage(message) {
    // 发送消息到渠道
    return api.send({
      chatId: message.recipientId,
      text: message.text
    });
  }
}

数据存储

配置存储

  • 主配置:~/.openclaw/openclaw.json 或 YAML 格式
  • 工作空间:~/.openclaw/workspace/
  • 技能存储:~/.openclaw/workspace/skills/
  • 运行时状态:内存 + SQLite

会话数据

  • 活跃会话在内存
  • 历史可选持久化
  • 工具执行结果可缓存

记忆存储

取决于选择的后端:

  • Built-in:本地 JSON 文件
  • Honcho:远程向量数据库
  • QmD:基于文件的知识库

项目有趣的特性

Live Canvas(A2UI)

Agent 可以在客户端实时渲染动态 UI。用户可以和这个 UI 交互,Agent 继续处理。

语音唤醒和对话

  • macOS/iOS:唤醒词识别
  • Android:连续语音对话
  • 集成 ElevenLabs TTS

多 Agent 路由

同一个网关可以管理多个 Agent,根据渠道或用户路由到不同的 Agent。每个工作空间隔离。

客户端应用

  • macOS:菜单栏集成
  • iOS:设备配对、语音触发
  • Android:Chat、语音、Canvas

开发工作流

本地开发

# 克隆和安装
git clone https://github.com/openclaw/openclaw
cd openclaw
pnpm install

# 首次设置
pnpm openclaw setup

# 开发模式
pnpm gateway:watch  # 网关热重载
pnpm ui:dev         # UI 开发服务器

# 测试
pnpm test
pnpm test:changed

构建

# 完整构建
pnpm build
pnpm ui:build

# 类型检查
pnpm tsgo

# 代码格式化
pnpm format

# Lint
pnpm lint
posted @ 2026-05-07 15:37  WinjayYu  阅读(56)  评论(0)    收藏  举报