基础部署只是开始,真正的威力在于自定义技能。本文教你如何为 OpenClaw 开发专属技能,打造属于自己的 AI 助手生态。

🎯 你将学到什么

  • OpenClaw 技能系统架构
  • 如何开发自定义技能
  • 技能市场和分享
  • 实战案例:开发 5 个实用技能
  • 技能调试和测试
  • 发布到 Clawhub 技能市场

前置知识: 需要先阅读 OpenClaw 基础教程


一、OpenClaw 技能系统架构

1.1 什么是技能?

技能 = 工具 + 文档 + 配置

skill/
├── SKILL.md          # 技能文档(必需)
├── tools.py          # 工具实现(Python)
├── tools.js          # 工具实现(JavaScript)
├── config.yaml       # 配置文件(可选)
├── assets/           # 资源文件(可选)
└── examples/         # 示例代码(可选)

1.2 技能生命周期

┌─────────────────────────────────────┐
│         开发技能                     │
│    (编写 SKILL.md + tools)           │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│         测试技能                     │
│    (本地测试 + 调试)                 │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│         发布技能                     │
│    (上传到 Clawhub)                  │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│         使用技能                     │
│    (openclaw skills install)         │
└─────────────────────────────────────┘

二、开发第一个技能

2.1 需求分析

目标: 开发一个天气查询技能

功能:

  • 查询指定城市的天气
  • 支持多日天气预报
  • 自动识别用户位置

2.2 创建技能目录

# 创建技能目录
mkdir -p ~/.openclaw/workspace/skills/weather-pro
cd ~/.openclaw/workspace/skills/weather-pro

2.3 编写 SKILL.md

---
name: weather-pro
description: 专业天气查询技能,支持全球城市和多日预报
version: 1.0.0
author: 你的名字
tags: [weather, forecast, location]
---

# Weather Pro - 专业天气查询

专业的天气查询技能,支持全球城市和多日天气预报。

## 功能特性

- ✅ 查询当前天气
- ✅ 7 天天气预报
- ✅ 自动识别用户位置
- ✅ 支持全球主要城市
- ✅ 温度、湿度、风速等详细信息

## 工具列表

### get_current_weather

查询指定城市的当前天气。

**参数:**
- `city` (string, 必需): 城市名称(中文或英文)
- `unit` (string, 可选): 温度单位(celsius/fahrenheit),默认 celsius

**返回:**
```json
{
  "city": "北京",
  "temperature": 15,
  "unit": "celsius",
  "condition": "晴",
  "humidity": 45,
  "wind_speed": 12
}

示例:

用户: 北京今天天气怎么样?
助手: [调用 get_current_weather(city="北京")]
输出: 北京今天晴,温度 15°C,湿度 45%,风速 12 km/h

get_forecast

查询指定城市的多日天气预报。

参数:

  • city (string, 必需): 城市名称
  • days (int, 可选): 预报天数(1-7),默认 3

返回:

{
  "city": "北京",
  "forecast": [
    {
      "date": "2026-02-23",
      "temperature_high": 18,
      "temperature_low": 8,
      "condition": "多云"
    
  ]
}

示例:

用户: 北京未来三天天气
助手: [调用 get_forecast(city="北京", days=3)]
输出: 北京未来三天天气预报...

配置

API 密钥

本技能使用 OpenWeatherMap API,需要配置 API 密钥:

openclaw skills config weather-pro --api-key YOUR_API_KEY

获取 API 密钥:https://openweathermap.org/api

默认城市

可以设置默认城市,当用户未指定城市时使用:

openclaw skills config weather-pro --default-city 北京

使用示例

查询当前天气:

你: 今天天气怎么样?
AI: 北京今天晴,温度 15°C,适合出行。

查询其他城市:

你: 上海天气如何?
AI: 上海今天多云,温度 20°C,湿度较高。

查询天气预报:

你: 未来三天天气
AI: 北京未来三天天气预报:
    - 明天:晴,8-18°C
    - 后天:多云,10-20°C
    - 大后天:小雨,12-16°C

依赖

  • Python 3.8+
  • requests 库

安装

openclaw skills install weather-pro

许可证

MIT License


### 2.4 实现工具(tools.py)

```python
# tools.py

from langchain.tools import tool
from typing import Optional, Dict, List
import requests
import os

# 从环境变量或配置文件读取 API 密钥
API_KEY = os.getenv("OPENWEATHER_API_KEY", "")
BASE_URL = "https://api.openweathermap.org/data/2.5"

@tool
def get_current_weather(city: str, unit: str = "celsius") -> Dict:
    """
    查询指定城市的当前天气
    
    Args:
        city: 城市名称(中文或英文)
   unit: 温度单位(celsius/fahrenheit)
    
    Returns:
        天气信息字典
    """
    try:
        # 转换单位
        units = "metric" if unit == "celsius" else "imperial"
        
        # 调用 API
        url = f"{BASE_URL}/weather"
        params = {
            "q": city,
            "appid": API_KEY,
            "units": units,
            "lang": "zh_cn"
        }
        
        response = requests.get(url, params=params, timeout=10)
        response.raise_for_status()
        
        data = response.json()
        
        # 解析数据
      result = {
            "city": city,
            "temperature": round(data["main"]["temp"]),
            "unit": unit,
            "condition": data["weather"][0]["description"],
            "humidity": data["main"]["humidity"],
            "wind_speed": round(data["wind"]["speed"] * 3.6)  # m/s 转 km/h
        }
        
        return result
        
    except requests.exceptions.RequestException as e:
        return {
            "error": f"查询天气失败: {str(e)}",
            "city": city
        }
    except KeyError as e:
        return {
            "error": f"解析天气数据失败: {str(e)}",
            "city": city
        }

@tool
def get_forecast(city: str, days: int = 3) -> Dict:
    """
    查询指定城市的多日天气预报
    
    Args:
        city: 城市名称
        days: 预报天数(1-7)
    
    Returns:
        天气预报列表
    """
    try:
        # 限制天数
        days = max(1, min(days, 7))
        
        # 调用 API
        url = f"{BASE_URL}/forecast"
        params = {
            "q": city,
            "appid": API_KEY,
            "units": "metric",
            "lang": "zh_cn",
            "cnt": days * 8  # 每天 8 个时间点
        }
        
        response = requests.get(url, params=params, timeout=10)
        response.raise_for_status()
        
        data = response.json()
        
        # 按天分组
        forecast_by_day = {}
        for item in data["list"]:
            date = item["dt_txt"].split()[0]
            
            if date not in forecast_by_day:
                forecast_by_day[date] = {
                    "date": date,
                    "temperatures": [],
                    "conditions": []
                }
            
            forecast_by_day[date]["temperatures"].atem["main"]["temp"])
            forecast_by_day[date]["conditions"].append(item["weather"][0]["description"])
        
        # 计算每天的最高/最低温度和主要天气
        forecast = []
        for date, day_data in list(forecast_by_day.items())[:days]:
            temps = day_data["temperatures"]
            forecast.append({
                "date": date,
                "temperature_high": round(max(temps)),
                "temperature_low": round(min(temps)),
                "condition": max(set(day_data["conditions"]), key=day_data["conditions"].count)
            })
        
        return {
            "city": city,
            "forecast": forecast
        }
        
    except requests.exceptions.RequestException as e:
        return {
            "error": f"查询天气预报失败: {str(e)}",
            "city": city
        }
    except (KeyError, IndexError) as e:
        return {
            "error": f"解析天气预报数据失败: {str(e)}",
            "city": city
        }

# 导出工具列表
tools = [get_current_weather, get_forecast]

2.5 创建配置文件(config.yaml)

# config.yaml

# 技能元数据
metadata:
  name: weather-pro
  version: 1.0.0
  aut  description: 专业天气查询技能

# 配置项
config:
  api_key:
    type: string
    required: true
    description: OpenWeatherMap API 密钥
    env: OPENWEATHER_API_KEY
  
  default_city:
    type: string
    required: false
    default: 北京
    description: 默认城市

# 依赖
dependencies:
  python:
    - requests>=2.28.0

# 权限
permissions:
  - network  # 需要网络访问权限

三、测试技能

3.1 本地测试

# 进入技能目录
cd ~/.openclaw/workspace/skills/weather-pro

# 测试工具
python3 -c "
from tools import get_current_weather, get_forecast

# 测试当前天气
print(get_current_weather.invoke({'city': '北京'}))

# 测试天气预报
print(get_forecast.invoke({'city': '北京', 'days': 3}))
"
n
### 3.2 集成测试

```bash
# 重启 Gateway
openclaw gateway restart

# 在聊天中测试
你: 北京今天天气怎么样?
AI: [调用 weather-pro 技能]
    北京今天晴,温度 15°C,湿度 45%,风速 12 km/h

3.3 调试技巧

启用详细日志:

# 编辑 config.yaml
logging:
  level: debug  # info → debug

# 重启 Gateway
openclaw gateway restart

# 查看日志
tail -f ~/.openclaw/logs/openclaw.log

使用 Python 调试器:

# 在 tools.py 中添加断点
import pdb

@tool
def get_current_weather(city: str, unit: str = "celsius") -> Dict:
    pdb.set_trace()  # 断点
    # ... 代码

四、更多实战案例

4.1 案例 1:GitHub 集成技能

功能:

  • 创建 issue
  • 查看 PR
  • 合并代码

SKILL.md 片段:

### create_issue

创建 GitHub issue

**参数:**
- `repo` (string): 仓库名称(格式:owner/repo)
- `title` (string): Issue 标题
- `body` (string): Issue 内容

**示例:**

用户: 在 myrepo 创建一个 issue,标题是"修复登录 bug"
助手: [调用 create_issue(repo=“username/myrepo”, title=“修复登录 bug”, body=“…”)]

tools.py 片段:

from github import Github
import os

GITHUB_TOKEN = os.getenv("GITHUB_TOKEN", "")
g = Github(GITHUB_TOKEN)

@tool
def create_issue(repo: str, title: str, body: str = "") -> Dict:
    """创建 GitHub issue"""
    try:
        repository = g.get_repo(repo)
        issue = repository.create_issue(title=title, body=body)
        
        return {
            "status": "success",
            "issue_number": issue.number,
            "url": issue.html_url
        }
    except Exception as e:
        return {
            "status": "error",
            "message": str(e)
        }

tools = [create_issue]

4.2 案例 2:数据库查询技能

功能:

  • 执行 SQL 查询
  • 导出数据
  • 数据统计

tools.py 片段:

import psycopg2
import os

DATABASE_URL = ov("DATABASE_URL", "")

@tool
def query_database(sql: str, limit: int = 100) -> Dict:
    """
    执行 SQL 查询
    
    Args:
        sql: SQL 查询语句
        limit: 返回结果数量限制
    
    Returns:
        查询结果
    """
    try:
        conn = psycopg2.connect(DATABASE_URL)
        cursor = conn.cursor()
        
        # 添加 LIMIT
        if "LIMIT" not in sql.upper():
            sql += f" LIMIT {limit}"
        
        cursor.execute(sql)
        results = cursor.fetchall()
        columns = [desc[0] for desc in cursor.description]
        
        cursor.close()
        conn.close()
        
        return {
            "status": "success",
            "columns": columns,
            "rows": results,
            "count": len(results)
        }
        
    except Exception as e:
        return {
            "status": "error",
            "message": str(e)
        }

tools = [query_database]

4.3 案例 3:文件处理技能

功能:

  • 读取文件
  • 搜索文件
  • 批量重命名

tools.py 片段:

import os
import glob
from pathlib import Path

@tool
def search_files(pattern: str, directory: str = ".") -> List[str]:
    """
    搜索文件
    
    Args:
        pattern: 文件名模式(支持通配符)
        directory: 搜索目录
    
    Returns:
  列表
    """
    try:
        search_path = os.path.join(directory, "**", pattern)
        files = glob.glob(search_path, recursive=True)
        
        return {
            "status": "success",
            "files": files,
            "count": len(files)
        }
        
    except Exception as e:
        return {
            "status": "error",
            "message": str(e)
        }

@tool
def batch_rename(directory: str, old_pattern: str, new_pattern: str) -> Dict:
    """
    批量重命名文件
    
    Args:
        directory: 目录路径
        old_pattern: 旧文件名模式
        new_pattern: 新文件名模式
    
    Returns:
        重命名结果
    """
    try:
        renamed = []
        
        for file_path in Path(directory).glob(old_pattern):
            new_name = file_path.name.replace(old_pattern.replace("*", ""), new_pattern)
            new_path = file_path.parent / new_name
            
            file_path.rename(new_path)
            renamed.append({
                "old": str(file_path),
                "new": str(new_path)
            })
        
        return {
            "status": "success",
            "renamed": renamed,
            "count": len(renamed)
        }
        
    except Exception as e:
        return {
            "status": "error",
            "message": str(e)
        }

tools = [search_files, batch_rename]

4.4 案例 4:邮件自动化技能

功能:

  • 发送邮件
  • 搜索邮件
  • 自动分类

tools.py 片段:

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import os

SMTP_SERVER = os.getenv("SMTP_SERVER", "smtp.gmail.com")
SMTP_PORT = int(os.getenv("SMTP_PORT", "587"))
SMTP_USER = os.getenv("SMTP_USER", "")
SMTP_PASSWORD = etenv("SMTP_PASSWORD", "")

@tool
def send_email(to: str, subject: str, body: str, cc: str = "") -> Dict:
    """
    发送邮件
    
    Args:
        to: 收件人邮箱
        subject: 邮件主题
        body: 邮件正文
        cc: 抄送(可选)
    
    Returns:
        发送结果
    """
    try:
        msg = MIMEMultipart()
        msg['From'] = SMTP_USER
        msg['To'] = to
        msg['Subject'] = subject
        
        if cc:
            msg['Cc'] = cc
        
        msg.attach(MIMEText(body, 'plain'))
        
        server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
        server.starttls()
        server.login(SMTP_USER, SMTP_PASSWORD)
        
        recipients = [to]
        if cc:
            recipients.extend(cc.split(','))
        
        server.send_message(msg)
        server.quit()
        
        return {
            "status": "success",
            "to": to,
            "subject": subject
        }
        
    except Exception as e:
        return {
            "status": "error",
            "message": str(e)
        }

tools = [send_email]

4.5 案例 5:定时提醒技能

功能:

  • 创建提醒
  • 查看提醒
  • 删除提醒

tools.py 片段:

import json
import os
from datetime import datetime
from typing import List, Dict

REMINDERS_FILE = os.path.expanduser("~/.openclaw/reminders.json")

def load_reminders() -> List[Dict]:
    """加载提醒列表"""
    if os.path.exists(REMINDERS_FILE):
        with open(REMINDERS_FILE, 'r') as f:
            return json.load(f)
    return []

def save_reminders(reminders: List[Dict]):
    """保存提醒列表"""
    os.makedirs(os.path.dirname(REMINDERS_FILE), exist_ok=True)
    with open(REMINDERS_FILE, 'w') as f:
        json.dump(reminders, f, indent=2, ensure_ascii=False)

@tool
def create_reminder(title: str, time: str, description: str = "") -> Dict:
    """
    创建提醒
    
    Args:
        title: 提醒标题
        time: 提醒时间(格式:YYYY-MM-DD HH:MM)
        description: 提醒描述(可选)
    
    Returns:
        创建结果
    """
    try:
        # 验证时间格式
        datetime.strptime(time, "%Y-%m-%d %H:%M")
        
        reminders = load_reminders()
        
        reminder = {
            "id": len(reminders) + 1,
            "title": title,
            "time": time,
            "description": description,
            "created_at": datetime.now().isoformat(),
            "status": "pending"
        }
        
        reminders.append(reminder)
        save_reminders(reminders)
        
        return {
            "status": "success",
            "reminder": reminder
        }
        
    except ValueError as e:
        return {
            "status": "error",
            "message": f"时间格式错误: {str(e)}"
        }
    except Exception as e:
        return {
            "status": "error",
            "message": str(e)
        }

@tool
def list_reminders(status: str = "all") -> Dict:
    """
    查看提醒列表
    
    Args:
        status: 状态筛选(all/pending/completed)
    
    Returns:
        提醒列表
  
    try:
        reminders = load_reminders()
        
        if status != "all":
            reminders = [r for r in reminders if r["status"] == status]
        
        return {
            "status": "success",
            "reminders": reminders,
            "count": len(reminders)
        }
        
    except Exception as e:
        return {
            "status": "error",
            "message": str(e)
        }

tools = [create_reminder, list_reminders]

五、发布到 Clawhub

5.1 准备发布

检查清单:

  • SKILL.md 文档完整
  • 工具实现正确
  • 本地测试通过
  • 添加示例代码
  • 编写 README
  • 添加许可证

5.2 发布命令

# 登录 Clawhub
openclaw login

# 发布技能
openclaw skills publish weather-pro

# 输出:
# ✅ 技能已发布到 Clawhub
# 📦 技能名称:weather-pro
# 🔗 链接:https://clawhub.com/skills/weather-pro

5.3 更新技能

# 修改版本号(config.yaml)
version: 1.1.0

# 发布更新
openclaw skills publish weather-pro --version 1.1.0

六、技能最佳实践

6.1 文档规范

DO ✅:

  • 详细的功能说明
  • 清晰的参数说明
  • 丰富的使用示例
  • 配置说明
  • 依赖列表

DON’T ❌:

  • 文档过于简单
  • 缺少示例
  • 参数说明不清
  • 没有配置说明

6.2 代码规范

DO ✅:

  • 使用类型注解
  • 添加详细注释
  • 错误处理完善
  • 返回结构化数据
  • 遵循 PEP 8

DON’T ❌:

  • 没有错误处理
  • 返回非结构化文本
  • 代码混乱
  • 缺少注释

6.3 安全规范

DO ✅:

  • API 密钥使用环境变量
  • 输入验证
  • 权限检查
  • 敏感信息加密

DON’T ❌:

  • 硬编码密钥
  • 不验证输入
  • 忽略权限
  • 明文存储密码

七、常见问题

Q1: 技能开发用 Python 还是 JavaScript?

A: 都可以!

  • Python:适合数据处理、API 调用、机器学习
  • JavaScript:适合前端交互、Node.js 生态

Q2: 如何调试技能?

A: 三种方法:

  1. 单元测试(推荐)
  2. 启用 debug 日志
  3. 使用 Python/Node.js 调试器

Q3: 技能可以访问文件系统吗?

A: 可以,但需要:

  1. 在 config.yaml 声明权限
  2. 用户确认授权
  3. 限制访问范围

Q4: 如何分享技能?

A: 两种方式:

  1. 发布到 Clawhub(推荐)
  2. 分享 GitHub 仓库

八、总结

8.1 关键要点

  1. 技能 = 工具 + 文档 + 配置
  2. SKILL.md 是技能的核心
  3. 工具实现要健壮
  4. 测试很重要
  5. 发布到 Clawhub 让更多人受益

8.2 技能开发流程

需求分析 → 创建目录 → 编写文档 → 实现工具 → 测试 → 发布

8.3 下一步

  • 🛠️ 开发更多实用技能
  • 📦 发布到 Clawhub
  • 🌟 获得社区反馈
  • 🔄 持续迭代优化

九、资源链接

官方资源:

  • Clawhub:https://clawhub.com
  • 技能开发文档:https://docs.openclaw.ai/skills
  • 示例技能:https://github.com/openclaw/skills

社区:

  • Discord:https://discord.gg/openclaw
  • GitHub Discussions:https://github.com/openclaw/openclaw/discussions

🎉 结语

OpenClaw 的威力在于它的可扩展性。

通过开发自定义技能,你可以让 AI 助手做任何事情。

现在就开始,打造属于你的技能生态吧! 🚀


关注我,获取更多 OpenClaw 开发干货! 💪


如果觉得有帮助,欢迎点赞、收藏、转发! ❤️

有问题欢迎在评论区交流!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐