openclaw架构原理-单进程应用 + 插件式扩展

openclaw架构原理-单进程应用 + 插件式扩展

文章目录

OpenClaw

github: https://github.com/openclaw/openclaw

从 Clawbot到 Moltbot再到 OpenClaw,这个爆火的项目经过 3 次改名,截至 2 月 4 日已经在 github 累积获得了 160K star。 OpenClaw 是一款开源自托管的个人 AI 代理网关,本质是运行在用户自有设备上的自主式智能体助手,主打 “本地优先、隐私可控” 的设计理念,通过自然语言指令实现 PC 全功能自动化,真正做到 替用户做事 而非 仅回答问题

OpenClaw 火爆全网!它不是第一个 AI Agent,但却是少数真正开始接管系统操作的那一类:读文件、跑命令、改代码,甚至拥有完整系统权限。

该项目由 Peter Steinberger([PSPDFKit]( 创始人)创建,目前已有 378 位贡献者,并催生了一个由 8,900+ 开发者组成的社区,致力于构建个人 AI 基础设施。

与云端聊天机器人不同,OpenClaw 持续运行在用户自有硬件(比如 Mac Mini 以及各种 PC 设备)上,执行 shell 命令、管理文件,并协调多步骤工作流程,无需人工审核。

用户可以在 PC 或者手机上的 WhatsApp、Telegram、Slack、Discord、Google Chat、Signal、iMessage、Microsoft Teams、WebChat 等通讯软件上通过文字或者语音发布任务,它就可以在 PC 另一台设备上完成工作并把结果发送到用户的通讯软件上。

openclaw架构-单进程应用 + 插件式扩展

OpenClaw 的核心是一个基于 TypeScript 开发的命令行应用(CLI),既非 Python 开发、也非基于 Next.js 的网页应用。作为一个独立运行进程。

核心理念是:常驻控制平面 + 可插拔大模型大脑 + 可扩展工具技能 + 会话/记忆/安全策略

┌─────────────────────────────────────────────────────────────────┐ │ 消息渠道(Channels) │ │ ┌──────┐ ┌──────┐ ┌────┐ ┌────┐ ┌────────┐ ┌──────┐ │ │ │企业微信│ │Telegram│ │飞书│ │QQ │ │WhatsApp│ │Web UI│ … │ │ └───┬──┘ └───┬──┘ └──┬─┘ └──┬─┘ └───┬────┘ └───┬──┘ │ │ └────────┴───────┴──────┴───────┴──────────┘ │ │ │ 统一内部事件格式 │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Gateway(网关守护进程):18789 │ │ │ │ │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ Router │ │ Session │ │ Security │ │ │ │ │ │ 路由分发 │ │ 会话管理 │ │ 安全策略 │ │ │ │ │ │ 鉴权/限流 │ │ 上下文恢复│ │ 审批机制 │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │ └───────────────────────┬─────────────────────────────────┘ │ │ │ │ │ ┌─────────────┼──────────────┐ │ │ ▼ ▼ ▼ │ │ ┌──────────────┐ ┌───────────┐ ┌──────────────┐ │ │ │ Agent Runtime│ │ Nodes │ │ Skills & │ │ │ │ 智能体运行时 │ │ 设备节点 │ │ Sandbox │ │ │ │ │ │ │ │ 技能系统+沙箱 │ │ │ │ ┌────────┐ │ │ macOS │ │ │ │ │ │ │Prompt │ │ │ iOS │ │ SKILL.md │ │ │ │ │Builder │ │ │ Android │ │ Docker 隔离 │ │ │ │ ├────────┤ │ │ Linux │ │ ClawHub 市场 │ │ │ │ │Context │ │ │ │ │ │ │ │ │ │Guard │ │ └───────────┘ └──────────────┘ │ │ │ ├────────┤ │ │ │ │ │Tool │ │ │ │ │ │Executor│ │ │ │ │ └────────┘ │ │ │ └──────┬──────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────┐ │ │ │ LLM Provider(模型适配层) │ │ │ │ │ │ │ │ Claude │ GPT │ DeepSeek │ Ollama │ … │ │ │ └──────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────┐ │ │ │ Memory(记忆系统) │ │ │ │ │ │ │ │ .jsonl 会话历史 │ Markdown 长期记忆 │ │ │ │ SQLite 索引 │ Git 版本管理 │ │ │ └──────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ 

在即时通讯工具中向 Clawd 发送指令后,会依次触发以下环节:

1. 接入层 Channel(通道适配器)

```text 用户在 IM 发送消息 → 平台服务器回调/推送 → Gateway Channel Adapter 接收 → 消息标准化(提取文本、附件、发送者信息等) → 生成统一的内部事件 → 交给 Router 分发 ``` 通道适配器接收用户消息并进行预处理,包括消息标准化、提取附件等。不同的即时通讯工具和输入流,都配有专属的适配器。 每个通道适配器还负责反向通路:**将 Agent 的回复格式化为目标平台所需的格式 (如 Markdown 转 IM 富文本、长文本分段、文件直链等),并通过原通道发回**。 

2. 网关服务器:路由与会话层 Router + Session

Gateway 是整个系统的控制中心,是单机唯一实例的常驻守护进程。

  • Router:鉴权、去重、限流、把消息分发给对应 Agent/工作流
  • Session:找到/创建会话(conversation_id),取出最近对话、用户信息等上下文
    通信协议:
    所有组件间通过 WebSocket + JSON 通信,消息分三种类型:

类型 方向 说明
req 客户端 → 服务端 请求,包含唯一 id(UUID)
res 服务端 → 客户端 对 req 的响应,含 ok 状态
event 服务端 → 客户端 单向推送(消息到达、状态变更等)

连接鉴权流程:

客户端发起 WebSocket 连接 → 服务端发送 connect.challenge(含 nonce + 时间戳,防重放) → 客户端发送 req: connect(含协议版本、角色、权限范围、设备签名) → 若配置了 Token,验证 Bearer Token → 若是新设备,进入 Device Pairing 配对流程 → 鉴权通过,连接建立 

会话映射规则:
场景 Session Key 说明
私聊(DM) 默认共享主会话 dmScope: “main”,可配 per-peer 隔离
群组 agent:::group: 每个群独立会话
定时任务 cron:: 独立会话
Webhook webhook:: 独立会话

3. Agent 核心 Orchestrator(编排器) ——“大脑”

Agent Runtime 是系统的决策核心,负责推理与编排。

  • 决定下一步做什么:直接回答还是调用工具
  • 维护对话回合:模型→工具→模型→…直到产出最终回复
  • 这里通常包含:提示词组装、策略、错误恢复、输出格式化

​ 这是真正承载 AI 能力的模块。该模块会确定待调用的模型、匹配对应的 API 密钥(若密钥失效,会将该配置标记为冷却状态并尝试下一个),若主模型调用失败,会自动切换至备用模型。 智能体运行器会结合可用工具、技能、记忆内容动态生成系统提示词,再加入会话历史(存储于.jsonl 文件),随后将完整提示词传入上下文窗口防护机制,校验是否有足够的上下文空间。若上下文空间即将耗尽,系统会选择压缩会话内容(对上下文进行总结)或优雅降级终止执行。

系统提示词由多层动态组合而成:

最终 Prompt = 基础身份(AGENTS.md) + 工具声明(TOOLS.md,紧凑 XML 格式以节省 Token) + 动态技能列表 + 安全策略提示 + 用户记忆(USER.md 等 Markdown 文件) + 压缩后的会话历史 + 当前用户消息 

Agent Runtime 会结合可用工具、已加载的技能、记忆内容动态生成系统提示词, 再加入会话历史,随后将完整提示词传入上下文窗口守护者(Context Window Guard)。

4. LLM 适配层 LLM Provider(模型网关)

  • 把“调用模型”统一成一个接口
  • 适配不同厂商/本地模型;处理流式输出、重试、超时、并发等

​ 大模型调用环节会以流式方式返回结果,同时对不同服务商的 API 做了一层抽象封装;若所调用的模型支持深度思考功能,该模块还会触发模型的扩展思考逻辑。

Context Window Guard(上下文窗口守护)

这是确保输入不超过模型上下文限制的关键机制:

完整提示词 → Context Window Guard 校验 ├─ 空间充足 → 直接发送给 LLM ├─ 空间紧张 → 压缩会话历史(总结摘要替代原始对话) └─ 空间耗尽 → 优雅降级(告知用户需开启新会话) 
  • Pruning(剪枝):在发送给模型前,自动裁剪过时的工具调用中间结果
  • Compression(压缩):将冗长的历史对话替换为总结摘要
  • Graceful Degradation(优雅降级):空间不足时终止执行并通知用户
模型调用与容错
选择主模型 → 匹配 API Key ├─ 调用成功 → 流式返回结果 ├─ Key 失效 → 标记冷却,尝试下一个 Key └─ 主模型故障 → 自动切换备用模型(Fallback) 
LLM Provider(模型适配层)

将"调用模型"统一抽象为一个接口,屏蔽各厂商 API 差异
支持的模型提供商:
Provider 示例模型 备注
Anthropic Claude 3.5/4 原生支持
OpenAI GPT-4o/o1 原生支持
DeepSeek DeepSeek-V3/R1 兼容 OpenAI 格式
OpenRouter 多模型聚合 统一入口
Ollama Llama/Qwen 等 本地模型

模型管理:

  • CLI 命令:openclaw models list/set/scan
  • 支持热切换模型,无需重启 Gateway
  • 配置集中在 models.json
Nodes(设备节点)——能力提供者

Nodes 是运行在各类设备上的能力提供者,通过 WebSocket 以 role: “node” 连接 Gatew
提供的能力:

能力 说明 system.run 执行系统命令(Bash/Shell) file.read / file.write 文件读写 browser.* 浏览器控制(Computer Use) camera.* 摄像头操作 canvas.* UI 画布操作 

执行流程:

Agent 决定调用工具 → Gateway 检查权限/安全策略 → Gateway 通过 node.invoke 转发指令给目标 Node → Node 在本地执行 → 执行结果返回 Gateway → Gateway 将结果传回 Agent Runtime 
Skills & Sandbox(技能系统与沙箱隔离)

Skills(技能系统)
Skills 是 OpenClaw 的插件式扩展机制,本质上是对工具的语义封装

skill/ ├── SKILL.md # 技能描述(LLM 可读的说明文档) ├── tools/ # 工具脚本(Bash/Python/Node.js) └── prompts/ # 可选的提示词模板 

技能来源:

  • 本地目录
  • Agent Workspace 内嵌
  • ClawHub 在线市场(社区贡献的 93+ 预置技能)https://clawhub.ai/
    ClawHub 是一个最小化的技能注册中心。启用 ClawHub 后,代理可以自动搜索技能并根据需要拉取新技能。
    覆盖领域:办公自动化、开发工具、智能家居、内容创作等。

Sandbox(沙箱隔离)
对于非主会话(如群聊场景),默认启用 Docker 沙箱隔离执行

会话类型 执行环境 权限 主对话(DM) 本地直接执行 完整权限 群组对话 Docker 沙箱 受限工具(bash, read 等) Webhook 触发 Docker 沙箱 受限 

5.智能体循环(Agent Loop)

若大模型返回工具调用指令,Clawd 会在本地执行该指令,并将执行结果补充至对话中。这一过程会反复执行,直至大模型返回最终文本结果,或达到最大循环次数(默认约 20 次)。 正是在这一环节,Clawd 实现了其核心能力——电脑操作功能。

用户发送消息 │ ▼ ┌─────────────────────────────────────┐ │ Agent Runtime 接收 │ │ 构造 Prompt + 会话历史 + 工具列表 │ │ Context Window Guard 校验 │ └───────────────┬─────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ 调用 LLM(流式) │ │ LLM Provider 适配 + 重试 + 超时 │ └───────────────┬─────────────────────┘ │ ┌───────┴───────┐ │ │ ▼ ▼ ┌──────────┐ ┌──────────────┐ │ 最终文本 │ │ 工具调用指令 │ │ 回复用户 │ │ │ └──────────┘ └──────┬───────┘ │ ▼ ┌────────────────┐ │ 权限检查 │ │ 安全审批 │ │ 沙箱策略判断 │ └───────┬────────┘ │ ▼ ┌────────────────┐ │ 执行工具 │ │ (本地/Node/ │ │ Docker 沙箱) │ └───────┬────────┘ │ ▼ ┌────────────────┐ │ 执行结果 │ │ 追加到对话 │ └───────┬────────┘ │ ▼ 回到 "调用 LLM" 步骤 (循环直至最终文本或达到上限) 默认最大循环次数:约 20 次 

这是 OpenClaw 实现核心能力的关键机制。当大模型返回工具调用指令时, 系统会在本地执行该指令,并将执行结果补充至对话中, 这一过程反复执行直至大模型返回最终文本结果

审批机制:高危命令(如 system.run 执行危险操作)可配置为需要人工审批:

Agent 请求执行危险工具 → Gateway 广播 exec.approval.requested 事件 → Operator(用户)在 Web UI 或 IM 中确认/拒绝 → Gateway 将审批结果传回 Agent → 继续或终止执行 

6.记忆系统

OpenClaw 的记忆系统遵循 “文件即记忆” 的设计哲学, Markdown 是真相的来源(Source of Truth)。

会话记忆(短期)

存储格式:.jsonl(JSON Lines),每行一个 JSON 对象
存储路径:~/.openclaw/agents//sessions/.jsonl
记录内容:用户消息、工具调用指令、执行结果、模型回复
元数据:sessions.json 记录所有会话的索引信息

长期记忆(持久)

存储格式:Markdown 文件
关键文件:
USER.md:用户偏好、习惯、个人信息
AGENTS.md:Agent 身份定义
TOOLS.md:工具声明
Workspace 中的其他 .md 文件

记忆管理策略
策略 说明 Pruning(剪枝) 发送给模型前裁剪过时的工具调用中间结果 Compression(压缩) 将冗长历史替换为总结摘要 Lifecycle(生命周期) 按空闲时间/固定时间重置,或 /new 命令手动重置 Git 版本管理 记忆文件可被 Git 追踪,支持回溯和协作 

OpenClaw 有意选择 Markdown + SQLite 而非向量数据库,原因是:

  • 可读性:开发者可直接打开文件查看 Agent 记住了什么
  • 可编辑性:人类可以直接修正 Agent 的错误认知
  • 可审计性:Git 历史记录所有变更
  • 轻量级:无需额外的向量数据库依赖

OpenClaw 认证机制-公网暴露的最佳实践

不需要 Nginx Basic Auth,OpenClaw 自身的两层防护就足够:

| 层级 | 机制 | 保护什么 ||| ----- | ------------------------------- | ------------------ | ---- || 第1层 | **Device Identity**(设备配对) | Control UI 界面 ||| 第2层 | **Gateway Token** | API/WebSocket 调用 ||

你的浏览器首次访问 → 发起配对请求(Pending)

你在服务器终端执行:devices approve

浏览器获得设备凭证(存 localStorage)→ 以后自动认证

别人的浏览器访问 → 也发起配对请求 → 但你不 approve → 永远进不去。

这比密码更安全,因为:

  • 没有密码可以暴力破解
  • 每台设备需要服务器端显式批准
  • 可以随时 devices revoke 撤销某台设备的访问权

配置(openclaw.json)

{"gateway":{"controlUi":{"dangerouslyDisableDeviceAuth":false}}}
⚠️ 切勿设置 dangerouslyDisableDeviceAuth: true,这会关闭设备认证,任何人打开 URL 都能直接控制你的 AI Agent。名字中的 dangerously 就是在警告你。
最佳实践
打开 Device Auth,关掉 dangerouslyDisableDeviceAuth

1. Gateway Auth Token(API 层认证)

配置位置:

"auth":{"mode":"token","token":"xxxxxxxxxxxxxxxxxxxxxxx"}

所有 API/WebSocket 请求必须携带 Authorization: Bearer <token>,否则拒绝。这保护了你的 AI Agent 不被随意调用。

作用:保护 Gateway 的 API/WebSocket 接口(如 /v1/chat/v1/agents 等)。

使用方式:客户端(如 Cursor、Claude Desktop、MCP Client)在连接时通过 HTTP Header 传递:

2. Device Identity(Control UI 层认证)

专门保护 Web 控制面板(即你浏览器打开的那个界面)。流程是:

浏览器打开 UI → WebSocket 连接 → Gateway 要求 device identity ↓ 浏览器本地没有已授权的设备凭证 ↓ 连接被拒绝 (code=1008) 

这是专门保护 Control UI 的。正常流程:

  1. 浏览器首次打开 UI → 提示 device identity required
  2. 服务器终端运行授权命令,批准该设备
  3. 浏览器获得设备凭证,之后都能访问

这就是 OpenClaw 的最佳实践 —— 不是用密码,而是用设备授权,类似 SSH 的 trust-on-first-use 机制。

3. Bind 范围限制

"bind":"lan" // 只监听局域网 

3. dangerouslyDisableDeviceAuth: true 的作用

"gateway":{"controlUi":{"dangerouslyDisableDeviceAuth":true}}

这个配置的意思是:跳过 Device Identity 验证,任何人打开 UI 都不需要设备授权就能直接使用。
名字带 dangerously 是因为这意味着只要知道 URL 的人都能控制你的 AI Agent。

OpenClaw 安装部署架构

典型的生产部署架构如下:

 ┌──────────┐ │ 浏览器 │ │ (Web UI) │ └────┬─────┘ │ HTTPS ▼ ┌─────────────────────────────────────────────────────────────┐ │ Nginx 反代层 (:443) │ │ • SSL 终止 • WebSocket 代理 │ │ • Origin 覆写 • 信任边界 │ └──────────┬───────────────────────────────────┬──────────────┘ │ proxy_pass │ │ http://127.0.0.1:18789 │ ▼ │ ┌──────────────────────────┐ │ │ IM 通道 Webhook 回调 │ │ │ 企业微信/QQ/钉钉/飞书 │ │ └──────────┬───────────────┘ │ │ │ ▼ ▼ ┌─────────────────────────────────────────────────────────────┐ │ OpenClaw Gateway (:18789 仅本地监听) │ │ │ │ Channel Adapters → Router → Session → Agent Runtime │ │ ↕ │ │ LLM Provider │ │ ↕ │ │ Tool Execution │ │ (Nodes / Sandbox) │ │ ↕ │ │ Memory System │ │ (.jsonl + .md) │ └─────────────────────────────────────────────────────────────┘ 端口说明: :443 — Nginx HTTPS(对外唯一入口) :18789 — OpenClaw Gateway(仅 127.0.0.1,不对外暴露) :18790 — OpenClaw Bridge(多设备局域网发现通道) 

使用总结

配置企业微信通道

编辑 openclaw.json
配置文件位于:data/.openclaw/openclaw.json(相对于 docker-compose.yml 目录)

channels 中添加 wecom 配置:

{"channels":{"wecom":{"enabled":true,"token":"<你的企业微信 Token>","encodingAESKey":"<你的企业微信 EncodingAESKey>"}}}

手动注册插件(关键步骤)
这是最容易踩的坑! OpenClaw 的 doctor 会自动尝试在 plugins.entries 中以通道 ID(wecom)注册插件,但实际的插件 ID 是 openclaw-wecom,导致 plugin not found: wecom 错误。

必须手动在 openclaw.json 中添加:

{"plugins":{"entries":{"openclaw-wecom":{"enabled":true}}}}
注意plugins.entries 的 key 必须是 openclaw-wecom(npm 包名去掉 @marshulll/ 前缀),而不是 wecom(通道 ID)。

Read more

EnvPilot:一款基于 Rust 的跨平台环境变量神器,一键搞定 Windows/Linux 环境配置!

EnvPilot:一款基于 Rust 的跨平台环境变量神器,一键搞定 Windows/Linux 环境配置!

文章目录 * 1. 项目介绍🎯 * 1.1. 什么是 EnvPilot? * 1.2. 为什么选择 EnvPilot? * 2. 核心优势:四大痛点全部解决!💪 * ✅ 痛点一:添加不生效?已修复! * ✅ 痛点二:删除删不掉?已修复! * ✅ 痛点三:PATH 清理失效?已修复! * ✅ 痛点四:误操作无法恢复?已解决! * 3. 支持的开发环境🛠️ * 4. 详细使用教程📖 * 4.1. Windows 平台使用教程 * 1️⃣ 下载安装 * 2️⃣ 配置环境变量 * 3️⃣ 清除环境变量 * 4.2. Linux 平台使用教程 * 1️⃣ 从源码编译 * 2️⃣ 配置环境变量 * 3️

By Ne0inhk
MySQL 表约束核心指南:从基础约束到外键关联(含实战案例)

MySQL 表约束核心指南:从基础约束到外键关联(含实战案例)

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 表约束核心概念 * 二. 基础约束:NULL/NOT NULL 与 DEFAULT * 2.1 空属性约束(NULL/NOT NULL) * 2.2 默认值约束(DEFAULT) * 2.3 列描述(COMMENT) * 2.4 零填充约束(ZEROFILL) * 三. 核心约束:主键、自增长与唯一键 * 3.1 主键约束(PRIMARY KEY) * 3.

By Ne0inhk
【MYSQL】MYSQL学习的一大重点:MYSQL表的操作

【MYSQL】MYSQL学习的一大重点:MYSQL表的操作

🎬 个人主页:艾莉丝努力练剑 ❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》 《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》 ⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平 🎬 艾莉丝的简介: 文章目录 * 0 ~> 概要 * 1 ~> 创建表 * 2 ~> 创建表的案例详解 * 3 ~> 查看表结构 * 4 ~> 修改表 * 4.1 什么时候需要修改表 * 4.2 修改方式 * 4.3 案例 * 4.3.1 在users表添加二条记录 * 4.

By Ne0inhk
RUST异步并发安全与内存管理的最佳实践

RUST异步并发安全与内存管理的最佳实践

RUST异步并发安全与内存管理的最佳实践 一、引言 异步并发编程在提高系统性能和响应时间的同时,也带来了并发安全和内存管理的挑战。Rust语言以其独特的所有权、借用和生命周期系统,为解决这些问题提供了强大的工具。本章将深入探讨异步并发安全与内存管理的核心概念、常见问题及解决方案,并通过实战项目优化演示这些方法的应用。 二、异步并发安全的基础概念 2.1 所有权、借用与生命周期 Rust的所有权系统是其并发安全的基础。每个值都有唯一的所有者,当所有者离开作用域时,值会被自动释放。借用分为可变借用和不可变借用,同一时间只能有一个可变借用或多个不可变借用,从而避免数据竞争。生命周期则确保引用在所有者有效的时间内使用。 fnmain(){letmut s =String::from("hello");// s是所有者let r1 =&s;// 不可变借用let r2 =&s;// 不可变借用(允许)// let r3 = &mut s; // 可变借用(禁止,

By Ne0inhk