0

OpenClaw Skills技能开发实战:从SKILL.md到ClawHub发布全流程

2026.06.10 | youres | 15次围观

OpenClaw Skills技能开发实战:从SKILL.md到ClawHub发布全流程

过去三个月,我陆续开发了七个 OpenClaw Skill,踩过的坑比用过的功能还多。从最初以为 Skill 就是一堆 Markdown 指令的简单堆砌,到后来摸清 YAML 元数据的优先级机制、scripts 脚本与主文档的协同逻辑,我才意识到 Skill 开发其实是门"让 AI 学会做事"的艺术。本文记录我从零开发到 ClawHub 上架的完整过程,以及那些官方文档没写、但踩过的人才知道的关键细节。

先搞清楚一件事:Skill 和 Prompt 到底有什么区别

很多人把 Skill 和普通 Prompt 混为一谈,觉得"反正都是写一堆指令让 AI 照做"。这种理解在简单场景下能跑通,但一旦 Skill 复杂度上升,就会遇到指令失效、流程断裂的问题。

核心差异在于加载机制。OpenClaw 不会把 Skill 的全文都塞进每次对话的 Prompt——那样 token 消耗太大,响应速度也会明显下降。实际的机制是:OpenClaw 根据用户消息中的触发关键词,从 Skill 目录里提取 SKILL.md 的 YAML 头(name + description + triggers),注入到模型的基础指令中。只有当模型判断"这个 Skill 适用于当前任务"时,才会真正去读取完整文档。

这带来一个实际影响:description 字段写得是否精准,直接决定 Skill 的激活率。我见过很多人把 description 写成"这是一个处理文件的技能"——这种模糊描述对模型判断毫无帮助。正确的写法应该包含具体的触发场景和输出格式,例如:"当用户需要从文件夹中按类型归类文件、删除重复文件或清理空目录时使用此技能,输出处理结果摘要。"

SKILL.md 的双段式结构:YAML 头不是装饰

OpenClaw Skill 的核心文件是 SKILL.md,采用"YAML 头 + Markdown 体"的双段式结构。这个格式设计看起来简单,但很多人忽略了 YAML 头里几个关键字段的实际作用。

name 字段:别用中文,这是内部标识符

name 是 Skill 的内部唯一标识,会被 OpenClaw 用于 Skill 目录管理和 API 调用。我见过有人写 name: 文件整理技能,结果在 Skill 列表里显示乱码,后来才知道 name 字段应该用英文加连字符的格式。

--- ✅ 正确写法
name: file-organizer
description: 当用户需要整理文件时使用...
triggers:
  - 整理文件
  - 分类文件
  - 清理文件夹
priority: 80

❌ 错误写法
name: 文件整理技能
description: 整理文件用的...

priority 字段:数字越大越优先,但默认值是 50

这是一个容易被忽略但很实用的字段。当多条 Skill 的 triggers 都可能匹配用户消息时,priority 决定模型优先考虑哪个 Skill。比如你的工作流中同时有"文件整理"和"文件搜索"两个 Skill,priority 更高的会被优先激活。

我个人的经验是:核心流程 Skill 设置 priority 80~100,辅助工具类 Skill 设置 50~60。这样既能保证关键 Skill 被优先调用,又不会完全压制工具类 Skill 的使用。

metadata 字段:我踩过的最隐蔽的坑

SKILL.md 的 metadata 区块是可选的,但如果你想在 ClawHub 上发布或与其他用户共享,这个字段至关重要。我在第一次提交 Skill 时,完全没填 metadata,结果在 ClawHub 上显示"作者未知、版本缺失",用户无法正确安装。

metadata:
  openclaw:
    emoji: "📁"
    os: ["darwin", "linux", "win32"]
    requires:
      bins: ["node"]
      package: "@some/package"

另一个常被忽略的是 requires 字段。如果你开发的 Skill 依赖特定的二进制工具(如 ffmpegcurl)或 npm 包,必须在 requires 中声明。否则用户安装 Skill 后,OpenClaw 在执行时会报"command not found",而这个错误信息对调试毫无帮助。

目录结构设计:scripts 文件夹的正确用法

一个完整的 Skill 目录结构如下:

my-skill/
  SKILL.md          # 核心配置文件(必需)
  scripts/
    main.py         # 可选:Python 执行脚本
    helper.sh       # 可选:Shell 辅助脚本
  references/
    api_examples.md # 可选:API 规范或参考文档
  assets/
    template.xlsx    # 可选:模板文件或静态资源

关于 scripts 文件夹的使用,有两个关键原则需要理解:

原则一:SKILL.md 是指令层,scripts 是执行层。很多人把整个 Skill 逻辑都塞进 SKILL.md 的 Markdown 正文里,导致指令过于冗长,模型在复杂场景下容易丢失关键步骤。正确的做法是:SKILL.md 只写"做什么"和"怎么做"的高层描述,具体的脚本执行细节放到 scripts/ 目录中。

原则二:scripts 中的文件命名要与 SKILL.md 正文中的引用保持一致。OpenClaw 的执行机制是:模型读取 SKILL.md 后,根据正文中的指令调用对应的脚本。如果你在正文中写"执行 node scripts/analyze.js",但实际文件路径是 scripts/analyse.js(英式拼写),模型就会报文件不存在。

我的第一个 Skill 开发全过程

我的第三个 Skill 是"会议纪要生成器",目标是让 OpenClaw 自动从邮件或聊天记录中提取会议信息,生成结构化的纪要文档。这个 Skill 的开发过程最能体现从需求到上架的完整路径。

第一步:明确触发场景和边界

在动笔写 SKILL.md 之前,我先花了两天时间记录"哪些场景需要生成会议纪要"。这个前置工作比写代码本身更重要——它帮我厘清了 Skill 的真实边界,避免陷入"什么都想做"的陷阱。

最终确定的触发场景是:用户发来一段文字(邮件、微信聊天、Slack 消息),需要从中提取会议时间、地点、参与人、议题和行动项,输出结构化文档。如果用户只是要求"帮我写一份会议纪要"而不是提供原始文本,这个 Skill 就不应该被激活。

第二步:设计 SKILL.md 的指令框架

基于触发场景分析,我设计了 SKILL.md 的三层指令结构:

  • 第一层:输入识别——判断用户提供的文本是否包含会议要素(时间/地点/人名/议题关键词)
  • 第二层:信息提取——使用正则表达式和关键词匹配从文本中提取结构化数据
  • 第三层:格式输出——按照固定模板生成 Markdown 格式的会议纪要

这个分层设计的灵感来自工程上的"关注点分离"原则。它的实际好处是:当 Skill 失效时,我可以快速定位是哪个层级出了问题,而不是对着整个 SKILL.md 抓瞎。

第三步:编写辅助脚本

为了让信息提取更可靠,我用 Python 写了一个轻量级的 scripts/extract_meeting.py。这个脚本接收用户输入文本,输出 JSON 格式的结构化数据:

{
  "meeting_time": "2026年6月10日 14:00",
  "location": "线上(腾讯会议)",
  "participants": ["张三", "李四", "王五"],
  "topics": ["Q2复盘", "Q3规划"],
  "action_items": [
    {"owner": "张三", "task": "完成竞品分析报告", "deadline": "2026-06-15"},
    {"owner": "李四", "task": "更新OKR文档", "deadline": "2026-06-12"}
  ]
}

这里有个关键细节:Python 脚本输出的 JSON 必须包含中文字符的 Unicode 转义,否则在 Windows PowerShell 环境下会被当作乱码截断。我花了两小时调试这个问题,最后的解决方案是显式设置 PYTHONIOENCODING=utf-8 环境变量。

第四步:本地测试与迭代

Skill 开发中最痛苦的环节是本地测试。OpenClaw 没有提供 Skill 的单元测试框架,我的做法是建立了一个"测试用例库",包含正面案例(应该触发 Skill 的输入)和负面案例(不应该触发 Skill 的输入)。

测试过程中我发现了一个意料之外的问题:当用户输入的会议信息缺少某个字段时,模型倾向于"捏造"默认值,而不是输出"字段缺失"的提示。这在实际工作中会导致纪要内容不可靠。解决方案是在 SKILL.md 的输出格式部分,明确要求模型对缺失字段标注"[未提及]"而不是自行补全。

发布到 ClawHub:我遇到的三道坎

Skill 开发完成后,我把它提交到了 ClawHub。这个过程比我预想的要折腾,主要卡在三个环节。

坎一:metadata 缺失导致审核被拒

第一次提交时,我的 SKILL.md 完全没有 metadata 字段。ClawHub 的审核系统检测到"缺少必需字段"后直接拒绝,但没有给出具体的缺失提示。我是在翻遍了 ClawHub 的文档后才发现,metadata.openclaw.emojimetadata.version 是发布到 ClawHub 的必需字段。

坎二:trigger 关键词过度泛化

我的初始版本包含了大量触发关键词,如"会议""纪要""记录""总结"等。审核反馈指出,这些关键词过于宽泛,会导致 Skill 在不相关的场景下被激活,降低用户体验。建议的优化方向是:trigger 关键词应该与具体动作绑定,而不是通用名词。

修正后的 triggers 是:["生成会议纪要", "整理会议记录", "提取会议要点", "会议action items"]

坎三:scripts 路径在不同系统下的兼容性

我的 scripts/extract_meeting.py 在 macOS 和 Linux 上测试正常,但 Windows 用户反馈"脚本找不到"。问题出在脚本调用方式上:我在 SKILL.md 中写的是 python3 scripts/extract_meeting.py,但 Windows 默认的 Python 命令是 python 而不是 python3

最终解决方案是使用跨平台的脚本调用语法,并在 SKILL.md 中添加系统判断逻辑:Windows 系统使用 node 包装脚本,Unix 系统使用 python3。这个坑提醒我:OpenClaw 是跨平台工具,Skill 开发必须考虑 Windows 用户。

Skill 开发最佳实践:来自三次迭代的总结

经过七个 Skill 的开发实践,我总结出以下经验教训:

原则 原因 具体做法
description 要包含触发场景和输出格式 决定模型何时激活 Skill 参考模板:"当用户需要[具体任务]时使用此技能,输出[具体格式]"
复杂逻辑下沉到 scripts SKILL.md 过长会导致指令丢失 SKILL.md 只写"做什么",scripts/ 目录放"怎么做"
声明所有依赖 避免用户运行时遇到"command not found" 在 metadata.requires 中列出 bins 和 package
trigger 关键词要与动作绑定 通用名词会导致误激活 用"生成XX"而非"XX"
考虑跨平台兼容性 Windows 和 Unix 系统命令差异大 避免硬编码 python3/node 等命令
建立测试用例库 OpenClaw 没有 Skill 单元测试框架 维护正面/负面案例的文本集合

从 Skill 到工作流:组合多个 Skill 的思路

单个 Skill 的能力有限,真正的价值在于 Skill 之间的组合。例如,我的"会议纪要生成器"可以和"文件发送"Skill 组合,实现"自动生成纪要→发送到邮箱"的完整工作流。

OpenClaw 的 Skill 组合机制基于上下文共享:当一个 Skill 执行完成后,其输出结果会被注入到下一个 Skill 的上下文中,供其读取和使用。这要求每个 Skill 在输出时遵循一致的格式约定——这也是为什么我在前文强调"JSON 输出结构要标准化"的原因。

如果你在开发某个领域的 Skill,建议先调研 ClawHub 上已有的相关 Skill,评估是否可以复用或扩展,而不是从零开始开发完整功能。站在前人的肩膀上,既能节省开发时间,也能让你的 Skill 与生态更好地融合。

写在最后

Skill 开发本质上是一种"流程编码"——你不是在写代码让机器执行,而是在写指令让 AI 理解并转化为行动。这个转化的质量,取决于你对任务边界的界定是否清晰、对输出格式的约定是否一致、对平台差异的考虑是否周全。

我的第七个 Skill 从构思到上架花了整整两周,但第一个 Skill 只用了两天。速度差异不是因为后者更简单,而是因为我已经在前六个 Skill 中踩完了所有该踩的坑。希望这篇实战记录能帮你绕开这些坑,把时间花在真正创造价值的地方。

如果你也在开发 OpenClaw Skill,欢迎通过我的 Claude Code 接入教程里提到的社区渠道交流经验。OpenClaw 的生态还在快速成长,现在参与进来,你的内容会获得更高的长尾搜索曝光。

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论