如何为你的智能体添加 Skills 支持
本页为客户端实现指南的非官方中文翻译。
如何为你的智能体添加 Skills 支持
Section titled “如何为你的智能体添加 Skills 支持”本指南介绍如何为 AI 智能体或开发工具添加 Agent Skills 支持。涵盖完整的生命周期:发现 Skills、告知模型、将其内容加载到上下文中,并长期保持这些内容的有效性。
无论你的智能体采用何种架构,核心集成都是相同的。实现细节因两个因素而异:
- Skills 存放在哪里? 本地运行的智能体可以扫描用户文件系统中的 Skill 目录。云托管或沙箱化的智能体则需要替代的发现机制 — 如 API、远程注册中心或打包的资源。
- 模型如何访问 Skill 内容? 如果模型具备读取文件的能力,可以直接读取
SKILL.md文件。否则,你需要提供一个专用工具,或以编程方式将 Skill 内容注入提示。
本指南会标注这些差异的影响点。你无需支持所有场景 — 选择适合你的智能体的路径即可。
前置条件:熟悉 Agent Skills 规范,它定义了 SKILL.md 文件格式、frontmatter 字段和目录约定。
核心原则:Progressive Disclosure / 渐进式披露
Section titled “核心原则:Progressive Disclosure / 渐进式披露”每个兼容 Skills 的智能体都遵循相同的三层加载策略:
| 层级 | 加载内容 | 时机 | Token 开销 |
|---|---|---|---|
| 1. 目录 | 名称 + 描述 | 会话开始时 | 每个 Skill 约 50-100 tokens |
| 2. 指令 | 完整的 SKILL.md 正文 | 激活 Skill 时 | 小于 5000 tokens(建议) |
| 3. 资源 | 脚本、参考资料、资源 | 指令引用它们时 | 各异 |
模型从一开始就能看到目录,因此它知道哪些 Skills 可用。当它判定某个 Skill 相关时,会加载完整指令。如果这些指令引用了支持文件,模型会根据需要单独加载它们。
这使得基础上下文保持较小,同时让模型按需访问专业知识。一个安装了 20 个 Skills 的智能体不会预先承担 20 套完整指令的 token 开销 — 只有在给定对话中实际用到的那些。
步骤 1:发现 Skills
Section titled “步骤 1:发现 Skills”在会话开始时,找到所有可用的 Skills 并加载它们的元数据。
要扫描哪些目录取决于你的智能体环境。大多数本地运行的智能体至少扫描两个范围:
- 项目级别(相对于工作目录):特定于项目或代码库的 Skills。
- 用户级别(相对于主目录):特定用户在所有项目中可用的 Skills。
其他范围也是可能的 — 例如,由管理员部署的组织范围 Skills,或与智能体本身打包在一起的 Skills。正确的范围集取决于你的智能体部署模型。
在每个范围内,请考虑同时扫描 特定于客户端的目录 和 .agents/skills/ 约定:
| 范围 | 路径 | 用途 |
|---|---|---|
| 项目 | <project>/.<your-client>/skills/ | 你的客户端的原生位置 |
| 项目 | <project>/.agents/skills/ | 跨客户端互操作性 |
| 用户 | ~/.<your-client>/skills/ | 你的客户端的原生位置 |
| 用户 | ~/.agents/skills/ | 跨客户端互操作性 |
.agents/skills/ 路径已成为跨客户端 Skill 共享的广泛采用的约定。虽然 Agent Skills 规范并未强制规定 Skill 目录的存放位置(它仅定义目录内的内容),但扫描 .agents/skills/ 意味着其他兼容客户端安装的 Skills 会自动对你的客户端可见,反之亦然。
译者注:一些实现还会扫描
.claude/skills/(包括项目级别和用户级别)以获得实用的兼容性,因为许多现有 Skills 安装在那个位置。其他附加位置包括向上到 git 根目录的祖先目录(对 monorepo 很有用)、XDG 配置目录,以及用户配置的路径。
扫描什么内容
Section titled “扫描什么内容”在每个 Skills 目录中,查找 包含确切命名为 SKILL.md 的文件的子目录:
~/.agents/skills/├── pdf-processing/│ ├── SKILL.md ← 已发现│ └── scripts/│ └── extract.py├── data-analysis/│ └── SKILL.md ← 已发现└── README.md ← 忽略(非 Skill 目录)实际扫描规则:
- 跳过不可能包含 Skills 的目录,例如
.git/和node_modules/ - 可选地遵守
.gitignore以避免扫描构建产物 - 设置合理的边界(例如,最大深度 4-6 层、最大 2000 个目录)以防止大型目录树中的失控扫描
处理名称冲突
Section titled “处理名称冲突”当两个 Skills 共享相同的 name 时,应用确定性的优先级规则。
跨现有实现的通用约定:项目级别 Skills 覆盖用户级别 Skills。
在同一范围内(例如,在 <project>/.agents/skills/ 和 <project>/.<your-client>/skills/ 下都发现了名为 code-review 的两个 Skills),先找到或后找到都是可以接受的 — 选择一种并保持一致。当发生冲突时记录警告,让用户知道某个 Skill 被遮蔽了。
项目级别 Skills 来自正在处理的代码库,该代码库可能不受信任(例如,一个刚克隆的开源项目)。考虑对项目级别的 Skill 加载进行信任检查 — 仅在用户已将项目文件夹标记为受信任时才加载它们。这可以防止不受信任的代码库悄悄将指令注入智能体的上下文中。
云托管和沙箱化的智能体
Section titled “云托管和沙箱化的智能体”如果你的智能体在容器中或远程服务器上运行,它将无法访问用户的本地文件系统。发现机制需要根据 Skill 范围以不同方式工作:
- 项目级别 Skills 通常是最简单的情况。如果智能体对一个克隆的代码库进行操作(即使在沙箱内),项目级别 Skills 会随代码一起,可以从代码库的目录树中扫描。
- 用户级别和组织级别 Skills 在沙箱中不存在。你需要从外部源配置它们 — 例如,克隆配置代码库、通过智能体的设置接受 Skill URL 或软件包,或让用户通过 Web UI 上传 Skill 目录。
- 内置 Skills 可以作为静态资源打包在智能体的部署工件中,使其在每个会话中都可用,而无需外部获取。
一旦智能体可以访问 Skills,生命周期其余部分 — 解析、披露、激活 — 都是一样的。
步骤 2:解析 SKILL.md 文件
Section titled “步骤 2:解析 SKILL.md 文件”对于每个发现的 SKILL.md,提取元数据和正文内容。
Frontmatter 提取
Section titled “Frontmatter 提取”SKILL.md 文件由两部分组成:--- 分隔符之间的 YAML frontmatter,以及闭合分隔符之后的 markdown 正文。解析方法:
- 在文件开头找到开始的
---以及之后的闭合---。 - 解析它们之间的 YAML 块。提取
name和description(必需),以及任何可选字段。 - 闭合
---之后的全部内容(去除首尾空白)即为 Skill 的正文内容。
有关 frontmatter 字段及其约束的完整列表,请参阅 规范。
处理格式错误的 YAML
Section titled “处理格式错误的 YAML”为其他客户端编写的 Skill 文件可能包含它们各自的解析器恰好能接受但技术上无效的 YAML。最常见的问题是包含冒号但未加引号的值:
# 技术上无效的 YAML — 冒号破坏了解析description: Use this skill when: the user asks about PDFs考虑一个回退方案,将此类值用引号包裹,或在重试前将其转换为 YAML 块标量。这以最小的成本提高了跨客户端兼容性。
在出现问题时给出警告,但尽可能仍然加载该 Skill:
- 名称与父目录名称不匹配 → 警告,仍然加载
- 名称超过 64 个字符 → 警告,仍然加载
- 描述缺失或为空 → 跳过该 Skill(描述对于披露至关重要),记录错误
- YAML 完全无法解析 → 跳过该 Skill,记录错误
记录诊断信息以便向用户展示(在调试命令、日志文件或 UI 中),但不要因表面问题阻塞 Skill 加载。
译者注:规范 对
name字段定义了严格的约束(与父目录匹配、字符集、最大长度)。上面的宽松方法有意放宽这些约束,以提高与其他客户端编写的 Skills 的兼容性。
要存储什么内容
Section titled “要存储什么内容”每个 Skill 记录至少需要三个字段:
| 字段 | 描述 |
|---|---|
name | 来自 frontmatter |
description | 来自 frontmatter |
location | SKILL.md 文件的绝对路径 |
将这些存储在以 name 为键的内存映射中,以便在激活期间快速查找。
你还可以在发现时存储 正文(frontmatter 之后的 markdown 内容),或在激活时从 location 读取它。存储它使激活更快;在激活时读取它会总体上占用更少的内存,并能捕获两次激活之间对 Skill 文件的更改。
Skill 的 基础目录(location 的父目录)在以后解析相对路径和枚举打包资源时会用到 — 在需要时从 location 派生。
步骤 3:向模型披露可用的 Skills
Section titled “步骤 3:向模型披露可用的 Skills”告诉模型存在哪些 Skills,而无需加载它们的完整内容。这是 Progressive Disclosure / 渐进式披露的第 1 层。
构建 Skill 目录
Section titled “构建 Skill 目录”对于每个发现的 Skill,包含 name、description,以及可选的 location(指向 SKILL.md 文件的路径),以适合你的技术栈的结构化格式(XML、JSON 或项目符号列表都可以):
<available_skills> <skill> <name>pdf-processing</name> <description>Extract PDF text, fill forms, merge files. Use when handling PDFs.</description> <location>/home/user/.agents/skills/pdf-processing/SKILL.md</location> </skill> <skill> <name>data-analysis</name> <description>Analyze datasets, generate charts, and create summary reports.</description> <location>/home/user/project/.agents/skills/data-analysis/SKILL.md</location> </skill></available_skills>location 字段有两个用途:支持文件读取激活(参见 步骤 4),并为模型提供解析 Skill 正文中相对引用的基础路径(如 scripts/evaluate.py)。如果你的专用激活工具在结果中提供了 Skill 目录路径(参见 步骤 4 中的结构化包装),则可以从目录中省略 location。否则,请包含它。
每个 Skill 大约向目录中添加 50-100 tokens。即使安装了数十个 Skills,目录仍然保持紧凑。
目录放在哪里
Section titled “目录放在哪里”两种方法都很常见:
系统提示部分:将目录作为带标签的部分添加到系统提示中,前面加上关于如何使用 Skills 的简要说明。这是最简单的方法,适用于任何可以访问文件读取工具的模型。
工具描述:将目录嵌入到专用 Skill 激活工具的描述中(参见 步骤 4)。这使得系统提示保持简洁,自然地将发现和激活耦合在一起。
两种方法都可以。系统提示位置更简单、兼容性更广;工具描述嵌入在你拥有专用激活工具时更简洁。
在目录旁边包含一个简短的指令块,告诉模型如何以及何时使用 Skills。措辞取决于你支持的激活机制(参见 步骤 4):
如果模型通过读取文件来激活 Skills:
The following skills provide specialized instructions for specific tasks.When a task matches a skill's description, use your file-read tool to loadthe SKILL.md at the listed location before proceeding.When a skill references relative paths, resolve them against the skill'sdirectory (the parent of SKILL.md) and use absolute paths in tool calls.如果模型通过专用工具激活 Skills:
The following skills provide specialized instructions for specific tasks.When a task matches a skill's description, call the activate_skill toolwith the skill's name to load its full instructions.请保持这些说明简洁。目标是告诉模型 Skills 存在以及如何加载 — Skill 内容本身会在加载后提供详细的指令。
某些 Skills 应该从目录中排除。常见原因:
- 用户已在设置中禁用了该 Skill
- 权限系统拒绝访问该 Skill
- 该 Skill 选择不参与模型驱动的激活(例如,通过
disable-model-invocation标志)
完全隐藏被过滤的 Skills,而不是列出它们并在激活时阻止。这样可以防止模型在试图加载它无法使用的 Skills 上浪费回合。
当没有可用 Skills 时
Section titled “当没有可用 Skills 时”如果没有发现 Skills,则完全省略目录和行为说明。不要显示空的 <available_skills/> 块或注册没有有效选项的 Skill 工具 — 这会让模型感到困惑。
步骤 4:激活 Skills
Section titled “步骤 4:激活 Skills”当模型或用户选择某个 Skill 时,将完整指令传递到对话上下文中。这是 Progressive Disclosure / 渐进式披露的第 2 层。
模型驱动的激活
Section titled “模型驱动的激活”大多数实现依赖模型自身的判断作为激活机制,而不是在智能体侧实现触发器匹配或关键字检测。模型从 步骤 3 中读取目录,判断某个 Skill 与当前任务相关,并加载它。
两种实现模式:
文件读取激活:模型使用标准的文件读取工具调用,参数为目录中的 SKILL.md 路径。无需特殊的基础设施 — 智能体现有的文件读取能力就够了。模型将文件内容作为工具结果接收。当模型可以访问文件时,这是最简单的方法。
专用工具激活:注册一个工具(例如 activate_skill),它接受 Skill 名称并返回其内容。这在模型无法直接读取文件时是必需的,在模型可以读取文件时也是可选的(但很有用)。相对于原始文件读取的优点:
- 控制返回的内容 — 例如,去除 YAML frontmatter 或保留它(参见下面的 模型接收到什么)
- 用结构化标签包装内容,以便在上下文管理期间进行识别
- 列出打包的资源(例如
references/*)以及指令 - 强制权限或提示用户同意
- 跟踪激活以进行分析
译者注:如果使用专用激活工具,请将
name参数限制为有效 Skill 名称的集合(例如,作为工具模式中的 enum)。这可以防止模型幻觉出不存在的 Skill 名称。如果没有可用的 Skills,则根本不要注册该工具。
用户显式激活
Section titled “用户显式激活”用户也应该能够直接激活 Skills,而无需等待模型决定。最常见的模式是 斜杠命令或提及语法(/skill-name 或 $skill-name),由智能体捕获。具体语法取决于你 — 关键思想是智能体处理查找和注入,这样模型无需自行采取激活操作即可接收 Skill 内容。
自动补全小部件(在用户输入时列出可用的 Skills)也可以使这更易发现。
模型接收到什么
Section titled “模型接收到什么”当某个 Skill 被激活时,模型会接收到该 Skill 的指令。确切的内容有两种选择:
完整文件:模型看到整个 SKILL.md,包括 YAML frontmatter。这是文件读取激活的自然结果,即模型读取原始文件。对于专用工具来说,这也是一个有效的选择。frontmatter 可能包含激活时有用的字段 — 例如,compatibility 记录了环境要求,可以让模型了解如何执行 Skill 的指令。
仅正文(剥离 frontmatter):智能体解析并删除 YAML frontmatter,仅返回 markdown 指令。在使用专用激活工具的现有实现中,大多数采用这种方法 — 在发现过程中提取 name 和 description 后剥离 frontmatter。
两种方法在实践中都有效。
如果使用专用激活工具,请考虑用识别标签包装 Skill 内容。例如:
<skill_content name="pdf-processing"># PDF Processing
## When to use this skillUse this skill when the user needs to work with PDF files...
[rest of SKILL.md body]
Skill directory: /home/user/.agents/skills/pdf-processingRelative paths in this skill are relative to the skill directory.
<skill_resources> <file>scripts/extract.py</file> <file>scripts/merge.py</file> <file>references/pdf-spec-summary.md</file></skill_resources></skill_content>这样做有以下实际好处:
- 模型可以清楚地区分 Skill 指令和其他对话内容
- 智能体可以在上下文压缩期间识别 Skill 内容(步骤 5)
- 打包的资源会被展示给模型,而不会被主动加载
列出打包的资源
Section titled “列出打包的资源”当专用激活工具返回 Skill 内容时,它还可以枚举 Skill 目录中的支持文件(脚本、参考资料、资源),但它 不应该主动读取它们。模型在 Skill 指令引用它们时,根据需要使用其文件读取工具加载特定的文件。
对于大型 Skill 目录,请考虑对列表进行上限限制并注明它可能不完整。
如果你的智能体具有限制文件访问的权限系统,请 将 Skill 目录加入白名单,以便模型可以在不触发用户确认提示的情况下读取打包的资源。否则,每次引用打包的脚本或参考文件都会导致权限对话框,从而中断 Skill 流程,特别是包含 SKILL.md 之外资源的 Skill。
步骤 5:长期管理 Skill 上下文
Section titled “步骤 5:长期管理 Skill 上下文”一旦 Skill 指令进入对话上下文,就要在整个会话期间保持其有效性。
在上下文压缩时保护 Skill 内容
Section titled “在上下文压缩时保护 Skill 内容”如果你的智能体在上下文窗口填满时截断或汇总较早的消息,请 豁免 Skill 内容免于剪裁。Skill 指令是持久的行为指导 — 在对话过程中丢失它们会悄悄降低智能体的性能,而不会显示任何可见的错误。模型会继续运行,但失去了 Skill 提供的专门指令。
常见方法:
- 将 Skill 工具输出标记为受保护,以便剪裁算法跳过它们
- 使用 步骤 4 中的结构化标签 来识别 Skill 内容并在压缩期间保留它
去除重复激活
Section titled “去除重复激活”考虑跟踪当前会话中已激活的 Skills。如果模型(或用户)尝试加载已在上下文中的 Skill,你可以跳过重新注入,以避免同一指令在对话中重复出现。
子智能体委托(可选)
Section titled “子智能体委托(可选)”这是仅由某些客户端支持的进阶模式。Skill 不再将指令注入主对话,而是在 单独的子智能体会话 中运行。子智能体接收 Skill 指令、执行任务,并向主对话返回其工作摘要。
当 Skill 的工作流复杂到足以受益于专用、专注的会话时,此模式非常有用。