基于 v2026.4.9 源码调研: - 能力注册表模型(14 种能力类型) - 插件生命周期(Discovery → Enablement → Loading → Registration → Consumption) - Provider 44-hook 链分析 - Channel 插件的共享 message 工具设计 - Plugin SDK 子路径导入体系 - 与 Mitsein Agent 平台的关联思考
311 lines
12 KiB
Markdown
311 lines
12 KiB
Markdown
# OpenClaw 插件化扩展机制分析
|
|
|
|
!!! info "作者"
|
|
星月 🌙 — SORA 小队 | 2026-04-08
|
|
|
|
!!! tip "基于"
|
|
OpenClaw 源码 v2026.4.9,`src/plugins/`、`packages/plugin-sdk/`、`docs/plugins/`
|
|
|
|
---
|
|
|
|
## 一句话概括
|
|
|
|
OpenClaw 的插件系统是一个**基于能力注册的进程内扩展模型**。插件跑在 Gateway 进程里,通过统一的 `api.register*()` 接口向中央注册表声明自己的能力,核心系统通过读注册表来消费这些能力。
|
|
|
|
---
|
|
|
|
## 架构全景
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────┐
|
|
│ OpenClaw Gateway 进程 │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────┐ │
|
|
│ │ Plugin Registry(中央注册表) │ │
|
|
│ │ │ │
|
|
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
|
|
│ │ │ Provider │ │ Channel │ │ Tools │ ... │ │
|
|
│ │ │ 注册表 │ │ 注册表 │ │ 注册表 │ │ │
|
|
│ │ └────▲─────┘ └────▲─────┘ └────▲─────┘ │ │
|
|
│ └───────┼─────────────┼───────────┼───────────────────┘ │
|
|
│ │ │ │ │
|
|
│ ┌───────┴──┐ ┌───────┴──┐ ┌────┴─────┐ │
|
|
│ │ openai │ │ telegram │ │ webhooks │ ... │
|
|
│ │ plugin │ │ plugin │ │ plugin │ │
|
|
│ └──────────┘ └──────────┘ └──────────┘ │
|
|
│ (bundled) (bundled) (bundled/external) │
|
|
│ │
|
|
│ 核心系统(Agent Loop / Router / CLI) │
|
|
│ └── 只读注册表 → 消费能力 │
|
|
└──────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 关键设计原则
|
|
|
|
1. **单向注册** — 插件 → 注册表 → 核心消费。核心不直接调插件模块。
|
|
2. **能力优先** — 注册的是"我能做什么"(text inference / speech / channel),不是"我是谁"。
|
|
3. **进程内信任** — 原生插件和核心代码在同一进程,同等信任级别。
|
|
4. **Manifest 先行** — 配置验证和 UI 展示从 manifest 读,不执行插件代码。
|
|
|
|
---
|
|
|
|
## 插件类型
|
|
|
|
### 按能力分类
|
|
|
|
| 能力 | 注册方法 | 典型插件 |
|
|
|:-----|:---------|:---------|
|
|
| LLM 推理 | `api.registerProvider(...)` | openai, anthropic, google |
|
|
| 语音合成/识别 | `api.registerSpeechProvider(...)` | elevenlabs, microsoft |
|
|
| 实时语音 | `api.registerRealtimeVoiceProvider(...)` | openai |
|
|
| 媒体理解 | `api.registerMediaUnderstandingProvider(...)` | openai, google |
|
|
| 图像生成 | `api.registerImageGenerationProvider(...)` | openai, fal, minimax |
|
|
| 视频生成 | `api.registerVideoGenerationProvider(...)` | qwen |
|
|
| 网页抓取 | `api.registerWebFetchProvider(...)` | firecrawl |
|
|
| 网页搜索 | `api.registerWebSearchProvider(...)` | google |
|
|
| 消息渠道 | `api.registerChannel(...)` | telegram, discord, slack |
|
|
| Agent 工具 | `api.registerTool(...)` | 自定义工具 |
|
|
| HTTP 路由 | `api.registerHttpRoute(...)` | webhooks |
|
|
| CLI 命令 | `api.registerCli(...)` | 自定义命令 |
|
|
| 事件钩子 | `api.registerHook(...)` | 自定义事件处理 |
|
|
|
|
### 按形态分类
|
|
|
|
| 形态 | 说明 | 示例 |
|
|
|:-----|:-----|:-----|
|
|
| **plain-capability** | 注册一种能力 | mistral(只有 LLM) |
|
|
| **hybrid-capability** | 注册多种能力 | openai(LLM + speech + image + media) |
|
|
| **hook-only** | 只注册钩子 | 旧式插件(仍支持但标记为 legacy) |
|
|
| **non-capability** | 注册工具/命令/服务/路由 | webhooks, voice-call |
|
|
|
|
---
|
|
|
|
## 插件生命周期
|
|
|
|
```
|
|
Discovery → Enablement → Loading → Registration → Consumption
|
|
│ │ │ │ │
|
|
读 manifest 判断是否 jiti 加载 调用 register 核心读
|
|
+ package.json 启用/禁用 插件模块 (api) 注册能力 注册表
|
|
```
|
|
|
|
### 1. Discovery(发现)
|
|
|
|
OpenClaw 从以下位置发现插件:
|
|
- 内置插件(bundled,随 OpenClaw 安装)
|
|
- `plugins.load.paths` 配置的路径
|
|
- workspace 目录
|
|
- 全局扩展目录(`~/.openclaw/extensions/`)
|
|
|
|
关键文件:
|
|
- `openclaw.plugin.json` — 插件 manifest(id、name、configSchema)
|
|
- `package.json` — npm 元数据 + `openclaw.extensions` 入口声明
|
|
|
|
### 2. Enablement(启用)
|
|
|
|
通过 `openclaw.json` 的 `plugins` 配置控制:
|
|
|
|
```json5
|
|
{
|
|
plugins: {
|
|
entries: {
|
|
"my-plugin": {
|
|
enabled: true,
|
|
config: { /* 插件特定配置 */ }
|
|
}
|
|
},
|
|
allow: ["my-plugin"], // 信任白名单
|
|
deny: ["bad-plugin"], // 拒绝黑名单
|
|
slots: {
|
|
memory: "memory-wiki", // 独占插槽
|
|
contextEngine: "default"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
安全门控在加载前执行:入口路径逃逸检查、目录权限检查。
|
|
|
|
### 3. Loading(加载)
|
|
|
|
通过 `jiti`(动态 TypeScript/ESM 加载器)在进程内加载。不是沙箱隔离。
|
|
|
|
### 4. Registration(注册)
|
|
|
|
插件导出一个 `register(api)` 函数:
|
|
|
|
```typescript
|
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
|
|
export default definePluginEntry({
|
|
id: "my-plugin",
|
|
name: "My Plugin",
|
|
register(api) {
|
|
// 注册能力
|
|
api.registerTool({ ... });
|
|
api.registerProvider({ ... });
|
|
api.registerHook("before_agent_start", async (ctx) => { ... });
|
|
},
|
|
});
|
|
```
|
|
|
|
### 5. Consumption(消费)
|
|
|
|
核心系统读注册表,不直接调插件:
|
|
|
|
```
|
|
Agent Loop → 读 Provider 注册表 → 选择 LLM provider → 调用推理
|
|
Message Router → 读 Channel 注册表 → 选择渠道 → 发送消息
|
|
Tool Executor → 读 Tool 注册表 → 选择工具 → 执行
|
|
```
|
|
|
|
---
|
|
|
|
## 插件 SDK
|
|
|
|
`@openclaw/plugin-sdk` 提供类型化的开发接口,按子路径导入:
|
|
|
|
```typescript
|
|
// 插件入口
|
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
|
|
// 渠道插件入口
|
|
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
|
|
// 核心类型
|
|
import { ... } from "openclaw/plugin-sdk/core";
|
|
|
|
// 运行时助手
|
|
import { ... } from "openclaw/plugin-sdk/config-runtime";
|
|
import { ... } from "openclaw/plugin-sdk/text-runtime";
|
|
```
|
|
|
|
设计原则:**导出能力,不导出实现。** 插件只用 `plugin-sdk/*` 子路径,不直接导入核心 `src/` 或其他插件的内部模块。
|
|
|
|
---
|
|
|
|
## Provider 插件的 Hook 体系
|
|
|
|
Provider 插件(LLM 提供商)有最复杂的 hook 链,共 **44 个 hook 点**,覆盖从模型发现到推理执行的完整生命周期:
|
|
|
|
```
|
|
catalog → normalizeModelId → normalizeTransport → normalizeConfig
|
|
→ resolveConfigApiKey → resolveSyntheticAuth → resolveDynamicModel
|
|
→ prepareDynamicModel → normalizeResolvedModel → capabilities
|
|
→ normalizeToolSchemas → prepareExtraParams → createStreamFn / wrapStreamFn
|
|
→ prepareRuntimeAuth → resolveUsageAuth → fetchUsageSnapshot
|
|
→ buildReplayPolicy → sanitizeReplayHistory → onModelSelected
|
|
```
|
|
|
|
这个 hook 链的设计思想:**核心拥有推理循环,Provider 插件只拥有供应商特定行为。**
|
|
|
|
每个 hook 都是可选的。大多数 Provider 只实现几个(catalog + resolveDynamicModel + capabilities 是最常见的组合)。
|
|
|
|
---
|
|
|
|
## 渠道(Channel)插件
|
|
|
|
渠道插件连接 OpenClaw 到消息平台(Telegram, Discord, Slack, WhatsApp 等)。
|
|
|
|
关键设计:
|
|
- **共享 `message` 工具** — 核心拥有统一的消息工具,渠道插件提供平台特定的发送/编辑/反应适配
|
|
- **渠道不关心 Provider** — 渠道通过核心消费 TTS/图像/搜索等能力,不直接调供应商代码
|
|
- **scoped discovery** — 渠道可以根据当前 account/chat/thread 动态暴露/隐藏消息操作
|
|
|
|
```typescript
|
|
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
|
|
export default defineChannelPluginEntry({
|
|
id: "my-channel",
|
|
name: "My Channel",
|
|
register(api) {
|
|
api.registerChannel({
|
|
id: "my-channel",
|
|
// 消息适配器、事件处理、认证流程...
|
|
});
|
|
},
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 安装和分发
|
|
|
|
```bash
|
|
# 从 ClawHub(推荐)
|
|
openclaw plugins install clawhub:@myorg/my-plugin
|
|
|
|
# 从 npm
|
|
openclaw plugins install @myorg/my-plugin
|
|
|
|
# 本地开发
|
|
# 放到 ~/.openclaw/extensions/my-plugin/ 自动发现
|
|
|
|
# 发布到 ClawHub
|
|
clawhub package publish my-org/my-plugin
|
|
```
|
|
|
|
安全约束:
|
|
- `npm install --omit=dev --ignore-scripts` — 不执行 postinstall 脚本
|
|
- 入口路径必须在插件目录内(防止路径逃逸)
|
|
- 非内置插件检查目录权限和所有权
|
|
|
|
---
|
|
|
|
## 运行时助手(api.runtime)
|
|
|
|
插件可以通过 `api.runtime` 消费核心能力:
|
|
|
|
| 助手 | 用途 |
|
|
|:-----|:-----|
|
|
| `api.runtime.tts.*` | 文字转语音 |
|
|
| `api.runtime.mediaUnderstanding.*` | 图像/音频/视频理解 |
|
|
| `api.runtime.imageGeneration.*` | 图像生成 |
|
|
| `api.runtime.videoGeneration.*` | 视频生成 |
|
|
| `api.runtime.webSearch.*` | 网页搜索 |
|
|
| `api.runtime.subagent.*` | 启动子 Agent |
|
|
|
|
这些助手是**核心拥有的能力合约**,底层具体用哪个 Provider 由核心决定。插件消费接口,不关心实现。
|
|
|
|
---
|
|
|
|
## 与 Mitsein 的关联思考
|
|
|
|
如果 Mitsein 要借鉴 OpenClaw 的插件机制,有几个值得注意的点:
|
|
|
|
### 1. 能力注册表模式适合 Agent 平台
|
|
|
|
Mitsein 的 Agent 系统(orchestrator-next)也有类似的需求:多 LLM provider、多工具、多渠道。把这些抽象为能力注册表,可以让 Agent 编排层更灵活。
|
|
|
|
### 2. Manifest 先行的思路
|
|
|
|
OpenClaw 在不执行插件代码的情况下就能验证配置和展示 UI。Mitsein 的 Skill/Agent 系统如果也做 manifest 先行,Agent Store 的展示和配置就不需要加载实际代码。
|
|
|
|
### 3. Provider Hook 链 vs Mitsein 的 LLM 路由
|
|
|
|
Mitsein 目前通过 LiteLLM 做 LLM 路由。OpenClaw 的 44-hook Provider 体系是更精细的控制——但也更复杂。对 Mitsein 来说,可能不需要这么重的 hook 链,但 `catalog` + `resolveDynamicModel` + `capabilities` 的核心三件套值得借鉴。
|
|
|
|
### 4. 进程内 vs 进程外
|
|
|
|
OpenClaw 插件跑在 Gateway 进程内,没有沙箱。这对性能好但安全差。如果 Mitsein 要做第三方插件生态,可能需要考虑进程隔离(Worker isolate / iframe / Container)。
|
|
|
|
---
|
|
|
|
## 总结
|
|
|
|
OpenClaw 的插件系统是一个**成熟的、能力驱动的扩展框架**:
|
|
|
|
- **扩展点丰富**:14 种能力类型 + 44 个 Provider hook + HTTP 路由 + CLI 命令
|
|
- **边界清晰**:核心拥有合约和编排,插件拥有实现
|
|
- **单向依赖**:插件 → 注册表 ← 核心,不双向耦合
|
|
- **Manifest 驱动**:配置验证和 UI 不需要执行插件代码
|
|
- **分发完善**:ClawHub / npm / 本地开发三条路
|
|
|
|
其设计哲学可以总结为:**定义能力合约,让插件实现合约,让核心消费合约。** 这个模式适用于任何需要多供应商、多渠道、多工具集成的 AI Agent 平台。
|
|
|
|
---
|
|
|
|
*星月 🌙(SORA Team)— 2026-04-08*
|
|
|
|
*源码:[openclaw/openclaw](https://github.com/openclaw/openclaw) v2026.4.9*
|