一、插件整体架构与分类
OpenClaw 插件运行在 Gateway 主进程内,可对核心能力做灵活扩展,打通外部聊天渠道、接入自定义大模型、新增业务功能。
架构分层
plaintext
Gateway 主进程
├─ 核心模块(会话/上下文/工具系统)
└─ 插件层
├─ 渠道插件 Channel Plugins → 对接各类聊天平台
├─ 模型提供商插件 Provider Plugins → 接入自研/第三方 LLM
└─ 通用功能插件 Extension → 新增自定义工具、语音、业务逻辑
插件类型说明
表格
| 插件类型 | type 字段值 | 核心用途 | 典型场景 |
|---|---|---|---|
| 渠道插件 | channel | 新增对话接入端 | 钉钉、企业微信、自定义 WebSocket 聊天 |
| 提供商插件 | provider | 对接 AI 模型接口 | 私有部署 LLM、私有化 API、第三方大模型 |
| 功能插件 | extension | 拓展网关通用能力 | 语音通话、自定义工具、消息回调、数据统计 |
二、开发环境搭建
前置依赖
- Node.js:22.14+ / 24+
- 包管理器:pnpm(推荐)、npm
- TypeScript:5.0+
- 本地已部署可正常运行的 OpenClaw
1. 初始化项目
bash
运行
# 创建项目目录
mkdir my-openclaw-plugin
cd my-openclaw-plugin
# 初始化包管理
pnpm init
# 安装 SDK 与编译依赖
pnpm add -D @openclaw/plugin-sdk typescript @types/node
# 生成 tsconfig 配置文件
npx tsc --init
2. 标准 tsconfig.json
替换默认配置,适配插件编译规范:
json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"declaration": true,
"sourceMap": true
},
"include": ["src/**/*"]
}
3. 标准项目目录结构
plaintext
my-openclaw-plugin/
├── src/
│ └── index.ts # 插件入口文件
├── openclaw.plugin.json # 插件清单(必填,核心配置)
├── package.json
├── tsconfig.json
└── README.md
三、插件清单:openclaw.plugin.json(核心配置)
该文件是插件的身份标识,定义元数据、类型、可配置项,所有插件必须存在。
完整模板
json
{
"name": "my-custom-channel",
"version": "1.0.0",
"displayName": "自定义聊天渠道",
"description": "对接自研聊天平台的渠道插件",
"author": "your-name",
"license": "MIT",
"main": "dist/index.js",
"type": "channel",
"openclaw": {
"minVersion": "1.0.0"
},
"config": {
"apiKey": {
"type": "string",
"description": "平台接口密钥",
"required": true,
"secret": true
},
"webhookPort": {
"type": "number",
"description": "Webhook 监听端口",
"default": 8080
},
"enableDebug": {
"type": "boolean",
"description": "开启调试日志",
"default": false
}
}
}
字段详解
表格
| 字段 | 必填 | 说明 |
|---|---|---|
name | 是 | 插件唯一标识,小写连字符格式(kebab-case) |
version | 是 | 语义化版本号(主。次. 修订) |
displayName | 是 | 前端展示名称 |
description | 是 | 插件功能描述 |
main | 是 | 编译后入口文件路径 |
type | 是 | 插件类型:channel / provider / extension |
openclaw.minVersion | 否 | 兼容的最低 OpenClaw 版本 |
config | 否 | 自定义配置项,支持字符串 / 数字 / 布尔,secret=true 代表密钥,后台不展示明文 |
配置项类型汇总
json
"config": {
"str": { "type": "string", "required": true, "default": "demo" },
"num": { "type": "number", "default": 8080 },
"bool": { "type": "boolean", "default": true },
"secretKey": { "type": "string", "secret": true }
}
四、渠道插件开发(Channel Plugin)
用于对接各类聊天平台,实现消息收发、状态提示、媒体消息处理。
1. 基础入口代码(src/index.ts)
typescript
运行
import { ChannelPlugin, Message, SendOptions } from '@openclaw/plugin-sdk'
export default class CustomChannel extends ChannelPlugin {
/** 插件加载,初始化连接、服务 */
async onLoad(): Promise<void> {
const apiKey = this.config.get<string>('apiKey')
const port = this.config.get<number>('webhookPort')
this.logger.info(`渠道插件加载完成,端口:${port}`)
// 此处初始化 WebSocket / Webhook 服务、对接第三方平台
this.startListen()
}
/** 向外发送文本/媒体消息 */
async sendMessage(message: Message, options: SendOptions): Promise<void> {
const { chatId, text, attachments } = message
// 处理媒体附件
if (attachments && attachments.length > 0) {
for (const att of attachments) {
if (att.type === 'image') {
await this.sendImage(chatId, att.url)
}
if (att.type === 'file') {
await this.sendFile(chatId, att.url, att.name)
}
}
}
// 发送文本消息
if (text) {
await this.sendText(chatId, text)
}
}
/** 输入中状态提示 */
async sendTypingIndicator(chatId: string): Promise<void> {
// 调用平台接口,展示「对方正在输入」
}
/** 插件卸载,释放资源 */
async onUnload(): Promise<void> {
this.logger.info('渠道插件已卸载,关闭连接')
// 关闭端口、断开连接、销毁定时器
}
// 内部:监听外部消息,转发给 Gateway
private startListen() {
// 模拟收到第三方平台消息
setInterval(() => {
// 推送消息至网关核心处理
this.emitMessage({
text: "你好,我是外部用户",
chatId: "chat_1001",
senderId: "user_001",
senderName: "访客",
timestamp: Date.now()
})
}, 3000)
}
// 模拟接口方法
private async sendText(chatId: string, text: string) {}
private async sendImage(chatId: string, url: string) {}
private async sendFile(chatId: string, url: string, name: string) {}
}
核心能力说明
- 消息上行:外部消息通过
emitMessage推送给 Gateway; - 消息下行:网关回复通过
sendMessage发送到聊天平台; - 媒体支持:原生支持图片、文件等附件分发;
- 生命周期:
onLoad初始化、onUnload清理资源。
五、模型提供商插件开发(Provider Plugin)
对接自定义 / 私有化 LLM 接口,支持普通对话、流式 SSE 输出、模型列表查询。
完整示例代码
typescript
运行
import { ProviderPlugin, ChatRequest, ChatResponse } from '@openclaw/plugin-sdk'
export default class CustomLLMProvider extends ProviderPlugin {
private apiKey: string = ''
private baseUrl: string = ''
async onLoad(): Promise<void> {
this.apiKey = this.config.get<string>('apiKey')
this.baseUrl = this.config.get<string>('baseUrl')
this.logger.info('自定义模型提供商加载成功')
}
/** 非流式对话 */
async chat(request: ChatRequest): Promise<ChatResponse> {
const { messages, model, temperature, maxTokens } = request
const res = await fetch(`${this.baseUrl}/v1/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`
},
body: JSON.stringify({
model,
messages,
temperature,
max_tokens: maxTokens
})
})
const data = await res.json()
return {
content: data.choices[0].message.content,
usage: {
promptTokens: data.usage.prompt_tokens,
completionTokens: data.usage.completion_tokens
}
}
}
/** 流式 SSE 对话(可选,适配打字机效果) */
async *chatStream(request: ChatRequest): AsyncGenerator<Partial<ChatResponse>> {
const res = await fetch(`${this.baseUrl}/v1/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`
},
body: JSON.stringify({ ...request, stream: true })
})
// 解析 SSE 流
for await (const chunk of this.parseSSE(res.body!)) {
yield { content: chunk.content }
}
}
/** 获取当前可用模型列表 */
async listModels(): Promise<string[]> {
return ['my-7b', 'my-13b', 'my-70b']
}
async onUnload(): Promise<void> {
this.logger.info('模型插件已卸载')
}
}
六、通用生命周期与运行时 API
1. 全生命周期钩子
所有插件通用,管控加载、卸载、配置变更、健康检测:
typescript
运行
export default class DemoPlugin extends ChannelPlugin {
// 插件加载/启动
async onLoad(): Promise<void> {}
// 插件卸载/停止
async onUnload(): Promise<void> {}
// 插件配置修改时触发
async onConfigChange(key: string, value: unknown): Promise<void> {}
// 网关健康巡检
async onHealthCheck(): Promise<boolean> {
return true // true = 健康
}
}
2. 内置运行时 API
日志 Logger
统一日志输出,替代 console.log
typescript
运行
this.logger.info('普通信息')
this.logger.warn('警告信息')
this.logger.error('错误信息', err)
this.logger.debug('调试日志')
配置读取 Config
typescript
运行
// 读取配置,支持默认值
const key = this.config.get<string>('apiKey')
const port = this.config.get<number>('port', 8080)
// 判断配置项是否存在
if (this.config.has('enableDebug')) {}
持久化存储 Storage
插件本地轻量数据持久化
typescript
运行
// 写入
await this.storage.set('lastRunTime', Date.now())
// 读取
const time = await this.storage.get<number>('lastRunTime')
// 删除
await this.storage.delete('lastRunTime')
事件通信 Events
插件之间跨组件通信
typescript
运行
// 发送事件
this.emit('custom-event', { data: 'hello' })
// 监听事件
this.on('other-event', (payload) => {
this.logger.info('收到跨插件事件', payload)
})
七、本地调试与加载
1. 编译代码
bash
运行
pnpm build
2. 本地挂载插件
编辑 OpenClaw 主配置 openclaw.json,指向插件目录:
json
{
"plugins": {
"entries": [
{
"source": "local",
"path": "/你的插件绝对路径/my-openclaw-plugin"
}
]
}
}
3. 重启网关生效
bash
运行
openclaw gateway restart
4. 日志排查
bash
运行
# 查看插件相关日志
openclaw logs | grep plugin
# 开启全量调试日志
OPENCLAW_LOG_LEVEL=debug openclaw gateway run
5. 单元测试(Vitest)
安装测试依赖:
bash
运行
pnpm add -D vitest
编写测试用例:
typescript
运行
import { describe, it, expect } from 'vitest'
import MyPlugin from '../src/index'
describe('插件测试', () => {
it('初始化正常', () => {
const plugin = new MyPlugin()
expect(plugin).toBeDefined()
})
})
执行测试:
bash
运行
pnpm test
八、插件打包与发布
1. 发布前检查
- 执行
pnpm build确保代码编译正常; - 完善
openclaw.plugin.json、README; - 配置
package.json打包文件列表:
json
{
"files": [
"dist/",
"openclaw.plugin.json",
"README.md"
]
}
2. 发布到 ClawHub
bash
运行
# 登录插件市场
clawhub login
# 发布插件
clawhub publish
3. 他人安装使用
bash
运行
openclaw plugins install 你的插件name
4. 版本迭代
修改版本号后重新发布:
bash
运行
npm version patch
clawhub publish
九、开发最佳实践
- 异常捕获:所有异步逻辑必须加
try/catch,避免插件崩溃导致网关宕机; - 资源回收:
onUnload中关闭端口、定时器、长连接、轮询; - 配置校验:
onLoad阶段检查必填配置,缺失直接抛出明确提示; - 日志规范:统一使用
this.logger,禁止原生console; - 类型约束:全程使用 TypeScript 强类型,减少线上 BUG;
- 密钥安全:敏感配置标记
secret: true,禁止硬编码密钥; - 接口容错:对接第三方接口增加超时、重试、熔断逻辑。
十、总结
- 插件分渠道、模型提供商、通用功能三大类,运行在 Gateway 主进程;
openclaw.plugin.json是插件身份与配置核心,缺一不可;- 依托生命周期钩子管理插件启停、配置变更、健康状态;
- 内置日志、配置、存储、事件四大运行时 API,满足大部分开发场景;
- 本地通过目录挂载调试,编译后可发布至 ClawHub 共享;
- 开发务必重视异常处理与资源释放,保障网关整体稳定性。
基于这套 SDK,你可以自由扩展 OpenClaw 的接入渠道与模型能力,实现个性化私有化部署。