ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenClaw架构与源码解读:从SKILL.md构建你自己的Skill

OpenClaw架构与源码解读:从SKILL.md构建你自己的Skill 1. 从一次 Skill 不触发说起OpenClaw Skill 机制到底怎么跑你写了一个 SKILL.md放进~/.openclaw/workspace/skills/重启 OpenClaw然后在对话里输入触发词结果 Agent 像没看见一样继续用通用 bash 硬解。这个场景我遇到过不止一次问题往往不在模型而在 Skill 的加载、解析和调度链路里某一环断了。OpenClaw 的 Skill 机制本质上是一套「Markdown 即插件」的约定一个目录、一个 SKILL.md、一段 YAML frontmatter加上若干 bash 命令示例就能让 Agent 在合适的时机调用它。它不编译、不打包、不注册二进制加载器只做三件事——扫描目录、解析 frontmatter、把 description 注入到模型的系统提示里。理解这条链路你才能判断「为什么我的 Skill 没被识别」和「为什么识别了却不触发」。这篇内容面向已经跑通 OpenClaw 基础对话、想写第一个自定义 Skill 的读者。我会从源码视角拆开 Skill 的加载与解析流程给出可直接复制的 SKILL.md 模板和目录结构再用 todo-local 和 github-digest 两个例子跑通本地加载验证。如果你还没配好模型接入可以先用 TaoToken 的模型对话快速验证 Agent 是否能正常响应再回来调 Skill。核心检索词先摆出来OpenClaw Skill 是基于 SKILL.md 的 Markdown 插件机制SKILL.md 里的 description 字段决定调用时机requires.bins 决定加载前置检查Cron 决定定时触发。这四件事串起来就是本篇要拆的完整链路。2. OpenClaw Skill 加载链路与 SKILL.md 解析源码拆解2.1 Skill 目录扫描与 workspace 优先级OpenClaw 启动时会扫描多个 Skill 根目录按优先级从高到低大致是workspace 级~/.openclaw/workspace/skills/、用户级~/.openclaw/skills/、内置 skills 目录。同名 Skill 以高优先级覆盖低优先级这也是为什么你本地改的 Skill 能盖过内置版本。扫描逻辑不递归太深通常只认一级子目录每个子目录里必须有SKILL.md才算一个合法 Skill。目录名建议和 frontmatter 里的name保持一致否则openclaw skill list显示的名字可能和你预期不符。我试过把目录叫todo、name 写todo-local列表里显示的是 name但排障时容易对不上号后来统一成同名就清爽了。2.2 frontmatter 解析name、description、metadata 三段式SKILL.md 的解析入口是 YAML frontmatter也就是文件开头---之间的部分。解析器读三个关键字段name是 Skill 的唯一标识用于openclaw skill status name查询。description是写给模型看的自然语言说明它会被拼进系统提示模型据此判断「当前用户意图是否匹配这个 Skill」。metadata.openclaw下面挂emoji、requires.bins等扩展字段其中requires.bins是加载时的硬性前置检查——声明的二进制不存在Skill 状态直接标为不可用而不是等到执行时才报错。这里有个容易踩的坑frontmatter 的 YAML 对缩进和引号敏感。description 里如果包含冒号、井号、引号必须用双引号包起来否则解析会截断。我见过 description 写成Use when: user says #todo没加引号结果#被当成注释description 只剩前半句模型自然不触发。2.3 description 如何影响模型调用决策description 不是给人看的文档是给模型的「调用说明书」。加载器把它注入系统提示后模型在每轮对话里都会拿用户输入和所有 Skill 的 description 做语义匹配。匹配成功模型生成调用该 Skill 的意图再由执行层跑 SKILL.md 里对应的 bash 命令。所以 description 的写法直接决定触发率。模糊的Manage todo items几乎不会触发因为模型不知道「什么时候该用」。好的写法是「做什么 使用时机多个示例短语 不适合什么 前置条件」。这一点在后面的模板里会给出完整示例。2.4 Cron 调度与 Skill 的衔接点Cron 配置在~/.openclaw/openclaw.json的cron数组里每条 job 有id、schedule标准 cron 表达式、message。调度器到点后把message当作一次用户输入投给 AgentAgent 再走正常的 Skill 匹配流程。也就是说Cron 不直接调用 Skill它只是「定时伪造一条用户消息」Skill 是否被用上仍然取决于 description 匹配。这个设计的好处是解耦你不需要为定时任务单独写调度代码只要保证 message 的措辞能命中某个 Skill 的 description 即可。github-digest 的 Cron message 里写「Generate a GitHub digest for today」正好命中 description 里的「daily digest of GitHub activity」链路就通了。3. 可复制的 SKILL.md 模板与目录结构配置3.1 标准目录结构与文件清单一个最小可用的 Skill 目录长这样~/.openclaw/workspace/skills/ └── todo-local/ └── SKILL.md就一个文件。如果 Skill 需要附带脚本、模板、静态资源可以在同目录下放scripts/、assets/子目录SKILL.md 里用相对路径引用。但绝大多数场景纯 Markdown 内联 bash 就够了这也是 OpenClaw Skill 相比传统插件最轻的地方。创建目录的命令mkdir -p ~/.openclaw/workspace/skills/todo-local3.2 完整 SKILL.md 模板含 frontmatter 与命令段下面这份模板可以直接复制改 name 和 description 就能用。注意 frontmatter 的引号和缩进--- name: todo-local description: Append a todo item to the local ~/todo.txt file. Use when: user says #todo item, add a todo, remember to..., or asks you to record a task. Also use when user asks to list their todos. NOT for: project management tools, remote task services (use those specific skills). metadata: openclaw: emoji: requires: bins: [bash] --- # Todo Local Skill Manage a simple local todo list stored in ~/todo.txt. ## Append a Todo Item When the user wants to add a todo: bash echo - [ ] ITEM ($(date %Y-%m-%d %H:%M)) ~/todo.txt echo Added to ~/todo.txtReplace ITEM with the actual todo text extracted from the users message.List TodosWhen the user wants to see their todos:if [ -f ~/todo.txt ]; then cat ~/todo.txt else echo (~/todo.txt is empty or doesnt exist) fiMark as DoneWhen the user marks a todo as done:cat -n ~/todo.txt sed -i s/- \[ \] ITEM/- [x] ITEM/ ~/todo.txtNotesThe file is plain text, one item per lineCompleted items use [x], pending items use [ ]Always confirm after adding: Added: ITEM### 3.3 requires.bins 与加载前置检查配置 requires.bins 是加载期的守门员。上面模板里声明了 bash因为命令段依赖 shell。如果 Skill 依赖 gh、jq就要写全 yaml metadata: openclaw: emoji: requires: bins: [gh, jq]OpenClaw 在加载时逐个检查这些二进制是否在 PATH 里。缺任何一个openclaw skill status会显示不可用并提示缺哪个。这比执行到一半报command not found友好得多。注意requires.bins只做存在性检查不检查版本也不检查是否已登录比如gh auth登录态要在 SKILL.md 的 Notes 里提醒用户。3.4 Cron Job 的 JSON 配置片段定时触发写在~/.openclaw/openclaw.json{ agent: { model: anthropic/claude-opus-4-6 }, cron: [ { id: github-daily-digest, schedule: 0 9 * * *, message: Generate a GitHub digest for today. Check my tracked repositories for new issues and PRs opened in the last 24 hours. Format as a daily standup summary. } ] }schedule是标准五段 cron0 9 * * *表示每天 9 点。message的措辞要能命中目标 Skill 的 description否则定时任务会退化成通用对话。改完这个文件需要重启 OpenClaw 让 Cron 重新加载。4. 本地加载验证与成功结果确认4.1 openclaw skill list 与 status 验证写完 SKILL.md先别急着对话用命令行确认加载状态openclaw skill list预期输出里能看到✓ todo-local (workspace)前面的勾表示加载成功括号里是来源层级。如果没出现说明目录层级或文件名不对。接着查详情openclaw skill status todo-local预期✓ todo-local: ready (no binary requirements)如果显示missing bins: gh就去装对应工具或者把requires.bins里用不到的项删掉。4.2 用 --verbose 观察 Agent 是否读到 descriptionSkill 加载成功不等于会触发。用 verbose 模式看 Agent 的完整推理openclaw agent --message #todo 买牛奶 --verbose输出里会打印系统提示的拼装过程你能看到 todo-local 的 description 是否被注入、模型是否在候选列表里选中了它。如果 description 没出现说明加载器没读到如果出现了但模型没选说明 description 的措辞和用户输入匹配度不够回去改 description。4.3 实际对话触发与文件写入结果在 Slack 或 WebChat 里发#todo 买牛奶Agent 应该识别到这是 todo-local 的使用场景生成并执行echo - [ ] 买牛奶 (2026-03-02 15:30) ~/todo.txt然后回复「已添加到 ~/todo.txt买牛奶」。验证文件确实写入了cat ~/todo.txt看到- [ ] 买牛奶 (2026-03-02 15:30)就说明整条链路通了加载 → 解析 → description 注入 → 模型匹配 → 命令执行 → 文件落盘。4.4 github-digest 的 Cron 触发验证进阶例子 github-digest 依赖gh和jq先确认登录态gh auth statusSKILL.md 里列出最近 24 小时的 Issue 和 PRgh issue list \ --repo OWNER/REPO \ --state open \ --json number,title,createdAt,author,labels \ --jq .[] | select(.createdAt (now - 86400 | strftime(%Y-%m-%dT%H:%M:%SZ))) | #\(.number) \(.title) (\(.author.login)) \ 2/dev/null || echo (none)把OWNER/REPO换成实际仓库比如facebook/react。Cron 到点后调度器投递 messageAgent 匹配到 github-digest跑上面的命令并汇总成日报。验证 Cron 是否生效可以临时把 schedule 改成*/5 * * * *每 5 分钟观察日志里是否有对应 job 的执行记录确认后再改回0 9 * * *。5. 本篇常见报错排查401、local proxy failed、reading choices、OAuth5.1 401 与鉴权失败如果 Agent 在调用模型时报 401先确认模型接入的 Key 是否有效。用 TaoToken 的 API Keys 页面核对当前 Key 状态再检查openclaw.json里agent.model对应的 provider 配置。401 通常和 Skill 无关是模型接入层的问题但会表现为「Skill 完全不触发」因为 Agent 根本没跑起来。5.2 local proxy failed 与网络层排查local proxy failed一般出现在 Agent 尝试访问外部服务时。先确认本地网络能正常访问目标 API再检查 OpenClaw 的代理配置是否指向了不可用的地址。这个报错和 Skill 的 bash 命令执行是两回事Skill 命令跑在本地 shell模型请求走网络层两者要分开定位。5.3 reading choices 报错与响应解析reading choices类报错通常意味着模型返回的响应结构不符合预期解析器读不到choices字段。常见原因是模型接入返回了非标准格式或者请求参数里 model ID 写错。核对agent.model的 Model ID 是否和接入方文档一致必要时用模型对话单独发一条请求验证返回结构。5.4 OAuth 与 gh auth login 失败github-digest 依赖gh auth login。如果 OAuth 流程卡住先确认gh版本再重新走一遍gh auth login选择 HTTPS 和浏览器授权。授权完成后gh auth status应显示已登录账号。注意requires.bins只检查gh存在不检查登录态所以登录失败不会在加载期暴露而是在执行gh issue list时报错。SKILL.md 的 Notes 里要明确写「If gh is not authenticated, prompt: Please run gh auth login first」。5.5 Skill 三件套核对清单出现任何 Skill 不触发的情况按这三件套核对Base URL 是否指向正确的接入地址、Key 是否有效、Model ID 是否和接入方一致。这三项在openclaw.json的agent段里。CC Switch、Cline MCP、Codex auth.json 这类配置工具如果参与也要保证三件套一致否则会出现「Skill 加载正常但 Agent 不响应」的割裂现象。6. 把 Skill 跑起来之后接入与验证的下一步Skill 写完之后真正决定体验的是模型接入是否稳定。你可以用 TaoToken 的模型对话先验证 Agent 基础响应确认模型能正常返回再回来调 Skill 的 description 和命令段。如果打算长期跑编码类或 Agent 类任务Coding Plan 更适合持续调用场景避免频繁切换 Key。接入文档里有完整的 Base URL、Key、Model ID 配置说明照着填openclaw.json的agent段即可。排障时优先看 API Keys 状态和接入文档的报错对照表大部分 401、reading choices、local proxy failed 都能在那里找到对应解法。最后留一个实用技巧Skill 的 description 改完后不需要重启整个 OpenClawopenclaw skill list会重新扫描目录。但 Cron 配置改动需要重启才生效。把这两件事分开记能省不少来回折腾的时间。
返回列表