OpenClaw 入门指南 – OG_023|OpenClaw 插件开发实战:从 0 到 1 写一个天气查询插件

作者:Alex 合集:OpenClaw 入门指南 第 023 篇 标签:#OpenClaw #插件开发 #Node.js #教程 #实战
开篇:插件是什么?为什么要学?
用 OpenClaw 三个月,我发现一个规律:
凡是重复做 3 次以上的事,都应该写个插件。
比如每天查天气决定穿什么、定时备份配置文件、批量处理图片……这些事原本要手动敲命令或者写脚本,但写成插件后,一个命令就能搞定,还能分享给其他人用。
插件就是 OpenClaw 的”外挂”——官方没提供的功能,你自己造。
写插件比写独立脚本爽多了,因为 OpenClaw 已经帮你搭好了框架:配置管理、权限控制、日志记录、错误处理,你只需要写核心逻辑。
今天这篇,手把手教你从 0 到 1 写一个天气查询插件,完整走一遍开发、调试、发布全流程。
看完这篇,你就能给 OpenClaw 写任何你想要的扩展功能。
第一章:插件开发基础——先搞清楚架构
1.1 插件是什么?
OpenClaw 插件 = 一个带配置文件的 Node.js 模块。
它长这样:
my-plugin/
├── SKILL.md # 插件说明文档
├── src/
│ └── index.ts # 入口文件(核心逻辑)
├── config/
│ └── schema.json # 配置参数定义
├── package.json # 依赖管理
└── tsconfig.json # TypeScript 配置
核心概念:
- • SKILL.md:告诉 OpenClaw 这个插件是干嘛的、怎么用
- • src/index.ts:插件的核心代码,导出功能函数
- • config/schema.json:定义用户可以配置哪些参数(比如 API Key)
1.2 插件能做什么?
| 能力 | 说明 | 示例 |
|---|---|---|
| 调用外部 API | HTTP 请求获取数据 | 查天气、查股价 |
| 文件操作 | 读写本地文件 | 备份配置、生成报告 |
| 系统命令 | 执行 shell 命令 | 系统监控、批量处理 |
| 数据转换 | 格式化、解析 | JSON 转 CSV、Markdown 转 HTML |
| 集成第三方服务 | 调用 SDK | 飞书通知、微信推送 |
1.3 开发环境准备
# 1. 确认 Node.js 版本(需要 18+)
node --version
# 2. 确认 OpenClaw CLI 已安装
openclaw --version
# 3. 创建插件开发目录
mkdir -p ~/.agents/skills/my-first-plugin
cd ~/.agents/skills/my-first-plugin
# 4. 初始化项目
npm init -y
npm install typescript @types/node --save-dev
npx tsc --init
验证环境:
# 应该能看到版本号,不是"command not found"
which openclaw
node --version # v18.x.x 或更高
第二章:实战——开发天气查询插件
2.1 需求分析
我们要做一个这样的插件:
# 查询北京天气
openclaw run weather --city 北京
# 输出:
# 🌤️ 北京今日天气
# 温度:22°C / 15°C
# 天气:多云转晴
# 空气质量:良
# 建议:适合户外活动,记得涂防晒
技术方案:
- • 调用高德天气 API(免费额度够个人用)
- • 支持命令行参数
--city - • 返回格式化后的天气信息
2.2 创建插件结构
mkdir -p ~/.agents/skills/weather-query-plugin/{src,config}
cd ~/.agents/skills/weather-query-plugin
创建 SKILL.md:
# Weather Query Plugin
查询指定城市的实时天气。
## 用法
```bash
openclaw run weather --city <城市名>
配置
在 ~/.openclaw/config.json 中添加:
{
"plugins": {
"weather": {
"apiKey": "你的高德API Key"
}
}
}
数据来源
高德地图天气 API(https://lbs.amap.com)
### 2.3 编写核心代码
创建 `src/index.ts`:
```typescript
import { execSync } from 'child_process';
interface WeatherConfig {
apiKey: string;
defaultCity?: string;
}
interface WeatherResult {
city: string;
temperature: string;
weather: string;
humidity: string;
wind: string;
airQuality: string;
advice: string;
}
export async function queryWeather(city: string, config: WeatherConfig): Promise<string> {
// 1. 参数校验
if (!config.apiKey) {
throw new Error('缺少 API Key,请在配置文件中设置 plugins.weather.apiKey');
}
if (!city) {
city = config.defaultCity || '北京';
}
// 2. 调用高德 API(这里用 curl 演示,实际可用 axios)
const apiUrl = `https://restapi.amap.com/v3/weather/weatherInfo?key=${config.apiKey}&city=${encodeURIComponent(city)}`;
try {
const response = execSync(`curl -s "${apiUrl}"`, { encoding: 'utf-8' });
const data = JSON.parse(response);
if (data.status !== '1') {
throw new Error(`API 错误:${data.info}`);
}
const weather = data.lives[0];
// 3. 格式化输出
return formatWeather({
city: weather.city,
temperature: `${weather.temperature}°C`,
weather: weather.weather,
humidity: `${weather.humidity}%`,
wind: `${weather.winddirection}风 ${weather.windpower}级`,
airQuality: '待查询', // 高德免费版不包含空气质量
advice: getWeatherAdvice(weather.weather, parseInt(weather.temperature))
});
} catch (error) {
throw new Error(`查询天气失败:${error.message}`);
}
}
function formatWeather(result: WeatherResult): string {
return `
🌤️ ${result.city} 实时天气
━━━━━━━━━━━━━━━━━━━━
🌡️ 温度:${result.temperature}
☁️ 天气:${result.weather}
💧 湿度:${result.humidity}
🌬️ 风力:${result.wind}
🫁 空气:${result.airQuality}
━━━━━━━━━━━━━━━━━━━━
💡 建议:${result.advice}
`.trim();
}
function getWeatherAdvice(weather: string, temp: number): string {
if (weather.includes('雨')) {
return '记得带伞,路面湿滑注意安全';
} else if (weather.includes('雪')) {
return '注意保暖,穿防滑鞋';
} else if (temp > 30) {
return '高温预警,多喝水避免中暑';
} else if (temp < 5) {
return '天气寒冷,注意保暖';
} else {
return '天气不错,适合户外活动';
}
}
2.4 配置参数定义
创建 config/schema.json:
{
"type": "object",
"properties": {
"apiKey": {
"type": "string",
"description": "高德地图 API Key",
"required": true
},
"defaultCity": {
"type": "string",
"description": "默认查询城市",
"default": "北京"
}
}
}
2.5 编译配置
tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*"]
}
package.json:
{
"name": "weather-query-plugin",
"version": "1.0.0",
"description": "OpenClaw 天气查询插件",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
},
"keywords": ["openclaw", "plugin", "weather"],
"author": "Alex",
"license": "MIT"
}
第三章:调试与测试
3.1 本地测试流程
# 1. 编译插件
cd ~/.agents/skills/weather-query-plugin
npm run build
# 2. 配置 API Key
openclaw config set plugins.weather.apiKey "你的高德APIKey"
# 3. 运行测试
openclaw run weather --city 上海
3.2 常见问题排查
| 问题 | 原因 | 解决 |
|---|---|---|
API Key 无效 |
Key 未配置或错误 | 检查 openclaw config get plugins.weather.apiKey |
城市不存在 |
城市名不匹配 | 用标准城市名,如”北京市”而非”北京” |
网络超时 |
API 请求失败 | 检查网络,或增加超时参数 |
编译错误 |
TypeScript 语法问题 | 检查 tsc 输出,修复类型错误 |
3.3 调试技巧
# 开启详细日志
openclaw run weather --city 北京 --verbose
# 查看插件加载状态
openclaw plugins list
# 测试配置是否正确
openclaw config get plugins.weather
第四章:发布与分享
4.1 打包插件
# 1. 确保编译成功
npm run build
# 2. 检查文件完整性
ls -la dist/
# 应该看到 index.js 和 index.d.ts
# 3. 创建发布包
mkdir -p release
cp -r dist/ config/ SKILL.md package.json release/
cd release && tar czvf weather-query-plugin-v1.0.0.tar.gz *
4.2 提交到插件市场
OpenClaw 插件市场接受 GitHub 仓库链接:
# 1. 创建 GitHub 仓库(假设叫 weather-query-plugin)
# 2. 推送代码
git init
git add .
git commit -m "feat: 天气查询插件 v1.0.0"
git remote add origin https://github.com/yourname/weather-query-plugin.git
git push -u origin master
4.3 用户安装指南
# 方式 1:从 GitHub 安装
openclaw plugin install https://github.com/yourname/weather-query-plugin
# 方式 2:本地安装
openclaw plugin install ~/.agents/skills/weather-query-plugin
# 配置 API Key
openclaw config set plugins.weather.apiKey "用户自己的Key"
第五章:进阶——让插件更专业
5.1 添加缓存机制
避免每次查询都调用 API(免费额度有限):
// 简单内存缓存(5分钟)
const cache = new Map<string, { data: string; time: number }>();
const CACHE_TTL = 5 * 60 * 1000; // 5分钟
export async function queryWeather(city: string, config: WeatherConfig): Promise<string> {
const cacheKey = city;
const cached = cache.get(cacheKey);
if (cached && Date.now() - cached.time < CACHE_TTL) {
return cached.data + '\n\n[缓存数据]';
}
const result = await fetchWeather(city, config);
cache.set(cacheKey, { data: result, time: Date.now() });
return result;
}
5.2 添加错误重试
async function fetchWithRetry(url: string, maxRetries = 3): Promise<string> {
for (let i = 0; i < maxRetries; i++) {
try {
return execSync(`curl -s "${url}"`, { encoding: 'utf-8', timeout: 10000 });
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise(r => setTimeout(r, 1000 * (i + 1))); // 指数退避
}
}
throw new Error('重试耗尽');
}
5.3 添加多城市支持
# 批量查询
openclaw run weather --cities 北京,上海,广州,深圳
export async function queryMultipleCities(cities: string[], config: WeatherConfig): Promise<string> {
const results = await Promise.all(
cities.map(city => queryWeather(city, config).catch(e => `${city}: 查询失败`))
);
return results.join('\n\n');
}
第六章:实战检查清单
开发前准备
- • [ ] Node.js 18+ 已安装
- • [ ] OpenClaw CLI 已安装
- • [ ] 高德 API Key 已申请(https://lbs.amap.com)
开发过程
- • [ ] 插件目录结构正确
- • [ ] SKILL.md 文档完整
- • [ ] 核心逻辑代码编写完成
- • [ ] 配置参数定义完成
- • [ ] TypeScript 编译通过
测试验证
- • [ ] 本地运行测试通过
- • [ ] 错误处理测试通过
- • [ ] 配置读取测试通过
- • [ ] 缓存机制测试通过
发布准备
- • [ ] 代码推送到 GitHub
- • [ ] README 安装说明完整
- • [ ] 版本号遵循语义化(v1.0.0)
- • [ ] 开源协议已选择(MIT)
结尾:插件开发的核心心法
写完这个天气插件,你会发现 OpenClaw 插件开发就三件事:
1. 定义好输入输出 —— 用户给什么参数,返回什么格式 2. 处理好异常情况 —— API 挂了、参数错了、网络断了都要优雅处理\ 3. 写好文档 —— SKILL.md 就是插件的说明书,写清楚别人才能用
2021 年上岸的程序员最后送你一句话:
好插件的标准不是功能多复杂,而是别人拿过来就能用,用了不出错。
现在,去写你的第一个插件吧。
📌 行动清单
- • [ ] 申请高德天气 API Key
- • [ ] 按本文步骤创建天气查询插件
- • [ ] 测试北京、上海、广州三个城市的查询
- • [ ] 给插件添加缓存机制(5分钟)
- • [ ] 把插件推送到 GitHub 并分享给朋友
👇 互动话题
你打算用 OpenClaw 插件解决什么问题?评论区聊聊~
如果这篇文章对你有帮助,欢迎「在看」+「转发」给需要的朋友
夜雨聆风