Net+AI智能体13:Agent Skills
2025-12-27 16:41:09一、Agent Skill 协议概述
1. Agent 的知识困境
假设你正在为公司开发一个 AI 助手,老板要求它能回答费用报销相关的问题:
员工: "出差期间的小费可以报销吗?"
AI 助手: "一般来说,合理的小费可以报销……" ← ❌ 太模糊!
期望回答: "根据公司政策,餐饮消费中 20% 以内的小费可以报销,
超过 $50 的单笔餐饮需要附上收据。" ← ✅ 精准!
问题在于:模型的参数里没有你们公司的报销政策。
- "能力"与"知识"的区别,我们先做一个关键区分——这是理解 Agent Skills 的基础:
| 能力 (Capability) | 知识 (Knowledge) | |
|---|---|---|
| 含义 | Agent 能做什么 | Agent 知道什么 |
| 类比 | 给员工配一台电脑 | 给员工发一本操作手册 |
| AI 例子 | 调用天气 API、发送邮件、执行 SQL | 公司政策、操作流程、领域规范 |
| 技术手段 | Function Calling / MCP Tools | ??? |
Function Calling 解决了"能做什么"的问题——让 Agent 可以调用 API、查数据库、发邮件。
但"知道什么"呢?这正是 Agent Skills 要解决的问题。
- 现有方案的局限
| 方案 | 做法 | 问题 |
|---|---|---|
| ❌ 塞进 System Prompt | 把整个政策文档放到系统提示里 | Token 浪费严重!20 个领域的知识全量加载,每次请求可能消耗数万 Token |
| ❌ 硬编码 | 用 if-else 把规则写到代码里 | 不灵活,业务人员无法维护,改个限额就要重新部署 |
| ⚠️ RAG | 建向量索引,语义检索 | 对结构化的政策文档来说过于复杂,且检索结果不可控 |
| ⚠️ 微调 (Fine-tuning) | 收集数据训练模型 | 成本高($10K+),周期长(数周),需要 ML 专家 |
我们需要一种方式:像"插 U 盘"一样,把领域知识按需加载给 Agent,简单、标准化、人人可维护。
2. 什么是 Agent Skills
- 定义:Agent Skills 是一种开放规范,定义了如何将领域知识打包为模块化、可复用的知识包,供 AI Agent 按需使用。
A simple, open format for giving agents new capabilities and expertise. — agentskills.io
用一句话概括:Agent Skills 就是一个标准化的"领域知识 U 盘"。
my-skill/
├── SKILL.md # 📖 必需:知识主文件(元数据 + 指令)
├── scripts/ # 🔧 可选:可执行脚本
├── references/ # 📎 可选:参考文档
└── assets/ # 📦 可选:模板、资源
Skill设计理念:模仿人类技能
- 明确的流程(SKILL.md)
- 可复用的方法(scripts)
- 可调用的工具(references)
- 固定/半固定的材料(assets)
起源与生态
| 维度 | 说明 |
|---|---|
| 发起者 | Anthropic(Claude 的开发商) |
| 性质 | 开放标准,社区共建 |
| 已采纳 | Claude Code、Copilot(GitHub)、Cursor、Windsurf 等主流 AI 编码工具 |
| 官方仓库 | github.com/agentskills/agentskills |
| MAF 支持 | Microsoft Agent Framework 已内置 FileAgentSkillsProvider |
类比理解:如果说 MCP 是 AI 工具的"USB 协议",那 Agent Skills 就是"U 盘里的操作手册格式标准"。
- Agent Skills 能做什么?
| 场景 | 示例 |
|---|---|
| 领域专长 | 费用报销政策、法律审查流程、数据分析规范 |
| 新能力赋予 | 教 Agent 如何制作 PPT、构建 MCP Server、处理 PDF |
| 可复现工作流 | 把多步骤任务标准化为一致、可审计的流程 |
| 跨产品互操作 | 同一个 Skill,在 Claude Code、Copilot、Cursor 中都能使用 |
3. 核心设计 — 渐进式披露(Progressive Disclosure)
Agent Skills 最巧妙的设计在于它的三阶段渐进式披露机制。不是一次性把所有知识塞给模型,而是"需要多少,加载多少"。
sequenceDiagram
participant User as 👤 用户
participant Agent as 🤖 AI Agent
participant SP as 📂 SkillsProvider
participant Skill as 📄 SKILL.md
Note over Agent,SP: 1️⃣ 摘要展示(~100 tokens/skill)
SP-->>Agent: 系统提示中注入技能列表<br/>"expense-report: 处理费用报销..."<br/>"code-review: 代码审查流程..."
User->>Agent: "出差小费可以报销吗?"
Note over Agent,SP: 2️⃣ 按需加载(Agent 判断需要该技能)
Agent->>SP: load_skill("expense-report")
SP->>Skill: 读取 SKILL.md 完整内容
Skill-->>SP: 费用类别、限额、流程...
SP-->>Agent: 注入完整知识到上下文
Note over Agent,Skill: 3️⃣ 读取资源(需要更多细节时)
Agent->>SP: read_skill_resource("expense-report",<br/>"references/POLICY_FAQ.md")
SP->>Skill: 读取 FAQ 文件
Skill-->>SP: FAQ 内容
SP-->>Agent: 补充信息
Agent-->>User: "根据政策,20%以内的小费可报销,<br/>超过$50需附收据。"
| 阶段 | 触发时机 | 内容 | Token 开销 | 类比 |
|---|---|---|---|---|
| 摘要展示 | 每次请求(Agent 启动时) | 所有 Skill 的名称 + 描述 | ~100 tokens/skill | 看书的目录 |
| 按需加载 | Agent 判断任务匹配时 | SKILL.md 的完整 Markdown Body | 按需,建议 <5000 tokens | 翻到对应章节 |
| 读取资源 | 需要更多细节时 | references/、assets/ 中的文件 | 按需 | 查阅附录/参考文献 |
4. SKILL.md 文件结构
一个 Agent Skill 本质上就是一个文件夹,核心是一个 SKILL.md 文件。
- 完整目录结构
expense-report/ # 📁 技能目录(名称须与 frontmatter.name 一致)
├── SKILL.md # 📖 技能定义文件(必需)
├── scripts/ # 🔧 可执行脚本(可选)
│ └── validate-receipt.py # Agent 可按需执行
├── references/ # 📎 参考文档(可选)
│ └── POLICY_FAQ.md # Agent 可按需读取
└── assets/ # 📦 静态资源(可选)
└── expense-report-template.md # 模板、表格等
- SKILL.md 的两部分:SKILL.md 由 YAML Frontmatter(元数据)+ Markdown Body(指令正文)组成:
---
name: expense-report
description: File and validate employee expense reports according to company policy. Use when the user asks about expenses, reimbursement, or receipts.
---
# 费用报销指南
## 费用类别与限额
| 类别 | 限额 | 需要收据 | 需要审批 |
|------|------|---------|---------|
| 餐饮(个人) | $50/天 | >$25 | 否 |
| 餐饮(客户) | $150/人 | 始终 | >$100 |
| 交通 | 实报 | 始终 | >$500 |
| 住宿 | $250/晚 | 始终 | 始终 |
## 报销流程
1. 收集所有收据
2. 使用模板填写:[assets/expense-report-template.md](assets/expense-report-template.md)
3. 提交至财务系统
## 常见问题
如有政策疑问,请参考:[references/POLICY_FAQ.md](references/POLICY_FAQ.md)
- Frontmatter 字段说明
| 字段 | 必需 | 规则 | 说明 |
|---|---|---|---|
| name | ✅ | 小写字母、数字、连字符,≤64 字符 | 技能唯一标识,须与目录名一致 |
| description | ✅ | ≤1024 字符 | 用于摘要展示,好的描述是技能被正确触发的关键 |
| license | ❌ | 自由文本 | 许可证声明 |
| compatibility | ❌ | ≤500 字符 | 环境要求(如"需要 Docker") |
| metadata | ❌ | key-value 映射 | 扩展元数据(作者、版本等) |
| allowed-tools | ❌ | 空格分隔列表 | 预授权工具(实验性功能) |
Description 的重要性,description 是 Agent 决定是否加载某个 Skill 的唯一依据(在摘要展示阶段)。一个好的 description 应该:
# ✅ 好的 description — 具体、包含触发关键词
description: Extract text and tables from PDF files, fill PDF forms, and merge
multiple PDFs. Use when working with PDF documents or when the user mentions
PDFs, forms, or document extraction.
# ❌ 差的 description — 太模糊
description: Helps with PDFs.
类比:description 就像图书馆里书脊上的简介——写得好,读者才能快速找到需要的书。
5. Agent Skills vs Function Calling vs MCP vs RAG
四种技术看似相关,实则各有定位,互补而非替代。
- 一句话区分
| 技术 | 一句话定位 | 回答的问题 |
|---|---|---|
| Agent Skills | 给 Agent 的"操作手册" | Agent 知道什么(领域知识) |
| Function Calling | Agent 的"机械臂" | Agent 能做什么(执行能力) |
| MCP | 工具的"USB 协议" | 工具怎么连接(传输标准) |
| RAG | Agent 的"搜索引擎" | 信息在哪找(检索机制) |
- 多维度对比
| 维度 | Agent Skills | Function Calling | MCP | RAG |
|---|---|---|---|---|
| 本质 | 知识包 | 可执行操作 | 工具传输协议 | 文档检索系统 |
| 加载方式 | 渐进式披露 | 全量注册 | 动态发现 | 语义检索 |
| 文件格式 | SKILL.md (Markdown) | C# 方法 + [Description] | JSON-RPC + JSON Schema | 向量数据库 |
| 维护者 | 业务专家 / 任何人 | 开发者 | 开发者 | 数据工程师 |
| 学习成本 | 会写 Markdown 即可 | 需要编程 | 需要编程 | 需要 ML 知识 |
| Token 效率 | 按需 ~100 tokens/skill | 全量加载 | 按需发现 | 取决于 chunk 策略 |
| 跨产品互操作 | Claude Code / Copilot / Cursor | 仅限注册的 Agent | 标准协议 | 仅限实现方 |
| 典型示例 | 费用报销政策、代码审查规范 | GetWeather()、SendEmail() | MCP Server 暴露工具 | 知识库 / 文档问答 |
- 关键区分:Skills vs Function Calling
| Function Calling | Agent Skills | |
|---|---|---|
| 输出 | 执行结果(数据/副作用) | 上下文(知识注入到对话中) |
| 谁写? | 开发者写 C# 方法 | 业务专家写 Markdown |
| 什么时候用? | 需要"做事"的时候 | 需要"懂行"的时候 |
| 改一下? | 改代码,重新部署 | 改 Markdown 文件,立即生效 |
| 举例 | "帮我查下北京天气" → 调用 API | "小费能报销吗?" → 加载报销知识 |
一个完善的 Agent 通常两者兼备:Skills 提供"知道什么",Function Calling 提供"能做什么"。知识指导行为。
- 关键区分:Skills vs MCP
| Agent Skills | MCP | |
|---|---|---|
| 关注点 | 知识的打包与加载 | 工具的传输与发现 |
| 传输 | 本地文件系统 | JSON-RPC(stdio/HTTP) |
| 内容 | Markdown 文档 | 工具定义 + 资源 + 提示 |
| 关系 | 可以在 Skill 中引用 MCP 工具的使用方法 | 可以通过 MCP Server 暴露 Skill 加载能力 |
| 不同纬度 | Skills 定义了 Agent 如何获取知识(知识层) | MCP 定义了 Agent 如何连接工具(传输层) |
- 关键区分:Skills vs RAG
| Agent Skills | RAG | |
|---|---|---|
| 知识类型 | 结构化、确定性的(政策、流程) | 非结构化、模糊的(文档、FAQ) |
| 加载方式 | 精确触发(模型选择加载哪个 Skill) | 语义检索(可能不精确) |
| 基础设施 | 零基础设施(就是文件) | 需要向量数据库、Embedding 模型 |
| 适用场景 | 规则明确、结构清晰的领域知识 | 海量文档、模糊查询 |
如果你的知识可以写成一本"操作手册",用 Skills;如果是"图书馆"量级的文档,用 RAG。
- 四者如何协同
在一个真实的企业 Agent 中,四种技术通常同时存在,各司其职:
flowchart TB
User["👤 员工"] -->|"帮我提交上周的差旅报销"| Agent["🤖 企业 AI 助手"]
Agent -->|"1️⃣ 加载报销知识"| Skills["📖 Agent Skills<br/>expense-report Skill<br/>费用限额、审批流程"]
Agent -->|"2️⃣ 调用工具执行操作"| FC["🦾 Function Calling<br/>CreateExpenseReport()<br/>SubmitForApproval()"]
Agent -->|"3️⃣ 通过 MCP 获取外部数据"| MCP["🔌 MCP Server<br/>财务系统 API<br/>出差记录查询"]
Agent -->|"4️⃣ 检索相关参考"| RAG["🔍 RAG<br/>历史报销案例<br/>财务制度手册"]
Skills -.->|"知识指导行为"| FC
MCP -.->|"提供工具能力"| FC
style Skills fill:#4CAF50,stroke:#2E7D32,color:#fff
style FC fill:#F44336,stroke:#C62828,color:#fff
style MCP fill:#FF9800,stroke:#E65100,color:#fff
style RAG fill:#2196F3,stroke:#1565C0,color:#fff
style Agent fill:#9C27B0,stroke:#6A1B9A,color:#fff
协同流程:
- 📖 Skills 告诉 Agent:报销限额是多少、需要哪些收据、审批流程是什么
- 🦾 Function Calling 让 Agent 执行:创建报销单、提交审批
- 🔌 MCP 让 Agent 连接:查询出差记录、调用财务系统 API
- 🔍 RAG 让 Agent 参考:检索历史案例、查找制度细则
6. Agent Skills 在 Microsoft AI Stack 中的位置
- 技术栈全景,Agent Skills 并不是一个独立存在的概念,它在 Microsoft AI 技术栈中有明确的落地方式:
flowchart TB
subgraph "你的应用"
APP["🏢 企业 AI 应用"]
end
subgraph "Microsoft Agent Framework (MAF)"
AGENT["🤖 AIAgent"]
FC2["🦾 Function Calling<br/>ChatOptions.Tools"]
ACP["📖 AIContextProvider<br/>ChatOptions.AIContextProviders"]
end
subgraph "Agent Skills 实现"
FSP["📂 FileAgentSkillsProvider<br/>(AIContextProvider 的子类)"]
LOADER["🔧 FileAgentSkillLoader<br/>发现 & 解析 SKILL.md"]
TOOLS["🛠️ load_skill + read_skill_resource<br/>(自动注册的 AI 工具)"]
end
subgraph "文件系统"
SK1["📄 expense-report/SKILL.md"]
SK2["📄 code-review/SKILL.md"]
SK3["📄 ...更多 Skills"]
end
subgraph "Microsoft.Extensions.AI (MEAI)"
CC["💬 IChatClient"]
end
APP --> AGENT
AGENT --> FC2
AGENT --> ACP
ACP --> FSP
FSP --> LOADER
FSP --> TOOLS
LOADER --> SK1
LOADER --> SK2
LOADER --> SK3
AGENT --> CC
style FSP fill:#4CAF50,stroke:#2E7D32,color:#fff
style AGENT fill:#9C27B0,stroke:#6A1B9A,color:#fff
style CC fill:#2196F3,stroke:#1565C0,color:#fff
style ACP fill:#FF9800,stroke:#E65100,color:#fff
- 关键设计:AIContextProvider,在 MAF 中,Agent Skills 是通过 AIContextProvider 机制实现的:
| 概念 | 角色 | 说明 |
|---|---|---|
| AIContextProvider | 抽象基类 | 定义了为 Agent 提供上下文的通用接口 |
| FileAgentSkillsProvider | 具体实现 | 从文件系统发现和加载 Skills |
| load_skill | 自动注册的工具 | Agent 调用它来加载某个 Skill 的完整内容 |
| read_skill_resource | 自动注册的工具 | Agent 调用它来读取 Skill 的参考资料 |
Skills 巧妙地复用了 Function Calling 机制:load_skill 和 read_skill_resource 本身就是注册在 ChatOptions.Tools 中的工具。Agent 通过"调用工具"的方式来"加载知识",这就是 Skills 与 Function Calling 互补协作的体现。
var agent = new ChatCompletionAgent()
{
Name = "企业助手",
Instructions = "你是一个企业 AI 助手,请根据加载的技能知识回答问题。",
ChatClient = chatClient,
Options = new()
{
// Skills 通过 AIContextProviders 注册
AIContextProviders = [new FileAgentSkillsProvider("./skills")]
}
};
二、Skills.md 深入解析
1. 标准目录结构
一个 Agent Skill 本质上是一个结构化的文件夹。规范定义了以下标准结构:
expense-report/ # 📁 技能目录(名称须与 frontmatter.name 一致)
├── SKILL.md # 📄 技能定义文件(必需)
├── scripts/ # 🔧 可执行脚本(可选)
│ ├── validate-receipt.py # Python 脚本
│ └── calculate-total.ps1 # PowerShell 脚本
├── references/ # 📎 参考文档(可选)
│ ├── POLICY_FAQ.md # Agent 按需读取的文档
│ └── EXPENSE_CATEGORIES.md # 费用分类详表
└── assets/ # 📦 静态资源(可选)
├── expense-report-template.md # 模板文件
└── approval-flow.png # 流程图片
- 各目录职责详解
| 目录/文件 | 必需 | 职责 | 加载时机 |
|---|---|---|---|
| SKILL.md | ✅ | 技能的核心定义,包含元数据和全部指令 | 摘要展示(frontmatter);按需加载(body) |
| scripts/ | ❌ | 可执行脚本,Agent 可根据任务需要运行 | Agent 判断需要执行时 |
| references/ | ❌ | 参考文档,补充知识细节,过长不宜放入 SKILL.md | Agent 调用 read_skill_resource 时 |
| assets/ | ❌ | 静态资源:模板、图片、数据文件等 | Agent 调用 read_skill_resource 时 |
- 最小化 Skill 示例(仅 SKILL.md)
并非所有 Skill 都需要完整的四层结构。最简单的 Skill 只需一个文件:
git-commit-style/
└── SKILL.md # 只有这一个文件就足够了!
原则:从最小化开始,随着知识体系的增长按需添加子目录。不要过度设计。
2. YAML Frontmatter 字段全解
SKILL.md 文件由两部分组成:YAML Frontmatter(元数据) + Markdown Body(指令正文)。
- 完整 Frontmatter 示例
---
name: expense-report
description: |
File and validate employee expense reports according to company policy.
Use when the user asks about expenses, reimbursement, receipts, or travel costs.
license: MIT
compatibility: Requires access to the company expense management system.
metadata:
author: finance-team
version: 2.1.0
domain: finance
allowed-tools: read_file write_file
---
- 字段详解
| 字段 | 必需 | 类型 | 长度限制 | 说明 |
|---|---|---|---|---|
| name | ✅ | 字符串 | ≤64 字符 | 技能唯一标识,须与目录名完全一致;只允许小写字母、数字和连字符 - |
| description | ✅ | 字符串 | ≤1024 字符 | 用于摘要展示阶段,是 Agent 决定是否加载的依据,对触发准确性至关重要 |
| license | ❌ | 字符串 | 自由长度 | 开源许可证(如 MIT、Apache-2.0)或版权声明 |
| compatibility | ❌ | 字符串 | ≤500 字符 | 环境约束说明(如需要 Docker、特定 Python 版本等) |
| metadata | ❌ | 映射 | 无限制 | 扩展元数据,key-value 格式,可存放作者、版本、标签等 |
| allowed-tools | ❌ | 空格分隔列表 | — | 预授权工具列表,预先允许 Agent 使用这些工具(实验性) |
- name 字段规范
# ✅ 合法的 name
name: expense-report # 小写 + 连字符
name: code-reviewer # 动词-名词格式
name: dotnet-ci-standards # 具体前缀
name: pdf-extractor # 功能描述
# ❌ 不合法的 name
name: Expense Report # 含大写和空格
name: expense_report # 下划线不允许
name: 费用报销 # 中文不允许
name: my-super-long-skill-name-that-exceeds-64-chars-for-clarity # 超长
name 必须与目录名完全一致! 如果目录叫 expense-report/,那么 SKILL.md 中的 name 也必须是 expense-report。
3. Description — 触发的钥匙
在所有字段中,description 是最关键的一个,它直接决定 Skill 能否在正确的时机被触发。
Agent 在摘要展示阶段只能看到 description 字段的内容,Markdown Body 要等到 load_skill 调用后才可见。因此,一个质量差的 description 会导致:
- ❌ 漏触发(Miss):该用到 Skill 的时候,Agent 没有加载
- ❌ 误触发(False Positive):不该加载时加载了,浪费 Token
- ❌ 加载错误(Wrong Skill):加载了不相关的 Skill
| 对比维度 | ❌ 差的 Description | ✅ 好的 Description |
|---|---|---|
| 具体性 | 太模糊 | 明确说明适用场景 |
| 触发关键词 | 没有显式关键词 | 包含用户可能使用的词汇 |
| 使用时机 | 没有说明何时使用 | 明确说明 Use when... |
| 范围边界 | 越权或范围不清 | 明确能做什么、不能做什么 |
- 实例对比
# ❌ 差的 description — 太模糊,触发概率低且不准确
description: Helps with PDF files.
# ✅ 好的 description — 具体、包含触发关键词、说明使用时机
description: |
Extract text and tables from PDF files, fill out PDF forms, and merge or
split PDF documents. Use when the user mentions PDFs, forms, document
extraction, or asks to work with PDF files.
# ❌ 差的 description
description: Code review assistant.
# ✅ 好的 description
description: |
Review code for bugs, security vulnerabilities, performance issues, and
style violations. Use when asked to review, audit, check, or improve code
quality. Provides actionable feedback with severity levels.
- Description 撰写公式,一个高质量的 description 通常包含以下要素:
[做什么] + [具体场景/对象] + Use when [触发条件] + [可选:排除条件]
模板示例:
[动作] [对象/内容] according to [规范/标准].
Use when the user asks about [关键词1], [关键词2], or [关键词3].
[可选] Do not use for [排除场景].
类比:description 就像图书馆书脊上的简介 —— 写得好,读者(Agent)才能快速、准确地找到需要的书(Skill)。
4. Markdown Body 指令设计
Markdown Body 是 Skill 的知识主体,会在 load_skill 调用后完整注入 Agent 的上下文。
Body 是给 Agent 读的,不是给人类读的。它的核心目标是:
让 Agent 在收到相关问题时,能够给出准确、一致、可审计的回答。
- 好的 Body 设计原则
| 原则 | 说明 | 示例 |
|---|---|---|
| 指令明确 | 用祈使句,避免模糊描述 | Respond with the exact limit from the table below. |
| 结构化 | 使用标题、表格、有序列表 | 费用类别 → 限额表格 |
| 覆盖边界 | 明确说明例外情况 | When the amount exceeds $500, always require manager approval. |
| 引导资源 | 告诉 Agent 何时读取 references/ | For detailed FAQ, use read_skill_resource to load references/POLICY_FAQ.md |
| 避免重复 | 不要重复 description 中已说的内容 | 直接进入知识细节 |
- Body 结构模板
---
name: expense-report
description: ...
---
# 费用报销指南
## 费用类别与限额
| 类别 | 每日限额 | 需要收据 | 需要审批 |
|------|---------|---------|--------|
| 餐饮(个人) | $50 | 若 >$25 | 否 |
| 餐饮(客户) | $150/人 | 始终 | 若 >$100 |
| 交通 | 实报 | 始终 | 若 >$500 |
| 住宿 | $250/晚 | 始终 | 始终 |
## 报销流程
1. 收集所有收据(餐饮 >$25 必须有收据)
2. 使用标准模板:读取 [assets/expense-report-template.md](assets/expense-report-template.md)
3. 提交至 Concur 系统,分类标注每笔费用
4. 超过审批阈值的,发送审批请求至直接经理
## 例外与特殊情况
- 小费:餐饮消费 20% 以内可报销,需在备注中注明
- 国际差旅:参考 [references/INTERNATIONAL_TRAVEL.md](references/INTERNATIONAL_TRAVEL.md)
- 客户娱乐:>$200 需要 VP 级别审批
## 常见问题
如有政策细节疑问,读取 [references/POLICY_FAQ.md](references/POLICY_FAQ.md)
- 渐进式披露的分层策略,不是所有知识都应该放进 Body。遵循以下策略:
flowchart LR
Q{"这段知识多长?"} -->|"短,核心规则"| BODY["放入 SKILL.md Body<br>常规加载"]
Q -->|"长,但经常用"| SPLIT["拆成小文件<br>放 references/"]
Q -->|"很长,偶尔用"| REFS["放 references/<br>按需加载"]
Q -->|"模板/数据"| ASSETS["放 assets/<br>供 Agent 引用"]
style BODY fill:#4CAF50,stroke:#2E7D32,color:#fff
style SPLIT fill:#2196F3,stroke:#1565C0,color:#fff
style REFS fill:#FF9800,stroke:#E65100,color:#fff
style ASSETS fill:#9C27B0,stroke:#6A1B9A,color:#fff
经验法则:Body 建议控制在 5000 tokens 以内(约 4000 汉字或 6000 英文单词)。超出的部分请放入 references/ 并在 Body 中提供引用链接。
5. 资源引用语法
在 SKILL.md Body 中引用子目录文件,使用相对路径 Markdown 链接:
[显示文字](相对路径/文件名)
示例:
请参考:[费用政策 FAQ](references/POLICY_FAQ.md)
使用模板:[报销单模板](assets/expense-report-template.md)
执行脚本:[验证收据](scripts/validate-receipt.py)
- 引用的语义
| 引用类型 | 语义 | Agent 的行为 |
|---|---|---|
| references/*.md | 提示 Agent 可以获取更多细节 | 决定是否调用 read_skill_resource |
| assets/*.md | 提示 Agent 可以获取模板/数据 | 决定是否调用 read_skill_resource |
| scripts/*.py | 提示 Agent 可以执行该脚本 | 决定是否触发脚本执行 |
- 引用的触发时机
Agent 不会自动读取所有引用的文件 —— 它会根据任务的需要决定是否调用 read_skill_resource。因此,Body 中的引用描述很重要:
# ✅ 清晰提示 Agent 何时使用引用资源
## 例外情况
如果涉及国际差旅,必须读取 [references/INTERNATIONAL_TRAVEL.md](references/INTERNATIONAL_TRAVEL.md)
以获取完整的海外报销政策。
# ❌ 模糊的引用,Agent 不知道何时读取
相关文档:[references/INTERNATIONAL_TRAVEL.md](references/INTERNATIONAL_TRAVEL.md)
路径规范:所有引用路径都是相对于 Skill 根目录的。不要使用绝对路径,不要使用 ../ 引用技能目录之外的文件。
6. 实战阅读练习
通过剖析 3 个不同复杂度的真实 Skill,建立质量判断直觉。
- 练习 1:password-generator(含脚本)
目录结构:
password-generator/
├── SKILL.md
├── references/
│ └── PASSWORD_GUIDELINES.md
└── scripts/
└── generate.py
SKILL.md 内容:
---
name: password-generator
description: Generate secure passwords using a Python script. Use when asked to create passwords or credentials.
---
# Password Generator
This skill generates secure passwords using a Python script.
## Usage
When the user requests a password:
1. First, review `references/PASSWORD_GUIDELINES.md` to determine the recommended
password length and character sets for the user's use case
2. Load `scripts/generate.py` and adjust its parameters (length, character set)
based on the guidelines and user's requirements
3. Execute the script
4. Present the generated password clearly
质量分析:
| 评分维度 | 评分 | 说明 |
|---|---|---|
| description 质量 | ⭐⭐⭐⭐ | 包含触发关键词(passwords, credentials),有 Use when |
| Body 结构 | ⭐⭐⭐⭐⭐ | 清晰的步骤化指令,告诉 Agent 先读参考资料再执行脚本 |
| 资源引用 | ⭐⭐⭐⭐⭐ | 明确指出何时读取 references,何时执行 scripts |
| 渐进式披露 | ⭐⭐⭐⭐ | 先查指南(references)再调脚本,体现了分层加载 |
可改进之处: description 可以更详细,加入「Use when asked to generate secure passwords, API keys, or random tokens」
- conventional-commits(纯知识型)
SKILL.md 内容(节选):
---
name: conventional-commits
description: |
Write Git commit messages following the Conventional Commits specification.
Use when creating commit messages, writing git log entries, or when the user
asks for help formatting commits.
---
# Conventional Commits
All commit messages MUST follow this format:
[optional scope]:
[optional body]
[optional footer(s)]
## Types
| Type | When to Use |
|------|-------------|
| `feat` | New feature |
| `fix` | Bug fix |
| `docs` | Documentation only |
| `style` | Formatting, no logic change |
| `refactor` | Code change that neither fixes nor adds feature |
| `test` | Adding missing tests |
| `chore` | Build process or auxiliary tool changes |
## Rules
- Description line MUST NOT exceed 72 characters
- Use imperative mood: "add feature" not "added feature"
- Do NOT end description with a period
质量分析:
| 评分维度 | 评分 | 说明 |
|---|---|---|
| description 质量 | ⭐⭐⭐⭐⭐ | 三个 Use when 场景,关键词丰富 |
| Body 结构 | ⭐⭐⭐⭐⭐ | 精准的格式规范 + 规则表格 + 强制性语气(MUST) |
| 渐进式设计 | ⭐⭐⭐ | 简单 Skill,不需要子目录,这是正确的选择 |
- 练习 3:问题案例诊断
以下是一个质量很差的 SKILL.md,找出所有问题:
---
name: My Helper Skill
description: This skill helps with various tasks.
---
# Helper
I can help you do things. Just ask me anything and I'll try to assist.
See references/help.md for more information.
问题诊断:
| # | 问题 | 严重程度 | 修复方向 |
|---|---|---|---|
| 1 | name 含大写字母和空格 | ❌ 规范违反 | 改为 my-helper-skill |
| 2 | description 极度模糊 | ❌ 无法触发 | 明确说明具体用途和触发关键词 |
| 3 | Body 无实质内容 | ❌ 知识缺失 | 加入具体规则、流程、限制 |
| 4 | references/help.md 引用无上下文 | ⚠️ Agent 不知何时读取 | 加上触发条件说明 |
| 5 | Body 采用第一人称("I can help") | ⚠️ 混淆 Agent | 改用祈使句指令风格 |
7. Skill 质量自检清单
在开始创建自己的 Skill 之前,用这个清单来评估任何一个 Skill 的质量:
- Frontmatter 检查
| # | 检查项 | 标准 |
|---|---|---|
| 1 | name 格式 | 小写字母、数字、连字符,≤64 字符,与目录名一致 |
| 2 | description 长度 | 50-300 字符(英文),不超过 1024 |
| 3 | description 明确性 | 包含具体场景/对象,有 Use when 说明 |
| 4 | description 关键词 | 包含用户可能使用的关键词(动词 + 名词) |
| 5 | compatibility | 如有外部依赖,是否已声明 |
- Body 检查
| # | 检查项 | 标准 |
|---|---|---|
| 6 | Body 长度 | 建议 <5000 tokens,过长的内容放 references/ |
| 7 | 指令语气 | 使用祈使句,避免第一人称描述 |
| 8 | 结构清晰度 | 有明确的标题层级,关键规则用表格或列表 |
| 9 | 边界覆盖 | 例外情况、特殊场景是否有说明 |
| 10 | 资源引用 | 引用 references/ 时是否说明了触发时机 |
- 目录结构检查
| # | 检查项 | 标准 |
|---|---|---|
| 11 | 脚本安全 | scripts/ 中的脚本是否有潜在安全风险 |
| 12 | 文件命名 | 文件名使用全大写(如 POLICY_FAQ.md)或小写连字符均可,但保持一致 |
| 13 | 最小化原则 | 没有冗余子目录,只有确实需要的文件 |
- 质量评级参考
| 得分(通过项/13) | 评级 | 建议 |
|---|---|---|
| 13/13 | ⭐⭐⭐⭐⭐ 优秀 | 可发布 |
| 10-12/13 | ⭐⭐⭐⭐ 良好 | 修复剩余问题后发布 |
| 7-9/13 | ⭐⭐⭐ 中等 | 需要重写 description 和 Body |
| <7/13 | ⭐⭐ 及格 / ⭐ 不及格 | 从头重写 |
8. 实战:周报skill
- skill.md
---
name: weekly-report
description: 软件开发工程师工作周报生成助手。当用户提出"写周报"、"帮我写周报"、"生成工作周报"、"周报怎么写"、"工作总结"、"本周工作报告"等需求时,立即触发此 skill。即使用户只是说"周报"、"想写个总结",也应主动触发并引导用户完成周报撰写。该 skill 会主动分步骤收集用户的工作内容、风格偏好和下周计划,最终生成结构完整、语言专业的中文工作周报,可直接复制使用。
---
# 软件开发工程师工作周报生成助手
你是一位专业的工作周报撰写助手,帮助软件开发工程师将零散的工作描述整理成结构清晰、语言专业的周报。
## 核心原则
- **主动引导**:用户不需要知道该提供什么信息,你来问
- **口语化输入,专业化输出**:接受任何形式的输入(关键词、流水账、缩写),输出正式周报
- **尊重原意**:整理润色,不夸大也不缩减工作内容
- **术语一致**:参考 `references/project-glossary.md` 中的项目代码和企业术语,保持表述统一
## 分步收集信息流程
**不要一次性抛出所有问题**,按以下顺序逐步引导,每步等待用户回复后再进入下一步:
### 第一步:了解本周工作
用友好的方式开场,询问本周做了哪些工作。示例开场语:
> 好的,我来帮你写周报!先说说这周主要做了哪些事情?不用写得很正式,随便聊聊就行,比如"修了几个 bug"、"做了 xxx 功能"、"开了几个评审会"这样就够了。
接受所有形式的输入:
- 关键词列表:"登录优化、代码评审、接口联调"
- 流水账描述:"周一修了个线上 bug,周二周三一直在做用户模块,周四参加了产品评审..."
- 项目代号:参考 `references/project-glossary.md` 解析含义
### 第二步:询问遇到的问题(可选但重要)
> 这周有没有遇到什么卡点、风险,或者还没解决的问题?没有的话跳过也没关系。
常见类型:
- 技术难点(如第三方接口不稳定、性能瓶颈)
- 依赖阻塞(如等待其他团队的接口、需求变更)
- 进度风险(某功能可能延期)
### 第三步:了解下周计划
> 下周大概打算做什么?同样不用很正式,说个大方向就行。
### 第四步:确认风格偏好(首次使用或有特殊要求时询问)
> 最后确认一下,你们公司的周报风格是哪种?
给出选项:
- **汇报型**:适合向上级汇报,突出成果和价值,语气正式
- **记录型**:适合团队内部,详细记录工作事项,简洁务实
- **混合型**(默认推荐):成果导向,同时保留关键技术细节
> 如果有公司规定的固定格式,告诉我,我按那个格式来。
## 生成周报
收集完信息后,参考 `references/report-formats.md` 选择合适的格式模板生成周报。
在生成标题前,必须执行 `scripts/get_week_info.py` 获取当前标准周数,并将其填充至标题模板中。
### 输出规范
1. **标题**:`[姓名/团队] 工作周报(YYYY年MM月第X周)` —— 如果用户没提供姓名可省略
2. **语言**:中文,专业但不生硬
3. **工作项描述原则**:
- 动词开头,结果导向:"完成XXX功能开发,支持YYY场景"
- 量化描述优先:"优化查询性能,响应时间从800ms降至200ms"
- 专业术语参考 `references/project-glossary.md`
4. **格式**:使用 Markdown,可直接复制到企业内部系统
## 补充说明
- 如果用户描述中出现项目代码(如 "P2"、"OA系统"、"A模块"),先查 `references/project-glossary.md`,找不到则直接使用用户的原始表述
- 生成周报后,主动询问:"这样可以吗?需要调整哪里?"
- 如果用户提供了公司固定模板,优先使用用户的模板,不套用内置结构
## 参考文件
- `references/report-formats.md`:企业常见周报格式规范,包含不同风格的格式要求
- `references/project-glossary.md`:项目代码和企业术语对照表(用户自定义填写)
- references/report-formats.md
# 企业周报格式规范参考
本文件收录了软件研发团队常见的周报格式规范,供生成周报时参考。根据用户选择的风格或企业要求,选用对应格式。
---
## 格式一:汇报型(向上级汇报)
**适用场景**:向部门经理、总监汇报,强调产出成果和业务价值。
**格式要求**:
- 语气正式,用词专业
- 每个工作项先说**结论/成果**,再说过程
- 量化数据尽量提供(行数、接口数、优化幅度等)
- 问题与风险部分需提供**处理方案**或**寻求支持**的诉求
**示例结构**:
```
工作周报(XXXX年第XX周)
汇报人:XXX | 所属团队:XXX
【本周主要成果】
1. 完成用户中心模块登录功能重构,支持 SSO 单点登录,预计覆盖 3 个业务系统
2. 排查并修复线上订单状态不一致 Bug,影响约 200 笔订单已全部修复
【进行中工作】
1. 支付模块对接开发(进度 60%,预计下周三完成)
【风险与阻塞】
- 第三方支付接口文档尚未到位,需商务团队协助催促(已抄送至XXX)
【下周计划】
1. 完成支付模块开发并提测
2. 参与 Q3 技术规划评审
```
---
## 格式二:记录型(团队内部/工作日志)
**适用场景**:团队内部同步、项目群周报、自我工作记录。
**格式要求**:
- 简洁直接,可使用技术术语和缩写
- 按**日期或模块**分组均可
- 问题直接描述,不需要过多修饰
- 可包含技术细节(如 PR 编号、接口名称等)
**示例结构**:
```
## 工作周报(XXXX年第XX周)
### 完成事项
- [用户模块] 登录接口重构,迁移至 JWT 认证,PR #423 已合并
- [订单模块] 修复订单状态同步 Bug,原因:MQ 消费幂等问题
- [代码评审] 评审 3 个 PR,提出建议 7 条
### 进行中
- [支付模块] 对接银行 SDK,完成基础流程,沙箱联调中
### 问题
- 银行 SDK 文档版本不一致,已联系对方确认,待回复
### 下周计划
- 完成支付模块联调
- 补充单元测试覆盖率至 80%
```
---
## 格式三:混合型(推荐默认)
**适用场景**:大多数企业的通用周报,兼顾正式性和可读性。
**格式要求**:
- 成果导向,但保留必要技术背景
- 按**功能模块或项目**分组
- 问题部分提供状态说明
- 语气专业但不生硬
**示例结构**:
```
工作周报(XXXX年第XX周)
一、本周完成工作
【用户中心】
- 完成登录模块重构,引入 JWT 认证方案,已上线测试环境
- 修复用户头像上传偶发失败问题(根因:OSS 签名超时),已验证
【订单系统】
- 协助排查线上订单状态异常问题,定位为消息队列消费幂等性缺陷,已修复上线
- 参与需求评审会,输出技术方案初稿
二、问题与风险
| 问题 | 影响 | 当前状态 |
|------|------|---------|
| 支付 SDK 文档版本不一致 | 可能影响联调进度 | 已与对接方确认,等待回复 |
三、下周计划
1. 完成支付模块开发,推进联调
2. 单元测试补全(目标覆盖率 ≥ 80%)
3. 参与 Q3 技术规划讨论
```
---
## 常见企业附加规范
不同企业可能在基础结构上附加以下要求,生成时按实际情况处理:
### 工作量统计
部分企业要求在周报末尾附上工时统计:
```
【本周工时分布】
需求开发:20h
Bug修复:6h
评审/沟通:6h
学习/其他:4h
合计:36h
```
### OKR/KPI 对齐
部分企业要求说明工作与目标的关联:
```
本周工作与 Q2 目标对齐情况:
- 目标:提升支付成功率至 99.5%(当前进度:联调阶段)
- 目标:降低核心接口 P99 延迟(已完成登录接口优化,延迟降低 60%)
```
### 学习与成长(可选模块)
```
【本周学习】
- 阅读《分布式系统设计》第3章,了解 Raft 共识算法
- 学习 Kubernetes 滚动发布实践
```
### 协作事项(可选模块)
```
【跨团队协作】
- 协助前端团队排查接口跨域问题
- 与产品确认支付流程交互细节
```
---
## 格式选择建议
| 场景 | 推荐格式 |
|------|---------|
| 向部门负责人/总监汇报 | 格式一(汇报型) |
| 团队内部周同步 | 格式二(记录型) |
| 不确定/通用场景 | 格式三(混合型)|
| 用户有固定模板 | 优先使用用户模板 |
- references/project-glossary.md
# 项目代码与企业术语对照表
> **使用说明**:本文件用于记录你所在企业/团队的项目代号、系统缩写、业务术语,帮助周报助手正确理解和使用你的专属表述。
>
> **填写方式**:按照下方示例格式填写,每个条目包含:缩写/代号、全称、简短说明(可选)。
>
> **填写后**:周报助手会自动参考本文件,将你描述中的缩写替换为标准表述,或在必要时保留原始缩写。
---
## 项目代号
> 填写你负责的项目代号和对应的正式名称
| 代号 | 项目全称 | 备注 |
|------|---------|------|
| (示例)P1 | 用户中台重构项目 | 2025 Q1 立项 |
| (示例)P2 | 支付系统升级 | 与财务团队联合项目 |
| (示例)Alpha | 内测版本 | 仅供内部使用 |
---
## 系统/平台缩写
> 填写内部系统名称的缩写或俗称
| 缩写/俗称 | 正式名称 | 说明 |
|---------|---------|------|
| (示例)OA | 办公自动化系统 | 内部审批、请假等 |
| (示例)BMS | 业务管理系统 | 核心业务平台 |
| (示例)数据平台 | XX数据中台 | 数据查询和分析 |
---
## 业务术语
> 填写行业或公司内部特有的业务词汇
| 术语 | 含义 | 使用场景 |
|------|------|---------|
| (示例)灰度 | 灰度发布,指分批次上线功能 | 描述发布策略时使用 |
| (示例)压测 | 压力测试 | 性能测试相关工作 |
| (示例)UAT | 用户验收测试 | 上线前测试阶段 |
---
## 团队/人员代称
> 如周报中需要提及其他团队或角色,可在此记录常用称呼
| 称呼 | 说明 |
|------|------|
| (示例)前端团队 | 负责 Web 端开发 |
| (示例)QA | 测试团队 |
| (示例)PM | 产品经理 |
---
## 自定义填写区
> 其他不属于以上分类但需要记录的术语
<!-- 在此自由添加 -->
---
> **提示**:此文件为空时,周报助手会直接使用你描述中的原始表述,不做替换。建议根据自己的实际情况逐步填充,使用几次后会越来越顺手。
- scripts/get_week_info.py
import datetime
def get_work_week():
today = datetime.date.today()
year, week_num, day_of_week = today.isocalendar()
# 按照中国习惯,如果周一到周日跨年,做特殊处理
return f"{year}年{week_num}周"
if __name__ == "__main__":
print(get_work_week())
三、Skills 生态市场
1. agentskills.io — 官方规范站
agentskills.io 是 Agent Skills 规范的官方发布站点,由 Anthropic 主导,社区共建。
| 版块 | 内容 | 价值 |
|---|---|---|
| Specification | 完整的规范文档 | 了解规范细节,确保自己的 Skill 合规 |
| Registry | 官方认证的 Skill 索引 | 找到经过审核的高质量 Skill |
| Changelog | 规范版本历史 | 跟踪规范演进,评估兼容性风险 |
| Community | 论坛 / Discord | 参与标准讨论,获取帮助 |
- 作为开发者,以下章节最值得精读:
agentskills.io/specification
├── File Format → SKILL.md 的完整语法定义(对应我们第2课的内容)
├── Progressive Disclosure → 渐进式披露机制的标准实现
├── Script Execution → scripts/ 目录和执行规范
├── Security → 安全约束(沙盒要求、路径限制等)
└── Interoperability → 跨产品互操作的要求
官方 Registry 的价值,Registry 中的 Skill 通过质量审核,保证:
规范合规(frontmatter 完整,路径引用正确)
安全性审查(脚本无恶意代码)
有维护者(非废弃项目)
建议:在使用第三方来源的 Skill 之前,先在 agentskills.io/registry 搜索是否已有官方认证版本。
- 已采纳 Agent Skills 规范的产品
| 产品 | 官方支持 | 备注 |
|---|---|---|
| Claude Code | ✅ | 原生支持,claude skills 命令族 |
| GitHub Copilot | ✅ | .github/ 目录自动识别 |
| Cursor | ✅ | .cursor/skills/ 目录 |
| Windsurf | ✅ | 内置 Skills 面板 |
| Microsoft Agent Framework (MAF) | ✅ | FileAgentSkillsProvider |
2. skillsmp.com — Skills Marketplace
skillsmp.com 是目前最活跃的 Skills 第三方市场,类似于 npm 之于 Node.js 包。
搜索技巧
# 按关键词搜索
site: skillsmp.com 搜索词: "dotnet" → 找 .NET 相关 Skill
# 按分类过滤
Category: Development → Language: C# → Sort: Most Used
# 高级过滤器
✅ Has Scripts → 筛选包含可执行脚本的 Skill
✅ Verified → 只看经过验证的 Skill
✅ Recently Updated → 筛选近 6 个月内更新过的
✅ Compatible with: MAF → 筛选 MAF 兼容的
3. skills.sh — CLI Hub
skills.sh 是专为开发者设计的 Skills CLI 工具平台,背后由 Vercel Labs 开源维护(vercel-labs/skills)。
核心特点:
- 零安装:直接通过 npx skills 使用,无需全局安装
- 多 Agent 支持:支持 Claude Code、GitHub Copilot、Cursor、Windsurf 等 37+ 款 Agent
- 智能检测:自动检测当前系统已安装的 Agent,自动匹配安装路径
运行入口
# 无需安装,直接运行
npx skills
███████╗██╗ ██╗██╗██╗ ██╗ ███████╗
██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝
███████╗█████╔╝ ██║██║ ██║ ███████╗
╚════██║██╔═██╗ ██║██║ ██║ ╚════██║
███████║██║ ██╗██║███████╗███████╗███████║
╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝
The open agent skills ecosystem
$ npx skills add <package> Add a new skill
$ npx skills remove Remove installed skills
$ npx skills list List installed skills
$ npx skills find [query] Search for skills
$ npx skills check Check for updates
$ npx skills update Update all skills
$ npx skills init [name] Create a new skill
Discover more skills at https://skills.sh
- 核心命令:
# 搜索 Skill(交互式 fzf 风格浏览)
npx skills find
npx skills find "typescript" # 按关键词搜索
# 安装 Skill(支持多种来源格式)
npx skills add vercel-labs/agent-skills # GitHub shorthand(最常用)
npx skills add vercel-labs/agent-skills -g # 安装到用户全局目录
npx skills add vercel-labs/agent-skills -a claude-code -a cursor # 指定目标 Agent
# 安装仓库中特定 Skill
npx skills add vercel-labs/agent-skills --skill frontend-design
npx skills add vercel-labs/agent-skills --list # 先列出仓库中所有可用 Skill 再选择
# 查看已安装的 Skills
npx skills list # 列出当前项目的 Skills
npx skills ls -g # 列出全局安装的 Skills
npx skills ls -a claude-code # 按 Agent 过滤
# 检查 & 更新
npx skills check # 检查是否有可用更新
npx skills update # 更新所有已安装 Skill 到最新版本
# 移除 Skill
npx skills remove # 交互式选择要移除的 Skill
npx skills remove code-reviewer # 移除指定 Skill
npx skills remove --global code-reviewer # 从全局目录移除
# 创建新 Skill
npx skills init # 在当前目录生成 SKILL.md 模板
npx skills init my-skill # 在子目录创建新 Skill
- 安装来源格式,npx skills add 支持多种来源,非常灵活:
# GitHub shorthand(最常用)
npx skills add vercel-labs/agent-skills
# 完整 GitHub URL
npx skills add https://github.com/vercel-labs/agent-skills
# 直接指向仓库中某个 Skill 的路径
npx skills add https://github.com/vercel-labs/agent-skills/tree/main/skills/web-design-guidelines
# GitLab URL
npx skills add https://gitlab.com/org/repo
# 任意 git URL
npx skills add git@github.com:vercel-labs/agent-skills.git
# 本地路径
npx skills add ./my-local-skills
- 安装作用域
| 作用域 | 命令 | 安装位置 | 适用场景 |
|---|---|---|---|
| 项目(默认) | npx skills add |
./ |
随项目提交,团队共享 |
| 全局 | npx skills add |
~/ |
个人配置,跨项目生效 |
- 实际安装演示,以下是在项目根目录安装 code-reviewer Skill 的完整流程:
# 1. 搜索 Skill(交互式浏览)
npx skills find "code review"
# 2. 查看仓库中所有可用 Skill 再选择
npx skills add anthropics/skills --list
# 3. 安装到项目(自动检测已安装的 Agent)
cd E:\My\Project
npx skills add anthropics/skills --skill code-reviewer
# 输出:
# ✓ Fetching skills from anthropics/skills...
# ✓ Installing code-reviewer to .claude/skills/
# ✓ Installing code-reviewer to .agents/skills/ (Cursor detected)
# ✓ Done!
# 4. 验证已安装
npx skills list
# code-reviewer (anthropics/skills@1.3.2) claude-code, cursor
- CI/CD 集成(非交互模式)
# 非交互、一键完成,适合 CI/CD 脚本
npx skills add vercel-labs/agent-skills --skill frontend-design -g -a claude-code -y
- 主流 AI IDE 的 Skills 安装目录,各主流 AI IDE 有自己的安装目录约定,npx skills 会自动检测并安装到对应位置:
| AI IDE / Agent | 项目级目录 | 全局目录 |
|---|---|---|
| Claude Code | .claude/skills/ | ~/.claude/skills/ |
| GitHub Copilot | .agents/skills/ | ~/.copilot/skills/ |
| Cursor | .agents/skills/ | ~/.cursor/skills/ |
| Windsurf | .windsurf/skills/ | ~/.codeium/windsurf/skills/ |
| Codex (OpenAI) | .agents/skills/ | ~/.codex/skills/ |
| Gemini CLI | .agents/skills/ | ~/.gemini/skills/ |
| Cline | .agents/skills/ | ~/.agents/skills/ |
| RooCode | .roo/skills/ | ~/.roo/skills/ |
| OpenCode | .agents/skills/ | ~/.config/opencode/skills/ |
| Goose | .goose/skills/ | ~/.config/goose/skills/ |
| 统一目录(推荐) | .agents/skills/ | — |
可以看到,许多 Agent 已经统一使用 .agents/skills/ 作为项目级目录
四、使用 Skill Creator 插件创建 Skills
1. Skill Creator 插件介绍
- Skill Creator 是 Anthropic 官方发布并认证的 Claude Code 插件,专门用于 Skill 的全生命周期管理:
| 信息 | 详情 |
|---|---|
| 插件页面 | https://claude.com/plugins/skill-creator |
| 源代码 | https://github.com/anthropics/skills/tree/main/skills/skill-creator |
| 认证状态 | Anthropic Verified |
| 调用方式 | /skill-creator 斜杠命令(对话式 Agent) |
- claude plugin 命令族,Claude Code 通过 claude plugin 子命令管理所有插件:
claude plugin --help
# Usage: claude plugin [options] [command]
# Commands:
# install|i Install a plugin from available marketplaces
# list List installed plugins
# enable Enable a disabled plugin
# disable Disable an enabled plugin
# uninstall Uninstall an installed plugin
# update Update a plugin to the latest version
# validate Validate a plugin or marketplace manifest
# marketplace Manage Claude Code marketplaces
- 安装 Skill Creator 插件
# 确保已安装 Claude Code
npm install -g @anthropic-ai/claude-code
claude --version
# 安装 Skill Creator 插件(从默认 marketplace 获取)
claude plugin install skill-creator
# 验证安装
claude plugin list
# Installed plugins:
# ❯ skill-creator@anthropic-agent-skills
# Version: x.x.x
# Scope: user
# Status: ✔ enabled
插件安装后即可在 Claude Code 对话中使用 /skill-creator 斜杠命令。
marketplace 说明:skill-creator 来自 anthropic-agent-skills marketplace。 如需指定来源,可使用 claude plugin install skill-creator@anthropic-agent-skills。
- 四个使用场景,输入 /skill-creator 后,插件以对话式 Agent 方式启动,首先询问你处于哪个阶段:
● I'm ready to help you create, improve, or optimize skills!
Where are you starting from?
1. Creating a new skill from scratch
2. Improving an existing skill
3. Optimizing skill triggering
4. Something else
| 场景 | 适用情况 |
|---|---|
| 1. 从零创建 | 有新想法,需要生成 SKILL.md 骨架 |
| 2. 改进现有 | 已有 Skill,需优化规则和质量 |
| 3. 优化触发 | Skill 可用,但触发时机不准确 |
| 4. 其他需求 | 自由描述你的具体目标 |
Skill Creator 是对话式 Agent,不是命令行工具。 它会持续追问细节,引导你完成从构思到测试用例的完整闭环。
- 内置三个 Agent,Skill Creator 底层由四个专用 Agent 协作:
| Agent | 职责 |
|---|---|
| Grader | 对比期望输出,为结果打分 |
| Comparator | 对两个 Skill 版本做盲测 A/B 对比 |
| Analyzer | 分析评分结果,提出针对性改进建议 |
2. 使用 /skill-creator 从零创建 Skill
- 启动 Skill Creator,在 Claude Code 对话中输入斜杠命令(无需额外参数):
/skill-creator
插件启动后,你会看到如下对话(以下为真实输出):
● I'm ready to help you create, improve, or optimize skills!
Let me understand where you are in the process.
Where are you starting from?
1. Creating a new skill from scratch
— You have an idea for what you want the skill to do
2. Improving an existing skill
— You already have a skill that needs refinement
3. Optimizing skill triggering
— You have a working skill but want to improve when Claude invokes it
4. Something else — Tell me what you're working on
If you're creating something new, I can help you:
- Clarify what the skill should do and when it should trigger
- Write the initial SKILL.md draft
- Create test cases to verify it works
- Run evaluations and iterate based on your feedback
- Polish it until you're satisfied
If you already have a skill in progress, just point me to it
and let me know what you'd like to improve!
What would you like to work on today?
- 回答选项 1:从零创建,输入 1 或直接描述你要创建的 Skill:
You: 1
● Great! Let's create a new skill from scratch.
What should this skill do? Describe it in plain language —
don't worry about the format yet.
You: 审查 .NET C# 代码,检查 SOLID 原则、async/await 模式、命名规范
和安全漏洞,输出带严重程度分级(CRITICAL/HIGH/MEDIUM/LOW)的
中文审查报告,每个问题附修复代码示例。
● That's clear! A few follow-up questions:
1. When should Claude invoke this skill automatically?
(e.g., "when user asks to review code", "when code is pasted")
You: 当用户说「审查代码」「Review」「检查代码质量」时,
特别是 C#、.NET、ASP.NET Core、EF Core 相关代码
2. Do you want reference documents (checklists, severity tables)?
You: 是的,需要 REVIEW_SEVERITY_LEVELS.md 和 DOTNET_REVIEW_CHECKLIST.md
3. Any specific output format?
You: 用 🚨 ⚠️ 🔶 ℹ️ 标记等级,结尾输出汇总统计
● Writing your SKILL.md...
- Skill Creator 生成完整对话流程,Skill Creator 不会仅仅生成文件就结束,它会继续引导你做测试和迭代:
● I've drafted your SKILL.md. Here's a summary of what was created:
- Skill name: dotnet-code-reviewer
- Trigger: code review requests for C#/.NET code
- References: REVIEW_SEVERITY_LEVELS.md, DOTNET_REVIEW_CHECKLIST.md
- Output: severity-graded report with fix examples
Would you like to:
a) Review and edit the SKILL.md before proceeding
b) Create test cases to verify it works
c) Run a quick test with a sample input
You: b — 创建测试用例
● Let's create test cases. For each one, I need:
1. A prompt (what the user would say)
2. Expected behavior (what the skill should do)
Describe your first test case:
You: 用户提交一段有 SQL 注入漏洞的代码,期望检出 CRITICAL 级别问题
● Created: evals/sql-injection-test.md
Let's add another, or type "done" when finished.
- 生成的文件结构
skills/dotnet-code-reviewer/
├── SKILL.md # 核心技能定义
├── evals/
│ └── sql-injection-test.md # Skill Creator 协助生成的测试用例
└── references/
├── REVIEW_SEVERITY_LEVELS.md # 严重度分级规范
└── DOTNET_REVIEW_CHECKLIST.md # 审查清单
与手工创建的核心区别:Skill Creator 是对话式 Agent,不只是代码生成器。 它会追问触发条件、引导创建测试用例、并在你满意之前持续迭代—— 整个过程是「需求澄清 → 起草 → 测试 → 打磨」的闭环。
3. 分析生成结果,识别需要优化的地方
- 生成的 SKILL.md(原始版),查看生成结果:
cat skills/dotnet-code-reviewer/SKILL.md
---
name: dotnet-code-reviewer
description: |
Review .NET C# code for SOLID principles, async patterns, naming conventions,
and security vulnerabilities. Use when asked to review, audit, or check code
quality, especially for C#, .NET, and ASP.NET Core code.
metadata:
author: generated
version: 1.0.0
language: zh
---
# .NET 代码审查指南
作为 .NET 代码审查专家,当用户请求代码审查时,请按以下步骤进行系统化审查:
## 审查步骤
1. 首先查阅 [审查严重程度分级](references/REVIEW_SEVERITY_LEVELS.md)
2. 对照 [.NET 审查清单](references/DOTNET_REVIEW_CHECKLIST.md) 进行逐项检查
3. 按严重程度从高到低排列问题
4. 为每个问题提供具体的修复建议
## 审查重点
### SOLID 原则
- 单一职责、开闭原则、里氏替换、接口隔离、依赖倒置
### 异步编程
- async/await 正确使用
- 避免 async void(除事件处理器)
- ConfigureAwait(false) 在库代码中
### 安全
- SQL 注入风险
- 敏感信息硬编码
- 输入验证缺失
请用中文提供审查报告。
- 质量分析:哪些好,哪些需要改
| 评估项 | 评级 | 说明 |
|---|---|---|
| name 格式 | ✅ | 小写连字符,规范 |
| description 质量 | ✅ | 有 Use when,有关键词 |
| Body 结构 | ⚠️ | 步骤清晰但过于简略 |
| SOLID 说明 | ❌ | 只列举名称,没有具体规则 |
| 异步编程规则 | ⚠️ | 有要点但不够具体 |
| 安全检查 | ⚠️ | 覆盖面窄,只有 3 项 |
| 输出格式指定 | ❌ | 没有规定报告格式(分级、图标等) |
- 优化后的 SKILL.md(精修版)
---
name: dotnet-code-reviewer
description: |
Review .NET C# code for SOLID principles, async/await patterns, naming
conventions, security vulnerabilities, and performance issues. Use when
asked to review, audit, check, or improve C#, .NET, ASP.NET Core, or
EF Core code quality.
metadata:
author: agent-course
version: 1.1.0
---
# .NET 代码审查指南
## 审查流程
1. 读取 [references/REVIEW_SEVERITY_LEVELS.md](references/REVIEW_SEVERITY_LEVELS.md) 获取严重程度定义
2. 逐项执行 [references/DOTNET_REVIEW_CHECKLIST.md](references/DOTNET_REVIEW_CHECKLIST.md)
3. 按 🚨 CRITICAL → ⚠️ HIGH → 🔶 MEDIUM → ℹ️ LOW 顺序输出报告
4. 每个问题必须包含:**问题描述** + **修复代码示例**
## 核心审查规则
### 🔒 安全(优先级最高)
| 风险 | 示例(危险)| 修复方向 |
|------|-----------|----------|
| SQL 注入 | `$"SELECT * FROM users WHERE id='{id}'"` | 参数化查询 |
| 硬编码密钥 | `var key = "sk-abc123"` | 环境变量 / Key Vault |
| 不安全反序列化 | `JsonSerializer.Deserialize<dynamic>(input)` | 强类型反序列化 |
### ⚡ 异步编程
- `async void` 仅允许事件处理器,其余一律标记 HIGH
- `.Result` / `.Wait()` 在异步上下文中:标记 HIGH(死锁风险)
- 库代码中缺少 `ConfigureAwait(false)`:标记 MEDIUM
### 🏗️ SOLID 原则
- 单一职责(SRP):方法超过 50 行、类超过 300 行 → MEDIUM
- 依赖倒置(DIP):直接 `new` 具体类而非注入接口 → MEDIUM
- 开闭原则(OCP):大量 if-else / switch 可替换为策略模式 → LOW
### 📛 命名规范 (.NET 官方风格)
- 类/方法:PascalCase;局部变量/参数:camelCase
- 接口必须以 `I` 开头:`IUserRepository`
- 异步方法必须以 `Async` 结尾:`GetUserAsync()`
- 违反以上:LOW
## 报告格式
🔍 .NET 代码审查报告
━━━━━━━━━━━━━━━━━━━━
🚨 CRITICAL — [问题标题]
位置:第 N 行
说明:[具体说明]
修复:[代码示例]
...
📊 汇总:CRITICAL: X | HIGH: X | MEDIUM: X | LOW: X
优化重点:
- description 扩充了更多触发关键词(audit / improve / EF Core)
- 安全规则加入了具体的代码示例,让 Agent 能精确识别
- 报告格式明确规定,保证输出一致性
- 每类规则都指定了严重程度,无需 Agent 自行判断
4. 使用 Skill Creator 评估与迭代优化
- 准备测试用例,Skill Creator 会在创建 Skill 时引导你同步创建测试用例, 也可以后续手动补充。测试用例存放在 evals/ 目录下:
skills/dotnet-code-reviewer/
├── SKILL.md
├── evals/
│ ├── sql-injection-test.md # 测试:SQL 注入检测
│ ├── async-void-misuse.md # 测试:async void 误用
│ └── hardcoded-secret.md # 测试:硬编码密钥
└── references/
├── REVIEW_SEVERITY_LEVELS.md
└── DOTNET_REVIEW_CHECKLIST.md
测试用例格式示例(evals/sql-injection-test.md):
## Prompt
帮我审查以下代码:
```csharp
public User GetUser(string id)
{
return _db.Query($"SELECT * FROM users WHERE id='{id}'");
}
Expected
- 必须检出 SQL 注入漏洞
- 严重程度必须为 🚨 CRITICAL
- 必须提供参数化查询的修复示例
- 启动 Eval / Improve 流程,/skill-creator 是对话式 Agent,选择场景 2(改进现有 Skill)来进行评估:
/skill-creator
● Where are you starting from?
Creating a new skill from scratch
Improving an existing skill ← 选这个
Optimizing skill triggering
Something else
You: 2
● Great! Point me to your skill.
What's the path or name of the skill you'd like to improve?
You: skills/dotnet-code-reviewer
● I can see your skill. What would you like to improve?
Run evaluations against your test cases
Improve the skill's description or triggers
Refine the skill's instructions or output format
Something else
You: 运行 evals 目录下的所有测试用例,看看哪些通过、哪些失败
● Running evaluations against skills/dotnet-code-reviewer/evals/...
✓ sql-injection-test.md — Score: 1.00 ✅ CRITICAL detected
✗ async-void-misuse.md — Score: 0.60 ⚠️ HIGH 未标记
✗ hardcoded-secret.md — Score: 0.80 ✅ 检出,但缺少修复示例
Average score: 0.80
The main issues I found:
async void 规则说明不够具体,Agent 没能判断为 HIGH
hardcoded-secret 案例缺少 Key Vault / 环境变量修复代码示例
Would you like me to improve the skill based on these results?
You: 是的,请自动修复这两个问题
- Skill Creator 自动修改并重新评估
● Updating SKILL.md...
Changes made:
+ async void:明确标注严重程度为 HIGH,添加正确写法对比示例
+ hardcoded-secret:添加 Azure Key Vault + 环境变量两种修复示例
Re-running evaluations...
✓ sql-injection-test.md — Score: 1.00 (unchanged)
✓ async-void-misuse.md — Score: 1.00 (+0.40 ✅)
✓ hardcoded-secret.md — Score: 1.00 (+0.20 ✅)
Average score: 1.00 🎉
All evaluations pass! Your skill is ready for production use.
Would you like to add more test cases or call it done?
- 验证关键行为,在 Claude Code 对话中,确认以下 3 个关键点:
| 验证点 | 测试方法 | 期望结果 |
|---|---|---|
| Skill 被自动触发 | 说「审查代码」/ 「Review this code」 | Claude 主动加载 Skill 规则 |
| references 被引用 | 提问严重度分级定义 | 输出与 REVIEW_SEVERITY_LEVELS.md 一致 |
| 报告格式正确 | 提交任意代码片段 | 输出带 🚨⚠️🔶ℹ️ 图标的分级报告 |
5. 跨产品使用同一 Skill
- 在 GitHub Copilot 中使用
# 复制到 GitHub Copilot 的 Skills 目录
Copy-Item -Recurse skills/dotnet-code-reviewer .github/skills/
重启 VS Code 后,Copilot Chat 中说「Review this code」即可触发。
- 在 Cursor 中使用
# Cursor 的 Skills 目录位置
Copy-Item -Recurse skills/dotnet-code-reviewer .cursor/skills/
- 在 MAF 中使用
var skillsProvider = new FileAgentSkillsProvider(
skillPath: Path.Combine(AppContext.BaseDirectory, "skills"));
// 注册到 Agent
AIContextProviders = [skillsProvider]
「一次创作,到处使用」的价值,这正是 Agent Skills 开放规范的核心价值:无论选择哪个 AI 工具,领域知识只需维护一份
五、MAF 集成 Agent Skills
1. 源码架构深度解析
classDiagram
class AIContextProvider {
<<abstract>>
+InvokingAsync() AIContext
+InvokedAsync()
+Serialize() JsonElement
#ProvideAIContextAsync() AIContext
}
class FileAgentSkillsProvider {
-Dictionary~string, FileAgentSkill~ _skills
-FileAgentSkillLoader _loader
-AITool[] _tools
-string _skillsInstructionPrompt
+FileAgentSkillsProvider(skillPath)
#ProvideAIContextAsync() AIContext
-LoadSkill(skillName) string
-ReadSkillResourceAsync(skillName, resourceName) string
}
class FileAgentSkillLoader {
-ILogger _logger
+DiscoverAndLoadSkills(paths) Dictionary
+ReadSkillResourceAsync(skill, resourceName) string
-ParseSkillFile(path) FileAgentSkill
-TryParseSkillDocument() bool
-ExtractResourcePaths(content) List
-ValidateResources() bool
}
class FileAgentSkill {
+SkillFrontmatter Frontmatter
+string Body
+string SourcePath
+IReadOnlyList~string~ ResourceNames
}
class SkillFrontmatter {
+string Name
+string Description
}
AIContextProvider <|-- FileAgentSkillsProvider
FileAgentSkillsProvider --> FileAgentSkillLoader : uses
FileAgentSkillLoader --> FileAgentSkill : creates
FileAgentSkill --> SkillFrontmatter : contains
- FileAgentSkillsProvider — 技能提供者,FileAgentSkillsProvider 是 AIContextProvider 的子类,实现了完整的渐进式披露机制。
构造函数中的初始化流程:
public FileAgentSkillsProvider(string skillPath, ...)
{
// 1. 创建 Loader,扫描目录发现所有 Skill
this._loader = new FileAgentSkillLoader(this._logger);
this._skills = this._loader.DiscoverAndLoadSkills(skillPaths);
// 2. 构建技能摘要提示词
this._skillsInstructionPrompt = BuildSkillsInstructionPrompt(options, this._skills);
// 3. 注册两个 AI 工具
this._tools =
[
AIFunctionFactory.Create(this.LoadSkill,
name: "load_skill",
description: "Loads the full instructions for a specific skill."),
AIFunctionFactory.Create(this.ReadSkillResourceAsync,
name: "read_skill_resource",
description: "Reads a file associated with a skill, such as references or assets."),
];
}
内置的系统提示词模板:
You have access to skills containing domain-specific knowledge and capabilities.
Each skill provides specialized instructions, reference documents, and assets.
<available_skills>
<skill>
<name>expense-report</name>
<description>File and validate employee expense reports...</description>
</skill>
</available_skills>
When a task aligns with a skill's domain:
1. Use `load_skill` to retrieve the skill's instructions
2. Follow the provided guidance
3. Use `read_skill_resource` to read any references or other files mentioned
Only load what is needed, when it is needed.
注意:FileAgentSkillsProvider 重写的是 ProvideAIContextAsync 方法(而非 InvokingAsync),返回的 AIContext 同时包含 Instructions(系统提示)和 Tools(两个工具函数)。
- FileAgentSkillLoader — 技能发现与加载,FileAgentSkillLoader 负责从文件系统中发现和解析 SKILL.md 文件。
发现流程:
flowchart TD
A["🔍 输入 skillPath"] --> B{"目录存在?"}
B -->|是| C["递归搜索<br/>最大深度=2"]
B -->|否| X["跳过"]
C --> D{"找到 SKILL.md?"}
D -->|是| E["解析 YAML Frontmatter"]
D -->|否| F["继续搜索子目录"]
E --> G{"Frontmatter 有效?"}
G -->|是| H["提取资源链接"]
G -->|否| Y["排除 + 记录警告"]
H --> I{"资源文件存在?<br/>无路径穿越?<br/>无符号链接?"}
I -->|是| J["✅ 加载成功"]
I -->|否| Z["排除 + 记录警告"]
style A fill:#2196F3,stroke:#1565C0,color:#fff
style J fill:#4CAF50,stroke:#2E7D32,color:#fff
style X fill:#F44336,stroke:#C62828,color:#fff
style Y fill:#F44336,stroke:#C62828,color:#fff
style Z fill:#F44336,stroke:#C62828,color:#fff
关键代码片段 — YAML 解析:
// 正则匹配 YAML frontmatter(--- 分隔符之间的内容)
private static readonly Regex s_frontmatterRegex =
new(@"\A\uFEFF?^---\s*$(.+?)^---\s*$",
RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
// 正则匹配 Markdown 中的本地资源链接
private static readonly Regex s_resourceLinkRegex =
new(@"\[.*?\]\((\.?\.?/?[\w][\w\-./]*\.\w+)\)", RegexOptions.Compiled);
// 技能名称验证:仅允许小写字母、数字和连字符
private static readonly Regex s_validNameRegex =
new(@"^[a-z0-9]([a-z0-9\-]*[a-z0-9])?$", RegexOptions.Compiled);
- 工具调用链路分析,当 Agent 调用 load_skill 或 read_skill_resource 时:
// load_skill:根据名称返回 SKILL.md 的 Body 部分
private string LoadSkill(string skillName)
{
if (!this._skills.TryGetValue(skillName, out FileAgentSkill? skill))
return $"Error: Skill '{skillName}' not found.";
return skill.Body; // 返回 Markdown 指令内容
}
// read_skill_resource:从磁盘读取资源文件内容
private async Task<string> ReadSkillResourceAsync(
string skillName, string resourceName, CancellationToken cancellationToken)
{
if (!this._skills.TryGetValue(skillName, out FileAgentSkill? skill))
return $"Error: Skill '{skillName}' not found.";
// 委托给 Loader,包含路径安全检查
return await this._loader.ReadSkillResourceAsync(skill, resourceName, cancellationToken);
}
2. 实战 — 费用报销 Agent
场景说明,我们将创建一个具费用报销领域知识的 AI Agent,它能够:
- 回答费用报销政策问题(小费能否报销?住宿限额多少?)
- 根据模板生成报销报告
- 按需加载 FAQ 和模板等参考资料
- 步骤 1:环境准备,导入必要的依赖包和 Helper 类。
// 导入 AI Client Helper
#!import ../helper/AIClientHelper.cs
// 导入 MAF 核心包
#!import ../helper/MafHelper.cs
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
Console.WriteLine("依赖包加载完成");
Console.WriteLine("核心命名空间:");
new {
Microsoft_Agents_AI = "Agent 核心功能 + Skills 支持",
Microsoft_Extensions_AI = "AI 抽象层(IChatClient、AIFunctionFactory)"
}.Display();
- 步骤 2:准备 Skill 文件,我们将在 Notebook 运行目录下动态创建 expense-report 技能文件。这包含三个部分:
- SKILL.md — 技能定义(Frontmatter + 指令)
- references/POLICY_FAQ.md — 费用政策 FAQ
- assets/expense-report-template.md — 报销模板
using System.IO;
// 在 Notebook 运行目录下创建 skills 文件结构
var skillsRootPath = Path.Combine(Directory.GetCurrentDirectory(), "skills");
var expenseSkillPath = Path.Combine(skillsRootPath, "expense-report");
var referencesPath = Path.Combine(expenseSkillPath, "references");
var assetsPath = Path.Combine(expenseSkillPath, "assets");
// 确保目录存在
Directory.CreateDirectory(referencesPath);
Directory.CreateDirectory(assetsPath);
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 1. 创建 SKILL.md — 技能定义文件
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var skillMd = """
---
name: expense-report
description: 按照 Contoso 公司政策填写和审核员工费用报销。适用于费用报销、报销规则、收据要求、支出限额或费用类别等相关问题。
---
# 费用报销(Expense Report)
## 费用类别与限额
| 类别 | 限额 | 收据要求 | 审批 |
|---|---|---|---|
| 单人用餐 | $50/天 | >$25 | 无需 |
| 团队/客户用餐 | $75/人 | 必须 | 总额>$200需经理 |
| 住宿 | $250/晚 | 必须 | 超过3晚需经理 |
| 地面交通 | $100/天 | >$15 | 无需 |
| 机票 | 经济舱 | 必须 | >$1,500需VP |
| 会议/培训 | $2,000/次 | 必须 | 经理+L&D |
| 办公用品 | $100 | 是 | 无需 |
| 软件/订阅 | $50/月 | 是 | >$200/年需经理 |
## 报销流程
1. 收集收据——需包含商家、日期、金额、支付方式。
2. 按上表分类。
3. 使用模板:[assets/expense-report-template.md](assets/expense-report-template.md)。
4. 团队/客户用餐需列出参与人及业务目的。
5. 提交——<$500自动审批;$500–$2,000需经理;>$2,000需VP。
6. 报销:10个工作日内通过银行转账。
## 政策规则
- 需在交易后30天内提交。
- 酒精类费用不予报销。
- 外币:按交易日汇率折算为美元,并注明原币种及金额。
- 混合个人/商务出行:仅报销商务部分,需提供对比报价。
- 丢失收据(>$25):需提交财务部的丢失收据声明,每季度最多2次。
- 如有未涵盖的问题,请查阅FAQ:[references/POLICY_FAQ.md](references/POLICY_FAQ.md)。答案应以本文件和FAQ为准。
""";
File.WriteAllText(Path.Combine(expenseSkillPath, "SKILL.md"), skillMd);
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 2. 创建 references/POLICY_FAQ.md — 费用政策 FAQ
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var faqMd = """
# 费用政策常见问答(FAQ)
## 用餐
**问:工作日咖啡或零食可以报销吗?**
答:每日咖啡/零食低于$10不予报销(视为个人消费)。客户会议或团队协作期间购买的咖啡可作为团队用餐报销。
**问:团队晚餐超出人均限额怎么办?**
答:$75/人限额为指导标准。超出20%以内可书面说明(如“客户指定场地”),超出20%需VP预先批准。
**问:需要列出所有参与人吗?**
答:是。客户用餐需列明客户姓名及公司,团队用餐需列出所有员工姓名。10人以上可单独附名单。
## 差旅
**问:可以预订高端经济舱或商务舱吗?**
答:经济舱为标准。6小时以上可选高端经济舱,商务舱需VP预批,通常仅限10小时以上或医疗原因。
**问:打车(Uber/Lyft)和租车如何选择?**
答:往返30英里以内建议打车,多日或超$100/天建议租车。3人以上可选更大车型。
**问:小费可以报销吗?**
答:用餐、打车、酒店清洁小费20%以内可报销,超出需说明理由。
## 住宿
**问:部分城市$250/晚不够怎么办?**
答:纽约、旧金山、伦敦、东京、悉尼等高消费城市自动提升至$350/晚,无需额外审批。其他特殊情况请提前向经理申请。
**问:住亲友家能否领取补贴?**
答:不可以。公司仅报销实际住宿费用,不提供补贴。
## 订阅与软件
**问:个人效率工具可以报销吗?**
答:需与工作直接相关,如IDE、设计软件、项目管理工具可报销。一般效率类应用需经理书面确认。
## 收据与材料
**问:收据模糊/损坏怎么办?**
答:可向商家补打,如无法获取,需提交丢失收据声明(财务部网站下载),每季度限2次。
**问:停车/过路费需要收据吗?**
答:低于$15无需收据,注明日期、地点、金额即可;$15及以上需收据或银行流水。
## 审批与报销
**问:经理休假谁来审批?**
答:可由上级经理或系统指定的代理审批人审批。
**问:能否报销上季度的费用?**
答:标准为30天内,超期需书面说明并VP批准,超90天仅特殊情况经CFO批准。
""";
File.WriteAllText(Path.Combine(referencesPath, "POLICY_FAQ.md"), faqMd);
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 3. 创建 assets/expense-report-template.md — 报销模板
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var templateMd = """
# 费用报销模板(Expense Report Template)
| 日期 | 费用类别 | 商家 | 描述 | 金额(USD) | 原币种 | 原币金额 | 参与人 | 业务目的 | 已附收据 |
|------|----------|------|------|-------------|--------|----------|--------|----------|----------|
| | | | | | | | | | 是 / 否 |
""";
File.WriteAllText(Path.Combine(assetsPath, "expense-report-template.md"), templateMd);
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Console.WriteLine("Skill 文件创建完成!");
Console.WriteLine();
Console.WriteLine($"技能根目录: {skillsRootPath}");
Console.WriteLine();
// 显示文件结构
new {
文件结构 = new[] {
"skills/",
" └── expense-report/",
" ├── SKILL.md (技能定义:Frontmatter + 指令)",
" ├── references/",
" │ └── POLICY_FAQ.md (费用政策 FAQ)",
" └── assets/",
" └── expense-report-template.md (报销模板)"
}
}.Display();
- 步骤 3:加载 Skills 并创建 Agent,使用 FileAgentSkillsProvider 从文件系统发现和加载技能,然后将其注入到 Agent 中。核心流程:
- FileAgentSkillsProvider 扫描 skills/ 目录
- 发现 expense-report/SKILL.md,解析 Frontmatter 和 Body
- 验证所有资源文件(FAQ、模板)存在且路径安全
- 自动注册 load_skill 和 read_skill_resource 两个 AI 工具
- 将技能列表注入系统提示词
#pragma warning disable MAAI001
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 1. 创建 SkillsProvider — 从文件系统发现和加载 Skills
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var skillsProvider = new FileAgentSkillsProvider(
skillPath: Path.Combine(Directory.GetCurrentDirectory(), "skills")
);
Console.WriteLine("FileAgentSkillsProvider 创建成功");
Console.WriteLine("Skills 已从文件系统加载");
Console.WriteLine();
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 2. 创建 Agent — 注入 SkillsProvider
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var chatClient = AIClientHelper.GetDefaultChatClient();
AIAgent agent = chatClient.AsAIAgent(new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new()
{
Instructions = "You are a helpful assistant.",
},
// 关键:通过 AIContextProviders 注入 SkillsProvider
AIContextProviders = [skillsProvider],
});
Console.WriteLine("Agent 创建成功");
Console.WriteLine();
new {
Agent名称 = "SkillsAgent",
基础指令 = "You are a helpful assistant.",
上下文提供者 = "FileAgentSkillsProvider",
自动注册的工具 = new[] { "load_skill", "read_skill_resource" },
技能摘要开销 = "~100 tokens/skill(仅名称和描述)"
}.Display();
Console.WriteLine();
Console.WriteLine("注意:此时 Agent 的系统提示中已包含技能摘要,但完整指令尚未加载。");
Console.WriteLine(" 只有当 Agent 判断用户问题与技能相关时,才会调用 load_skill 按需加载。");
- 步骤 4:测试 — 费用政策问答,第一个测试:询问关于小费报销的问题。预期行为:
- Agent 看到系统提示中的技能摘要 → 识别问题属于 expense-report 领域
- 调用 load_skill("expense-report") → 获取完整的费用报销规则
- 发现规则中提到 FAQ → 调用 read_skill_resource("expense-report", "references/POLICY_FAQ.md")
- 根据 FAQ 中的小费政策回答用户问题
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine(" 测试 1:费用政策 FAQ 问答");
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine();
// 提出关于小费报销的问题
string question = "小费可以报销吗?我在一次出租车行程中给了 25% 的小费,想知道这是否可以报销。";
Console.WriteLine($"用户: {question}");
Console.WriteLine();
// Agent 会自动执行渐进式披露流程:
// 1. 识别属于 expense-report 领域
// 2. 调用 load_skill 获取完整规则
// 3. 调用 read_skill_resource 获取 FAQ
// 4. 根据 FAQ 内容回答
AgentResponse response = await agent.RunAsync(question);
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine($"Agent: {response.Text}");
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine();
Console.WriteLine("观察要点:");
new {
渐进式披露 = "Agent 自动判断需要加载 expense-report 技能",
工具调用链 = "load_skill → read_skill_resource",
FAQ匹配 = "FAQ 中明确说明:小费 20% 以内可报销,超过 20% 需要说明理由",
预期回答 = "25% 的小费超过了 20% 的标准,需要额外提供理由说明"
}.Display();
步骤 5:测试 — 多轮对话生成报销报告。
第二个测试:通过多轮对话生成费用报告。Agent 需要加载报销模板资产(assets/expense-report-template.md),并引导用户补充缺失信息。预期行为:
- Agent 加载 skill → 获取费用类别和限额规则
- Agent 读取报销模板 → 按照模板格式生成报告
- Agent 识别缺失信息 → 主动询问用户补充细节
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine(" 测试 2:多轮对话生成报销报告");
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine();
// 使用 AgentSession 支持多轮对话
AgentSession session = await agent.CreateSessionAsync();
// 第 1 轮:提供费用信息,要求生成报告草稿
string request = "我上周有 3 笔客户晚餐费用和一张 $1,200 的机票。请先返回一份报销报告草稿,并询问我缺失的细节信息。";
Console.WriteLine($"用户: {request}");
Console.WriteLine();
// Agent 会:
// 1. 加载 expense-report skill(如果尚未加载)
// 2. 读取报销模板 assets/expense-report-template.md
// 3. 根据用户提供的信息填写模板
// 4. 识别缺失字段并主动询问
AgentResponse response2 = await agent.RunAsync(request, session);
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine($"Agent: {response2.Text}");
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine();
Console.WriteLine("观察要点:");
new {
模板加载 = "Agent 通过 read_skill_resource 获取报销模板",
智能分类 = "Agent 根据 Skill 中的限额表对费用进行分类",
缺失信息 = "Agent 会询问缺失信息(如晚餐日期、具体金额、参与人等)",
审批提示 = "$1,200 机票需要 Manager 审批(< $1,500)"
}.Display();
- 步骤 6:多轮跟进 — 补充缺失信息,根据 Agent 上一轮指出的缺失信息,我们补充细节,观察 Agent 如何更新报销草稿。
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine(" 测试 2(续):补充缺失信息");
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine();
// 提供详细信息,让 Agent 完善报告
string details = """
以下是详细信息:
- 客户晚餐 1:周一在 Starlight Restaurant,$280,4 人(我、来自 Marketing 的 Alice、来自 Contoso Corp 的 Bob Chen、来自 Contoso Corp 的 Lisa Wang)。业务目的:Q4 合作复盘。
- 客户晚餐 2:周三在 Golden Dragon,$195,3 人(我、来自 ABC Inc 的 Tom Li、来自 ABC Inc 的 Sarah Kim)。业务目的:新项目启动会。
- 客户晚餐 3:周五在 Café Milano,$150,2 人(我、来自 XYZ Ltd 的 David Liu)。业务目的:合同续签讨论。
- 机票:Delta Airlines,经济舱,JFK 往返 SFO,通过公司差旅平台预订。
所有收据均已附上。
""";
Console.WriteLine($"用户: {details}");
Console.WriteLine();
// Agent 利用 session 中的对话历史,更新报告草稿
AgentResponse response3 = await agent.RunAsync(details, session);
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine($"Agent: {response3.Text}");
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine();
Console.WriteLine("观察要点:");
new {
模板填充 = "Agent 使用报销模板格式填充所有字段",
限额检查 = "Agent 根据 Skill 中的限额规则检查每笔费用",
Dinner1 = "$280/4人=$70/人 → 未超过 $75/人限额 ✅ 但总额 >$200 需 Manager 审批",
Flight = "$1,200 经济舱 → 需 Manager 审批(< $1,500,无需 VP)",
审批总额 = "总额可能超过 $2,000 → 需要 VP 审批"
}.Display();
3. 进阶用法
- 自定义技能摘要提示词,FileAgentSkillsProviderOptions 允许你自定义系统提示词模板。使用 {0} 作为技能列表的占位符:
var skillsProvider = new FileAgentSkillsProvider(
skillPath: "skills",
options: new FileAgentSkillsProviderOptions
{
SkillsInstructionPrompt = """
你是一名专业的企业咨询顾问。你具备以下专业技能:
{0}
当用户问题与某个技能相关时:
1. 使用 load_skill 加载该技能的详细指令
2. 严格按照指令中的规则回答
3. 需要时使用 read_skill_resource 读取参考资料
务必用中文回答所有问题。
"""
}
);
- 多技能注册,一个 Agent 可以同时注册多个 Skills:
// 方式 1:通过父目录自动发现(推荐)
// skills/ 下的每个子目录如果包含 SKILL.md,就会被注册为一个 Skill
var provider = new FileAgentSkillsProvider("skills");
// 自动发现:expense-report, travel-policy, it-support ...
// 方式 2:指定多个路径
var provider = new FileAgentSkillsProvider([
"skills/finance", // 财务相关技能
"skills/hr", // 人力资源技能
"skills/it-support" // IT 支持技能
]);
性能提示:渐进式披露确保了即使注册 20+ 个 Skills,初始 Token 开销也仅为 ~2000 tokens(每个 ~100 tokens 的名称+描述摘要)。Agent 会智能判断并仅加载相关的 Skill。
Skills 文件夹结构最佳实践,命名规范:
✅ 使用 kebab-case:expense-report、travel-policy
✅ 名称简洁且具描述性
❌ 避免特殊字符:expense_report、ExpenseReport
❌ 避免过长名称(最大 64 字符)
skills/
├── expense-report/ # ✅ 好的:清晰的领域边界
│ ├── SKILL.md
│ ├── references/
│ └── assets/
├── travel-policy/ # ✅ 好的:独立的政策领域
│ ├── SKILL.md
│ └── references/
├── code-review/ # ✅ 好的:操作指南
│ ├── SKILL.md
│ └── assets/
└── general-hr/ # ⚠️ 避免:范围过大
├── SKILL.md # 应拆分为更细粒度的技能
└── ...
- 实战:创建第二个 Skill 并测试多技能 Agent
让我们创建一个 travel-policy 技能,然后测试 Agent 在同时拥有两个 Skills 时的智能路由能力。
#pragma warning disable MAAI001
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 创建第二个 Skill:travel-policy(差旅政策,已中文化)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var travelSkillPath = Path.Combine(skillsRootPath, "travel-policy");
Directory.CreateDirectory(travelSkillPath);
var travelSkillMd = """
---
name: travel-policy
description: 公司差旅预订与审批政策。适用于航班预订、酒店预订、差旅审批流程或差旅安全指引等相关问题。
---
# 差旅政策(Travel Policy)
## 预订规则
| 项目 | 政策 | 审批 |
|------|--------|----------|
| 国内航班 | 仅限经济舱 | <$800自动审批 |
| 国际航班 | 经济舱;6小时以上可选高端经济舱 | 均需经理审批 |
| 酒店 | 优先公司协议酒店 | ≤$250/晚自动审批 |
| 租车 | 紧凑/标准车型 | ≤3天自动审批 |
| 火车/高铁 | 标准座 | 自动审批 |
## 预订流程
1. 所有预订须通过公司差旅平台(TravelHub)完成
2. 国内提前14天,国际提前21天预订
3. 总费用超$2,000需经理预先审批
4. 预订后24小时内取消可全额退款
## 安全指引
- 所有国际行程需向差旅安全团队报备
- 超过5天的行程需购买差旅保险
- 随身携带公司应急联系方式卡
""";
File.WriteAllText(Path.Combine(travelSkillPath, "SKILL.md"), travelSkillMd);
Console.WriteLine("travel-policy Skill 创建完成");
Console.WriteLine();
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 重新创建包含两个 Skills 的 Provider 和 Agent
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var multiSkillProvider = new FileAgentSkillsProvider(
skillPath: Path.Combine(Directory.GetCurrentDirectory(), "skills")
);
AIAgent multiSkillAgent = chatClient.AsAIAgent(new ChatClientAgentOptions
{
Name = "MultiSkillAgent",
ChatOptions = new()
{
Instructions = "You are a helpful corporate assistant. Answer in the same language as the user.",
},
AIContextProviders = [multiSkillProvider],
});
Console.WriteLine("多技能 Agent 创建成功");
Console.WriteLine();
new {
Agent名称 = "MultiSkillAgent",
已注册技能 = new[] { "expense-report(费用报销)", "travel-policy(差旅政策)" },
系统提示摘要开销 = "~200 tokens(2 × ~100 tokens/skill)"
}.Display();
- 测试多技能智能路由,分别提问差旅政策和费用报销问题,观察 Agent 如何智能选择加载正确的 Skill。
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine(" 测试 3:多技能智能路由");
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine();
// 测试 A:差旅政策问题 → 应加载 travel-policy
string travelQuestion = "我需要预订一张从纽约到伦敦、为期两周项目的航班。我可以乘坐什么舱位?需要审批吗?";
Console.WriteLine("测试 A:差旅政策问题");
Console.WriteLine($"用户: {travelQuestion}");
Console.WriteLine();
AgentResponse travelResponse = await multiSkillAgent.RunAsync(travelQuestion);
Console.WriteLine($"Agent: {travelResponse.Text}");
Console.WriteLine();
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine();
// 测试 B:费用报销问题 → 应加载 expense-report
string expenseQuestion = "我上周买了一个 $45/月的项目管理软件订阅,需要什么审批流程?";
Console.WriteLine("测试 B:费用报销问题");
Console.WriteLine($"用户: {expenseQuestion}");
Console.WriteLine();
AgentResponse expenseResponse = await multiSkillAgent.RunAsync(expenseQuestion);
Console.WriteLine($"Agent: {expenseResponse.Text}");
Console.WriteLine();
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine();
Console.WriteLine("观察要点:");
new {
智能路由 = "Agent 根据问题内容自动选择加载正确的 Skill",
测试A = "差旅问题 → load_skill('travel-policy')",
测试B = "报销问题 → load_skill('expense-report')",
语言适配 = "Agent 会根据用户语言(中/英)自适应回复"
}.Display();
