一、插件整体架构与分类

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) {}
}

核心能力说明

  1. 消息上行:外部消息通过 emitMessage 推送给 Gateway;
  2. 消息下行:网关回复通过 sendMessage 发送到聊天平台;
  3. 媒体支持:原生支持图片、文件等附件分发;
  4. 生命周期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. 发布前检查

  1. 执行 pnpm build 确保代码编译正常;
  2. 完善 openclaw.plugin.json、README;
  3. 配置 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

九、开发最佳实践

  1. 异常捕获:所有异步逻辑必须加 try/catch,避免插件崩溃导致网关宕机;
  2. 资源回收onUnload 中关闭端口、定时器、长连接、轮询;
  3. 配置校验onLoad 阶段检查必填配置,缺失直接抛出明确提示;
  4. 日志规范:统一使用 this.logger,禁止原生 console
  5. 类型约束:全程使用 TypeScript 强类型,减少线上 BUG;
  6. 密钥安全:敏感配置标记 secret: true,禁止硬编码密钥;
  7. 接口容错:对接第三方接口增加超时、重试、熔断逻辑。

十、总结

  1. 插件分渠道、模型提供商、通用功能三大类,运行在 Gateway 主进程;
  2. openclaw.plugin.json 是插件身份与配置核心,缺一不可;
  3. 依托生命周期钩子管理插件启停、配置变更、健康状态;
  4. 内置日志、配置、存储、事件四大运行时 API,满足大部分开发场景;
  5. 本地通过目录挂载调试,编译后可发布至 ClawHub 共享;
  6. 开发务必重视异常处理与资源释放,保障网关整体稳定性。

基于这套 SDK,你可以自由扩展 OpenClaw 的接入渠道与模型能力,实现个性化私有化部署。