
Agent Skills 是一个开放标准,用于为 AI Agent 扩展专用能力。本文将从概念、工作原理、规范、分类、脚本支持、最佳实践等多个维度,带你全面了解 Agent Skills。
一、什么是 Agent Skill?
1.1 基本概念
Agent Skill(技能) 是一种可移植、受版本控制的包,用来教会 AI Agent 执行特定领域的任务。你可以把它理解为给 AI Agent 安装的「插件」或「技能包」------它把特定领域的知识、工作流程、脚本和最佳实践打包封装,供 Agent 在合适的时机自动调用。
用一个更直观的比喻:如果 AI Agent 是一位通才型的新员工,那么 Skill 就是你为他准备的入职培训手册------它不会改变员工的智力水平,但会让他立刻掌握公司特定的工作流程和领域知识。
1.2 四大特性
| 特性 | 说明 |
|---|---|
| 可移植 | Skill 可用于任何支持 Agent Skills 标准的 Agent,不锁定到特定平台 |
| 受版本控制 | Skill 以文件形式存储,可以在代码仓库中追踪,通过 GitHub 仓库链接安装 |
| 可操作 | Skill 可以包含脚本、模板和参考信息,Agent 会通过其工具对这些内容进行操作 |
| 渐进式 | Skill 按需加载资源,使上下文使用更加高效 |
1.3 为什么需要 Skill?
问题场景:你每次和 AI Agent 对话时,都需要反复提供相同的上下文------比如公司的代码规范、部署流程、数据库表结构等。这既浪费时间,也容易遗漏。
Skill 的解决方案:
- 专业化:让通用 Agent 变成特定领域的专家
- 减少重复:一次创建,自动使用
- 能力组合:多个 Skill 可以组合使用,构建复杂工作流
- 知识沉淀:将团队的工作流程、最佳实践和机构知识固化下来
二、核心设计理念:渐进式披露
渐进式披露(Progressive Disclosure)是 Agent Skills 最核心的设计理念。它确保 Agent 只在需要时加载必要的信息,而非一开始就把所有内容塞进上下文窗口。
2.1 三级加载机制
~100 tokens/Skill
启动时始终加载"] --> B{"用户任务是否
匹配 Skill?"} B -->|是| C["🟡 Level 2: 指令内容
< 5000 tokens
Skill 被触发时加载"] B -->|否| D["不加载,零消耗"] C --> E{"指令中引用了
其他文件?"} E -->|是| F["🔴 Level 3: 资源文件
按需加载
脚本、参考文档等"] E -->|否| G["直接执行任务"] F --> G style A fill:#d4edda,stroke:#28a745 style C fill:#fff3cd,stroke:#ffc107 style F fill:#f8d7da,stroke:#dc3545 style D fill:#e2e3e5,stroke:#6c757d
| 级别 | 加载时机 | Token 消耗 | 内容 |
|---|---|---|---|
| Level 1: 元数据 | 启动时始终加载 | ~100 tokens/Skill | YAML frontmatter 中的 name 和 description |
| Level 2: 指令 | Skill 被触发时 | < 5000 tokens | SKILL.md 主体内容(指令和指南) |
| Level 3: 资源 | 按需加载 | 理论上无限 | 脚本、参考文档、模板等附属文件 |
2.2 为什么这很重要?
上下文窗口是一种公共资源,你的 Skill 和以下内容共享这个空间:
- 系统提示词(System Prompt)
- 对话历史
- 其他 Skill 的元数据
- 用户的实际请求
渐进式披露让你可以安装几十个 Skill 而不会产生上下文压力------Agent 只知道每个 Skill 的存在和用途,只有在真正需要时才加载完整内容。
三、Agent 如何消费 Skill?
理解 Skill 的消费机制是理解整个体系的关键。这里需要区分三个角色:Agent(程序) 、LLM(大模型) 和 Skill 文件(文件系统)。Agent 是 LLM 的"外壳程序",负责管理对话、调用工具、组装 prompt;LLM 是做决策的大脑;Skill 文件是静态的知识包。
3.1 Agent、LLM 与 Skill 的完整交互流程
下面这张图完整展示了从 Agent 启动到 Skill 被使用的全过程。注意关键点:Skill 的筛选和激活是由 LLM 决策的,Agent 只负责执行 LLM 的指令(读文件、跑脚本)。
(Skill 文件) participant A as Agent
(程序/外壳) participant LLM as LLM
(大模型) participant U as 用户 rect rgb(240, 248, 255) Note over FS,U: 阶段一:启动 --- Agent 发现 Skill 并构建目录 A->>FS: 扫描 .agents/skills/、~/.cursor/skills/ 等目录 FS-->>A: 返回所有 SKILL.md 文件路径 A->>A: 解析每个 SKILL.md 的 YAML frontmatter A->>A: 提取 name + description,构建 Skill 目录 Note over A: 将 Skill 目录注入 System Prompt end rect rgb(255, 253, 240) Note over FS,U: 阶段二:请求 --- 用户提问,LLM 决策是否需要 Skill U->>A: "帮我从这个 PDF 中提取文本并总结" A->>LLM: 发送 prompt =
System Prompt(含 Skill 目录)
+ 对话历史
+ 用户消息
+ 可用工具列表 Note over LLM: LLM 看到 System Prompt 中的 Skill 目录:
pdf-processing: "Extract PDF text..."
data-analysis: "Analyze datasets..."
→ 判断 pdf-processing 相关 LLM-->>A: 返回 tool_use: Read("pdf-processing/SKILL.md") end rect rgb(240, 255, 240) Note over FS,U: 阶段三:激活 --- Agent 加载 Skill 内容,返回给 LLM A->>FS: 读取 pdf-processing/SKILL.md FS-->>A: 返回 SKILL.md 完整内容(指令 + 工作流) A->>LLM: 将 SKILL.md 内容作为 tool_result 返回
(指令进入上下文窗口) Note over LLM: LLM 现在拥有了 PDF 处理的
完整专业指令 end rect rgb(255, 240, 245) Note over FS,U: 阶段四:执行 --- LLM 按照 Skill 指令操作 LLM-->>A: tool_use: Bash("python scripts/extract.py input.pdf") A->>FS: 执行脚本 extract.py FS-->>A: 脚本输出:"Extracted 15 pages of text..." A->>LLM: 将脚本输出作为 tool_result 返回 LLM-->>A: tool_use: Read("references/FORMS.md") Note over LLM: 判断不需要 FORMS.md,跳过 LLM-->>A: 生成最终回复(文本) A->>U: 返回 PDF 提取和总结结果 end
关键要点
上面这张图有几个值得特别注意的地方:
1. Skill 目录在启动时就注入 System Prompt
Agent 启动时扫描文件系统,提取每个 Skill 的 name 和 description(每个约 100 tokens),拼接成一个"技能目录"块,注入到 System Prompt 中。这个目录类似这样:
xml
<available_skills>
<skill>
<name>pdf-processing</name>
<description>Extract PDF text, fill forms, merge files. Use when handling PDFs.</description>
<location>~/.agents/skills/pdf-processing/SKILL.md</location>
</skill>
<skill>
<name>data-analysis</name>
<description>Analyze datasets, generate charts, and create summary reports.</description>
<location>~/project/.agents/skills/data-analysis/SKILL.md</location>
</skill>
</available_skills>
2. Skill 筛选由 LLM 完成,不是 Agent 硬编码匹配
Agent 不会自己做关键词匹配来决定用哪个 Skill。而是将"技能目录"和用户消息一起发给 LLM,由 LLM 根据语义理解决定是否加载某个 Skill。LLM 的决策体现为一次工具调用------调用 Read 工具读取对应的 SKILL.md 文件。
3. Skill 内容通过"工具调用-工具结果"机制进入上下文
SKILL.md 的内容不是直接塞进 prompt 的,而是通过 LLM 主动发起一次 Read 工具调用,Agent 执行读取后将内容作为 tool_result 返回。这意味着 Skill 的加载使用的是和其他工具调用完全相同的通信机制。
4. 后续操作(读引用文件、执行脚本)也都是 LLM 驱动的
加载 SKILL.md 后,LLM 可能继续发起工具调用来读取参考文档或执行脚本。每次都是 LLM 做决策、Agent 执行、结果返回,循环进行。
3.2 与 MCP Tool 交互流程的对比
Skills 和 MCP Tools 都是扩展 Agent 能力的方式,但交互模式有本质区别。下面用两张并排的时序图来对比:
MCP Tool 的交互流程
(外部工具) participant A as Agent
(程序/外壳) participant LLM as LLM
(大模型) participant U as 用户 rect rgb(240, 248, 255) Note over T,U: 步骤一:工具定义随请求发送 U->>A: "帮我查一下北京今天的天气" A->>LLM: 发送 prompt +
tools: [get_weather 的 JSON Schema 定义] end rect rgb(255, 253, 240) Note over T,U: 步骤二:LLM 决定调用工具 LLM-->>A: tool_use: get_weather(city="北京") end rect rgb(240, 255, 240) Note over T,U: 步骤三:Agent 执行工具,拼接结果 A->>T: 调用 MCP Server 的 get_weather T-->>A: {"temp": "22°C", "weather": "晴"} A->>LLM: 拼接 tool_result 到对话中,再次请求 end rect rgb(255, 240, 245) Note over T,U: 步骤四:LLM 生成最终回复 LLM-->>A: "北京今天天气晴,气温 22°C" A->>U: 返回回复 end
Skill 与 MCP Tool 的本质区别
随每次请求发送"] --> M2["LLM 决定调用工具"] M2 --> M3["Agent 执行工具"] M3 --> M4["工具返回 数据"] M4 --> M5["LLM 基于数据生成回复"] end subgraph SK["Skill 模式"] direction TB S1["技能目录(name + description)
注入 System Prompt"] --> S2["LLM 决定激活 Skill"] S2 --> S3["Agent 读取 SKILL.md"] S3 --> S4["Skill 返回 指令"] S4 --> S5["LLM 按照指令 执行后续操作
(可能继续调用工具/脚本)"] end style M4 fill:#e3f2fd,stroke:#1976D2 style S4 fill:#e8f5e9,stroke:#388E3C
总结两者的核心差异:
| 维度 | MCP Tool | Agent Skill |
|---|---|---|
| 本质 | 提供能力(做某件事) | 提供指令(教会怎么做) |
| 信息注入位置 | 工具定义随 tools 参数发送 |
技能目录注入 System Prompt |
| 触发结果 | 返回数据(API 响应、查询结果) | 返回指令(工作流程、最佳实践) |
| LLM 行为变化 | 获得一个新的数据源 | 获得一整套新的行为指南 |
| 类比 | 给员工一把新工具 | 给员工一本操作手册 |
| 组合使用 | --- | Skill 指令中可以指导 LLM 如何使用 MCP Tool |
一个常见的强力组合场景:MCP 给 Agent 提供了调用 BigQuery 的能力(工具),Skill 教会 Agent 你们公司的表结构、查询规范和注意事项(指令)。两者互补,缺一不可。
3.3 完整的 Prompt 拼接示意
为了更直观地理解 Skill 是如何融入 Agent 与 LLM 的对话流程中的,下面展示一次完整交互中 Agent 发给 LLM 的 prompt 结构:
less
┌──────────────────────────────────────────────────────────┐
│ System Prompt │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 基础指令(你是一个 AI 助手...) │ │
│ ├────────────────────────────────────────────────────┤ │
│ │ 📦 可用技能目录(~100 tokens × N 个 Skill) │ │
│ │ • pdf-processing: Extract PDF text, fill forms... │ │
│ │ • data-analysis: Analyze datasets, generate... │ │
│ │ • deploy-app: Deploy the application to... │ │
│ │ 当任务匹配技能描述时,使用 Read 工具加载 SKILL.md │ │
│ ├────────────────────────────────────────────────────┤ │
│ │ 🔧 可用工具列表 │ │
│ │ • Read(读取文件) │ │
│ │ • Bash(执行命令) │ │
│ │ • get_weather(MCP 工具) │ │
│ │ • ... │ │
│ └────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────┤
│ 对话历史 │
│ [user]: 帮我从这个 PDF 中提取文本 │
│ [assistant]: tool_use → Read("pdf-processing/SKILL.md") │
│ [tool_result]: # PDF Processing ...(SKILL.md 内容) │
│ [assistant]: tool_use → Bash("python scripts/extract.py")│
│ [tool_result]: Extracted 15 pages of text... │
│ [assistant]: 已从 PDF 中提取文本,以下是总结... │
├──────────────────────────────────────────────────────────┤
│ 当前用户消息 │
│ [user]: 再帮我把提取的内容生成一份 Word 文档 │
└──────────────────────────────────────────────────────────┘
可以看到:
- Skill 目录 和 MCP 工具定义同时存在于 prompt 中
- Skill 的激活(读取 SKILL.md)在对话历史中表现为一次普通的工具调用
- SKILL.md 的内容作为
tool_result留在对话历史中,持续影响后续 LLM 的行为
3.4 发现阶段详解
Agent 启动时,会从以下目录自动发现技能:
| 位置 | 级别 | 说明 |
|---|---|---|
.agents/skills/ |
项目级 | 跨客户端通用目录 |
.cursor/skills/ |
项目级 | Cursor 专用目录 |
~/.cursor/skills/ |
用户级(全局) | 所有项目可用 |
.claude/skills/ |
项目级 | Claude Code 兼容目录 |
~/.claude/skills/ |
用户级 | Claude Code 全局兼容 |
扫描规则:
- 跳过
.git/、node_modules/等无关目录 - 设置合理的扫描深度(一般 4-6 层)和目录数上限(~2000 个)
- 项目级 Skill 优先级高于用户级 Skill(同名时覆盖)
3.5 触发激活方式
Skill 有两种激活方式:
自动触发(Model-driven) :LLM 看到 System Prompt 中的技能目录后,根据用户请求的语义自动判断是否需要加载某个 Skill。这是最常见的方式------LLM 的决策体现为一次读取 SKILL.md 的工具调用。
手动调用(User-explicit) :用户在对话中输入 /skill-name(斜杠命令)来显式调用特定 Skill。此时 Agent(程序侧)直接将 SKILL.md 内容注入上下文,不需要 LLM 做判断。适用于设置了 disable-model-invocation: true 的 Skill。
3.6 脚本执行的高效性
当 Skill 中的指令引用了脚本文件时,Agent 通过 bash 直接执行脚本,而不是将脚本代码读入上下文:
scripts/extract.py"} B --> C["执行脚本
bash: python scripts/extract.py"] C --> D["只有脚本输出
进入上下文窗口"] style D fill:#d4edda,stroke:#28a745
这意味着:
- 脚本代码本身不会消耗上下文 token
- 只有脚本的输出结果会进入 Agent 的上下文
- 比让 Agent 临时生成代码更可靠、更高效
四、Skill 的规范与结构
4.1 目录结构
每个 Skill 是一个包含 SKILL.md 文件的文件夹:
perl
my-skill/
├── SKILL.md # 必需:元数据 + 指令
├── scripts/ # 可选:可执行代码
│ ├── deploy.sh
│ └── validate.py
├── references/ # 可选:补充文档
│ ├── REFERENCE.md
│ └── FORMS.md
├── assets/ # 可选:模板、图片等静态资源
│ └── config-template.json
└── ... # 任何其他文件或目录
各目录的职责:
| 目录 | 用途 | 加载时机 |
|---|---|---|
SKILL.md |
主要指令文件(核心) | Skill 被触发时加载 |
scripts/ |
Agent 可执行的代码 | 被指令引用时执行 |
references/ |
按需加载的补充文档 | 被指令引用时读取 |
assets/ |
模板、图片、数据文件等静态资源 | 被指令引用时读取 |
4.2 SKILL.md 文件格式
每个 Skill 在带有 YAML frontmatter 的 SKILL.md 文件中定义:
markdown
---
name: pdf-processing
description: Extract PDF text, fill forms, merge files. Use when handling PDFs.
license: Apache-2.0
metadata:
author: example-org
version: "1.0"
---
# PDF Processing
## Quick start
Use pdfplumber to extract text from PDFs:
```python
import pdfplumber
with pdfplumber.open("file.pdf") as pdf:
text = pdf.pages[0].extract_text()
Advanced features
Form filling : See FORMS.md for complete guide API reference : See REFERENCE.md for all methods
yaml
### 4.3 Frontmatter 字段详解
#### 必填字段
| 字段 | 约束 | 说明 |
|------|------|------|
| `name` | 最多 64 字符,仅允许小写字母、数字和连字符,不能以连字符开头或结尾,不能包含连续连字符,必须与父文件夹名一致 | 技能标识符 |
| `description` | 最多 1024 字符,不能为空 | 描述技能功能和使用场景,Agent 用它来判断相关性 |
#### 可选字段
| 字段 | 约束 | 说明 |
|------|------|------|
| `license` | 无 | 许可证名称或对随附许可证文件的引用 |
| `compatibility` | 最多 500 字符 | 环境要求(目标产品、系统软件包、网络访问等) |
| `metadata` | 键值对映射 | 用于附加元数据(如 author、version) |
| `disable-model-invocation` | 布尔值 | 为 `true` 时仅在通过 `/skill-name` 显式调用时才使用 |
| `allowed-tools` | 空格分隔的工具列表 | 预批准该 Skill 可使用的工具(实验性功能) |
#### name 字段示例
```yaml
# ✅ 合法
name: pdf-processing
name: data-analysis
name: code-review
# ❌ 非法
name: PDF-Processing # 不允许大写
name: -pdf # 不能以连字符开头
name: pdf--processing # 不能有连续连字符
description 字段示例
yaml
# ✅ 好的描述:具体且包含触发关键词
description: >
Extract text and tables from PDF files, fill forms, merge documents.
Use when working with PDF files or when the user mentions PDFs,
forms, or document extraction.
# ❌ 差的描述:太模糊
description: Helps with PDFs.
4.4 文件引用规范
在 Skill 中引用其他文件时,使用相对于 Skill 根目录的路径:
markdown
See [the reference guide](references/REFERENCE.md) for details.
Run the extraction script:
scripts/extract.py
关键规则:
- 始终使用正斜杠
references/guide.md,而非反斜杠 - 文件引用保持一层深度,避免嵌套引用链
- 文件名应当有描述性:用
form_validation_rules.md而不是doc2.md
五、Skill 的分类
(Anthropic 官方)"] S --> B["自定义 Skill
(Custom Skills)"] S --> C["组织级 Skill
(Organization Provisioned)"] S --> D["合作伙伴 Skill
(Partner Skills)"] A --> A1["PowerPoint (pptx)"] A --> A2["Excel (xlsx)"] A --> A3["Word (docx)"] A --> A4["PDF (pdf)"] B --> B1["纯指令型 Skill"] B --> B2["包含脚本的 Skill"] B --> B3["包含参考文档的 Skill"] B --> B4["复合型 Skill"] C --> C1["管理员统一分发"] C --> C2["团队共享标准流程"] D --> D1["Notion"] D --> D2["Figma"] D --> D3["Atlassian"] style A fill:#e3f2fd,stroke:#1976D2 style B fill:#e8f5e9,stroke:#388E3C style C fill:#fff3e0,stroke:#F57C00 style D fill:#f3e5f5,stroke:#7B1FA2
5.1 预构建 Skill(Anthropic Skills)
由 Anthropic 官方创建和维护的 Skill,开箱即用:
| Skill | skill_id | 功能 |
|---|---|---|
| PowerPoint | pptx |
创建演示文稿、编辑幻灯片、分析演示内容 |
| Excel | xlsx |
创建电子表格、分析数据、生成图表报告 |
| Word | docx |
创建文档、编辑内容、格式化文本 |
pdf |
生成格式化的 PDF 文档和报告 |
这些 Skill 在 claude.ai 和 Claude API 上对所有用户可用,Agent 会在相关任务中自动调用。
5.2 自定义 Skill(Custom Skills)
用户或组织自行创建的 Skill,用于特定领域的工作流。按内容构成可分为:
纯指令型 Skill
只包含 SKILL.md,通过自然语言指令指导 Agent:
css
code-review/
└── SKILL.md
适用场景:代码审查流程、写作风格指南、会议纪要模板等不需要执行代码的任务。
包含参考文档的 Skill
除主指令外,附带额外的参考文档,Agent 按需读取:
markdown
bigquery-skill/
├── SKILL.md
└── reference/
├── finance.md
├── sales.md
└── product.md
适用场景:需要大量领域知识的任务,如数据库分析、API 对接等。
包含脚本的 Skill
附带可执行脚本,Agent 在执行任务时调用:
markdown
deploy-app/
├── SKILL.md
└── scripts/
├── deploy.sh
└── validate.py
适用场景:部署、数据处理、表单填充等需要确定性操作的任务。
复合型 Skill
同时包含指令、参考文档、脚本和资源:
arduino
pdf-processing/
├── SKILL.md
├── FORMS.md
├── REFERENCE.md
├── examples.md
├── scripts/
│ ├── analyze_form.py
│ ├── fill_form.py
│ └── validate.py
└── assets/
└── template.json
5.3 组织级 Skill(Organization Provisioned)
针对 Team 和 Enterprise 计划,组织的管理员可以为所有用户统一配置 Skill:
- 分发经过审批的工作流,确保全员一致
- 确保团队使用标准化的流程和最佳实践
- 部署新能力无需每个用户单独上传
- Skill 可设为默认启用或禁用
5.4 合作伙伴 Skill(Partner Skills)
由合作伙伴(如 Notion、Figma、Atlassian 等)专业构建的 Skill,设计为与对应的 MCP 连接器无缝配合使用,实现强大的集成工作流。
六、支持脚本的 Skill
支持脚本是 Agent Skill 最强大的能力之一。它将确定性的代码执行与 Agent 的灵活决策结合起来。
6.1 脚本 vs 指令的选择
确定性结果?"} B -->|是| C{"操作是否复杂
且容易出错?"} B -->|否| D["使用文本指令
(高自由度)"] C -->|是| E["使用脚本
(低自由度)"] C -->|否| F["使用伪代码或
带参数的脚本
(中等自由度)"] style D fill:#d4edda style E fill:#f8d7da style F fill:#fff3cd
| 自由度 | 方式 | 适用场景 | 示例 |
|---|---|---|---|
| 高 | 文本指令 | 多种方法均可、依赖上下文判断 | 代码审查、写作指导 |
| 中 | 伪代码/带参数脚本 | 有推荐模式但允许变通 | 报告生成、数据转换 |
| 低 | 固定脚本 | 操作脆弱、一致性关键 | 数据库迁移、部署流程 |
6.2 一次性命令
当现有工具包已经能满足需求时,可以直接在 SKILL.md 中引用,而不需要 scripts/ 目录:
| 工具 | 语言生态 | 命令示例 |
|---|---|---|
uvx |
Python | uvx ruff@0.8.0 check . |
pipx |
Python | pipx run 'black==24.10.0' . |
npx |
Node.js | npx eslint@9 --fix . |
bunx |
Bun | bunx eslint@9 --fix . |
deno run |
Deno | deno run npm:create-vite@6 my-app |
go run |
Go | go run golang.org/x/tools/cmd/goimports@v0.28.0 . |
关键原则:锁定版本号,确保行为一致。
6.3 自包含脚本
当需要自定义逻辑时,将脚本放入 scripts/ 目录并声明内联依赖:
Python 示例(PEP 723):
python
# /// script
# dependencies = [
# "beautifulsoup4",
# ]
# ///
from bs4 import BeautifulSoup
html = '<html><body><h1>Welcome</h1><p class="info">Test.</p></body></html>'
print(BeautifulSoup(html, "html.parser").select_one("p.info").get_text())
使用 uv run scripts/extract.py 运行,uv 会自动创建隔离环境并安装依赖。
Deno 示例:
typescript
#!/usr/bin/env -S deno run
import * as cheerio from "npm:cheerio@1.0.0";
const html = `<html><body><p class="info">Test.</p></body></html>`;
const $ = cheerio.load(html);
console.log($("p.info").text());
6.4 脚本设计原则
为 Agent 设计脚本时,需要遵循以下原则:
禁止交互式提示
Agent 在非交互式 shell 中运行,无法响应 TTY 提示。所有输入通过命令行参数、环境变量或 stdin 接收:
bash
# ❌ 错误:会挂起等待输入
$ python scripts/deploy.py
Target environment: _
# ✅ 正确:清晰的错误提示
$ python scripts/deploy.py
Error: --env is required. Options: development, staging, production.
Usage: python scripts/deploy.py --env staging --tag v1.2.3
提供 --help 文档
--help 输出是 Agent 了解脚本接口的主要方式:
lua
Usage: scripts/process.py [OPTIONS] INPUT_FILE
Process input data and produce a summary report.
Options:
--format FORMAT Output format: json, csv, table (default: json)
--output FILE Write output to FILE instead of stdout
--verbose Print progress to stderr
提供有意义的错误信息
makefile
# ❌ 不好:模糊
Error: invalid input
# ✅ 好:具体且有指导性
Error: --format must be one of: json, csv, table.
Received: "xml"
使用结构化输出
优先使用 JSON、CSV 等结构化格式,而非自由文本。将数据输出到 stdout,诊断信息输出到 stderr。
其他原则
- 幂等性:Agent 可能重试命令,「不存在则创建」比「创建然后在重复时失败」更安全
- 干运行支持 :对于破坏性操作,提供
--dry-run标志 - 有意义的退出码:不同失败类型使用不同退出码
- 可预测的输出大小 :Agent 的工具输出通常有截断阈值,支持
--offset等分页参数
6.5 工作流与反馈循环
支持脚本的 Skill 特别适合构建验证反馈循环:
analyze_form.py"] --> B["2. 创建计划
fields.json"] B --> C["3. 验证计划
validate_fields.py"] C -->|失败| B C -->|通过| D["4. 执行
fill_form.py"] D --> E["5. 验证输出
verify_output.py"] E -->|失败| B E -->|通过| F["完成 ✅"] style F fill:#d4edda,stroke:#28a745
这种「计划-验证-执行」模式通过在每个关键步骤后加入机器可验证的检查,大幅提高输出质量:
- 早期捕获错误:验证在变更应用之前发现问题
- 机器可验证:脚本提供客观验证
- 可逆规划:Agent 可以在不触碰原始文件的情况下迭代计划
6.6 实战 Demo:天气查询 Skill
下面通过一个完整的、可运行的天气查询 Skill,来展示脚本型 Skill 的完整结构和工作方式。
目录结构
sql
check-weather/
├── SKILL.md
└── scripts/
└── get-weather.mjs
SKILL.md 文件
markdown
---
name: check-weather
description: >
Query current weather conditions for any city worldwide.
Use when the user asks about weather, temperature, wind,
humidity, or atmospheric conditions for a specific location.
compatibility: Requires Node.js 18+ (uses native fetch API)
metadata:
author: demo
version: "1.0"
---
# Check Weather
Query real-time weather data for any city using the wttr.in API.
## Usage
Run the weather script with the city name:
```bash
node scripts/get-weather.mjs <city>
Examples:
bash
node scripts/get-weather.mjs Beijing
node scripts/get-weather.mjs "New York"
node scripts/get-weather.mjs Tokyo
Output Format
The script outputs JSON with the following fields:
json
{
"city": "Beijing",
"country": "China",
"temperature": "22°C",
"feels_like": "20°C",
"weather": "Partly cloudy",
"humidity": "45%",
"wind_speed": "15 km/h",
"wind_direction": "NE",
"visibility": "10 km",
"pressure": "1015 mb",
"uv_index": "5",
"observation_time": "02:30 PM"
}
Guidelines
- If the user provides a Chinese city name, translate it to English before calling the script (e.g. 北京 → Beijing)
- If the script fails due to network issues, inform the user and suggest trying again later
- Present the weather data in a readable, conversational format rather than dumping raw JSON
javascript
#### scripts/get-weather.mjs 脚本
```javascript
#!/usr/bin/env node
const city = process.argv[2];
if (!city) {
console.error(JSON.stringify({
error: "City name is required",
usage: "node scripts/get-weather.mjs <city>",
examples: [
'node scripts/get-weather.mjs Beijing',
'node scripts/get-weather.mjs "New York"'
]
}, null, 2));
process.exit(1);
}
try {
const url = `https://wttr.in/${encodeURIComponent(city)}?format=j1`;
const response = await fetch(url);
if (!response.ok) {
console.error(JSON.stringify({
error: `HTTP ${response.status}: Failed to fetch weather for "${city}"`,
suggestion: "Check the city name and try again"
}));
process.exit(1);
}
const data = await response.json();
const current = data.current_condition?.[0];
const area = data.nearest_area?.[0];
if (!current) {
console.error(JSON.stringify({
error: `No weather data available for "${city}"`
}));
process.exit(1);
}
const result = {
city: area?.areaName?.[0]?.value ?? city,
country: area?.country?.[0]?.value ?? "Unknown",
temperature: `${current.temp_C}°C`,
feels_like: `${current.FeelsLikeC}°C`,
weather: current.weatherDesc?.[0]?.value ?? "Unknown",
humidity: `${current.humidity}%`,
wind_speed: `${current.windspeedKmph} km/h`,
wind_direction: current.winddir16Point,
visibility: `${current.visibility} km`,
pressure: `${current.pressure} mb`,
uv_index: current.uvIndex,
observation_time: current.observation_time
};
console.log(JSON.stringify(result, null, 2));
} catch (err) {
console.error(JSON.stringify({
error: `Network error: ${err.message}`,
suggestion: "Check your internet connection and try again"
}));
process.exit(1);
}
实际交互过程
当用户说 "北京今天天气怎么样",Agent 和 LLM 的交互过程如下:
北京 → Beijing,然后执行脚本 LLM-->>A: tool_use: Bash('node scripts/get-weather.mjs Beijing') A->>FS: 执行脚本 FS-->>A: {"city":"Beijing","temperature":"22°C","weather":"Partly cloudy",...} A->>LLM: tool_result: JSON 天气数据 Note over LLM: 按照指令中的 Guidelines:
"以可读的对话格式呈现" LLM-->>A: "北京今天天气多云,气温 22°C,体感温度 20°C,
湿度 45%,东北风 15km/h。" A->>U: 返回天气信息
这个 Demo 体现了脚本型 Skill 的几个核心价值:
- 脚本提供确定性能力:API 调用和数据解析由脚本保证,不依赖 LLM 生成代码
- 指令提供灵活指导:翻译城市名、格式化输出等由 LLM 根据指令灵活完成
- 错误处理自包含:脚本自己处理各种异常,提供结构化的错误信息
- 零 token 浪费:脚本代码不进入上下文,只有 JSON 输出进入
七、Skill 在不同平台的使用
Agent Skills 可以在多个平台上使用,但各平台的支持程度和限制有所不同:
7.1 平台支持矩阵
| 特性 | Claude API | Claude Code | Claude.ai | Agent SDK |
|---|---|---|---|---|
| 预构建 Skill | ✅ | ❌ | ✅ | ❌ |
| 自定义 Skill | ✅ | ✅ | ✅ | ✅ |
| 网络访问 | ❌ | ✅ | 视设置而定 | ✅ |
| 运行时安装包 | ❌ | ✅(建议仅本地安装) | ✅(npm/PyPI) | ✅ |
| 共享范围 | 工作区级 | 个人/项目级 | 仅个人 | 项目级 |
7.2 跨平台限制
自定义 Skill 不会在不同平台之间自动同步:
- 上传到 claude.ai 的 Skill 需要单独上传到 API
- 通过 API 上传的 Skill 在 claude.ai 上不可用
- Claude Code 的 Skill 是基于文件系统的,与 claude.ai 和 API 均独立
7.3 在 Claude API 中使用
使用 Claude API 时,通过 container 参数指定 Skill:
python
response = client.beta.messages.create(
model="claude-opus-4-6",
max_tokens=4096,
betas=["code-execution-2025-08-25", "skills-2025-10-02"],
container={
"skills": [
{"type": "anthropic", "skill_id": "pptx", "version": "latest"}
]
},
messages=[
{"role": "user", "content": "Create a presentation about AI"}
],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
需要三个 beta 头:
code-execution-2025-08-25:Skill 在代码执行容器中运行skills-2025-10-02:启用 Skills 功能files-api-2025-04-14:用于上传/下载文件到容器
7.4 在 Cursor 中使用
Cursor 支持自定义 Skill,从以下目录自动发现:
| 位置 | 级别 |
|---|---|
.agents/skills/ |
项目级 |
.cursor/skills/ |
项目级 |
~/.cursor/skills/ |
用户级(全局) |
也可以在 Cursor Settings → Rules 的「Agent Decides」区域查看已发现的 Skill。
手动调用方式:在 Agent 对话中输入 / 并搜索技能名称。
八、Skill 的安装与管理
8.1 本地创建
最简单的方式,直接在项目或全局目录中创建 Skill 文件夹:
bash
# 项目级
mkdir -p .agents/skills/my-skill
touch .agents/skills/my-skill/SKILL.md
# 全局级
mkdir -p ~/.agents/skills/my-skill
touch ~/.agents/skills/my-skill/SKILL.md
8.2 从 GitHub 安装
在 Cursor 中:
- 打开 Cursor Settings → Rules
- 在 Project Rules 部分,点击 Add Rule
- 选择 Remote Rule (Github)
- 输入 GitHub 仓库地址
8.3 通过 API 上传
使用 Skills API (/v1/skills 端点) 上传自定义 Skill,上传后在整个工作区范围内共享。
8.4 在 claude.ai 上传
通过 Settings > Features 上传 Skill 的 zip 文件。需要 Pro、Max、Team 或 Enterprise 计划,且启用代码执行。
8.5 规则和命令迁移
Cursor 2.4 版本内置了 /migrate-to-skills 技能,可以将现有的动态规则和斜杠命令转换为 Skill:
- 动态规则 (
alwaysApply: false)→ 转换为标准 Skill - 斜杠命令 → 转换为设置了
disable-model-invocation: true的 Skill
8.6 使用验证工具
使用 skills-ref 参考库验证 Skill:
bash
skills-ref validate ./my-skill
九、编写高质量 Skill 的最佳实践
9.1 简洁是关键
Agent 已经非常聪明,只添加它真正不知道的信息:
markdown
# ✅ 好的:简洁(~50 tokens)
## Extract PDF text
Use pdfplumber for text extraction:
```python
import pdfplumber
with pdfplumber.open("file.pdf") as pdf:
text = pdf.pages[0].extract_text()
❌ 差的:啰嗦(~150 tokens)
Extract PDF text
PDF (Portable Document Format) files are a common file format that contains text, images, and other content. To extract text from a PDF, you'll need to use a library...
markdown
对每条信息的价值进行挑战:
- "Agent 真的需要这个解释吗?"
- "我能假设 Agent 已经知道这个吗?"
- "这段内容值得它占用的 token 吗?"
### 9.2 编写有效的 description
`description` 字段是 Skill 能否被正确触发的**决定性因素**:
- **使用第三人称**:`"Processes Excel files"` 而非 `"I can help you process"`
- **包含触发关键词**:既描述做什么,也描述何时使用
- **具体而不模糊**:列出具体的操作和文件类型
- **适度宽泛**:包含用户可能不会直接点名但仍然相关的场景
```yaml
# ✅ 优秀的 description
description: >
Analyze CSV and tabular data files --- compute summary statistics,
add derived columns, generate charts, and clean messy data. Use
when the user has a CSV, TSV, or Excel file and wants to explore,
transform, or visualize the data, even if they don't explicitly
mention "CSV" or "analysis."
# ❌ 糟糕的 description
description: Process CSV files.
9.3 命名规范
推荐使用动名词形式(gerund),清晰描述 Skill 提供的能力:
| 推荐 | 可接受 | 避免 |
|---|---|---|
processing-pdfs |
pdf-processing |
helper |
analyzing-spreadsheets |
spreadsheet-analysis |
utils |
managing-databases |
process-pdfs |
tools |
testing-code |
analyze-spreadsheets |
documents |
9.4 渐进式披露的文件组织
(< 500 行)
总览 + 导航"] --> B["references/finance.md
收入指标"] A --> C["references/sales.md
管道数据"] A --> D["references/product.md
使用分析"] A --> E["scripts/validate.py
验证脚本"] style A fill:#e3f2fd,stroke:#1976D2 style B fill:#f5f5f5,stroke:#9E9E9E style C fill:#f5f5f5,stroke:#9E9E9E style D fill:#f5f5f5,stroke:#9E9E9E style E fill:#fff3e0,stroke:#F57C00
核心原则:
- SKILL.md 主体控制在 500 行以内
- 详细内容拆分到独立文件
- 文件引用保持一层深度(不嵌套引用)
- 超过 100 行的参考文件加上目录索引
9.5 避免常见反模式
| 反模式 | 正确做法 |
|---|---|
使用 Windows 风格路径 scripts\helper.py |
使用正斜杠 scripts/helper.py |
| 提供过多选项让 Agent 困惑 | 给出一个默认方案 + 备选方案 |
嵌套引用链 A → B → C → 实际内容 |
所有文件从 SKILL.md 直接引用 |
| 包含时效性信息 | 使用「当前方法」+「旧模式」结构 |
| 术语不一致(混用 API endpoint/URL/route) | 选定一个术语,全程一致 |
| 脚本中使用魔法数字 | 每个配置值都有注释说明理由 |
9.6 使用一致的术语
markdown
# ✅ 一致
Always "API endpoint"
Always "field"
Always "extract"
# ❌ 不一致
Mix "API endpoint", "URL", "API route", "path"
Mix "field", "box", "element", "control"
Mix "extract", "pull", "get", "retrieve"
十、Skill 的评估与迭代
10.1 评估驱动的开发
在编写大量文档之前,先创建评估用例。这确保你的 Skill 解决的是真实问题:
无 Skill 时测试"] --> B["2. 创建评估
3 个测试场景"] B --> C["3. 建立基准
无 Skill 的表现"] C --> D["4. 编写最小指令
仅解决差距"] D --> E["5. 运行评估
对比基准"] E -->|未达标| D E -->|达标| F["完成 ✅"] style F fill:#d4edda,stroke:#28a745
10.2 测试用例结构
json
{
"skill_name": "csv-analyzer",
"evals": [
{
"id": 1,
"prompt": "我有一个月度销售数据的 CSV 文件,能找出收入最高的 3 个月并做一个柱状图吗?",
"expected_output": "柱状图显示收入最高的 3 个月,有标注的坐标轴和数值。",
"files": ["evals/files/sales_2025.csv"],
"assertions": [
"输出包含柱状图文件",
"图表恰好显示 3 个月",
"两个坐标轴都有标签",
"图表标题或说明提到了收入"
]
}
]
}
10.3 双实例迭代法
最有效的 Skill 开发过程涉及两个 Agent 实例协作:
| 角色 | 职责 |
|---|---|
| Claude A(设计者) | 帮助设计和优化 Skill 内容 |
| Claude B(使用者) | 使用 Skill 执行真实任务,暴露问题 |
迭代步骤:
- 用 Claude A 完成一个没有 Skill 的任务,记录你提供的上下文
- 让 Claude A 将这些上下文转化为 Skill
- 用 Claude B 测试 Skill 在相似任务上的表现
- 将观察结果反馈给 Claude A 进行改进
- 循环往复
10.4 触发描述优化
通过设计触发评估查询来测试和优化 description 的准确性:
- 准备约 20 个查询:8-10 个应当触发、8-10 个不应触发
- 每个查询运行多次(至少 3 次),计算触发率
- 使用训练集/验证集拆分(60%/40%)避免过拟合
- 迭代 5 次通常足够
10.5 观察 Agent 如何使用 Skill
在迭代过程中注意观察:
- 意外的浏览路径:Agent 是否按你预期的顺序读取文件?
- 遗漏的连接:Agent 是否未能跟踪到重要文件的引用?
- 过度依赖某些部分:Agent 反复读取同一个文件,可能该内容应放入主 SKILL.md
- 被忽略的内容:Agent 从未访问的文件,可能是不必要的
十一、安全考量
11.1 信任模型
可信?"} B -->|自己创建| C["✅ 安全"] B -->|Anthropic 官方| C B -->|未知/第三方| D["⚠️ 需要审计"] D --> E["审查所有文件:
SKILL.md、脚本、资源"] E --> F{"是否发现
异常模式?"} F -->|否| G["谨慎使用"] F -->|是| H["❌ 拒绝使用"] style C fill:#d4edda,stroke:#28a745 style D fill:#fff3cd,stroke:#ffc107 style H fill:#f8d7da,stroke:#dc3545
11.2 关键安全原则
| 风险类别 | 说明 | 防范建议 |
|---|---|---|
| 工具滥用 | 恶意 Skill 可能以有害方式调用工具(文件操作、bash 命令) | 审查所有脚本和指令 |
| 数据泄露 | 具有敏感数据访问权限的 Skill 可能向外部系统泄露信息 | 检查是否有意外的网络调用 |
| 外部源风险 | 从外部 URL 获取数据的 Skill 风险特别高,获取的内容可能包含恶意指令 | 避免 Skill 依赖外部数据源 |
| 项目级注入 | 不受信任的仓库可能通过项目级 Skill 注入指令 | 对不受信任的项目设置信任检查 |
11.3 审计清单
- 审查 SKILL.md 中的所有指令
- 审查 scripts/ 中的所有脚本文件
- 检查是否有意外的网络请求
- 检查文件访问模式是否与 Skill 声明的用途一致
- 检查是否有操作不匹配 Skill 声明用途的行为
十二、与其他能力的对比
Agent Skills 并不是 Agent 扩展能力的唯一方式,理解它与其他方式的区别有助于在正确的场景选择正确的工具:
| 维度 | Agent Skills | Projects(项目) | MCP | Custom Instructions |
|---|---|---|---|---|
| 定位 | 特定任务的专业能力 | 静态背景知识 | 连接外部服务和数据源 | 全局通用偏好 |
| 加载方式 | 动态按需加载 | 始终加载 | 始终可用 | 始终加载 |
| 适用范围 | 特定任务类型 | 特定项目内 | 跨对话 | 所有对话 |
| 典型内容 | 工作流、脚本、领域知识 | 项目文档、代码 | 工具连接 | 语言、风格偏好 |
| 组合使用 | 可与 MCP 配合 | 独立使用 | 可与 Skills 配合 | 独立使用 |
一个常见的强力组合:MCP 提供工具访问,Skill 教会 Agent 如何有效使用这些工具。
例如,MCP 连接让 Agent 可以调用 BigQuery API,而 Skill 告诉 Agent 你们公司的表结构、命名规范和常见查询模式。
十三、开放标准与生态
13.1 开放标准
Agent Skills 规范作为开放标准发布在 agentskills.io。这意味着:
- 你创建的 Skill 不会被锁定到特定平台
- 同一套 Skill 格式可以在所有采用该标准的 AI 平台和工具中使用
- 提供 Python 参考 SDK 供开发者在自己的平台中实现 Skills 支持
13.2 为你的 Agent 添加 Skills 支持
如果你在开发自己的 AI Agent 或开发工具,可以按照以下步骤添加 Skills 支持:
发现 Skill"] --> B["Step 2
解析 SKILL.md"] B --> C["Step 3
向模型披露
可用 Skill"] C --> D["Step 4
激活 Skill"] D --> E["Step 5
管理 Skill
上下文"] style A fill:#e3f2fd style B fill:#e8f5e9 style C fill:#fff3e0 style D fill:#f3e5f5 style E fill:#fce4ec
核心实现要点:
- 发现 :扫描约定目录,查找包含
SKILL.md的子目录 - 解析:提取 YAML frontmatter 和 markdown 主体
- 披露:在系统提示词中注入技能目录(仅 name + description)
- 激活:通过文件读取或专用工具将完整指令加载到上下文
- 上下文管理:保护 Skill 内容不被上下文压缩算法移除,去重重复激活
13.3 生态现状
目前支持 Agent Skills 标准的平台包括:
- Cursor:通过文件系统自动发现和使用
- Claude Code:原生支持,文件系统集成
- Claude API:通过 Skills API 上传和使用
- Claude.ai:通过设置上传和使用
- Agent SDK:TypeScript 和 Python SDK 支持
附录:Skill 效果检查清单
在分享你的 Skill 之前,逐一确认以下项目:
核心质量
-
description具体且包含关键词 -
description同时说明做什么和何时使用 - SKILL.md 主体在 500 行以内
- 额外细节放在独立文件中
- 没有时效性信息(或放在「旧模式」区域)
- 全程术语一致
- 示例具体,非抽象
- 文件引用只有一层深度
- 合理使用渐进式披露
- 工作流有清晰的步骤
代码和脚本
- 脚本主动处理错误,而非把问题抛给 Agent
- 错误处理明确且有帮助
- 没有「魔法常数」(所有值都有注释说明)
- 所需软件包在指令中列出并验证可用
- 脚本有清晰的
--help文档 - 不使用 Windows 风格路径
- 关键操作有验证/确认步骤
- 质量关键任务包含反馈循环
测试
- 至少创建 3 个评估用例
- 在计划使用的所有模型上测试
- 使用真实使用场景测试
- 纳入团队反馈(如适用)