【AI Agent】Agent Skills:扩展Agent能力的开放格式
Agent Skills是Anthropic推出的一种轻量级、开放的格式,用于扩展AI Agent的能力和专业知识。Skills是包含指令、脚本和资源的文件夹,Agent可以发现并使用它们来更好地执行特定任务。本文详细介绍Agent Skills的规范、创建方法和客户端实现。
什么是Agent Skills 定义 Agent Skills是一种简单的基于文件的格式 ,让Agent能够获得新的能力和专业知识。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ┌─────────────────────────────────────────────────────────────────┐ │ Agent Skills概念 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 核心理念:Write once, use everywhere │ │ │ │ 一个Skill就是一个文件夹: │ │ │ │ my-skill/ │ │ ├── SKILL.md # 必需:指令 + 元数据 │ │ ├── scripts/ # 可选:可执行代码 │ │ ├── references/ # 可选:参考文档 │ │ └── assets/ # 可选:模板、资源 │ │ │ │ 特点: │ │ ├── 自文档化:人类可读,易于审查和改进 │ │ ├── 可扩展:从纯文本指令到可执行代码 │ │ ├── 可移植:只是文件,易于编辑、版本控制和分享 │ │ └── 跨客户端:任何支持Skills的Agent都可以使用 │ │ │ └─────────────────────────────────────────────────────────────────┘
Skills的工作原理 Skills采用**渐进式披露(Progressive Disclosure)**来高效管理上下文:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ┌─────────────────────────────────────────────────────────────────┐ │ 渐进式披露 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 层级 │ 加载内容 │ 时机 │ Token消耗 │ │ ─────┼─────────────────┼───────────────┼───────────────────── │ │ 1 │ 名称 + 描述 │ 会话开始时 │ ~50-100 tokens/skill │ │ 2 │ 完整SKILL.md内容 │ Skill被激活时 │ <5000 tokens (建议) │ │ 3 │ 脚本、引用、资源 │ 指令引用时 │ 按需加载 │ │ │ │ 流程: │ │ │ │ 1. 发现(Discovery) │ │ Agent启动时,只加载每个Skill的name和description │ │ 足够让Agent知道何时可能需要它 │ │ │ │ 2. 激活(Activation) │ │ 当任务匹配Skill的描述时,Agent读取完整的SKILL.md指令 │ │ │ │ 3. 执行(Execution) │ │ Agent按照指令执行,按需加载引用的文件或执行捆绑的代码 │ │ │ │ 优势:保持Agent快速响应,同时能按需访问更多上下文 │ │ │ └─────────────────────────────────────────────────────────────────┘
SKILL.md文件格式 基本结构 每个Skill都以SKILL.md文件开始,包含YAML frontmatter和Markdown指令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 --- name: pdf-processing description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF documents or when the user mentions PDFs, forms, or document extraction. --- # PDF Processing ## When to use this skill Use this skill when the user needs to work with PDF files... ## How to extract text 1. Use pdfplumber for text extraction...## How to fill forms ...
Frontmatter字段
字段
必需
说明
name
是
最多64字符,小写字母、数字和连字符,必须与父目录名匹配
description
是
最多1024字符,描述Skill做什么以及何时使用
license
否
许可证名称或引用
compatibility
否
最多500字符,环境要求说明
metadata
否
任意键值对的额外元数据
allowed-tools
否
预授权工具列表(实验性)
name字段规范 1 2 3 4 5 6 7 8 9 name: pdf-processing name: data-analysis name: code-review name: PDF-Processing name: -pdf name: pdf--processing
description字段规范 好的描述应该说明做什么 和何时使用 :
1 2 3 4 5 description: Extracts text and tables from PDF files, fills PDF forms, and merges multiple PDFs. Use when working with PDF documents or when the user mentions PDFs, forms, or document extraction. description: Helps with PDFs.
完整示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 --- name: pdf-processing description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF documents or when the user mentions PDFs. license: Apache-2.0 compatibility: Requires Python 3.8 + with pypdf and pdfplumber packages metadata: author: example-org version: "1.0" allowed-tools: Bash(python:*) Read Write --- This skill provides comprehensive PDF manipulation capabilities using Python. ```python from pypdf import PdfReader, PdfWriter reader = PdfReader("document.pdf") print(f"Pages: {len(reader.pages) }") # Extract text for page in reader.pages: print(page.extract_text())
Common Operations Merge PDFs 1 2 3 4 5 6 7 8 writer = PdfWriter() for pdf_file in ["doc1.pdf" , "doc2.pdf" ]: reader = PdfReader(pdf_file) for page in reader.pages: writer.add_page(page) with open ("merged.pdf" , "wb" ) as output: writer.write(output)
1 2 3 4 5 6 7 import pdfplumberwith pdfplumber.open ("document.pdf" ) as pdf: for page in pdf.pages: tables = page.extract_tables() for table in tables: print (table)
Reference Files For advanced features, see:
Scripts
scripts/extract.py - Text extraction utility
scripts/merge.py - PDF merging tool
1 2 3 4 5 ## 目录结构 ### 完整的Skill目录
pdf-processing/ ├── SKILL.md # 必需:主要指令文件 ├── LICENSE.txt # 可选:许可证文件 ├── scripts/ # 可选:可执行脚本 │ ├── extract.py │ ├── merge.py │ └── convert.py ├── references/ # 可选:参考文档 │ ├── REFERENCE.md # 详细技术参考 │ ├── FORMS.md # 表单模板 │ └── api-spec.md # API规范 └── assets/ # 可选:静态资源 ├── templates/ # 文档模板 ├── schemas/ # 数据模式 └── examples/ # 示例文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ### scripts/目录 包含Agent可以执行的代码: ```python # scripts/extract.py #!/usr/bin/env python3 """PDF text extraction utility.""" import sys from pypdf import PdfReader def extract_text(pdf_path: str) -> str: """Extract all text from a PDF file.""" reader = PdfReader(pdf_path) text = [] for page in reader.pages: text.append(page.extract_text()) return "\n".join(text) if __name__ == "__main__": if len(sys.argv) != 2: print("Usage: extract.py <pdf_file>") sys.exit(1) print(extract_text(sys.argv[1]))
脚本应该:
自包含或清楚记录依赖
包含有用的错误消息
优雅处理边界情况
references/目录 包含Agent可以按需读取的额外文档:
1 2 3 4 5 6 7 # references/REFERENCE.md ## Advanced PDF Operations ### Encryption ```python writer.encrypt("password", algorithm="AES-256")
Watermarks 1 2 3 watermark = PdfReader("watermark.pdf" ).pages[0 ] for page in writer.pages: page.merge_page(watermark)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 保持单个参考文件聚焦,因为Agent按需加载它们。 ### assets/目录 包含静态资源: - 模板(文档模板、配置模板) - 图像(图表、示例) - 数据文件(查找表、Schema) ## Skill发现机制 ### 扫描位置 Agent通常扫描多个作用域的Skills:
┌─────────────────────────────────────────────────────────────────┐ │ Skills扫描位置 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 作用域 │ 路径 │ 用途 │ │ ───────────┼──────────────────────────────┼───────────────── │ │ 项目级 │ /.agents/skills/ │ 项目特定Skills │ │ 项目级 │ /.claude/skills/ │ Claude Code兼容 │ │ 用户级 │ ~/.agents/skills/ │ 跨项目Skills │ │ 用户级 │ ~/.claude/skills/ │ Claude Code兼容 │ │ │ │ 优先级:项目级 > 用户级(同名时项目级覆盖用户级) │ │ │ │ 示例目录结构: │ │ │ │ ~/.agents/skills/ │ │ ├── pdf-processing/ │ │ │ ├── SKILL.md ← 被发现 │ │ │ └── scripts/ │ │ ├── data-analysis/ │ │ │ └── SKILL.md ← 被发现 │ │ └── README.md ← 忽略(不是Skill目录) │ │ │ └─────────────────────────────────────────────────────────────────┘
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ### 发现规则 ```python def discover_skills(search_paths: list[str]) -> dict[str, Skill]: """发现所有可用的Skills""" skills = {} for base_path in search_paths: skills_dir = Path(base_path) if not skills_dir.exists(): continue # 查找包含SKILL.md的子目录 for skill_dir in skills_dir.iterdir(): if not skill_dir.is_dir(): continue skill_md = skill_dir / "SKILL.md" if not skill_md.exists(): continue # 解析SKILL.md skill = parse_skill_md(skill_md) # 处理名称冲突(先发现的优先) if skill.name not in skills: skills[skill.name] = skill else: logger.warning(f"Skill '{skill.name}' shadowed by existing skill") return skills
信任考虑 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ┌─────────────────────────────────────────────────────────────────┐ │ 信任机制 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 项目级Skills来自正在处理的仓库,可能不受信任 │ │ (例如,刚克隆的开源项目) │ │ │ │ 建议: │ │ 1. 对项目级Skill加载进行信任检查 │ │ 2. 只有用户标记项目为"信任"后才加载 │ │ 3. 防止不受信任的仓库静默注入指令 │ │ │ │ 用户级Skills(~/.agents/skills/)通常被认为是可信的 │ │ │ └─────────────────────────────────────────────────────────────────┘
Skill激活 激活方式 Agent可以通过两种方式激活Skill:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ┌─────────────────────────────────────────────────────────────────┐ │ Skill激活方式 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 1. 模型驱动激活(Model-driven) │ │ Agent根据任务自动判断是否需要激活某个Skill │ │ │ │ 方式A:文件读取激活 │ │ Agent使用标准的文件读取工具读取SKILL.md │ │ │ │ 方式B:专用工具激活 │ │ Agent调用 activate_skill(name) 工具获取内容 │ │ │ │ 2. 用户显式激活(User-explicit) │ │ 用户通过命令直接激活:/skill-name 或 $skill-name │ │ │ └─────────────────────────────────────────────────────────────────┘
Skill目录(Catalog) 会话开始时,Agent加载所有Skill的元数据:
1 2 3 4 5 6 7 8 9 10 11 12 <available_skills > <skill > <name > pdf-processing</name > <description > Extract text and tables from PDF files, fill forms, merge documents.</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 >
激活工具实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 from dataclasses import dataclassfrom pathlib import Pathimport yaml@dataclass class Skill : name: str description: str location: Path body: str = "" class SkillManager : def __init__ (self ): self .skills: dict [str , Skill] = {} self .activated: set [str ] = set () def discover (self, search_paths: list [str ] ): """发现所有可用的Skills""" for base_path in search_paths: skills_dir = Path(base_path) if not skills_dir.exists(): continue for skill_dir in skills_dir.iterdir(): skill_md = skill_dir / "SKILL.md" if skill_md.exists(): skill = self ._parse_skill(skill_md) if skill.name not in self .skills: self .skills[skill.name] = skill def _parse_skill (self, skill_md: Path ) -> Skill: """解析SKILL.md文件""" content = skill_md.read_text() if content.startswith("---" ): _, frontmatter, body = content.split("---" , 2 ) meta = yaml.safe_load(frontmatter) else : raise ValueError("SKILL.md must have YAML frontmatter" ) return Skill( name=meta["name" ], description=meta["description" ], location=skill_md, body=body.strip() ) def get_catalog (self ) -> str : """获取Skill目录(用于模型上下文)""" catalog = ["<available_skills>" ] for skill in self .skills.values(): catalog.append(f""" <skill> <name>{skill.name} </name> <description>{skill.description} </description> <location>{skill.location} </location> </skill>""" ) catalog.append("</available_skills>" ) return "\n" .join(catalog) def activate (self, name: str ) -> dict : """激活指定的Skill""" if name not in self .skills: return {"error" : f"Skill '{name} ' not found" } skill = self .skills[name] self .activated.add(name) skill_dir = skill.location.parent resources = [] for subdir in ["scripts" , "references" , "assets" ]: dir_path = skill_dir / subdir if dir_path.exists(): for f in dir_path.rglob("*" ): if f.is_file(): resources.append(str (f.relative_to(skill_dir))) return { "name" : skill.name, "content" : skill.body, "skill_directory" : str (skill_dir), "resources" : resources }
激活响应格式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <skill_content name ="pdf-processing" > # PDF Processing Guide ## Overview This skill provides comprehensive PDF manipulation capabilities... [完整的SKILL.md内容] 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/advanced.md</file > </skill_resources > </skill_content >
上下文管理 保护Skill内容 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ┌─────────────────────────────────────────────────────────────────┐ │ 上下文管理策略 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 问题:当上下文窗口填满时,Agent可能会截断或压缩旧消息 │ │ │ │ 关键:Skill指令不应被修剪! │ │ │ │ Skill指令是持久的行为指导,丢失它们会静默降低Agent性能 │ │ 模型继续运行但没有Skill提供的专业指令 │ │ │ │ 解决方案: │ │ 1. 将Skill工具输出标记为"受保护" │ │ 2. 使用结构化标签(<skill_content>)识别Skill内容 │ │ 3. 压缩算法跳过受保护的内容 │ │ │ │ 去重: │ │ 跟踪已激活的Skills,防止重复加载 │ │ │ └─────────────────────────────────────────────────────────────────┘
子代理委托(高级) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class SubagentExecutor : """使用子代理执行Skill(高级模式)""" async def execute_skill_in_subagent ( self, skill: Skill, task: str ) -> str : """ 在独立的子代理会话中执行Skill 优势: - 复杂工作流可以在专注的会话中运行 - 不污染主对话上下文 - 子代理完成后返回摘要 """ subagent = await self .create_subagent() await subagent.inject_context(skill.body) result = await subagent.execute(task) return result.summary
创建Skills最佳实践 目录结构建议 1 2 3 4 5 6 7 8 9 my-skill/ ├── SKILL.md # 保持在500行以内 ├── references/ │ ├── REFERENCE.md # 详细技术参考 │ └── EXAMPLES.md # 更多示例 ├── scripts/ │ └── helper.py # 辅助脚本 └── assets/ └── template.json # 模板文件
编写有效的SKILL.md 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ┌─────────────────────────────────────────────────────────────────┐ │ SKILL.md编写建议 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 1. 描述要具体 │ │ 包含关键词帮助Agent识别相关任务 │ │ 说明"做什么"和"何时使用" │ │ │ │ 2. 指令要清晰 │ │ 提供分步骤的操作说明 │ │ 包含代码示例 │ │ 说明常见边界情况 │ │ │ │ 3. 保持简洁 │ │ 主SKILL.md保持在500行以内 │ │ 详细内容放到references/目录 │ │ │ │ 4. 文件引用 │ │ 使用相对路径:scripts/extract.py │ │ 避免深层嵌套的引用链 │ │ │ └─────────────────────────────────────────────────────────────────┘
示例:完整的数据分析Skill 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 --- name: data-analysis description: Analyze datasets, generate statistics, create visualizations, and produce reports. Use when the user wants to explore data, find patterns, create charts, or summarize datasets in CSV, Excel, or JSON format. license: MIT compatibility: Requires Python 3.8+ with pandas, matplotlib, and seaborn metadata: author: data-team version: "2.0" --- # Data Analysis Skill ## When to use - User mentions CSV, Excel, or data files- User asks for statistics, trends, or patterns- User wants charts, plots, or visualizations- User needs data summaries or reports## Quick Start ```python import pandas as pd import matplotlib.pyplot as plt # Load data df = pd.read_csv("data.csv") # Basic statistics print(df.describe()) # Create visualization df.plot(kind='bar', x='category', y='value') plt.savefig("chart.png")
Common Operations 1 2 3 4 5 6 7 8 df = pd.read_csv("file.csv" ) df = pd.read_excel("file.xlsx" , sheet_name="Sheet1" ) df = pd.read_json("file.json" )
Statistical Analysis 1 2 3 4 5 6 7 8 df.describe() df.corr() df.groupby('category' ).agg({'value' : ['mean' , 'sum' , 'count' ]})
Visualization 1 2 3 4 5 6 7 8 9 10 import seaborn as snssns.histplot(df['column' ]) sns.regplot(x='x_col' , y='y_col' , data=df) sns.heatmap(df.corr(), annot=True )
Reference Files For advanced analysis techniques, see:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ## 验证Skills ### 使用skills-ref库 ```bash # 安装 npm install -g @agentskills/skills-ref # 验证Skill skills-ref validate ./my-skill # 输出 ✓ SKILL.md found ✓ Frontmatter is valid ✓ Name matches directory ✓ Description is present ✓ All referenced files exist
验证检查项
检查项
说明
SKILL.md存在
必须有SKILL.md文件
Frontmatter有效
YAML格式正确
name字段有效
符合命名规范,与目录名匹配
description存在
非空,描述清晰
文件引用有效
引用的文件都存在
官方示例Skills Anthropic提供了一系列官方示例Skills:
Skill
功能
pdf
PDF文件处理:提取文本、合并、拆分、填表
xlsx
Excel文件处理:读写、分析、格式化
docx
Word文档处理:创建、编辑、格式转换
pptx
PowerPoint处理:创建演示文稿
data-analysis
数据分析:统计、可视化、报告
code-review
代码审查:质量检查、建议改进
mcp-builder
MCP服务器构建:创建MCP服务
claude-api
Claude API使用:SDK集成指南
完整示例见:https://github.com/anthropics/skills
总结 Agent Skills核心概念 1 2 3 4 5 6 7 ┌─────────────────────────────────────────────────────────────────┐ │ 1. 文件格式:SKILL.md + 可选目录(scripts/references/assets/)│ │ 2. 元数据:name + description(必需) │ │ 3. 渐进式披露:目录 → 指令 → 资源(按需加载) │ │ 4. 跨客户端:统一格式,任何兼容Agent都可使用 │ │ 5. 可审查:人类可读,易于版本控制 │ └─────────────────────────────────────────────────────────────────┘
最佳实践
方面
建议
描述
说明”做什么”+”何时使用”,包含关键词
长度
SKILL.md保持500行以内
结构
分步骤指令 + 代码示例 + 边界情况
引用
详细内容放references/,按需加载
测试
使用skills-ref验证格式
相关资源
Agent Skills为AI Agent提供了一种简单、可移植、可扩展的能力扩展方式,是构建专业化Agent的重要基础设施。