🎭 开场白:一个技能的诞生
从前有座山,山里有个庙,庙里有个老和尚在教小和尚——「如何写一个Agent Skill」。
小和尚问:「师父,我写完 SKILL.md 是不是就大功告成了?」
老和尚摇摇头:「傻孩子,那只是开始。你还要过五关斩六将——创建提案、等待审批、修改再提交、最终上线。这叫Skill Workshop 工作流。」
小和尚又问:「那要是审批不通过呢?」
老和尚笑了:「那就再改,改到通过为止。就像周星驰说的——『我到现在还不明白,为什么我写的代码总是不通过review。』」
🎯 什么是 Skill Workshop?为什么要用它?
在 OpenClaw v2026.6 之前,发布一个技能是这样的:
- 写好
SKILL.md - 直接扔到
~/.openclaw/skills/目录 - 祈祷它不会把系统搞崩
这种方式的问题是:没有审核、没有版本管理、没有安全保障。就像周星驰电影里说的——「我猜中了开头,却猜不中这结局。」
「每个人都会写代码,但不是每个人都会写安全的代码。Skill Workshop 就是那个让你慢下来思考的地方。—— 王家卫」
Skill Workshop 引入了一个完整的提案审批工作流:
创建提案(Create Proposal)
把你的技能想法写成一个「提案」,包含 SKILL.md 和支持文件。此时技能还不会生效,只是个「草稿」。
等待审批(Pending Review)
提案进入待审批状态。就像投稿到杂志社,编辑会review你的内容。
审核详情(Inspect)
通过 skill_workshop action=inspect 查看提案的完整内容,检查是否有问题。
批准或拒绝(Approve / Reject)
如果提案合格,使用 action=apply 批准,技能正式上线。不合格则用 action=reject 拒绝并附上原因。
技能上线(Live)
审批通过后,技能正式生效,OpenClaw 可以调用它了。
🚀 实战一:创建你的第一个 Skill 提案
我们来创建一个实用的技能:「每日AI新闻摘要生成器」。这个技能可以自动抓取RSS、生成摘要、发送到飞书。
第一步:设计技能功能
先明确技能要解决什么问题:
- ✅ 自动抓取指定RSS源的最新内容
- ✅ 用AI生成100字摘要
- ✅ 自动发送到飞书群/Discord频道
- ✅ 支持定时执行(cron)
第二步:编写 SKILL.md
SKILL.md 是技能的「说明书」,必须包含以下章节:
# AI News Digest Skill
# 每日AI新闻摘要生成器
## 功能描述
自动抓取RSS源的最新AI新闻,用AI生成摘要,发送到飞书或Discord。
## 使用方法
### 快速开始
```bash
openclaw run ai-news-digest --rss https://openclaw.ai/blog
```
### 参数说明
- `--rss`:RSS URL(必填)
- `--limit`:抓取条数,默认5条
- `--send-to`:发送目标(feishu / discord / both)
- `--cron`:定时表达式,如 `0 9 * * *`(每天9点)
## 代码示例
```python
import feedparser
import openai
def generate_digest(rss_url, limit=5):
feed = feedparser.parse(rss_url)
entries = feed.entries[:limit]
summaries = []
for entry in entries:
summary = call_ai_summary(entry.title, entry.summary)
summaries.append(f"📌 {entry.title}\n{summary}\n")
return "\n".join(summaries)
def call_ai_summary(title, content):
response = openai.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": f"总结以下内容为50字:{title}\n{content}"}]
)
return response.choices[0].message.content
```
## 依赖
- feedparser>=6.0.0
- openai>=1.0.0
- requests>=2.28.0
## 配置要求
需要在 ~/.openclaw/config.json 中配置:
```json
{
"ai_news_digest": {
"openai_api_key": "sk-xxx",
"feishu_webhook": "https://open.feishu.cn/xxx",
"discord_webhook": "https://discord.com/api/webhooks/xxx"
}
}
```
## 安全考虑
- API Key 加密存储,不记录到日志
- RSS 内容仅读取,不执行其中脚本
- 发送内容经过敏感词过滤
## 作者
妙趣AI (miaoquai.com)
## 版本
v1.0.0 (2026-06-30)
第三步:创建提案
现在用 skill_workshop 工具创建提案:
# 创建技能提案(使用 heredoc 传 proposal_content)
openclaw skill_workshop action=create \
name="ai-news-digest" \
description="每日AI新闻摘要:RSS抓取+AI总结+多平台发送" \
proposal_content="$(cat <<'EOF'
# AI News Digest Skill
## 功能描述
自动抓取RSS源的最新AI新闻,用AI生成摘要,发送到飞书或Discord。
## 使用方法
...
EOF
)"
星爷小贴士:description 不能超过 160 字节!
这是最常见的错误。Skill Workshop 对 description 字段有严格限制:
# 错误示范:description 太长
description="这是一个非常长的描述,超过了160字节的限制,会导致提案创建失败"
# 正确示范:简短有力
description="AI新闻摘要:RSS+AI+多平台"
记住:description 是提案的「一句话简介」,不是详细文档!
📋 实战二:管理提案状态
提案创建后,你需要跟踪它的状态。就像追剧一样,每集都要看——
| 状态 | 含义 | 可执行操作 | 典型场景 |
|---|---|---|---|
| Pending | 提案已创建,等待审批 | inspect / apply / reject / revise | 刚提交,心里忐忑 |
| Applied | 提案已批准,技能上线 | update(更新技能内容) | 梦想成真,技能可以用了 |
| Rejected | 提案被拒绝 | revise(修改后重新提交) | 被编辑打回来了,要改 |
| Quarantined | 提案被隔离(安全问题) | inspect(查看原因) | 技能有安全风险,被隔离 |
| Stale | 提案过期(30天未处理) | revise(重新激活) | 拖延症发作,提案过期了 |
查看所有提案
# 查看所有待审批提案
openclaw skill_workshop action=list status=pending
# 查看所有已批准的技能
openclaw skill_workshop action=list status=applied
# 查看我提交的所有提案(不限状态)
openclaw skill_workshop action=list
审批提案
# 先查看提案详情(一定要看!)
openclaw skill_workshop action=inspect proposal_id=abc123
# 如果内容OK,批准它
openclaw skill_workshop action=apply proposal_id=abc123
# 如果有问题,拒绝并说明原因
openclaw skill_workshop action=reject \
proposal_id=abc123 \
reason="缺少错误处理,请补充try-catch逻辑"
踩坑实录:proposal_id 找不到?
问题:创建提案后,返回结果里有 proposal_id,但你没记下来,后来找不到它了。
解决:用 action=list 列出所有提案,从结果中找到对应的 proposal_id。也可以根据 name 参数过滤:
openclaw skill_workshop action=list query="ai-news-digest"
教训:创建提案后,立即把 proposal_id 保存到记事本!
🔄 实战三:更新已上线的技能
技能上线后,如果需要修改,怎么办?不是直接改文件,而是——
使用 action=update 创建更新提案
更新已上线的技能会创建一个新的pending proposal,需要重新审批。
等待新提案审批通过
审批通过后,新版本覆盖旧版本,技能完成更新。
# 更新技能描述
openclaw skill_workshop action=update \
skill_name="ai-news-digest" \
description="AI新闻摘要v2:支持飞书+Discord+邮件"
# 更新技能内容(会创建新的pending proposal)
openclaw skill_workshop action=update \
skill_name="ai-news-digest" \
proposal_content="$(cat NEW_SKILL.md)"
「更新一个技能,就像重新认识一个人。你以为你了解它,其实它已经变了。—— 王家卫」
📝 实战四:SKILL.md 编写规范
一个合格的 SKILL.md 需要包含以下必需章节:
| 章节 | 是否必需 | 说明 |
|---|---|---|
## 功能描述 |
✅ 必需 | 一句话说清楚技能解决什么问题 |
## 使用方法 |
✅ 必需 | 包含快速开始和参数说明 |
## 代码示例 |
✅ 必需 | 至少一个可运行的代码示例 |
## 依赖 |
✅ 必需 | 列出所有依赖包及版本 |
## 安全考虑 |
✅ 必需 | 说明安全机制和潜在风险 |
## 配置要求 |
⭕ 推荐 | 如果需要配置,说明配置格式 |
## 作者 / 版本 |
⭕ 推荐 | 方便联系和版本管理 |
星爷金句:SKILL.md 的「三要三不要」
- ✅ 要 写清楚「为什么需要这个技能」
- ✅ 要 提供「复制即运行」的代码示例
- ✅ 要 说明安全风险和应对措施
- ❌ 不要 假设用户已经懂了(写详细点)
- ❌ 不要 把依赖版本写死(用 >= 而不是 ==)
- ❌ 不要 忘记写错误处理(try-catch 是基本礼仪)
🛡️ 实战五:安全审核清单
在提交提案前,务必检查以下安全事项:
凭证安全
API Key / 密码等敏感信息是否加密存储?是否记录到日志中?
输入验证
是否对用户输入做了验证?是否存在命令注入风险?
权限最小化
技能是否请求了不必要的权限?比如一个RSS阅读器为什么要访问文件系统?
外部调用
是否调用了外部API?是否有超时和重试机制?
数据处理
是否处理敏感数据?是否有数据脱敏机制?
真实案例:一个「无害」的RSS阅读器
有个开发者提交了「RSS阅读器」技能,看起来很安全。但审核发现:
- 技能会执行RSS内容中的
<script>标签(XSS风险) - 没有对RSS URL做白名单限制(SSRF风险)
- 错误信息暴露了服务器路径(信息泄露)
结果:提案被拒绝,要求修复后才能重新提交。
🚀 实战六:从 Ideas 到 ClawHub 发布
技能上线后,你还可以发布到 ClawHub,让全世界的开发者使用!
发布流程
# 1. 先确保技能已经通过 Skill Workshop 审批
openclaw skill_workshop action=list status=applied
# 2. 登录 ClawHub
openclaw hub login
# 3. 打包技能
openclaw skill package ai-news-digest
# 4. 发布到 ClawHub
openclaw skill publish ai-news-digest
# 5. 查看发布状态
openclaw skill status ai-news-digest
发布前的检查清单
- ✅ SKILL.md 完整且格式正确
- ✅ 包含至少一个使用示例
- ✅ 添加了 LICENSE 文件
- ✅ 版本号符合语义化版本规范(如 v1.0.0)
- ✅ 已在本地测试通过
- ✅ 已通过 Skill Workshop 安全审核
「有些技能,生来就是为了被使用的。有些技能,发布后才发现没人需要。但至少,你试过了。—— 王家卫」
📊 实战七:批量管理和自动化
如果你有多个技能提案要管理,手动一个个操作太慢了。这里分享一个自动化脚本:
#!/bin/bash
# batch-review.sh - 批量审批提案脚本
echo "🔍 查找所有待审批提案..."
proposals=$(openclaw skill_workshop action=list status=pending --json | jq -r '.[].proposal_id')
for pid in $proposals; do
echo "📋 检查提案: $pid"
openclaw skill_workshop action=inspect proposal_id=$pid
read -p "是否批准?(y/n): " confirm
if [ "$confirm" = "y" ]; then
openclaw skill_workshop action=apply proposal_id=$pid
echo "✅ 提案 $pid 已批准"
else
read -p "拒绝原因: " reason
openclaw skill_workshop action=reject proposal_id=$pid reason="$reason"
echo "❌ 提案 $pid 已拒绝"
fi
done
🎓 最佳实践总结
🛡️ 安全优先
永远假设你的技能会被恶意使用。提前做好防御。
📝 文档为王
代码能跑不算完,文档清晰才算好。
🔄 小步迭代
先发布 v1.0.0,再根据反馈逐步完善。
🧪 充分测试
用 sessions_spawn 在隔离环境中测试技能。
星爷闭幕词
「技能这条路,一旦走上了,就回不了头。不是因为路太长,而是因为——你已经爱上写 SKILL.md 了。」
—— 周星驰《大话西游》· OpenClaw 版