基于 7 个真实 Skill 案例的深度解析,从零到发布,手把手教你开发 OpenClaw Skill。
一、什么是 Skill?
Skill 是 OpenClaw 的核心扩展机制。通过编写一个 SKILL.md 文件,你就能教会 AI Agent 新的能力。
简单理解:
- Tool(工具) = Agent 的手脚(文件读写、Shell 执行、网络请求等通道)
- Skill(技能) = 加载到这些通道上的具体能力(搜索、查票、股票分析等)
Skill 的加载优先级(从高到低):
| 优先级 | 类型 | 路径 | 说明 |
|---|---|---|---|
| 1 | 工作区 Skill | ~/.openclaw/workspace/skills/ |
当前工作区专属 |
| 2 | 托管 Skill | ~/.openclaw/skills/ |
通过 ClawHub 安装的共享 Skill |
| 3 | 内置 Skill | 随 OpenClaw 分发 | 官方内置 |
二、Skill 的目录结构
每个 Skill 就是一个文件夹,核心是 SKILL.md:
perl
my-skill/
├── SKILL.md # 必须:技能定义文件(YAML frontmatter + Markdown 指令)
├── _meta.json # 可选:ClawHub 发布元数据
├── .clawhub/ # 可选:ClawHub 安装来源信息
│ └── origin.json
├── scripts/ # 可选:可执行脚本
├── references/ # 可选:参考文档(按需加载,不常驻上下文)
└── assets/ # 可选:模板、图标等静态资源
我们来看 7 个真实案例的目录结构对比:
| Skill | 目录结构 | 复杂度 |
|---|---|---|
| summarize | 仅 SKILL.md + _meta.json |
⭐ 最简单 --- 纯提示词 Skill |
| skill-vetter | 仅 SKILL.md + _meta.json |
⭐ 纯提示词 + 流程协议 |
| 12306-query | SKILL.md + scripts/query_tickets.py |
⭐⭐ 单脚本 Skill |
| tavily-search | SKILL.md + search.sh |
⭐⭐ 单脚本(Shell) |
| akshare-stock | SKILL.md + scripts/stock_cli.py |
⭐⭐ 单脚本 + 丰富 API 文档 |
| agent-browser | 仅 SKILL.md |
⭐⭐ 外部 CLI 工具封装 |
| firecrawl | SKILL.md + scripts/ × 3 + references/api.md |
⭐⭐⭐ 多脚本 + 参考文档 |
三、SKILL.md 的核心格式
SKILL.md 由两部分组成:YAML frontmatter(元数据) + Markdown body(指令正文)。
3.1 Frontmatter 字段详解
yaml
---
name: my-skill # 必须:技能标识符,小写字母+连字符
description: 技能描述... # 必须:AI 根据这个决定何时调用该技能
version: 1.0.0 # 可选:版本号
author: your-name # 可选:作者
user-invocable: true # 可选:是否可通过斜杠命令手动调用
disable-model-invocation: false # 可选:设为 true 则禁止 AI 自动触发
triggers: # 可选:触发关键词列表
- keyword1
- keyword2
metadata: # 可选:扩展元数据
openclaw:
requires:
env:
- MY_API_KEY # 需要的环境变量
bins:
- python # 需要的系统命令
---
最关键的字段是 description --- AI 完全依赖它来判断何时调用你的 Skill。
3.2 七个案例的 Frontmatter 对比分析
让我们看看 7 个真实 Skill 是怎么写 frontmatter 的:
案例 1:summarize(纯提示词 Skill)
yaml
---
name: summarize-pro
description: When user asks to summarize text, articles, documents, meetings,
emails, YouTube transcripts, books, PDFs, reports, conversations, or any
long content. Also handles bullet points, key takeaways, action items,
TL;DR, ELI5, executive summaries...
---
📌 分析:description 极其详尽,列举了所有可能的触发场景。这是纯提示词 Skill 的典型写法 --- 因为没有脚本,全靠 description 让 AI 知道"什么时候该用我"。
案例 2:12306-query(API 调用 Skill)
yaml
---
name: 12306-query
description: 中国铁路 12306 火车票余票查询。使用官方 API 查询车次、票价、余票信息。
支持按出发站/到达站/日期筛选。当用户需要查询火车票信息(余票、车次、票价、时刻表)时使用此技能。
---
📌 分析:description 用中文写,明确说明了"做什么"和"什么时候用"。最后一句"当用户需要查询火车票信息时使用此技能"是关键的触发条件描述。
案例 3:firecrawl(需要 API Key 的 Skill)
yaml
---
name: firecrawl
description: Web search and scraping via Firecrawl API. Use when you need to
search the web, scrape websites (including JS-heavy pages), crawl entire
sites, or extract structured data from web pages. Requires FIRECRAWL_API_KEY
environment variable.
---
📌 分析:在 description 中直接提到了环境变量依赖,让用户一眼就知道需要配置什么。
案例 4:tavily-search(带 triggers 的 Skill)
yaml
---
name: tavily-search-skill
description: Tavily API integration with real-time quota management and paid mode toggle.
version: 1.0.4
author: JayeGT002
triggers:
- tavily
- search
- web search
---
📌 分析:使用了
triggers字段列出触发关键词,这是除 description 之外的另一种触发机制。
案例 5:agent-browser(外部工具封装 Skill)
yaml
---
name: agent-browser
description: Headless browser automation CLI optimized for AI agents with
accessibility tree snapshots and ref-based element selection
metadata: {"clawdbot":{"emoji":"🌐","requires":{"commands":["agent-browser"]}}}
---
📌 分析:通过
metadata.requires.commands声明了外部依赖agent-browserCLI 工具。
四、五种 Skill 类型实战
类型 1:纯提示词 Skill(无脚本)
最简单的 Skill 类型,不需要任何脚本,完全通过 Markdown 指令引导 AI 行为。
代表案例:summarize(文本摘要)和 skill-vetter(安全审查)
summarize 的核心设计思路:
markdown
# Summarize Pro --- Your AI Summarization Engine
You are a powerful text summarizer...
## Examples
User: "summarize this: [pastes long article]"
User: "tldr: [pastes text]"
User: "eli5: quantum computing"
## FEATURE 1: Quick Summary (Default)
When user pastes text or says "summarize this":
1. Analyze the text length and content type
2. Produce a summary in the user's default format
📝 SUMMARY
━━━━━━━━━━━━━━━━━━
[3-5 bullet points capturing the main ideas]
📊 Stats: [X] words → [Y] words ([Z]% reduction)
这个 Skill 的精髓在于:
- 角色设定:开头就告诉 AI "You are a powerful text summarizer"
- 示例驱动:列出大量用户可能的输入方式
- 格式模板:为每种摘要类型定义了精确的输出格式
- 行为规则:明确的 Behavior Rules 约束 AI 行为
skill-vetter 则是另一种纯提示词模式 --- 流程协议型:
markdown
## Vetting Protocol
### Step 1: Source Check
- [ ] Where did this skill come from?
- [ ] Is the author known/reputable?
### Step 2: Code Review (MANDATORY)
🚨 REJECT IMMEDIATELY IF YOU SEE:
• curl/wget to unknown URLs
• Sends data to external servers
• Uses eval() or exec() with external input
...
### Step 3: Permission Scope
### Step 4: Risk Classification
它定义了一套完整的安全审查流程,AI 按步骤执行即可。
纯提示词 Skill 的开发要点:
- description 要尽可能详尽地列举触发场景
- 正文用清晰的结构化格式(标题、列表、表格)
- 提供输出模板,让 AI 的回复格式一致
- 设定明确的行为边界和规则
类型 2:单脚本 Skill(Python)
通过 Python 脚本调用外部 API,是最常见的 Skill 类型。
代表案例:12306-query(火车票查询)
核心脚本 scripts/query_tickets.py 的设计模式:
python
#!/usr/bin/env python3
"""12306 火车票余票查询脚本"""
# 1. 常量定义 --- API 地址和缓存数据
TICKET_QUERY_URL = "https://kyfw.12306.cn/otn/leftTicket/query"
COMMON_STATIONS = {
"北京": "BJP",
"上海": "SHH",
"广州": "GZQ",
# ...
}
# 2. 辅助函数 --- 站点编码查询
def get_station_code(station_name):
"""先查缓存,再查 API"""
if station_name in COMMON_STATIONS:
return COMMON_STATIONS[station_name]
# 从 12306 官方 JS 文件解析...
# 3. 核心函数 --- 调用 API 查询
def query_tickets(from_station, to_station, date):
from_code = get_station_code(from_station)
to_code = get_station_code(to_station)
session = requests.Session()
params = {
"leftTicketDTO.train_date": date,
"leftTicketDTO.from_station": from_code,
"leftTicketDTO.to_station": to_code,
"purpose_codes": "ADULT",
}
response = session.get(TICKET_QUERY_URL, params=params, headers=headers, timeout=10)
# 解析返回数据...
# 4. 格式化输出 --- 表格形式,AI 友好
def format_tickets(tickets):
print("{:<8} {:<10} {:<10} {:<8} ...".format(
"Train", "Depart", "Arrive", "Duration", ...))
for t in tickets:
print(...)
# 5. 命令行入口
def main():
if len(sys.argv) < 4:
print("用法:python query_tickets.py <出发站> <到达站> <日期>")
sys.exit(1)
# ...
if __name__ == "__main__":
main()
对应的 SKILL.md 中这样引导 AI 调用脚本:
markdown
## 快速开始
使用脚本查询余票:
```bash
python scripts/query_tickets.py <出发站> <到达站> <日期>
```
日期格式:YYYY-MM-DD(如 2026-04-01)
单脚本 Skill 的设计四原则:
| 原则 | 做法 | 原因 |
|---|---|---|
| 输出结构化 | 表格/Markdown/JSON 格式 | AI 能直接解析结构化结果 |
| 参数校验优先 | 缺参数时 sys.exit(1) |
让 OpenClaw 捕获错误并提示用户 |
| 结果截断 | 限制输出长度 | 防止过长输出撑爆上下文窗口 |
使用 {baseDir} |
脚本路径用变量引用 | 运行时自动替换为实际路径 |
类型 3:单脚本 Skill(Shell)
代表案例:tavily-search(Tavily 搜索)
Shell 脚本适合调用 REST API 的场景,search.sh 的核心结构:
bash
#!/bin/bash
# 1. 环境变量校验 --- 最重要的第一步
if [ -z "$TAVILY_API_KEY" ]; then
echo "ERROR: TAVILY_API_KEY environment variable is not set" >&2
exit 1
fi
# 2. 依赖检查
if ! command -v curl &> /dev/null; then
echo '{"error":"curl is not installed"}'
exit 1
fi
if ! command -v jq &> /dev/null; then
echo '{"error":"jq is not installed"}'
exit 1
fi
# 3. 核心搜索函数 --- 带重试机制
perform_search() {
local query="$1"
local max_results="${2:-5}"
local response=$(curl -s -X POST "$TAVILY_ENDPOINT" \
-H "Content-Type: application/json" \
-d "{
\"api_key\": \"$TAVILY_API_KEY\",
\"query\": \"$query\",
\"max_results\": $max_results
}")
# 输出 JSON 格式结果
echo "$body" | jq '{query: .query, results: .results, quota_info: ...}'
}
# 4. 子命令路由
case "$1" in
--usage) show_usage ;;
--status) show_status ;;
--toggle-paid-mode) toggle_paid_mode ;;
*) perform_search "$1" "$2" "$3" ;;
esac
这个 Skill 的亮点是配额管理:每次搜索后自动查询剩余配额,避免超额使用。
类型 4:外部 CLI 工具封装 Skill
代表案例:agent-browser(浏览器自动化)
这类 Skill 不自带脚本,而是封装已有的 CLI 工具。SKILL.md 的核心是命令手册:
markdown
## Core Workflow
```bash
# 1. Navigate and snapshot
agent-browser open https://example.com
agent-browser snapshot -i --json
# 2. Parse refs from JSON, then interact
agent-browser click @e2
agent-browser fill @e3 "text"
# 3. Re-snapshot after page changes
agent-browser snapshot -i --json
```
## Key Commands
### Navigation
```bash
agent-browser open <url>
agent-browser back | forward | reload | close
```
### Interactions (Ref-based)
```bash
agent-browser click @e2
agent-browser fill @e3 "text"
agent-browser hover @e4
```
封装型 Skill 的写法要点:
- 提供完整的命令参考,让 AI 知道有哪些命令可用
- 给出典型工作流(Workflow),而不只是命令列表
- 说明何时用这个工具、何时用其他替代方案
- 声明安装方式,让用户知道如何获取外部工具
类型 5:多脚本 + 参考文档 Skill
代表案例:firecrawl(网页抓取)
这是最完整的 Skill 结构:
bash
firecrawl/
├── SKILL.md # 简洁的入口文档
├── scripts/
│ ├── search.py # 搜索脚本
│ ├── scrape.py # 单页抓取脚本
│ └── crawl.py # 全站爬取脚本
└── references/
└── api.md # 详细 API 文档(按需加载)
SKILL.md 保持简洁,只提供快速入口:
markdown
## Quick Start
### Search the web
```bash
firecrawl_search "your search query" --limit 10
```
### Scrape a single page
```bash
firecrawl_scrape "https://example.com"
```
## API Reference
See [references/api.md](references/api.md) for detailed API documentation.
详细的 API 文档放在 references/api.md 中,只在需要时加载。这利用了 OpenClaw 的三级加载机制:
| 层级 | 内容 | 加载时机 | 建议大小 |
|---|---|---|---|
| 第 1 级 | name + description | 始终在上下文中 | ~100 词 |
| 第 2 级 | SKILL.md 正文 | 技能被触发时 | < 500 行 |
| 第 3 级 | references/ 中的文件 | 正文指示读取时 | 不限 |
三个脚本共享相同的设计模式:
python
# 所有脚本的统一模式
def main_function(params):
# 1. 读取 API Key
api_key = os.environ.get("FIRECRAWL_API_KEY")
if not api_key:
print("Error: FIRECRAWL_API_KEY not set", file=sys.stderr)
sys.exit(1)
# 2. 构建请求
data = json.dumps({"url": url, "formats": ["markdown"]}).encode()
req = urllib.request.Request(url, data=data, headers={...})
# 3. 发送请求 + 错误处理
try:
with urllib.request.urlopen(req, timeout=30) as resp:
result = json.loads(resp.read().decode())
return result
except HTTPError as e:
print(f"Error: {e.code}", file=sys.stderr)
sys.exit(1)
# 4. argparse 命令行接口
def main():
parser = argparse.ArgumentParser()
parser.add_argument("url", help="URL to scrape")
parser.add_argument("--json", action="store_true")
args = parser.parse_args()
# ...
📌 注意:firecrawl 的脚本只用了标准库
urllib.request,没有引入requests等第三方依赖,这降低了安装门槛。
五、_meta.json 与 .clawhub/ 详解
_meta.json --- ClawHub 发布元数据
当你通过 ClawHub 发布 Skill 后,会自动生成 _meta.json:
json
{
"ownerId": "kn78ns1svg36jybcqfkxhtvcp182kf18", // 作者 ID
"slug": "tavily-search-skill", // URL 标识符
"version": "1.0.4", // 当前版本
"publishedAt": 1773128020068 // 发布时间戳
}
.clawhub/origin.json --- 安装来源信息
通过 clawhub install 安装的 Skill 会有这个文件:
json
{
"version": 1,
"registry": "https://clawhub.ai", // 注册中心地址
"slug": "tavily-search-skill", // Skill 标识
"installedVersion": "1.0.4", // 安装的版本
"installedAt": 1774932128743 // 安装时间戳
}
六、从零开发一个 Skill --- 完整流程
假设我们要开发一个"GitHub 仓库信息查询"Skill:
Step 1:创建目录
bash
mkdir -p ~/.openclaw/workspace/skills/github-repo-info
Step 2:编写 SKILL.md
markdown
---
name: github-repo-info
description: 查询 GitHub 仓库信息,包括 star 数、fork 数、最近更新时间、主要语言等。
当用户询问某个 GitHub 仓库的信息、统计数据或状态时使用此技能。
metadata:
openclaw:
requires:
bins:
- curl
---
# GitHub 仓库信息查询
查询任意 GitHub 公开仓库的基本信息。
## 使用方式
```bash
bash {baseDir}/scripts/query.sh <owner> <repo>
```
示例:
```bash
bash {baseDir}/scripts/query.sh facebook react
bash {baseDir}/scripts/query.sh microsoft vscode
```
## 输出内容
- 仓库名称和描述
- Star / Fork / Issue 数量
- 主要编程语言
- 最近更新时间
- 开源协议
## 注意事项
- 仅支持公开仓库
- GitHub API 未认证时限制 60 次/小时
- 如需更高频率,可设置 GITHUB_TOKEN 环境变量
Step 3:编写脚本
bash
#!/bin/bash
# scripts/query.sh --- GitHub 仓库信息查询
if [ -z "$1" ] || [ -z "$2" ]; then
echo "用法: query.sh <owner> <repo>"
echo "示例: query.sh facebook react"
exit 1
fi
OWNER="$1"
REPO="$2"
AUTH_HEADER=""
if [ -n "$GITHUB_TOKEN" ]; then
AUTH_HEADER="-H \"Authorization: token $GITHUB_TOKEN\""
fi
RESPONSE=$(curl -s "https://api.github.com/repos/$OWNER/$REPO" $AUTH_HEADER)
if echo "$RESPONSE" | jq -e '.message' > /dev/null 2>&1; then
echo "Error: $(echo $RESPONSE | jq -r '.message')"
exit 1
fi
# 输出结构化结果
echo "$RESPONSE" | jq '{
name: .full_name,
description: .description,
stars: .stargazers_count,
forks: .forks_count,
open_issues: .open_issues_count,
language: .language,
license: .license.name,
updated_at: .updated_at,
homepage: .homepage
}'
Step 4:本地测试
bash
# 检查 Skill 状态
openclaw skills check
openclaw skills info github-repo-info
# 在 OpenClaw 对话中测试
# 输入:"帮我查一下 facebook/react 这个仓库的信息"
# AI 应该自动触发 github-repo-info Skill
Step 5:发布到 ClawHub
- 访问 clawhub.ai,用 GitHub 账号登录
- 点击 "Publish",填写 Slug、Display Name、Version
- 上传包含
SKILL.md的文件夹 - 系统自动校验格式
- 确认 MIT-0 许可证,点击发布
七、开发最佳实践总结
description 写作技巧
从 7 个案例中提炼的 description 写作模式:
css
[做什么] + [使用什么技术/API] + [什么时候用/触发条件]
好的例子:
- ✅ "中国铁路 12306 火车票余票查询...当用户需要查询火车票信息时使用此技能"
- ✅ "Web search and scraping via Firecrawl API. Use when you need to search the web..."
- ✅ "Security-first skill vetting for AI agents. Use before installing any skill..."
脚本设计模式
从 7 个案例中总结的通用脚本模板:
python
#!/usr/bin/env python3
"""脚本描述"""
import sys, json, os
# 1. 环境变量/参数校验(失败时 exit(1))
api_key = os.environ.get("MY_API_KEY")
if not api_key:
print("Error: MY_API_KEY not set", file=sys.stderr)
sys.exit(1)
# 2. 核心逻辑(API 调用 + 数据处理)
def do_work(params):
try:
response = requests.get(API_URL, params=params, timeout=10)
return response.json()
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
# 3. 格式化输出(Markdown/JSON/表格)
def format_output(data):
print(json.dumps(data, indent=2, ensure_ascii=False))
# 4. CLI 入口(argparse 或 sys.argv)
if __name__ == "__main__":
# ...
安全检查清单
参考 skill-vetter 的审查标准,你的 Skill 应该:
- ❌ 不要向未知 URL 发送数据
- ❌ 不要硬编码 API Key 或密码
- ❌ 不要使用
eval()/exec()处理外部输入 - ❌ 不要访问
~/.ssh、~/.aws等敏感目录 - ✅ 使用环境变量存储敏感信息
- ✅ 最小化权限范围
- ✅ 所有网络请求设置超时
- ✅ 完善的错误处理
开发检查清单
scss
[ ] SKILL.md frontmatter 包含 name 和 description
[ ] description 清晰描述触发条件和能力
[ ] 环境变量依赖声明在 metadata.requires.env
[ ] 系统命令依赖声明在 metadata.requires.bins
[ ] 脚本输出为结构化格式(Markdown/JSON/表格)
[ ] 敏感信息使用环境变量,不硬编码
[ ] 错误处理完善(缺参数 exit(1),API 失败有清晰提示)
[ ] 本地测试通过
[ ] 发布前文件夹只包含 SKILL.md 和纯文本文件
八、参考资源
- OpenClaw 官方文档 --- Skill 开发与发布指南
- ClawHub --- Skill 市场
- skill-creator --- 官方 Skill 开发辅助工具(通过
clawhub install skill-creator安装)