菜鸟AI - 让提示词生成更简单! 全站导航 全站导航
AI工具安装 新手教程 进阶教程 辅助资源 AI提示词 热点资讯 技术资讯 产业资讯 内容生成 模型技术 AI信息库

已有账号?

首页 > AI教程 > OpenClaw Skill系统评测:LLM工作流按需学习指南
进阶教程 Skill系统

OpenClaw Skill系统评测:LLM工作流按需学习指南

2026-06-07
阅读 0
热度 0
作者 菜鸟AI编辑部
摘要

摘要

Skill系统通过SKILL md文件为LLM提供操作手册,采用元数据与正文分离、资格过滤仅暴露可用

场景:AI 如何精准调用对应命令?

向 OpenClaw 提问:「帮我查一下上海今天的天气。」

OpenClaw 深度解析(八):Skill 系统——让 LLM 按需学习工作流

AI 随即生成 curl "wttr.in/Shanghai?format=3" 命令,执行后正确返回天气数据。

但这里隐藏着一个关键机制问题:LLM 作为语言模型,并非天生知道查天气需要 wttr.in,也不了解管理 GitHub PR 依赖 gh CLI,更别提控制 Spotify 要用 spotify-player 这类专属工具。

因此,必然存在某种机制让 LLM“学会”这些技能。然而,若将 50 个工具的完整文档一股脑塞进系统提示,文档体积会瞬间撑爆上下文窗口。

这正是 Skill 系统要解决的核心矛盾:

  1. 文档规模瓶颈:50+ 工具各有详尽文档。全部预加载,LLM 的上下文根本容纳不下。
  2. 工具可用性校验gh CLI 未安装、spotify-player 环境变量缺失——将这些不可用工具暴露给 LLM,只会引发无效调用和错误。
  3. 工作流标准化需求:工具的使用方法必须让 LLM 精确理解并严格遵循,而非靠“猜测”运作。
  4. 用户体验优化:用户更倾向于输入 /weather 上海 快捷触发,而非每次都书写完整自然语言描述。

一、SKILL.md:面向 LLM 的文档规范

为何选用 Markdown 而非代码?

Skill 并非传统程序——它本质上是一份“给 LLM 阅读的操作指南”。LLM 最擅长处理自然语言与 Markdown,因此最佳格式是携带 YAML frontmatter 的 Markdown 文件。

每个 skill 对应一个目录,核心文件为 SKILL.md

---name: weatherdescription: "Get current weather and forecasts via wttr.in or Open-Meteo.Use when: user asks about weather, temperature, or forecasts for any location.NOT for: historical weather data, severe weather alerts."metadata:{ "openclaw": { "emoji": "?️", "requires": { "bins": ["curl"] } } }---# Weather Skill## When to Use**USE this skill when:**- "What's the weather?"- "Will it rain today/tomorrow?"## Commands```bash# One-line summarycurl "wttr.in/London?format=3"

文件拆分为两大区块。首先是 frontmatter(机器解析部分)

```typescript// src/agents/skills/types.tstype OpenClawSkillMetadata = {always?: boolean; // 绕过资格检查,强制包含emoji?: string; // 视觉展示primaryEnv?: string; // 主要依赖的环境变量requires?: {bins?: string[]; // 必需的可执行文件anyBins?: string[]; // 满足其中之一即可env?: string[]; // 必需的环境变量config?: string[]; // 必需的配置键};install?: SkillInstallSpec[]; // 依赖安装方式};

frontmatter 包含两个关键字段。其一是 description,相当于系统提示中唯一的“代言人”,LLM 凭借这一行决定是否启用该 skill。其二是 metadata.openclaw.requires.bins,声明依赖哪些可执行文件;运行时若缺失,整个 skill 会从系统提示中自动移除。

接着是 正文(LLM 阅读部分),详细说明“何时启用”“何时禁用”、命令模板和注意事项。这段内容不会预置在系统提示中,仅在 LLM 主动读取时才会载入上下文。

这种分离机制是整套系统的设计核心:元数据供机器解析,正文供 LLM 学习,摘要则处于中间层传递决策信号。

二、多来源发现与优先级(workspace.ts

问题:skill 从哪些来源获取?

一个用户可能同时拥有系统内置 skill、自行安装 skill 以及项目级 skill。所有这些技能都需要被系统发现,且同名时必须遵循明确的覆盖规则。

loadSkillEntries() 按优先级从低到高扫描六个来源:

extra(openclaw.yml 中 skills.load.extraDirs 指定)< bundled(核心内置,代码库 skills/ 目录,随 OpenClaw 发布)< managed(~/.openclaw/skills/,用户通过 openclaw skills install 安装的)< agents-skills-personal(~/.agents/skills/,个人全局 skill)< agents-skills-project(工作区 .agents/skills/,项目级 skill)< workspace(工作区 skills/,最高优先级)

优先级通过 Map 实现——后赋值的会覆盖先赋值的:

// src/agents/skills/workspace.tsconst merged = new Map<string, Skill>();for (const skill of extraSkills)merged.set(skill.name, skill);for (const skill of bundledSkills)merged.set(skill.name, skill);for (const skill of managedSkills)merged.set(skill.name, skill);for (const skill of personalAgentsSkills) merged.set(skill.name, skill);for (const skill of projectAgentsSkills)merged.set(skill.name, skill);for (const skill of workspaceSkills)merged.set(skill.name, skill);

换言之,若在项目中放入 skills/github/SKILL.md,则会完全取代系统内置的 github skill,而非合并。用户可为特定项目定制任意 skill 的行为。

嵌套目录探测

resolveNestedSkillsRoot() 采用精巧的启发式逻辑:若 dir/skills/*/SKILL.md 存在,则认定 dir/skills 为实际 skills 根目录。这样一来,~/.openclaw/skills/ 目录下既能直接存放 github/SKILL.md,也能容纳包含 skills/ 子目录的完整工具包——两种结构均可正确识别。

三、资格过滤:仅暴露可用的 skill

问题:gh CLI 未安装,是否还应向 LLM 展示 GitHub skill?

shouldIncludeSkill() 在加载后执行运行时资格检查:

// 检查 requires.bins:这些可执行文件是否存在?// 检查 requires.anyBins:至少有一个存在吗?// 检查 requires.env:这些环境变量是否已设置?// 检查 requires.config:配置文件中是否有这些键?// 检查 os:当前操作系统是否匹配(如仅 macOS 的 skill)// always: true → 跳过所有检查,强制包含

若未安装 ghrequires.bins: ["gh"] 检查失败,GitHub skill 直接从列表中移除——LLM 的系统提示中根本不会出现任何相关条目。

过滤之后还有第二步:剔除那些 disable-model-invocation: true 的 skill。此类 skill 只能通过 /命令 显式触发,LLM 自主决策时无法感知它们的存在。

资格上下文:远端信息

SkillEligibilityContext.remote 支持注入远端节点的状态:

type SkillEligibilityContext = {remote?: {platforms: string[];hasBin: (bin: string) => boolean; // 目标节点是否包含 curl?hasAnyBin: (bins: string[]) => boolean;note?: string;};};

当 Agent 在远端 Node Host 上执行时,资格检查针对的是目标节点的环境,而非 Gateway 所在机器。例如,远端 Linux 服务器上安装有 gh 而本地 Mac 没有,GitHub skill 依然会呈现给 LLM。

四、渐近式披露:系统提示仅包含摘要

问题:150 个 skill 的完整文档有多大?

假设每个 SKILL.md 平均 2000 字节,150 个 skill 总计 300KB 纯文本——远超大多数模型的上下文窗口承受能力。

解决方案是渐近式披露:系统提示中只存放每个 skill 的三个字段——name、description、location,正文留到 LLM 决定使用时才读取。

formatSkillsForPrompt() 将过滤后的 skill 列表格式化为:

<a vailable_skills><skill><name>weathername><description>Get current weather and forecasts via wttr.in or Open-Meteo.Use when: user asks about weather, temperature, or forecasts for any location.NOT for: historical weather data, severe weather alerts.description><location>~/.openclaw/skills/weather/SKILL.mdlocation>skill><skill><name>githubname><description>GitHub operations via gh CLI: issues, PRs, CI runs, code review.Use when: (1) checking PR status or CI, (2) creating/commenting on issues...description><location>~/.openclaw/skills/github/SKILL.mdlocation>skill>a vailable_skills>

注意 location 字段中的路径:/Users/alice/.openclaw/skills/weather/SKILL.md 被压缩为 ~/.openclaw/skills/weather/SKILL.md。该细节由 compactSkillPaths() 实现,每个路径约节省 5-6 个 token,150 个 skill 合计可节省 600-900 token。

Token 预算控制

// src/agents/skills/workspace.tsconst DEFAULT_MAX_SKILLS_IN_PROMPT = 150;const DEFAULT_MAX_SKILLS_PROMPT_CHARS = 30_000;const DEFAULT_MAX_SKILL_FILE_BYTES = 256_000;// 超出字符限制时,采用二分搜索定位最大可容纳前缀if (!fits(skillsForPrompt)) {let lo = 0, hi = skillsForPrompt.length;while (lo < hi) {const mid = Math.ceil((lo + hi) / 2);if (fits(skillsForPrompt.slice(0, mid))) lo = mid;else hi = mid - 1;}skillsForPrompt = skillsForPrompt.slice(0, lo);}

五、系统提示中的元指令:引导 LLM 正确使用

问题:LLM 拿到 skill 列表后,清楚自己该怎么做吗?

仅有列表还不够——LLM 还需要明确的行为规则。buildSkillsSection() 的职责是将列表与指令一并注入系统提示:

// src/agents/system-prompt.tsfunction buildSkillsSection(params: { skillsPrompt?: string; readToolName: string }) {return ["## Skills (mandatory)","Before replying: scan entries.",`- If exactly one skill clearly applies: read its SKILL.md at with `${readToolName}`, then follow it.`,"- If multiple could apply: choose the most specific one, then read/follow it.","- If none clearly apply: do not read any SKILL.md.","Constraints: never read more than one skill up front; only read after selecting.",trimmed, // ← 摘要块];}

该指令的设计包含几个关键要点:

  1. (mandatory) 标记为“强制”,意味着 LLM 每次回复前都必须扫描,而非“偶尔参考”。
  2. 明确指定使用 read 工具加载 处的 SKILL.md,LLM 无需猜测路径。
  3. “never read more than one skill up front” 规则防止 LLM 一次性读取所有可能相关的 skill,从而避免大量 token 浪费。
  4. “then follow it” 表示读取后必须遵循其中的指示,而非仅作参考。

最终效果是什么?用户提问「查一下上海天气」→ LLM 扫描摘要 → 匹配到 weather skill 的 description → 调用 read("~/.openclaw/skills/weather/SKILL.md") → 读取完整工作流 → 成功执行 curl "wttr.in/Shanghai?format=3"

整个过程中,LLM 是主动参与者,而非被动执行脚本的机器。Skill 系统通过“摘要 + 路径”为 LLM 提供恰好够用的决策信息,完整内容仅在真正需要时才加载。

六、/命令:用户显式触发路径

问题:用户更想输入 /weather 上海 而非自然语言

buildWorkspaceSkillCommandSpecs() 扫描所有 user-invocable: true 的 skill(默认为 true),然后为消息平台注册斜杠命令:

// src/auto-reply/skill-commands.ts// /weather → weather skill// /github → github skill// 冲突时自动追加 _2 后缀

命令名还会经过规范化处理:

function sanitizeSkillCommandName(raw: string): string {return raw.toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").slice(0, 32); // Discord 限制:命令名最长 32 字符}

两种触发模式

用户发送 /weather 上海 后,系统查找 weather 对应的 SkillCommandSpec,然后沿以下两条路径之一执行:

模式一:经过 LLM(默认)

/weather 上海→ resolveSkillCommandInvocation() 识别命令→ 将 "weather 上海" 作为用户消息注入会话→ LLM 正常处理(仍会读取 SKILL.md 并做出决策)

模式二:确定性工具分发(command-dispatch: tool

若 SKILL.md 的 frontmatter 中声明了:

command-dispatch: toolcommand-tool: execcommand-arg-mode: raw

那么触发将完全绕过 LLM:

/weather 上海→ dispatch.kind === "tool"→ 直接调用 exec 工具,args = "上海"(原样转发)→ LLM 不参与任何决策

这种模式对“输入明确、工具已知、无需推理”的场景非常高效,执行速度更快,且行为完全可预测。

七、沙盒环境下的 skill 同步

当 Agent 在 Docker 沙盒中运行时,skill 文件需要从宿主机同步至容器:

// src/agents/skills/workspace.tsexport async function syncSkillsToWorkspace(params: {sourceWorkspaceDir: string; // 宿主机工作区targetWorkspaceDir: string; // 容器内工作区}) {// 1. 加载宿主机 skill 列表// 2. 清空容器内的 skills/ 目录// 3. 将每个 skill 目录 cp 进容器// 4. 路径安全检查(防止路径遍历攻击)}

同步完成后,容器内的 read 工具读取的是容器内 SKILL.md 副本,而非宿主机路径。resolveSandboxPath() 确保每个 skill 目录名安全,不会通过 ../.. 等名称逃逸到容器外部。

小结:渐近式披露驱动的 LLM 工作流

Skill 系统的核心,其实是一个简洁的设计理念:不将文档转化为代码,而是将文档本身教给 LLM,让 LLM 按文档行事。

阶段机制目的
发现六来源扫描 + Map 优先级覆盖允许用户/项目覆盖系统内置 skill
过滤bins/env/os 资格检查仅向 LLM 暴露当前环境真正可用的 skill
摘要注入name + description + location,字符预算控制以最小 token 开销让 LLM 做出决策
元指令## Skills (mandatory) + read 工具路径告知 LLM 如何利用这些信息
渐近式披露LLM 决策后主动调用 read(SKILL.md)完整文档仅在真正需要时进入上下文
/命令buildWorkspaceSkillCommandSpecs() 注册斜杠命令用户显式触发,绕过自然语言推理
确定性分发command-dispatch: tool执行路径完全绕过 LLM

这套设计让 skill 作者只需编写 Markdown,无需了解 LLM 推理细节、工具注册或消息平台差异——一个 SKILL.md 文件,就能使 AI 严格遵循作者的意图行动。

来源:互联网

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

同类文章推荐

相关文章推荐

更多