技能系统 skills
第 2 周讲完了"大脑",第 3 周讲"手和嘴"。今天开篇:skills/ 里 52 个技能怎么定义(SKILL.md + frontmatter)、三层发现加载、以及一个反直觉的事实——技能不是可调用的工具,而是"渐进式披露的提示词片段"。它呼应 Day 09 系统提示里的"技能目录段",也为明天(Day 12)讲"扩展"做对照。
技能 vs 工具
SKILL.md——里面用大白话(+几行 curl/bash)教模型"遇到这类需求怎么办"。加一个技能 = 加一篇说明书,零代码。这让非程序员也能给助理"教新本领"。工具则相反:它是真能跑的函数(按钮)。OpenClaw 里"技能(skill)"和"工具(tool)"是两种不同机制,别混:
- 工具:一段可执行代码(
{name, description, parameters, execute}),模型调用它、它跑函数返回结果。 - 技能:一个
SKILL.mdmarkdown 文件(数据,无可执行代码),靠"提示词 + 模型自己读文件照做"生效。
👶 小白:既然技能不是代码、不能"被调用",那我写完 SKILL.md,助理到底怎么就"会"了?
👨🏫 老师:靠"读",不靠"调"。系统提示里会列出所有技能的目录(名字+简介+文件路径)。模型看到你的问题,觉得某个技能对口,就用它已有的 read 工具把那份 SKILL.md 读进来,然后照着手册里的步骤,用它已有的工具(跑 curl、写文件等)去做。所以技能本身零可执行代码,"执行力"全借自模型已有的通用工具——手册负责教方法,工具负责出力。
SKILL.md 长啥样
skills/ 下 52 个目录,每个核心是 SKILL.md(YAML frontmatter + markdown 正文)。真实例子 skills/weather/SKILL.md:1-6:
---
name: weather
description: "Get current weather and forecasts via wttr.in ... Use when: ... NOT for: ..."
homepage: https://wttr.in/:help
metadata: { "openclaw": { "emoji": "☔", "requires": { "bins": ["curl"] } } }
---
(正文:教模型怎么用 curl 调 wttr.in、怎么解析、怎么呈现)
description 里的 "Use when / NOT for" 很关键——它帮模型判断"这个技能该不该用"。skills/canvas/SKILL.md 甚至没有 frontmatter(说明 frontmatter 可选)。frontmatter 门控
metadata.openclaw.requires 声明技能的"启用前提"(Schema 在 src/agents/skills/types.ts):
requires.bins: ["curl"]:需要某命令存在(weather)。requires.anyBins+install:缺了可自动装(spotify-player,brew 公式)。requires.config: ["channels.slack"]:需要某配置(skills/slack)。os/requires.env:限定系统/环境变量。
shouldIncludeSkill(skills/config.ts:71-103)。frontmatter 解析 + 安全校验在 frontmatter.ts(含防 shell 注入的 normalizeSafeBrewFormula——防止恶意技能借"自动安装"跑任意命令)。三层发现加载
loadSkillEntries(skills/workspace.ts:292-527)扫多个 root:
- bundled:仓库自带
skills/(resolveBundledSkillsDir)。 - managed:
~/.openclaw/skills(用户装的)。 - workspace:
<workspace>/skills(本项目专属)。 - 外加
~/.agents/skills、插件贡献目录。
skills/refresh.ts,改了 SKILL.md 立即生效)。优先级覆盖
同名技能冲突时的优先级(后者覆盖前者,workspace.ts:491):
extra < bundled < managed < agents-personal < agents-project < workspace
weather 技能,但你想在自己的工作区改它,只要在 <workspace>/skills/weather/SKILL.md 放一个同名的,它就覆盖内置版——因为 workspace 优先级最高。这就像 CSS 的层叠、或配置文件的"本地覆盖全局":越"贴近你当前项目"的定义越优先。让你能定制内置技能而不用改仓库源码。渐进式披露(技能怎么"调用")
关键:技能不是可调用工具。运行流程是(呼应 Day 09 技能段):
- 系统提示里只放技能目录(name+description+location,XML 形式)。
- 模型按 description 判断该不该用某技能。
- 命中 → 模型用
read工具读那个SKILL.md的<location>。 - 模型遵循 markdown 正文(通常执行其中的 bash/curl)。
skills-runtime.ts,注入提示在 attempt.ts:1417/1654,格式化由 Pi 的 formatSkillsForPrompt 生成。/weather 北京 → 直接触发绑定的工具,不经过 LLM 推理,快且省。智能路径(本讲渐进式披露):你发
"北京天气?" → 模型看目录里 weather 的描述觉得对口 → 用 read 读 skills/weather/SKILL.md → 按手册执行 curl wttr.in/北京 → 整理成人话回你。斜杠命令直达
第二条路径:技能可注册成用户斜杠命令,甚至绕过 LLM 直接调工具(skills/workspace.ts:775-881 + auto-reply/skill-commands.ts):
// frontmatter 设 command-dispatch: tool + command-tool: <name>
// → 用户发 /skillname,直接调用指定工具,不经过 LLM 推理
// (SkillCommandDispatchSpec,types.ts:40-49)
skills-install.ts(含 security/skill-scanner 安全扫描,Day 17)。今日小结 + 动手
🧠 今天你应该能回答
- 技能和工具的本质区别?
- SKILL.md 的 frontmatter + 正文各是什么?
- requires 门控解决什么问题?
- 三层发现 + 优先级覆盖怎么让技能可定制?
- 渐进式披露是什么?为什么要它?斜杠命令直达又是什么?
✋ 动手
cd /Users/bitmart/work/codes/github/openclaw
ls skills/ | head -30
sed -n '1,10p' skills/weather/SKILL.md
grep -n 'extra.*bundled.*managed\|shouldIncludeSkill' src/agents/skills/workspace.ts src/agents/skills/config.ts | head
register(api) 加载流水线、生命周期钩子。