从零开始:如何开发Skill并上传到ClawHub完整教程

一、什么是ClawHub和Skill?

ClawHub是OpenClaw官方维护的技能(Skill)注册中心,类似于AI智能体的"应用商店"。目前已有13000+ Skills,开发者可以在这里分享和安装各种可复用的自动化能力单元。

Skill到底是什么?

Skill是一个可插拔的任务指令集,它让AI Agent能够处理特定领域的任务。简单来说:

  • Tools(工具):决定Agent能不能做某类动作(如文件读写、网络请求)
  • Skills(技能):给Agent增加特定能力(如天气查询、代码审查、网络搜索)

每个Skill是一个文件夹,核心是​​SKILL.md​​文件,包含技能元数据和使用指令。

二、Skill的目录结构

一个标准的Skill目录结构如下:

复制代码
my-skill/
├── SKILL.md           # 必需:技能定义文件
├── scripts/           # 可选:可执行脚本
│   └── main.py
├── references/        # 可选:参考文档
│   └── api-docs.md
└── assets/            # 可选:静态资源
    └── template.html

核心文件说明:

  • ​SKILL.md​:技能的核心定义,包含YAML frontmatter和Markdown指令
  • ​scripts/​:存放可执行脚本(Python、Node.js等)
  • ​references/​:参考文档,按需加载
  • ​assets/​:模板、图标等静态资源

三、实战案例:开发一个天气查询Skill

让我们从零开始开发一个实用的天气查询Skill。

步骤1:创建目录结构
复制代码
mkdir -p weather-skill/{scripts,references,assets}
cd weather-skill
touch SKILL.md scripts/weather.py
步骤2:编写SKILL.md文件

​SKILL.md​​是Skill的灵魂,包含两部分:YAML frontmatter (元数据)和Markdown正文(指令)。

复制代码
---
name: weather-query
description: 查询任意城市的实时天气和未来7天预报。支持温度、湿度、天气状况等信息获取。
user-invocable: true
disable-model-invocation: false
metadata:
  openclaw:
    requires:
      bins:
        - python3
      env: []
homepage: https://open-meteo.com/
---

# 天气查询技能

## 功能说明

本技能可以查询全球任意城市的实时天气和未来天气预报。

## 使用方法

### 基本查询
```bash
python3 {baseDir}/scripts/weather.py 北京

高级查询

复制代码
python3 {baseDir}/scripts/weather.py 上海 --days 5 --format json

参数说明

|----------|--------|----|------------------------|
| 参数 | 类型 | 必填 | 说明 |
| city | string | 是 | 城市名称(中文或英文) |
| --days | int | 否 | 预报天数(1-7,默认1) |
| --format | string | 否 | 输出格式(text/json,默认text) |

输出示例

文本格式:

复制代码
北京天气:
  温度:22°C
  天气:晴
  湿度:45%
  更新时间:2026-04-08T10:30:00

JSON格式:

复制代码
{
  "city": "北京",
  "temperature": 22,
  "condition": "晴",
  "humidity": 45
}

相关文档

如需了解API详情,请读取:{baseDir}/references/api-docs.md

复制代码
### 步骤3:编写可执行脚本

创建`scripts/weather.py`文件:

```python
#!/usr/bin/env python3
"""
天气查询脚本
使用Open-Meteo API(免费,无需API Key)
"""

import argparse
import json
import requests
from datetime import datetime
import sys

# 天气代码映射
WEATHER_CODES = {
    0: "晴朗", 1: "主要晴朗", 2: "部分多云", 3: "多云",
    45: "雾", 48: "雾凇", 51: "轻度毛毛雨", 53: "中度毛毛雨",
    55: "重度毛毛雨", 61: "轻度雨", 63: "中度雨", 65: "大雨",
    71: "轻度雪", 73: "中度雪", 75: "大雪", 77: "雪粒",
    80: "轻度阵雨", 81: "中度阵雨", 82: "强阵雨",
    95: "雷暴", 96: "雷暴带轻度冰雹", 99: "雷暴带重度冰雹"
}

def geocode_city(city_name):
    """获取城市的经纬度"""
    url = "https://geocoding-api.open-meteo.com/v1/search"
    params = {
        "name": city_name,
        "count": 1,
        "language": "zh",
        "format": "json"
    }
    
    try:
        response = requests.get(url, params=params, timeout=10)
        data = response.json()
        
        if not data.get("results"):
            return None
        
        return {
            "latitude": data["results"][0]["latitude"],
            "longitude": data["results"][0]["longitude"],
            "name": data["results"][0]["name"]
        }
    except Exception as e:
        print(f"地理编码错误:{e}", file=sys.stderr)
        return None

def get_weather_data(lat, lon, days=1):
    """获取天气数据"""
    url = "https://api.open-meteo.com/v1/forecast"
    params = {
        "latitude": lat,
        "longitude": lon,
        "current": [
            "temperature_2m",
            "relative_humidity_2m",
            "weather_code",
            "wind_speed_10m"
        ],
        "daily": [
            "temperature_2m_max",
            "temperature_2m_min",
            "weather_code",
            "sunrise",
            "sunset"
        ],
        "timezone": "auto",
        "forecast_days": days
    }
    
    try:
        response = requests.get(url, params=params, timeout=10)
        response.raise_for_status()
        return response.json()
    except Exception as e:
        print(f"获取天气数据错误:{e}", file=sys.stderr)
        return None

def format_text_output(city, current, daily=None):
    """格式化文本输出"""
    output = []
    output.append(f"\n{city}天气:")
    output.append(f"  温度:{current['temperature_2m']}°C")
    output.append(f"  天气:{WEATHER_CODES.get(current['weather_code'], '未知')}")
    output.append(f"  湿度:{current['relative_humidity_2m']}%")
    output.append(f"  风速:{current['wind_speed_10m']} km/h")
    
    if daily:
        output.append("\n未来预报:")
        for i, day in enumerate(daily['time'])::
            max_temp = daily['temperature_2m_max'][i]
            min_temp = daily['temperature_2m_min'][i]
            condition = WEATHER_CODES.get(daily['weather_code'][i], '未知')
            output.append(f"  {day}: {min_temp}°C - {max_temp}°C {condition}")
    
    return "\n".join(output)

def format_json_output(city, current, daily=None):
    """格式化JSON输出"""
    result = {
        "city": city,
        "temperature": current['temperature_2m'],
        "condition": WEATHER_CODES.get(current['weather_code'], '未知'),
        "humidity": current['relative_humidity_2m'],
        "wind_speed": current['wind_speed_10m'],
        "update_time": datetime.now().isoformat()
    }
    
    if daily:
        result["forecast"] = []
        for i in range(len(daily['time'])):
            result["forecast"].append({
                "date": daily['time'][i],
                "max_temp": daily['temperature_2m_max'][i],
                "min_temp": daily['temperature_2m_min'][i],
                "condition": WEATHER_CODES.get(daily['weather_code'][i], '未知')
            })
    
    return json.dumps(result, ensure_ascii=False, indent=2)

def main():
    parser = argparse.ArgumentParser(description="天气查询工具")
    parser.add_argument("city", help="城市名称")
    parser.add_argument("--days", type=int, default=1, 
                       help="预报天数(1-7,默认1)")
    parser.add_argument("--format", choices=["text", "json"], 
                       default="text", help="输出格式")
    
    args = parser.parse_args()
    
    # 验证天数
    if args.days < 1 or args.days > 7:
        print("错误:预报天数必须在1-7之间", file=sys.stderr)
        sys.exit(1)
    
    # 地理编码
    print(f"正在查询 {args.city} 的天气...", file=sys.stderr)
    location = geocode_city(args.city)
    
    if not location:
        print(f"错误:找不到城市 '{args.city}'", file=sys.stderr)
        sys.exit(1)
    
    # 获取天气数据
    weather_data = get_weather_data(
        location["latitude"],
        location["longitude"],
        args.days
    )
    
    if not weather_data:
        print("错误:获取天气数据失败", file=sys.stderr)
        sys.exit(1)
    
    # 格式化输出
    if args.format == "json":
        output = format_json_output(
            location["name"],
            weather_data["current"],
            weather_data.get("daily")
        )
    else:
        output = format_text_output(
            location["name"],
            weather_data["current"],
            weather_data.get("daily")
        )
    
    print(output)

if __name__ == "__main__":
    main()
步骤4:添加依赖文件

创建​​requirements.txt​​(可选):

复制代码
requests>=2.28.0
步骤5:本地测试Skill
复制代码
# 安装依赖
pip install requests

# 测试基本功能
python3 scripts/weather.py 北京

# 测试JSON输出
python3 scripts/weather.py 上海 --days 3 --format json

# 测试错误处理
python3 scripts/weather.py 不存在的城市

预期输出:

复制代码
北京天气:
  温度:22°C
  天气:晴朗
  湿度:45%
  风速:12 km/h

四、上传Skill到ClawHub

方式一:直接上传文件夹(推荐新手)
第一步:准备上传文件

确保你的文件夹结构完整,只包含纯文本文件

复制代码
# 清理不必要的文件
cd weather-skill
rm -rf .git __pycache__ *.pyc

注意: ClawHub不接受二进制文件、图片等,只支持SKILL.md和纯文本文件。

第二步:访问ClawHub发布页面
  1. 打开浏览器访问:​https://clawhub.ai/import​
  2. 使用GitHub账号登录(如果没有账号,先注册)
第三步:填写发布表单

|------------------|---------------------|---------------------|
| 字段 | 填写说明 | 示例 |
| Slug | 技能的URL标识符(小写字母+短横线) | ​​weather-query​​ |
| Display name | 显示名称(支持中文) | ​​天气查询助手​​ |
| Version | 版本号(遵循语义化版本) | ​​1.0.0​​ |
| Tags | 版本标签(默认latest) | ​​latest​​ |

⚠️ 重要提示: Slug必须是小写字母+短横线,不能有大写字母!

第四步:上传文件夹
  1. 点击"Drop a folder"区域
  2. 选择你的​weather-skill​文件夹
  3. 系统会自动检测SKILL.md文件
第五步:处理验证

ClawHub会自动验证:

  • ✅ SKILL.md是否存在
  • ✅ frontmatter是否包含name和description
  • ✅ 文件是否为纯文本

常见错误及解决:

  • ​Slug must be lowercase​:改为全小写
  • ​Remove non-text files​:删除.git、LICENSE等非文本文件
  • ​SKILL.md not found​确保文件夹根目录有SKILL.md
第六步:确认许可证

默认使用MIT-0许可证(最宽松的开源许可证):

  • 允许任何人免费使用、修改和重新分发
  • 无需署名

勾选同意条款。

第七步:填写Changelog并发布
复制代码
Initial release of Weather Query Skill
- 支持全球城市天气查询
- 支持1-7天预报
- 支持文本和JSON输出格式

点击"Publish skill"按钮。

方式二:从GitHub导入(适合已有仓库)

如果你已将代码推送到GitHub:

复制代码
# 初始化Git仓库
cd weather-skill
git init
git add .
git commit -m "Initial commit"

# 创建GitHub仓库并推送
gh repo create weather-query --public --source=. --push

然后在ClawHub选择"Import from GitHub",输入仓库地址即可。

五、发布后的管理

查看你的Skill

发布成功后,可以访问:

复制代码
https://clawhub.ai/你的用户名/weather-query
用户如何安装

用户可以通过以下命令安装你的Skill:

复制代码
# 通过ClawHub CLI安装
clawhub install 你的用户名/weather-query

# 或使用OpenClaw命令
openclaw skills install 你的用户名/weather-query
更新Skill
  1. 修改SKILL.md或脚本
  2. 递增版本号(如1.0.0 → 1.1.0)
  3. 重新上传文件夹
  4. 填写更新说明

六、Skill开发最佳实践

1. 编写优质的description

​description​​字段是AI决定是否调用技能的唯一依据[[6]]:

❌ 不好的例子:

复制代码
description: 天气查询

✅ 好的例子:

复制代码
description: 查询任意城市的实时天气和未来7天预报。
           当用户询问天气、气温、预报、下雨、穿衣建议时使用。
           支持中文和英文城市名称。
2. 合理的错误处理
复制代码
# 缺少API Key时
if not api_key:
    print("错误:缺少API_KEY环境变量", file=sys.stderr)
    sys.exit(1)

# API请求失败
try:
    response = requests.get(url, timeout=10)
    response.raise_for_status()
except requests.exceptions.Timeout:
    print("错误:请求超时,请检查网络连接", file=sys.stderr)
    sys.exit(1)
3. 输出Markdown格式

AI Agent能更好地解析Markdown格式:

复制代码
print("## 天气报告")
print(f"- **城市**:{city}")
print(f"- **温度**:{temp}°C")
print(f"- **天气**:{condition}")
4. 使用{baseDir}变量

在SKILL.md中使用​​{baseDir}​​引用脚本路径,运行时会自动替换为实际路径:

复制代码
python3 {baseDir}/scripts/weather.py 北京

七、常见问题FAQ

Q1:Skill审核需要多久? A:ClawHub采用"无门槛发布"策略,无需审核,即时发布。

Q2:可以收费吗? A:可以,支持$1-99的定价策略。

Q3:如何测试Skill? A:使用OpenClaw的测试命令:

复制代码
openclaw skills check
openclaw skills info weather-query

Q4:Skill被标记为可疑怎么办? A:ClawHub通过标注机制区分可信与可疑技能,确保代码质量即可。

八、总结

开发并上传Skill到ClawHub的完整流程:

  1. 设计Skill:确定功能和触发条件
  2. 创建目录:准备SKILL.md和脚本
  3. 编写代码:实现核心功能
  4. 本地测试:确保功能正常
  5. 上传ClawHub:填写表单,发布技能
  6. 维护更新:根据反馈迭代

收益:

  • 分享你的专业知识
  • 帮助全球开发者
  • 可能获得收入(ClawHub支持付费Skill)
  • 提升个人技术影响力
相关推荐
handsomestWei3 小时前
【开源】从设计文档到可交付技术交底书:专利.Skill
开源·大模型·agent·skill·clawhub·skillhub
AlfredZhao12 小时前
Codex 和 OpenClaw,到底差在哪?
codex·skill·mcp·a2a·openclaw·harness
LucaJu18 小时前
Agent Skill 踩坑记录 | SpringBoot 打包后 Skill 加载失败问题排查与解决
agent·skill·spring ai·spring ai alibaba
熊猫钓鱼>_>19 小时前
AI驱动的Web应用智能化:WebMCP、WebSkills与WebAgent的融合实践
前端·人工智能·ai·skill·webagent·webmcp·webskills
minhuan3 天前
智能体构建:基于SKILL的AI智能体构建:模块化能力编排+实时交互系统全实现.136
人工智能·skill·构建ai智能体·skill详解·skill智能体构建
一个处女座的程序猿3 天前
Agent之skills:colleague-skill的简介、安装和使用方法、案例应用之详细攻略
agent·skill· llms·colleague-skill
夏沫の梦5 天前
Agent Skills技术详解与实战
人工智能·a·skill
:mnong5 天前
智能体技能使用指南
skill
:mnong5 天前
智能体快速构建指南
skill