本指南逐步介绍如何为 AI Agent 或开发工具添加 Agent Skills 支持。它涵盖了完整的生命周期:发现技能、告知模型有关技能的信息、将技能内容加载到上下文中,以及随时间保持该内容的有效性。 无论你的 Agent 架构如何,核心集成方式都是相同的。实现细节因以下两个因素而异:Documentation Index
Fetch the complete documentation index at: https://agent-skills.zhcndoc.com/llms.txt
Use this file to discover all available pages before exploring further.
- 技能存储在哪里? 本地运行的 Agent 可以扫描用户的文件系统以查找技能目录。云托管或沙盒化的 Agent 则需要替代的发现机制——API、远程注册表或捆绑的资源。
- 模型如何访问技能内容? 如果模型具备文件读取能力,它可以直接读取
SKILL.md文件。否则,你需要提供专用工具或以编程方式将技能内容注入提示词中。
SKILL.md 文件格式、frontmatter 字段和目录约定。
核心原则:渐进式披露
每个兼容技能的 Agent 都遵循相同的三层加载策略:| 层级 | 加载内容 | 时机 | Token 成本 |
|---|---|---|---|
| 1. 目录 | 名称 + 描述 | 会话开始 | 每个技能 ~50-100 tokens |
| 2. 指令 | 完整的 SKILL.md 正文 | 当技能被激活时 | <5000 tokens(推荐) |
| 3. 资源 | 脚本、参考、资产 | 当指令引用它们时 | 可变 |
步骤 1:发现技能
在会话启动时,查找所有可用技能并加载它们的元数据。扫描位置
你扫描哪些目录取决于你的 Agent 环境。大多数本地运行的 Agent 至少扫描两个范围:- 项目级(相对于工作目录):特定于项目或仓库的技能。
- 用户级(相对于主目录):对给定用户的所有项目可用的技能。
.agents/skills/ 约定:
| 范围 | 路径 | 用途 |
|---|---|---|
| 项目 | <project>/.<your-client>/skills/ | 你的客户端的原生位置 |
| 项目 | <project>/.agents/skills/ | 跨客户端互操作性 |
| 用户 | ~/.<your-client>/skills/ | 你的客户端的原生位置 |
| 用户 | ~/.agents/skills/ | 跨客户端互操作性 |
.agents/skills/ 路径已成为跨客户端技能共享的广泛采用的约定。虽然 Agent Skills 规范不强制规定技能目录存储在哪里(它只定义其中的内容),但扫描 .agents/skills/ 意味着由其他兼容客户端安装的技能对你的客户端自动可见,反之亦然。
一些实现还会扫描
.claude/skills/(项目级和用户级)以实现务实的兼容性,因为许多现有技能安装在那里。其他附加位置包括直到 git 根目录的祖先目录(对单体仓库有用)、XDG 配置目录和用户配置的路径。扫描目标
在每个技能目录中,查找包含名为SKILL.md 文件的子目录:
- 跳过不会包含技能的目录,例如
.git/和node_modules/ - 可选地尊重
.gitignore以避免扫描构建产物 - 设置合理的界限(例如,最大深度 4-6 层,最大 2000 个目录)以防止在大型目录树中扫描失控
处理名称冲突
当两个技能共享相同的name 时,应用确定性优先规则。
现有实现中的通用约定:项目级技能覆盖用户级技能。
在同一范围内(例如,在 <project>/.agents/skills/ 和 <project>/.<your-client>/skills/ 下都找到名为 code-review 的两个技能),先找到或后找到都是可以接受的——选择一个并保持一致。当发生冲突时记录警告,以便用户知道某个技能被遮蔽了。
信任考量
项目级技能来自正在处理的仓库,该仓库可能不可信(例如, freshly cloned 的开源项目)。考虑基于信任检查来限制项目级技能加载——仅当用户已将项目文件夹标记为可信时才加载它们。这防止不可信的仓库静默地将指令注入 Agent 的上下文中。云托管和沙盒 Agent
如果你的 Agent 运行在容器或远程服务器上,它将无法访问用户的本地文件系统。发现机制需要根据技能范围以不同方式工作:- 项目级技能 通常是最简单的情况。如果 Agent 操作克隆的仓库(即使在沙盒内),项目级技能会随代码一起传输,可以从仓库的目录树中扫描。
- 用户级和组织级技能 不存在于沙盒中。你需要从外部源配置它们——例如,克隆配置仓库、通过 Agent 的设置接受技能 URL 或包,或让用户通过 Web UI 上传技能目录。
- 内置技能 可以打包为 Agent 部署工件中的静态资产,使它们在每个会话中可用而无需外部获取。
步骤 2:解析 SKILL.md 文件
对于每个发现的 SKILL.md,提取元数据和正文内容。
Frontmatter 提取
SKILL.md 文件有两部分:--- 分隔符之间的 YAML frontmatter,以及闭合分隔符之后的 markdown 正文。解析步骤:
- 找到文件开头的起始
---和其后的闭合---。 - 解析它们之间的 YAML 块。提取
name和description(必需),以及任何可选字段。 - 闭合
---之后的所有内容(修剪后)是技能的正文内容。
处理格式错误的 YAML
为其他客户端编写的技能文件可能包含技术上无效的 YAML,而它们的解析器恰好接受。最常见的问题是包含冒号的未引用值:宽松验证
在可能时警告问题但仍加载技能:- 名称与父目录名称不匹配 → 警告,仍加载
- 名称超过 64 个字符 → 警告,仍加载
- 描述缺失或为空 → 跳过技能(描述对于披露至关重要),记录错误
- YAML 完全无法解析 → 跳过技能,记录错误
规范 定义了
name 字段的严格约束(匹配父目录、字符集、最大长度)。上面的宽松方法故意放宽了这些约束,以提高为其他客户端编写的技能的兼容性。存储内容
至少,每个技能记录需要三个字段:| 字段 | 描述 |
|---|---|
name | 来自 frontmatter |
description | 来自 frontmatter |
location | SKILL.md 文件的绝对路径 |
name 为键的内存映射中,以便在激活期间快速查找。
你也可以在发现时存储 正文(frontmatter 之后的 markdown 内容),或在激活时从 location 读取。存储它使激活更快;在激活时读取它在总体上使用更少的内存,并拾取激活之间技能文件的变化。
技能的 基础目录(location 的父目录)稍后需要用于解析相对路径和枚举捆绑的资源——在需要时从 location 派生它。
步骤 3:向模型披露可用技能
告诉模型存在哪些技能,而不加载它们的完整内容。这是 渐进式披露的第 1 层。构建技能目录
对于每个发现的技能,在适合你堆栈的任何结构化格式中包含name、description 和可选的 location(SKILL.md 文件的路径)——XML、JSON 或项目符号列表都有效:
location 字段有两个用途:它启用文件读取激活(见 步骤 4),并且它为模型提供一个基础路径以解析技能正文中的相对引用(如 scripts/evaluate.py)。如果你的专用激活工具在其结果中提供技能目录路径(见步骤 4 中的 结构化包装),你可以从目录中省略 location。否则,包含它。
每个技能向目录添加大约 50-100 个 tokens。即使安装了数十个技能,目录仍然保持紧凑。
目录放置位置
两种方法很常见: 系统提示词部分:将目录作为标记部分添加到系统提示词中,前面是关于如何使用技能的简要说明。这是最简单的方法,适用于任何可以访问文件读取工具的模型。 工具描述:将目录嵌入专用技能激活工具的描述中(见 步骤 4)。这保持系统提示词干净,并自然地将发现与激活耦合。 两者都有效。系统提示词放置更简单且兼容性更广;当你有专用激活工具时,工具描述嵌入更干净。行为指令
在目录旁边包含一个简短的指令块,告诉模型如何以及何时使用技能。措辞取决于你支持的激活机制(见 步骤 4): 如果模型通过读取文件激活技能:过滤
某些技能应从目录中排除。常见原因:- 用户已在设置中禁用该技能
- 权限系统拒绝访问该技能
- 该技能已选择退出模型驱动的激活(例如,通过
disable-model-invocation标志)
当没有可用技能时
如果没有发现技能,完全省略目录和行为指令。不要显示空的<available_skills/> 块或注册没有有效选项的技能工具——这会混淆模型。
步骤 4:激活技能
当模型或用户选择技能时,将完整指令交付到对话上下文中。这是 渐进式披露的第 2 层。模型驱动的激活
大多数实现依赖于模型自身的判断作为激活机制,而不是实现 harness 端的触发匹配或关键词检测。模型读取目录(来自 步骤 3),决定某个技能与当前任务相关,然后加载它。 两种实现模式: 文件读取激活:模型调用其标准文件读取工具,使用目录中的SKILL.md 路径。不需要特殊的基础设施——代理现有的文件读取能力就足够了。模型接收文件内容作为工具结果。当模型具有文件访问权限时,这是最简单的方法。
专用工具激活:注册一个工具(例如 activate_skill),它接受技能名称并返回内容。当模型无法直接读取文件时,这是必需的;即使模型可以读取文件,这也是可选的(但有用)。相对于原始文件读取的优势:
- 控制返回的内容——例如,剥离 YAML frontmatter 或保留它(参见下面的 模型接收的内容)
- 在上下文管理期间,将内容包装在结构化标签中以便识别
- 列出捆绑资源(例如
references/*)以及指令 - 强制执行权限或提示用户同意
- 跟踪激活以进行分析
用户显式激活
用户也应该能够直接激活技能,而无需等待模型决定。最常见的模式是 斜杠命令或提及语法(/skill-name 或 $skill-name),由 harness 拦截。具体语法由您决定——关键在于 harness 处理查找和注入,因此模型接收技能内容而无需自己采取激活操作。
自动完成小部件(在用户输入时列出可用技能)也可以使其易于发现。
模型接收的内容
当技能被激活时,模型接收技能的指令。关于该内容具体样子的两种选项: 完整文件:模型看到整个SKILL.md,包括 YAML frontmatter。这是文件读取激活的自然结果,模型读取原始文件。对于专用工具来说,这也是一个有效的选择。Frontmatter 可能包含在激活时有用的字段——例如,compatibility 注明了环境要求,这些信息可以告知模型如何执行技能的指令。
仅正文(移除 frontmatter):Harness 解析并移除 YAML frontmatter,仅返回 markdown 指令。在现有使用专用激活工具的实现中,大多数采用这种方法——在发现期间提取 name 和 description 后剥离 frontmatter。
这两种方法在实践中都有效。
结构化包装
如果您使用专用激活工具,请考虑将技能内容包装在识别标签中。例如:- 模型可以清晰区分技能指令与其他对话内容
- Harness 可以在上下文压缩期间识别技能内容(步骤 5)
- 捆绑资源会展示给模型,而无需急于加载
列出捆绑资源
当专用激活工具返回技能内容时,它还可以枚举技能目录中的支持文件(脚本、参考、资产)——但它应该 不急于读取它们。当技能指令引用它们时,模型使用其文件读取工具按需加载特定文件。 对于大型技能目录,考虑限制列表数量并注明它可能不完整。权限白名单
如果您的代理具有控制文件访问的权限系统,请 将技能目录加入白名单,以便模型可以读取捆绑资源而不会触发用户确认提示。如果没有这样做,每次引用捆绑脚本或参考文件都会导致权限对话框,从而破坏包含SKILL.md 本身之外资源的技能的流程。
步骤 5:随时间管理技能上下文
一旦技能指令进入对话上下文,请在整个会话期间保持其有效。保护技能内容免受上下文压缩
如果您的代理在上下文窗口填满时截断或总结旧消息,请 免除技能内容的修剪。技能指令是持久的行为指导——在对话中途丢失它们会无声地降低代理的性能,而没有任何可见错误。模型继续运行,但没有了技能提供的 specialized 指令。 常见方法:- 将技能工具输出标记为受保护,以便修剪算法跳过它们
- 使用步骤 4 中的 结构化标签 来识别技能内容并在压缩期间保留它