8.2 Skills 核心机制
上一节介绍了 Skills 的基本概念和定位。本节深入剖析 Skills 的技术机制——文件规范、目录结构、发现与激活流程。
8.2.1 SKILL.md 文件规范
每个 Skill 只有一个必需文件:SKILL.md。它包含 Skill 的元数据声明和执行指令。
SKILL.md 由两部分组成:YAML Frontmatter 和 Markdown 正文。
YAML Frontmatter 位于文件顶部,用三条短横线 --- 包裹,定义 Skill 的元数据(Metadata)——即描述 Skill 自身属性的结构化信息。核心字段如下:
| 字段 | 类型 | 必需 | 说明 |
|---|---|---|---|
name |
字符串 | 是 | Skill 唯一标识符,必须与父目录名一致 |
description |
字符串 | 是 | 功能描述,决定智能体能否正确匹配到该 Skill |
allowed-tools |
列表 | 否 | 该 Skill 可调用的工具白名单 |
disable-model-invocation |
布尔值 | 否 | 是否禁止智能体自动调用 |
user-invocable |
布尔值 | 否 | 是否允许用户手动调用 |
name 字段遵循严格的命名规则:仅允许小写字母、数字和连字符(-),不允许空格或下划线。例如 explain-code、pdf-processing、stock-analysis 都是合法名称。name 必须与存放该 Skill 的父目录名完全一致,否则系统无法正确识别。
Markdown 正文 紧跟 Frontmatter 之后,包含智能体激活该 Skill 后需要遵循的全部指令。正文可以包含任务描述、执行步骤、输出格式要求等内容。
以下是一个最小 Skill 的完整示例。目录结构如下:
explain-code/
└── SKILL.mdSKILL.md 的内容:
---
name: explain-code
description: "Explains code snippets in plain language for beginners"
---## Instructions
When the user provides a code snippet:
1. Identify the programming language
2. Explain the overall purpose in one sentence
3. Walk through each section, using plain language
4. Highlight any potential issues or edge cases
Keep explanations concise. Avoid jargon unless you define it first.description 字段是 Skill 被正确发现的关键。用一句英文清晰概括 Skill 的核心功能,避免模糊表述。后文 8.2.4 节将详细讨论匹配机制。
8.2.2 完整的 Skill 目录结构
实际项目中,Skill 往往不只一个 SKILL.md 文件。一个功能完整的 Skill 目录结构如下:
pdf-processing/
├── SKILL.md # 核心指令(必需)
├── scripts/ # 可执行脚本(可选)
│ └── extract_text.py
├── references/ # 参考文档(可选)
│ └── api-docs.md
└── assets/ # 静态资源(可选)
└── template.json各目录的作用:
| 目录 | 用途 | 加载时机 |
|---|---|---|
SKILL.md |
定义元数据和执行指令 | 激活时立即加载 |
scripts/ |
存放 Python、Shell 等可执行脚本 | 执行阶段按需调用 |
references/ |
存放 API 文档、数据字典等参考资料 | 执行阶段按需读取 |
assets/ |
存放模板、配置文件等静态资源 | 执行阶段按需读取 |
scripts/ 目录中的脚本并非由 Skill 直接运行。智能体读取 SKILL.md 中的指令后,通过 Bash 等工具执行脚本。Skill 本身只是指令集,不具备独立的运行能力。

8.2.3 发现-激活-执行三阶段
Skills 的生命周期分为三个阶段:发现(Discovery)、激活(Activation)和执行(Execution)。
第一阶段:发现
智能体启动时,系统扫描所有 Skill 存储位置(见 8.2.6 节),解析每个 SKILL.md 的 Frontmatter,提取 name 和 description 字段。这些信息被注入智能体的系统提示(System Prompt),形成一份 Skill 清单。
此阶段不加载 SKILL.md 的 Markdown 正文,也不读取 scripts/ 或 references/ 中的文件。这是为了控制上下文窗口的 token 消耗——只加载必要的摘要信息。
第二阶段:激活
当用户发出任务请求时,智能体根据任务内容与 Skill 清单中的 description 进行语义匹配。如果判断某个 Skill 与当前任务相关,系统加载该 Skill 完整的 SKILL.md 正文到上下文中。
一次对话中可以激活多个 Skills。激活是动态的——只在需要时加载,用完即释放。
第三阶段:执行
智能体按照 SKILL.md 正文中的指令执行任务。执行过程中,智能体可能读取 references/ 中的参考文档获取额外信息,或调用 scripts/ 中的脚本完成特定操作。
三阶段设计的本质是延迟加载(Lazy Loading)策略。发现阶段只加载摘要,激活阶段才加载完整指令,执行阶段才访问外部资源。这种分层加载机制有效控制了上下文窗口的 token 占用。
8.2.4 Skill 匹配机制
Skills 的匹配完全依赖大语言模型的推理能力。系统不使用嵌入向量(Embedding)、不使用分类器(Classifier)、不使用正则表达式(Regular Expression)——匹配过程是纯粹的 LLM 语义推理。
这意味着 description 字段的质量直接决定匹配的准确度。
以下对比展示了同一个 Skill 的两种 description 写法:
| 质量 | description 内容 | 问题 |
|---|---|---|
| 差 | "A useful skill for finance" |
过于笼统,无法区分具体功能 |
| 好 | "Analyzes sentiment of financial news headlines and returns a polarity score between -1 and 1" |
明确指出输入(金融新闻标题)、操作(情感分析)和输出(极性分数) |
编写高质量 description 的原则:
- 明确输入和输出——说清楚 Skill 处理什么数据,返回什么结果
- 使用具体动词——用
analyzes、generates、extracts而非handles、processes - 包含领域关键词——如果 Skill 针对特定领域,在描述中体现领域术语
- 控制长度——一到两句话即可,过长的描述反而增加歧义
8.2.5 Token 预算管理
发现阶段加载所有 Skill 的 name 和 description 会占用上下文窗口空间。为防止 Skills 数量过多导致上下文溢出,系统设置了字符预算限制。
默认预算为上下文窗口总容量的 2%。如果无法获取上下文窗口大小,系统回退到 16,000 字符的固定上限。
当所有 Skill 的 description 总长度超出预算时,系统按优先级排序,排在后面的 Skill 将被排除出发现清单——这些 Skill 在当前会话中不可用。
对 SKILL.md 正文的长度也有建议上限:控制在 500 行以内。过长的正文在激活阶段会占用大量 token,压缩留给用户对话的空间。
项目中定义了 30 个 Skills,但每个 Skill 的 description 平均 200 字符,总计 6,000 字符。如果上下文窗口为 200K tokens,2% 的预算约为 4,000 tokens(大约 16,000 字符),此时所有 Skills 都能被发现。但如果 description 写得过长或 Skills 数量过多,部分 Skill 就会被排除。因此需要合理控制 description 长度和 Skills 总数。
8.2.6 存储位置层级
Skills 可以存储在四个层级,每个层级的适用范围不同:
| 级别 | 存储路径 | 适用范围 | 典型用途 |
|---|---|---|---|
| Enterprise | Managed Settings | 组织内所有用户 | 企业级合规指令、统一规范 |
| Personal | ~/.config/opencode/skills/ |
当前用户的所有项目 | 个人常用工具、通用辅助 |
| Project | .opencode/skills/ |
仅当前项目 | 项目专属功能、领域知识 |
| Plugin | plugin/skills/ |
命名空间隔离 | 第三方插件提供的功能 |
层级之间存在优先级关系:Enterprise > Personal > Project > Plugin。当不同层级存在同名 Skill 时,高优先级层级的版本生效。
对于本教材的读者,最常用的是 Project 级别——在项目的 .opencode/skills/ 目录下创建 Skills,仅服务于当前项目(也兼容 .claude/skills/ 目录结构)。Personal 级别适合存放跨项目通用的 Skills,例如代码解释、文档格式化等。
8.2.7 调用控制
Skills 提供两个布尔字段控制调用行为,组合后产生三种模式:
| 配置 | 用户可手动调用 | 智能体可自动调用 | 适用场景 |
|---|---|---|---|
| 默认(两项均不设置) | 是 | 是 | 通用知识型 Skill |
disable-model-invocation: true |
是 | 否 | 有副作用的操作(如删除文件、发送请求) |
user-invocable: false |
否 | 是 | 后台辅助知识,无需用户感知 |
默认模式 是最常见的配置。智能体根据任务需要自动激活 Skill,用户也可以在对话中主动提及 Skill 名称来触发。
禁止自动调用 适用于可能产生副作用(Side Effect)的 Skill。例如一个执行数据库写入操作的 Skill,如果被智能体误判激活,可能造成数据损坏。设置 disable-model-invocation: true 后,只有用户明确请求时才会激活。
禁止用户调用 适用于纯后台辅助型 Skill。例如一个提供内部编码规范的 Skill,智能体在生成代码时会自动参考,但用户无需直接与之交互。
初学阶段建议使用默认配置。当 Skill 涉及文件修改、网络请求等不可逆操作时,再考虑设置 disable-model-invocation: true 加以保护。