我第一次在OpenClaw里跑通自定义SKILL的时候,其实已经把官方仓库里的现成技能翻了个底朝天。那些现成技能确实能覆盖日常对话、信息摘要、待办管理一类的高频场景,但一遇到自己工作流里的具体需求——比如把会议记录按固定模板整理成客户能直接看的版本、把一堆零散的阅读笔记归类成周报素材——就怎么都不顺手。折腾过几个变通方案,又是改系统提示词,又是拼Prompt,效果都不稳定。后来我才明白,OpenClaw把自定义能力放在SKILL机制里,本身就是想让人按自己的方式扩展助手。这篇文章就是我基于实际摸索梳理出的完整方法,从机制原理、文件结构、完整案例,到调试经验和避坑清单,尽量一次性讲透。
1. 在动手写SKILL之前,先理解OpenClaw的技能运行机制
1.1 SKILL到底是什么
SKILL说白了,就是放在OpenClaw指定目录下的一个Markdown文件。这文件不是给人看的文档,而是给AI助手看的一份“操作说明书”。当你给OpenClaw下达任务时,系统会根据任务内容去匹配一系列skill文件,把匹配到的文件里的指令注入到当前会话的上下文中,大模型会沿着这些指令去完成特定流程,而不是天马行空自由发挥。
我一开始的理解也有偏差,以为SKILL和插件一样,是需要写代码、处理事件、注册钩子的东西。真上手才发现,绝大多数技能根本不需要写代码,核心工作是把你想让AI做的事情,用大模型能准确理解的文字描述出来。这有点像给新员工写SOP——你把流程写清楚了,他就能照着执行;你写得模糊,他就自由发挥,结果自然不稳定。
对比一下就更好懂:
普通对话里,你每次都要把需求重新说清楚,模型每次都是临场发挥,同样的需求换个说法结果可能就不一样。有了SKILL之后,你把流程、规则、输出格式固化下来,模型每次遇到这类任务都会按照同一条路径处理。最直观的感受是,输出的一致性明显提升,不会这次给你表格下次给你纯文本。
1.2 为什么OpenClaw选Markdown文件作为技能载体
这个问题当时我也好奇过。按照常规思路,技能这种东西好歹应该是个脚本或者可执行文件。但OpenClaw选择Markdown是有道理的。
第一,可读性高。技能文件首先是给人维护的,你打开一个markdown文件,标题、列表、步骤清清楚楚,整个技能的行为一目了然,出了问题也好排查,不用去读几千行代码。
第二,迭代成本低。改一个md文件只需要编辑保存,不需要编译部署,不需要重启服务,对日常使用的人来说非常友好。你在文本编辑器里改两行字,回头再跟OpenClaw说句话,新规则就生效了。这种即时反馈带来的体验,是用传统插件方式很难做到的。
第三,也是最重要的一点,大模型对自然语言的理解能力已经足够强,一篇写清楚的指令文档,就能让模型按照预期工作。这个方式比写复杂代码要经济得多,也更容易被非程序员用户掌握。你可以把SKILL文件理解成一篇高质量的Prompt工程文档,它最终要服务的不是解释器,而是大模型本身。这个认知直接决定了你后续怎么写、写到什么程度。
1.3 SKILL和ACTION的分工边界
在OpenClaw里,SKILL解决的是“怎么做”的问题,也就是流程和方法论;ACTION解决的是“做什么动作”的问题,也就是真正去调用外部能力,比如读取文件、请求接口、执行命令行。一个完整的技能往往是一个SKILL带着一串ACTION来跑的。
举几个分类场景:
| 任务类型 | 是否要外部操作 | 需要的机制 |
|---|---|---|
| 文本摘要、改写、整理 | 不需要,纯理解重组 | 一个SKILL足够 |
| 读取本地文件、操作邮箱、调用API | 需要实际动作 | SKILL + ACTION |
| 组合流水线:解析数据后归档 | 需要多个动作串联 | SKILL编排多个ACTION |
这里有个非常容易踩的坑:很多人一上来就给技能写一堆外部操作逻辑,其实大多数日常场景根本用不到。判断标准就一条——这个任务的结果是不是光靠“对已有文本做理解和重组”就能完成?如果是,先别考虑脚本和接口,老老实实把SKILL写好。
提示:先想清楚你的技能到底需不需要操作外部系统。如果只是加工文本、整理信息,纯SKILL就够用,别给自己找麻烦。
2. SKILL文件的骨架:目录、Frontmatter与正文的规范细节
2.1 技能文件放在哪里、怎么命名
不同安装方式下OpenClaw的配置目录位置不完全一样。我建议你第一次动手时,先在命令行里通过帮助命令或者配置入口确认配置根目录,然后找到skills子目录。所有自定义技能都放在这个统一目录里,一个技能对应一个Markdown文件,互不干扰。
命名方面我推荐kebab-case风格,也就是全小写、单词之间用短横线连接,例如meeting-notes、weekly-report、code-review。避免使用下划线和空格,原因很实际:下划线在文件系统和一些命令行场景里容易出问题,空格则可能在解析时造成奇怪的分割。另外技能名要尽量短并且能够直接表达用途,方便你在给OpenClaw下达指令时提到它。
目录结构大概是这样的:
配置根目录/ └── skills/ ├── meeting-notes.md ├── weekly-report.md └── code-review.md2.2 Frontmatter元信息字段
每个SKILL文件开头都有三横线包裹的一块YAML格式元信息区域,这里是技能的“身份证”。三个核心字段,我逐个说说:
| 字段 | 作用 | 填写建议 |
|---|---|---|
| name | 技能的唯一标识 | 与文件名一致,用kebab-case |
| description | 给模型看的技能说明 | 写清楚触发场景、输入与输出边界 |
| version | 版本号 | 如果习惯持续迭代,建议维护 |
其中description是最关键的。模型靠description判断“当前任务是否应该使用这个技能”,写得太含糊或者太宽泛,模型要么该用的时候不用,要么不该用的时候乱用。比如你写“处理文本”,那模型什么任务都会想用它;你写“将会议转写文本整理为结构化会议纪要,并在总结部分提取待办事项”,模型就能精准理解边界。
还有一点很实用:description里最好包含用户可能用的几种常见说法。用户不一定会说“整理会议纪要”,他可能说“帮我总结一下今天的会”,或者“把这段录音转写内容理一理”。这些说法如果都能写进description,技能被正确调用的概率会明显提高。
2.3 正文章节怎么写
正文是整个技能的核心指令,我的经验是严格按照三段式来组织:目标、步骤、约束。
目标部分明确这个技能要产出什么,为什么存在,让模型先建立整体认知。
步骤部分把流程拆成一个一个具体的操作节点,每个节点最好都能被模型独立执行,不需要再做复杂的推断。比如“识别会议主题”是一个清晰节点,“根据会议内容生成三个关键结论”也清晰;“判断会议氛围”这种就太模糊了,模型不知道判断标准是什么。
约束部分说明禁区,比如不许臆造原文没有的信息、输出字段必须完整、遇到缺失信息时如何占位等。没有约束的技能,模型自由发挥空间太大,输出质量就会飘。
另外正文里至少要包含一个示例片段。对模型来说,举例说明“什么是对的输出”比十句抽象的规则都管用。你可以在约束后面附上“参考输出示例”,让模型有样可依。这里多说一句:示例不要写得太完美、太理想化,要贴近真实使用场景,否则模型会按示例的样式强行套用在所有输入上,反而限制了灵活性。
3. 从零写一个可复用的SKILL:会议纪要与周报整理
3.1 需求分析与触发场景
我用一个真实工作中经常遇到的场景来演示完整流程。假设你手里有一堆会议转写文本和随手记的零散要点,需要每次会后都整理成固定格式的会议纪要,同时提取可用的周报素材。手动整理一次要十几分钟,而且格式经常不统一,换个模板就要重新整理一遍。
这个需求太适合做成SKILL了。拆解一下:
输入:会议转写文本、会议要点列表。 输出:结构化纪要,包括会议主题、核心结论、待办事项;再从纪要里抽取出适合发到周报里的素材条目。 触发方式:只需要给OpenClaw说一句“把这段会议记录整理成纪要”,系统就会靠description去匹配这个技能。
这类需求的共同点是输入输出边界清晰、流程固定、格式要求一致,不需要外部系统参与,所以一个纯SKILL就能搞定。
3.2 编写SKILL文件
在skills目录下新建meeting-notes.md,内容如下:
--- name: meeting-notes description: 将会议转写文本或会议要点整理为结构化会议纪要,并提取周报素材。当用户提供会议记录、转写文本、会议要点并要求整理、总结、生成纪要时使用。如果用户只是询问会议安排,不要使用本技能。 --- # 会议纪要整理任务 你是一名会议纪要整理助手。用户会提供原始会议记录,你的任务是整理出结构清晰、信息完整、可直接使用的会议纪要。 ## 整理步骤 1. 通读全部原始记录,先识别会议的背景信息:会议主题、参会人、会议时间。信息缺失时标注"未提及",不要自行编造。 2. 提炼会议核心议题,按议题维度分段,每个议题概括讨论内容与结论。 3. 从记录中识别待办事项或后续动作,整理成表格:事项、负责人、截止时间。原文没有对应信息时用"-"占位。 4. 根据纪要内容提取3-5条适合周报使用的素材,每条一句话概述,突出进展与结果。 5. 按规定的输出格式输出,不做多余解释。 ## 输出格式 ### 会议信息 - 主题:xxx - 时间:xxx - 参会人:xxx ### 核心议题 1. 议题一:讨论内容与结论摘要 2. 议题二:讨论内容与结论摘要 ### 待办事项 | 事项 | 负责人 | 截止时间 | | --- | --- | --- | | xxx | xxx | xxx | ### 周报素材 - xxx - xxx关键点在于:每条指令都明确到模型不需要猜测的程度,同时保留一定判断空间,比如“按议题维度分段”就是一个需要模型理解的操作,而不是死板的分段规则。这样技能既稳定又不僵硬,不会因为输入材料稍有变化就不知道怎么办。
3.3 保存后如何调用验证
保存文件后,先和OpenClaw打声招呼说“着手整理会议记录”,或者直接丢一段转写文本加一句“整理成纪要”,看模型是否命中这个技能。命中后输出应该严格遵循你定义的格式框架。
我实测了一个很短的例子,输入大概是一段四十多字的会议转写,输出就能稳定拆出会议信息、核心议题、待办事项和周报素材四块。第一次跑就发现两个问题:
一是原始材料里没写时间,模型自己编了一个日期,这属于典型的“凭空补全”,我后面在约束里加了一句“信息缺失时标注未提及”才算解决。
二是周报素材提取得过于空泛,像“讨论了项目进展”这种完全没有信息量的话。这个问题的根源是我没说明“突出进展与结果”的具体标准,我补充了一条约束:“禁止出现‘讨论’‘安排’等过程性描述,只保留可量化的结论或下一步动作。”补上之后效果立刻不一样了。
这两处修改的启示是:第一个版本的技能几乎不可能完美,你需要用真实输入去跑一遍,然后针对模型暴露出来的弱点逐条补充约束,迭代几轮之后就稳定了。
4. 让SKILL更聪明的进阶写法:参数、上下文与依赖声明
4.1 参数化的思路
基础SKILL写顺之后,你会渐渐觉得一个技能只干一件事有点浪费。下一个自然的方向是参数化。
所谓参数化,不是让你在Markdown里写代码变量,而是通过描述性的方式让技能适应不同输入。比如会议纪要技能,你可以让它在整理过程中感知材料里出现的会议类型、参会人数规模,再根据不同情况调整详略。写起来就是在正文里加一句:“如果会议是周会且议题超过五个,核心议题部分按‘背景、讨论、结论’三段压缩呈现;如果是专题会,则完整展开每个议题的讨论过程。”
这个做法的本质,是把判断逻辑明明白白地写进技能,让模型根据输入内容做自适应,而不是你每次重新捏一个技能。参数化写得越好,一个技能能覆盖的场景就越多。
4.2 多技能联动与上下文引用
另一个很实用的进阶能力是技能之间的联动。你可以在一个技能的正文里要求模型先执行另一个技能,再继续当前任务。
比如我整理完会议纪要后,通常还需要把纪要同步到项目文档里。这时可以在meeting-notes文档的一个小节里注明:“完成纪要后,检查是否存在名称为project-docs的技能,存在则调用它完成文档归档步骤。”这样单个技能就可以组成一条自动化的处理流水线。
需要说明的是,多技能联动对description的要求更高。被引用的技能如果description写得不清不楚,模型在执行联动时可能找不到对应技能。我的习惯是给每个技能写一句话的“用途摘要”,放在正文开头,方便模型快速识别该技能是否适合当前子任务。
4.3 将外部脚本接入技能
当任务确实需要调用外部程序时,可以在技能正文里直接描述命令行或脚本的调用方式。比如需要从一段日志里正则提取时间戳,你可以在技能里写:“当需要提取结构化字段时,调用extract-log脚本,传参为日志文本路径,结果以表格输出。”
这种方式衔接了SKILL与ACTION:技能负责判断什么时候需要脚本、如何解释脚本结果,ACTION负责真正执行调用。不需要在技能里实现脚本逻辑,只要把调用方式和参数约定写清楚即可。这样做的好处是,技能文件保持轻量,逻辑复杂度集中在脚本里,排查问题的时候也更容易定位到底是在决策层面出错,还是在执行层面出错。
5. 多轮调试与常见错误:我自己踩过的坑
5.1 高频翻车点清单
| 现象 | 根因 | 解决办法 |
|---|---|---|
| 模型完全不理睬技能 | description写得太宽或太窄 | 重写description,明确触发场景与禁用场景 |
| 技能偶尔失效 | 技能名与触发语境不匹配 | 在description中补充常用说法作为触发线索 |
| 输出格式反复漂移 | 正文缺少强约束 | 增加“必须严格按照输出格式”声明并附示例 |
| 模型返回的信息与原始材料不符 | 缺少禁止编造约束 | 加入“原文没有的信息标注未提及” |
| 技能文件被跳过 | YAML格式出错 | 检查三横线是否配对、冒号后是否有空格 |
第一个坑我踩得最狠。当时写了一个整理阅读笔记的技能,description写的“整理文本”,结果模型在总结邮件、生成回复的时候也会去尝试匹配它,行为变得很怪。后来我养成了一个习惯:description里除了写“什么时候用”,一定还要写“什么时候不用”,比如明确“如果用户只是询问会议安排,不要使用本技能”。这条规则几乎能解决一半的误触发问题。
5.2 一套可复用的排查链路
如果技能没生效,不要急着改正文,按顺序排查:
第一步,确认文件在正确的skills目录下,文件名和name字段一致,格式为kebab-case。很多人新建文件时复制了一个名字,改完内容忘了改文件名,导致匹配错位。
第二步,检查YAML块是否有语法错误,这是最容易忽略的,一个冒号后面忘加空格就可能让整个技能不被解析。这一块出问题,模型可能根本不知道有这个技能存在。
第三步,回想刚才的触发语境,对比description里写的触发条件,看看是否匹配。如果不匹配,问题多半出在描述上,而不是执行逻辑上。
第四步,直接用一句非常接近description原话的指令去触发,验证技能本身是否正常工作。这一步能快速区分“技能坏了”还是“触发条件没写对”。
第五步,如果都能触发但输出不对,再去调整正文里的步骤和约束,每次只改一个点,改完立刻验证,不要一次性改七八处。
这套顺序看起来普通,但能避免在错误方向上瞎使劲。我见过很多次,明明只是description写得不到位,有人却把正文步骤改了二十遍,越改越乱,最后整个技能都处于一种古怪的状态。
5.3 一次真实调试记录
最后分享一次让我印象很深的调试经历。当时我在写一个文章发布前的排版技能,为了让输出好看,我在技能里写了七八条排版规则,比如“标题层级要清晰”“列表符号要统一”“引用块前后要空行”等等,结果模型反而进入了“规则过载”状态——每条规则都执行了一下,但整体效果一塌糊涂,标题层级混乱,列表符号不统一,比不做排版还糟糕。
后来我换了个思路。把排版规则拆成两块:正文只保留三条必须遵守的核心规则,其他细节放进一个“可选参考”小标题下,并且明确说明“核心规则必须全部满足,参考规则在条件允许时尽量遵守”。实测下来效果立刻稳定了,模型不会顾此失彼。
这件事给我的启发是,技能正文不是规则越多越好。大模型的注意力是有限的,一次性给它几十条要求,它只会挑一部分执行。优先保证核心指令少而明确,再逐步补充细节,效果远比一次性堆规则强。这也解释了为什么很多看起来简单的技能反而比功能齐备的技能更可靠。
最后分享一个我一直在用的小习惯。每个技能文件我都会在description末尾加上一句“如果原始信息不完整,请先向用户确认”。这句话能极大减少幻觉输出,模型在信息缺失时会更倾向于问清楚,而不是自作主张地补全。
技能写得越多,越会发现维护成本主要不在写,而在让描述保持简洁清晰。隔一段时间回头看看哪些技能从不触发,果断删掉,能省下不少上下文资源。OpenClaw的自定义SKILL机制,说到底就是把你的工作方法沉淀成文字,让AI助手替你稳定执行。这一套流程跑顺之后,你会发现很多重复劳动都可以交给它,省下来的时间远比最初的学习成本多得多。