OpenClaw 插件开发入门:创建你的第一个插件
OpenClaw 插件开发入门:创建你的第一个插件
想给 OpenClaw 添加新能力,但不知道从哪里下手?本文从插件(Plugin)和技能(Skill)的本质区别讲起,带你用 TypeScript 写一个真正的工具插件,发布到 npm,全流程实战。
你能学到什么?
-
✅ 彻底搞懂插件(Plugin)和技能(Skill)的区别 -
✅ 用 TypeScript 创建第一个 OpenClaw 插件 -
✅ 掌握插件清单(manifest)写法 -
✅ 注册自定义工具到 AI 助手 -
✅ 发布到 npm 并安装使用
插件和技能,到底有什么区别?
这是最常被问到的问题。先看对比:
| 插件(Plugin) | 技能(Skill) | |
|---|---|---|
| 本质 | 代码包,运行在 OpenClaw 进程内 | Markdown 指令文件,告诉 AI 怎么做 |
| 开发语言 | TypeScript / JavaScript | 纯 Markdown |
| 安装方式 | openclaw plugins install |
clawhub install |
| 能做什么 | 注册新工具、新渠道、新模型 provider | 指导 AI 在什么场景用什么已有工具 |
| 需要重启吗 | 是(重启网关) | 否(新会话自动加载) |
| 适用场景 | 需要底层扩展(接入新平台、LLM) | 提示词增强、工作流规范 |
简单说:技能是”说明书”,插件是”新能力”。当你需要让 OpenClaw 做到它本来做不到的事(比如接入一个它不支持的聊天平台),才需要写插件。
重要关系:插件可以打包技能(Ship Skills),让技能跟着插件一起分发。
插件能做什么?
OpenClaw 插件通过 api 对象暴露以下能力:
| 能力 | 方法 | 说明 |
|---|---|---|
| 注册工具 | api.registerTool() |
给 AI 添加新的可调用工具 |
| LLM 模型 | api.registerModelProvider() |
接入新的推理模型 |
| 消息渠道 | defineChannelPluginEntry |
接入新的聊天平台 |
| 事件钩子 | api.registerHook() |
拦截消息、响应等事件 |
| 服务 | api.registerService() |
注册后台常驻服务 |
本文聚焦最常见的场景:注册一个自定义工具。
环境准备
确保已安装:
node --version # 需要 Node >= 22
npm --version
创建一个新目录(以 @yourname/openclaw-demo-plugin 为例):
mkdir openclaw-demo-plugin && cd openclaw-demo-plugin
npm init -y
安装 OpenClaw 插件 SDK:
npm install openclaw
npm install -D @types/node typescript
Step 1:创建插件清单
每个插件必须有 openclaw.plugin.json,放在项目根目录:
{
"id": "demo-plugin",
"name": "Demo Plugin",
"description": "一个演示插件,包含自定义工具",
"version": "1.0.0",
"configSchema": {
"type": "object",
"properties": {
"greeting": {
"type": "string",
"description": "自定义问候语",
"default": "Hello"
}
},
"additionalProperties": false
}
}
id 必须全局唯一,建议用 kebab-case。configSchema 定义用户在配置文件中可以填哪些参数。
Step 2:配置 package.json
{
"name": "@yourname/openclaw-demo-plugin",
"version": "1.0.0",
"type": "module",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
},
"openclaw": {
"extensions": ["./dist/index.js"]
},
"dependencies": {
"openclaw": "^1.0.0"
},
"devDependencies": {
"@types/node": "^22.0.0",
"typescript": "^5.0.0"
}
}
关键是 openclaw.extensions,告诉 OpenClaw 从哪个文件加载插件。
Step 3:编写入口文件
创建 src/index.ts(或直接用根目录 index.ts):
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { Type } from "@sinclair/typebox";
export default definePluginEntry({
id: "demo-plugin",
name: "Demo Plugin",
description: "演示插件:自定义问候工具 + 随机名言工具",
register(api) {
// 注册第一个工具:自定义问候
api.registerTool({
name: "demo_greet",
description: "生成一段问候语,可指定名字和语言",
parameters: Type.Object({
name: Type.String({ description: "被问候者的名字" }),
lang: Type.Optional(
Type.String({ description: "语言,zh 或 en", default: "zh" })
),
}),
async execute(_id, params) {
const { name, lang = "zh" } = params;
const greeting =
lang === "en"
? `Hello, ${name}! Welcome to OpenClaw!`
: `你好,${name}!欢迎使用 OpenClaw!`;
return {
content: [{ type: "text", text: greeting }],
};
},
});
// 注册第二个工具:随机名言
api.registerTool({
name: "demo_quote",
description: "返回一条程序员名言",
parameters: Type.Type({}), // 无参数
async execute(_id) {
const quotes = [
"Talk is cheap. Show me the code. — Linus Torvalds",
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand. — Martin Fowler",
"First, solve the problem. Then, write the code. — John Johnson",
"Code is like humor. When you have to explain it, it's bad. — Cory House",
];
const random = quotes[Math.floor(Math.random() * quotes.length)];
return {
content: [{ type: "text", text: random }],
};
},
});
// 读取用户配置(来自 openclaw.plugin.json 的 configSchema)
const config = api.getConfig<{ greeting?: string }>();
if (config?.greeting) {
console.log(`[demo-plugin] 自定义问候语: ${config.greeting}`);
}
},
});
关键点解释:
-
definePluginEntry是非渠道插件的标准入口 -
api.registerTool()注册的工具,AI 在对话中可以直接调用 -
parameters使用@sinclair/typebox定义参数 schema(和 Zod 类似) -
execute函数返回符合 OpenClaw 工具格式的内容块 -
api.getConfig()读取用户在配置文件中填写的参数
Step 4:TypeScript 配置
创建 tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"outDir": "dist",
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Step 5:编译并测试本地
npm run build
编译成功后,dist/index.js 即为插件入口。
本地安装测试:
# 在插件目录执行
cd /path/to/openclaw-demo-plugin
openclaw plugins install ./
# 或者从 tarball 安装
npm pack
openclaw plugins install ./openclaw-demo-plugin-1.0.0.tgz
# 重启网关使插件生效
openclaw gateway restart
# 查看已安装插件
openclaw plugins list
Step 6:发布到 npm(可选)
# 登录 npm
npm login
# 发布(scoped 包需要确认组织权限)
npm publish --access public
发布后,其他人可以通过以下方式安装你的插件:
openclaw plugins install @yourname/openclaw-demo-plugin
openclaw gateway restart
OpenClaw 会优先从 ClawHub 查找,找不到则回退到 npm。
如何在对话中使用插件工具?
安装插件并重启网关后,直接告诉 AI:
“请用 demo_greet 工具问候一下小明”
或者:
“来一条程序员名言试试”
AI 会识别到 demo_greet 和 demo_quote 是可用的工具,自动调用并返回结果。
完整项目结构一览
openclaw-demo-plugin/
├── package.json
├── openclaw.plugin.json
├── tsconfig.json
└── src/
└── index.ts
什么时候用插件?什么时候用技能?
我需要 OpenClaw 接入一个新的聊天平台(Discord、Telegram...)
→ 写插件(Channel Plugin)
我需要 OpenClaw 支持一个新的大模型(某个国产模型)
→ 写插件(Provider Plugin)
我需要给 AI 添加一个新能力(搜索、绘图、发送邮件...)
→ 写插件(Tool Plugin)
我需要 AI 知道在什么场景用什么已有工具、怎么组织工作流
→ 写技能(Skill,SKILL.md)
我需要增强 AI 的提示词(比如"回复风格指南")
→ 写技能(Skill)
常见问题
插件安装后不生效?
必须重启网关:openclaw gateway restart。仅安装不重启,插件不会被加载。
工具参数怎么定义?
使用 @sinclair/typebox 的 Type.Object() 定义参数 schema,支持嵌套对象、枚举、默认值。和 Zod 的用法非常接近。
怎么调试插件?
在 register 函数里加 console.log,然后 openclaw gateway restart,查看网关日志:
openclaw gateway logs
可以同时注册多个工具吗?
可以。一个插件可以调用任意次 api.registerTool(),注册任意数量的工具。
总结
本文从插件和技能的本质区别出发,带你完整走了一遍插件开发流程:
-
建项目 — package.json+openclaw.plugin.json -
写代码 — definePluginEntry+registerTool -
编译发布 — npm run build→npm publish -
安装使用 — openclaw plugins install→/restart→ 对话中调用
插件是 OpenClaw 的能力边界,技能是 OpenClaw 的使用智慧。两者配合,才能让 AI 助手真正成为你的数字员工。
下期预告:OpenClaw 高级技能编写:工作流自动化 — 教你用 SKILL.md 构建可复用的工作流模板。
夜雨聆风