"创建第一个 Skill"
龙虾学堂2026年5月7日
"从零开始创建 OpenClaw Skill:掌握 SKILL.md 编写规范和工具函数实现,让你的 Agent 拥有自定义能力。"
创建第一个 Skill
本文聚焦:SKILL.md 编写规范 + 工具函数实现
知识点 1:SKILL.md 编写规范
是什么
SKILL.md 是 Skill 的核心定义文件,它用 Markdown 格式描述 Skill 的功能、工具、使用场景和注意事项。Agent 通过读取 SKILL.md 来理解何时以及如何使用这个 Skill。
为什么需要规范
规范的 SKILL.md 能让 Agent:
- 准确理解 Skill 的用途和触发条件
- 正确使用 工具,避免参数错误
- 处理异常 情况,知道何时该放弃或重试
- 提供示例 供用户参考
标准结构模板
# Skill 名称
## 描述
一句话说明这个 Skill 是做什么的。
## 适用场景
- 场景 1:具体描述
- 场景 2:具体描述
## 工具清单
### tool_name_1
详细描述这个工具的作用。
**参数:**
- `param1` (string, 必需): 参数说明
- `param2` (number, 可选): 参数说明,默认值:xxx
**返回值:**
- 成功:返回什么
- 失败:返回什么
**示例:**
```json
{
"tool": "tool_name_1",
"arguments": {
"param1": "value",
"param2": 123
}
}
tool_name_2
...
注意事项
- 注意点 1
- 注意点 2
权限声明
read: 读取文件exec: 执行命令
### 关键字段详解
#### 1. 描述(Description)
**要求**:简洁、准确、包含关键词
❌ 差示例:"这是一个很有用的工具"
✅ 好示例:"将文本转换为语音并自动播放,支持 ElevenLabs 和 OpenAI TTS 服务"
#### 2. 适用场景(Use Cases)
**要求**:列出 2-5 个具体场景,帮助 Agent 判断何时调用
```markdown
## 适用场景
- 用户说"播放这段文字"或"读给我听"
- 需要为故事、新闻摘要添加语音效果
- 生成播客或语音消息内容
3. 工具参数定义
参数类型标记:
(string, 必需)- 必须提供(number, 可选)- 可选,需注明默认值(boolean, 可选)- 布尔值,默认 false(array, 必需)- 数组类型(object, 可选)- 对象类型
示例:
**参数:**
- `text` (string, 必需): 要转换为语音的文本内容
- `voice` (string, 可选): 语音类型,可选值:"nova" | "echo" | "onyx",默认:"nova"
- `speed` (number, 可选): 语速倍数,范围 0.5-2.0,默认:1.0
4. 示例代码块
要求:提供完整、可运行的示例
**示例:**
```json
{
"tool": "tts",
"arguments": {
"text": "你好,这是测试语音",
"voice": "nova",
"speed": 1.0
}
}
### 常见陷阱
**陷阱 1:参数描述模糊**
❌ 错误:
```markdown
**参数:**
- `input`: 输入内容
- `mode`: 模式
✅ 正确:
**参数:**
- `input` (string, 必需): 要处理的文本内容,最大长度 4000 字符
- `mode` (string, 可选): 处理模式,可选值:"fast" | "accurate",默认:"fast"
陷阱 2:缺少错误处理说明
❌ 错误:只写成功示例
✅ 正确:包含错误场景
**返回值:**
- 成功:`{ "success": true, "url": "https://..." }`
- 失败:`{ "success": false, "error": "Rate limit exceeded" }`
**常见错误:**
- 429: 请求频率过高,请等待 60 秒后重试
- 400: 文本内容为空或超过长度限制
陷阱 3:权限声明不完整
❌ 错误:完全不提权限
✅ 正确:明确声明
## 权限声明
本 Skill 需要以下权限:
- `read`: 读取配置文件 `~/.config/my-skill/config.json`
- `exec`: 执行系统命令 `curl` 进行网络请求
- `write`: 写入临时文件到 `/tmp/my-skill/`
知识点 2:工具函数实现
Skill 的执行方式
OpenClaw 支持两种 Skill 实现方式:
| 方式 | 说明 | 适用场景 |
|---|---|---|
| 纯 Markdown | 仅 SKILL.md,无代码 | 文档型 Skill、知识库 |
| Markdown + 脚本 | SKILL.md + scripts/ 目录 | 需要执行逻辑的 Skill |
脚本目录结构
my-skill/
├── SKILL.md # 技能定义
├── scripts/
│ ├── main.py # 主入口(可选)
│ ├── utils.py # 工具函数
│ └── config.json # 配置文件
└── references/
└── api-docs.md # 参考资料
实战示例:创建一个天气查询 Skill
步骤 1:创建目录
mkdir -p ~/.openclaw/skills/weather-query/scripts
cd ~/.openclaw/skills/weather-query
步骤 2:编写 SKILL.md
# 天气查询
## 描述
查询指定城市的实时天气信息,支持国内外主要城市。
## 适用场景
- 用户询问"今天天气怎么样"
- 需要获取某个城市的温度和天气状况
- 出行前查看目的地天气
## 工具清单
### get_weather
获取指定城市的实时天气数据。
**参数:**
- `city` (string, 必需): 城市名称,如"北京"、"Shanghai"
- `unit` (string, 可选): 温度单位,可选值:"celsius" | "fahrenheit",默认:"celsius"
**返回值:**
- 成功:返回天气对象
```json
{
"city": "北京",
"temperature": 25,
"condition": "晴",
"humidity": "45%",
"wind": "东南风 3级"
}
- 失败:返回错误信息
{ "error": "城市不存在或暂不支持" }
示例:
{
"tool": "get_weather",
"arguments": {
"city": "上海",
"unit": "celsius"
}
}
注意事项
- 城市名称支持中文和英文
- 部分偏远城市可能无法查询
- API 有频率限制,请勿频繁调用
权限声明
exec: 执行脚本查询天气 APIread: 读取本地城市代码映射表
#### 步骤 3:编写脚本
创建 `scripts/weather.py`:
```python
#!/usr/bin/env python3
import sys
import json
import urllib.request
import urllib.parse
def get_weather(city, unit="celsius"):
"""查询城市天气"""
try:
# 这里使用示例 API(实际开发需替换为真实天气 API)
encoded_city = urllib.parse.quote(city)
url = f"https://api.example.com/weather?city={encoded_city}&unit={unit}"
# 模拟 API 响应(实际开发中替换为真实请求)
# with urllib.request.urlopen(url, timeout=10) as response:
# data = json.loads(response.read().decode('utf-8'))
# 模拟数据
mock_data = {
"city": city,
"temperature": 25 if unit == "celsius" else 77,
"condition": "晴",
"humidity": "45%",
"wind": "东南风 3级",
"unit": unit
}
return {"success": True, "data": mock_data}
except Exception as e:
return {"success": False, "error": str(e)}
if __name__ == "__main__":
# 从命令行参数读取输入
if len(sys.argv) < 2:
print(json.dumps({"error": "缺少参数"}, ensure_ascii=False))
sys.exit(1)
# 解析参数
try:
params = json.loads(sys.argv[1])
city = params.get("city")
unit = params.get("unit", "celsius")
if not city:
print(json.dumps({"error": "city 参数不能为空"}, ensure_ascii=False))
sys.exit(1)
result = get_weather(city, unit)
print(json.dumps(result, ensure_ascii=False))
except json.JSONDecodeError:
print(json.dumps({"error": "参数格式错误,需要 JSON 格式"}, ensure_ascii=False))
sys.exit(1)
步骤 4:测试 Skill
# 给脚本添加执行权限
chmod +x scripts/weather.py
# 测试脚本
python3 scripts/weather.py '{"city": "北京", "unit": "celsius"}'
# 预期输出
{"success": true, "data": {"city": "北京", "temperature": 25, ...}}
步骤 5:重启 Gateway
openclaw gateway restart
重启后,Agent 就能识别并使用这个 Skill 了。
脚本编写最佳实践
1. 输入输出规范
# 输入:从命令行参数读取 JSON
params = json.loads(sys.argv[1])
# 输出:始终输出 JSON 到 stdout
print(json.dumps(result, ensure_ascii=False))
2. 错误处理
try:
result = do_something()
print(json.dumps({"success": True, "data": result}))
except Exception as e:
print(json.dumps({"success": False, "error": str(e)}))
sys.exit(1)
3. 超时处理
import socket
socket.setdefaulttimeout(30) # 全局超时 30 秒
# 或使用 urllib 的 timeout
urllib.request.urlopen(url, timeout=10)
常见陷阱
陷阱 1:脚本没有执行权限
❌ 错误:直接运行脚本提示 Permission denied
✅ 解决:
chmod +x scripts/*.py
陷阱 2:输出格式不统一
❌ 错误:有时输出字符串,有时输出 JSON
✅ 正确:始终输出 JSON 格式
# 错误
print("操作成功")
# 正确
print(json.dumps({"success": True, "message": "操作成功"}))
陷阱 3:中文编码问题
❌ 错误:输出中文显示为 \uXXXX
✅ 正确:使用 ensure_ascii=False
print(json.dumps(data, ensure_ascii=False))
实践建议
-
从简单开始
- 第一个 Skill 只做一件事,把它做好
- 不要一开始就追求复杂功能
-
充分测试
- 在本地反复测试脚本
- 模拟各种异常情况(网络失败、参数错误等)
-
文档先行
- 先写 SKILL.md,明确 Skill 要做什么
- 再写代码实现,避免方向偏离
-
版本管理
- 使用 Git 管理 Skill 代码
- 打标签标记稳定版本
-
分享与反馈
- 好用的 Skill 可以分享到 ClawHub
- 收集用户反馈持续改进
相关阅读
- 什么是 Skill —— Skill 基础概念和目录结构
- 安装 Skills —— 如何安装和管理 Skill
- 第一个 Agent —— Agent 基础概念
- 配置文件结构 —— 了解 Gateway 配置
创建 Skill 是扩展 OpenClaw 能力的核心方式。掌握 SKILL.md 规范和脚本实现,你就能为 Agent 赋予无限可能。
#["skill"#"开发"#"教程"]