> ## 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 添加技能支持

> 为 AI Agent 或开发工具添加 Agent Skills 支持的指南。

本指南逐步介绍如何为 AI Agent 或开发工具添加 Agent Skills 支持。它涵盖了完整的生命周期：发现技能、告知模型有关技能的信息、将技能内容加载到上下文中，以及随时间保持该内容的有效性。

无论你的 Agent 架构如何，核心集成方式都是相同的。实现细节因以下两个因素而异：

* **技能存储在哪里？** 本地运行的 Agent 可以扫描用户的文件系统以查找技能目录。云托管或沙盒化的 Agent 则需要替代的发现机制——API、远程注册表或捆绑的资源。
* **模型如何访问技能内容？** 如果模型具备文件读取能力，它可以直接读取 `SKILL.md` 文件。否则，你需要提供专用工具或以编程方式将技能内容注入提示词中。

本指南会指出这些差异重要的地方。你不需要支持每种场景——遵循适合你的 Agent 的路径即可。

**前置条件**：熟悉 [Agent Skills 规范](/specification)，该规范定义了 `SKILL.md` 文件格式、frontmatter 字段和目录约定。

## 核心原则：渐进式披露

每个兼容技能的 Agent 都遵循相同的三层加载策略：

| 层级    | 加载内容              | 时机       | Token 成本             |
| ----- | ----------------- | -------- | -------------------- |
| 1. 目录 | 名称 + 描述           | 会话开始     | 每个技能 \~50-100 tokens |
| 2. 指令 | 完整的 `SKILL.md` 正文 | 当技能被激活时  | \<5000 tokens（推荐）    |
| 3. 资源 | 脚本、参考、资产          | 当指令引用它们时 | 可变                   |

模型从一开始就能看到目录，因此它知道有哪些技能可用。当它决定某个技能相关时，它会加载完整的指令。如果这些指令引用了支持文件，模型会按需单独加载它们。

这使得基础上下文保持较小，同时让模型能够按需访问专业知识。拥有 20 个已安装技能的 Agent 不会预先支付 20 个完整指令集的 token 成本——只需支付给定对话中实际使用的技能成本。

## 步骤 1：发现技能

在会话启动时，查找所有可用技能并加载它们的元数据。

### 扫描位置

你扫描哪些目录取决于你的 Agent 环境。大多数本地运行的 Agent 至少扫描两个范围：

* **项目级**（相对于工作目录）：特定于项目或仓库的技能。
* **用户级**（相对于主目录）：对给定用户的所有项目可用的技能。

其他范围也是可能的——例如，由管理员部署的组织级技能，或与 Agent 本身捆绑的技能。正确的范围集取决于你的 Agent 部署模型。

在每个范围内，考虑扫描**客户端特定目录**和 **`.agents/skills/` 约定**：

| 范围 | 路径                                 | 用途         |
| -- | ---------------------------------- | ---------- |
| 项目 | `<project>/.<your-client>/skills/` | 你的客户端的原生位置 |
| 项目 | `<project>/.agents/skills/`        | 跨客户端互操作性   |
| 用户 | `~/.<your-client>/skills/`         | 你的客户端的原生位置 |
| 用户 | `~/.agents/skills/`                | 跨客户端互操作性   |

`.agents/skills/` 路径已成为跨客户端技能共享的广泛采用的约定。虽然 Agent Skills 规范不强制规定技能目录存储在哪里（它只定义其中的内容），但扫描 `.agents/skills/` 意味着由其他兼容客户端安装的技能对你的客户端自动可见，反之亦然。

<Note>
  一些实现还会扫描 `.claude/skills/`（项目级和用户级）以实现务实的兼容性，因为许多现有技能安装在那里。其他附加位置包括直到 git 根目录的祖先目录（对单体仓库有用）、[XDG](https://specifications.freedesktop.org/basedir-spec/latest/) 配置目录和用户配置的路径。
</Note>

### 扫描目标

在每个技能目录中，查找**包含名为 `SKILL.md` 文件的子目录**：

```
~/.agents/skills/
├── pdf-processing/
│   ├── SKILL.md          ← 已发现
│   └── scripts/
│       └── extract.py
├── data-analysis/
│   └── SKILL.md          ← 已发现
└── README.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 部署工件中的静态资产，使它们在每个会话中可用而无需外部获取。

一旦技能对 Agent 可用，生命周期的其余部分——解析、披露、激活——工作方式相同。

## 步骤 2：解析 `SKILL.md` 文件

对于每个发现的 `SKILL.md`，提取元数据和正文内容。

### Frontmatter 提取

`SKILL.md` 文件有两部分：`---` 分隔符之间的 YAML frontmatter，以及闭合分隔符之后的 markdown 正文。解析步骤：

1. 找到文件开头的起始 `---` 和其后的闭合 `---`。
2. 解析它们之间的 YAML 块。提取 `name` 和 `description`（必需），以及任何可选字段。
3. 闭合 `---` 之后的所有内容（修剪后）是技能的正文内容。

请参阅 [规范](/specification) 了解完整的 frontmatter 字段集及其约束。

### 处理格式错误的 YAML

为其他客户端编写的技能文件可能包含技术上无效的 YAML，而它们的解析器恰好接受。最常见的问题是包含冒号的未引用值：

```yaml theme={null}
# 技术上无效的 YAML — 冒号会破坏解析
description: Use this skill when: the user asks about PDFs
```

考虑一种回退机制，在重试前将此类值用引号包裹或转换为 YAML 块标量。这以最小的成本提高了跨客户端兼容性。

### 宽松验证

在可能时警告问题但仍加载技能：

* 名称与父目录名称不匹配 → 警告，仍加载
* 名称超过 64 个字符 → 警告，仍加载
* 描述缺失或为空 → 跳过技能（描述对于披露至关重要），记录错误
* YAML 完全无法解析 → 跳过技能，记录错误

记录诊断信息，以便它们可以展示给用户（在调试命令、日志文件或 UI 中），但不要因表面问题而阻止技能加载。

<Note>
  [规范](/specification) 定义了 `name` 字段的严格约束（匹配父目录、字符集、最大长度）。上面的宽松方法故意放宽了这些约束，以提高为其他客户端编写的技能的兼容性。
</Note>

### 存储内容

至少，每个技能记录需要三个字段：

| 字段            | 描述                 |
| ------------- | ------------------ |
| `name`        | 来自 frontmatter     |
| `description` | 来自 frontmatter     |
| `location`    | `SKILL.md` 文件的绝对路径 |

将这些存储在以 `name` 为键的内存映射中，以便在激活期间快速查找。

你也可以在发现时存储 **正文**（frontmatter 之后的 markdown 内容），或在激活时从 `location` 读取。存储它使激活更快；在激活时读取它在总体上使用更少的内存，并拾取激活之间技能文件的变化。

技能的 **基础目录**（`location` 的父目录）稍后需要用于解析相对路径和枚举捆绑的资源——在需要时从 `location` 派生它。

## 步骤 3：向模型披露可用技能

告诉模型存在哪些技能，而不加载它们的完整内容。这是 [渐进式披露的第 1 层](#the-core-principle-progressive-disclosure)。

### 构建技能目录

对于每个发现的技能，在适合你堆栈的任何结构化格式中包含 `name`、`description` 和可选的 `location`（`SKILL.md` 文件的路径）——XML、JSON 或项目符号列表都有效：

```xml theme={null}
<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](#step-4-activate-skills)），并且它为模型提供一个基础路径以解析技能正文中的相对引用（如 `scripts/evaluate.py`）。如果你的专用激活工具在其结果中提供技能目录路径（见步骤 4 中的 [结构化包装](#structured-wrapping)），你可以从目录中省略 `location`。否则，包含它。

每个技能向目录添加大约 50-100 个 tokens。即使安装了数十个技能，目录仍然保持紧凑。

### 目录放置位置

两种方法很常见：

**系统提示词部分**：将目录作为标记部分添加到系统提示词中，前面是关于如何使用技能的简要说明。这是最简单的方法，适用于任何可以访问文件读取工具的模型。

**工具描述**：将目录嵌入专用技能激活工具的描述中（见 [步骤 4](#step-4-activate-skills)）。这保持系统提示词干净，并自然地将发现与激活耦合。

两者都有效。系统提示词放置更简单且兼容性更广；当你有专用激活工具时，工具描述嵌入更干净。

### 行为指令

在目录旁边包含一个简短的指令块，告诉模型如何以及何时使用技能。措辞取决于你支持的激活机制（见 [步骤 4](#step-4-activate-skills)）：

**如果模型通过读取文件激活技能：**

```
The following skills provide specialized instructions for specific tasks.
When a task matches a skill's description, use your file-read tool to load
the SKILL.md at the listed location before proceeding.
When a skill references relative paths, resolve them against the skill's
directory (the parent of SKILL.md) and use absolute paths in tool calls.
```

**如果模型通过专用工具激活技能：**

```
The following skills provide specialized instructions for specific tasks.
When a task matches a skill's description, call the activate_skill tool
with the skill's name to load its full instructions.
```

保持这些指令简洁。目标是告诉模型技能存在以及如何加载它们——技能内容本身在加载后提供详细指令。

### 过滤

某些技能应从目录中排除。常见原因：

* 用户已在设置中禁用该技能
* 权限系统拒绝访问该技能
* 该技能已选择退出模型驱动的激活（例如，通过 `disable-model-invocation` 标志）

**从目录中完全隐藏过滤掉的技能**，而不是列出它们并在激活时阻止。这防止模型浪费回合尝试加载它无法使用的技能。

### 当没有可用技能时

如果没有发现技能，完全省略目录和行为指令。不要显示空的 `<available_skills/>` 块或注册没有有效选项的技能工具——这会混淆模型。

## 步骤 4：激活技能

当模型或用户选择技能时，将完整指令交付到对话上下文中。这是 [渐进式披露的第 2 层](#the-core-principle-progressive-disclosure)。

### 模型驱动的激活

大多数实现依赖于模型自身的判断作为激活机制，而不是实现 harness 端的触发匹配或关键词检测。模型读取目录（来自 [步骤 3](#step-3-disclose-available-skills-to-the-model)），决定某个技能与当前任务相关，然后加载它。

两种实现模式：

**文件读取激活**：模型调用其标准文件读取工具，使用目录中的 `SKILL.md` 路径。不需要特殊的基础设施——代理现有的文件读取能力就足够了。模型接收文件内容作为工具结果。当模型具有文件访问权限时，这是最简单的方法。

**专用工具激活**：注册一个工具（例如 `activate_skill`），它接受技能名称并返回内容。当模型无法直接读取文件时，这是必需的；即使模型可以读取文件，这也是可选的（但有用）。相对于原始文件读取的优势：

* 控制返回的内容——例如，剥离 YAML frontmatter 或保留它（参见下面的 [模型接收的内容](#what-the-model-receives)）
* 在上下文管理期间，将内容包装在结构化标签中以便识别
* 列出捆绑资源（例如 `references/*`）以及指令
* 强制执行权限或提示用户同意
* 跟踪激活以进行分析

<Tip>
  如果您使用专用激活工具，请将 `name` 参数限制为有效技能名称的集合（例如，作为工具模式中的枚举）。这可以防止模型幻觉出不存在的技能名称。如果没有可用技能，则根本不要注册该工具。
</Tip>

### 用户显式激活

用户也应该能够直接激活技能，而无需等待模型决定。最常见的模式是 **斜杠命令或提及语法**（`/skill-name` 或 `$skill-name`），由 harness 拦截。具体语法由您决定——关键在于 harness 处理查找和注入，因此模型接收技能内容而无需自己采取激活操作。

自动完成小部件（在用户输入时列出可用技能）也可以使其易于发现。

### 模型接收的内容

当技能被激活时，模型接收技能的指令。关于该内容具体样子的两种选项：

**完整文件**：模型看到整个 `SKILL.md`，包括 YAML frontmatter。这是文件读取激活的自然结果，模型读取原始文件。对于专用工具来说，这也是一个有效的选择。Frontmatter 可能包含在激活时有用的字段——例如，[`compatibility`](/specification#compatibility-field) 注明了环境要求，这些信息可以告知模型如何执行技能的指令。

**仅正文（移除 frontmatter）**：Harness 解析并移除 YAML frontmatter，仅返回 markdown 指令。在现有使用专用激活工具的实现中，大多数采用这种方法——在发现期间提取 `name` 和 `description` 后剥离 frontmatter。

这两种方法在实践中都有效。

### 结构化包装

如果您使用专用激活工具，请考虑将技能内容包装在识别标签中。例如：

```xml theme={null}
<skill_content name="pdf-processing">
# PDF Processing

## When to use this skill
Use this skill when the user needs to work with PDF files...

[rest of SKILL.md body]

Skill directory: /home/user/.agents/skills/pdf-processing
Relative 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>
```

这具有实际好处：

* 模型可以清晰区分技能指令与其他对话内容
* Harness 可以在上下文压缩期间识别技能内容（[步骤 5](#step-5-manage-skill-context-over-time)）
* 捆绑资源会展示给模型，而无需急于加载

### 列出捆绑资源

当专用激活工具返回技能内容时，它还可以枚举技能目录中的支持文件（脚本、参考、资产）——但它应该 **不急于读取它们**。当技能指令引用它们时，模型使用其文件读取工具按需加载特定文件。

对于大型技能目录，考虑限制列表数量并注明它可能不完整。

### 权限白名单

如果您的代理具有控制文件访问的权限系统，请 **将技能目录加入白名单**，以便模型可以读取捆绑资源而不会触发用户确认提示。如果没有这样做，每次引用捆绑脚本或参考文件都会导致权限对话框，从而破坏包含 `SKILL.md` 本身之外资源的技能的流程。

## 步骤 5：随时间管理技能上下文

一旦技能指令进入对话上下文，请在整个会话期间保持其有效。

### 保护技能内容免受上下文压缩

如果您的代理在上下文窗口填满时截断或总结旧消息，请 **免除技能内容的修剪**。技能指令是持久的行为指导——在对话中途丢失它们会无声地降低代理的性能，而没有任何可见错误。模型继续运行，但没有了技能提供的 specialized 指令。

常见方法：

* 将技能工具输出标记为受保护，以便修剪算法跳过它们
* 使用步骤 4 中的 [结构化标签](#structured-wrapping) 来识别技能内容并在压缩期间保留它

### 去重激活

考虑跟踪当前会话中已激活了哪些技能。如果模型（或用户）尝试加载已在上下文中的技能，您可以跳过重新注入，以避免相同指令在对话中多次出现。

### 子代理委托（可选）

这是一种仅受某些客户端支持的高级模式。技能指令不是注入到主对话中，而是在 **独立的子代理会话** 中运行技能。子代理接收技能指令，执行任务，并将其工作摘要返回到主对话。

当技能的工作流复杂到足以受益于专用的、专注的会话时，此模式非常有用。
