Skill:Agent 的能力扩展系统
一、Skill 的定义
Skill(技能) 是一种模块化的、自包含的能力扩展包,它为 AI Agent 注入特定领域的专业知识、工作流程和工具资源------它让一个通用型 Agent 转变为具备特定专业能力的领域专家。
Skill 能做什么
| 维度 | 说明 | 示例 |
|---|---|---|
| 专业工作流 | 多步骤的领域特定操作流程 | 创建 PowerPoint 的标准步骤、PDF 表单填写流程 |
| 工具集成 | 与特定文件格式或 API 的交互规范 | DOCX 的 OpenXML 操作、PDF 的文本提取方法 |
| 领域知识 | Agent 本身不具备的专有知识 | 公司内部业务规则、数据库 Schema、API 规范 |
| 复用资源 | 避免重复编写相同代码或重复查找文档 | PDF 旋转脚本、React 项目模板、品牌 Logo |
二、Skill 的组成结构
每个 Skill 是一个独立目录,包含一个必需的元数据文件和三类可选资源:
bash
skill-name/
├── SKILL.md # 必需:元数据 + 使用指令
├── scripts/ # 可选:可执行脚本
├── references/ # 可选:参考文档
└── assets/ # 可选:模板与素材资源
各组件说明
| 组件 | 必需 | 内容 | 加载时机 |
|---|---|---|---|
SKILL.md |
✅ | YAML 元数据(name、description)+ Markdown 指令 |
Skill 激活后加载 |
scripts/ |
❌ | Python、Bash 等可执行脚本 | Agent 按需执行 |
references/ |
❌ | API 文档、数据模式、策略规范等 | Agent 按需读取 |
assets/ |
❌ | 模板、图片、字体、代码脚手架等 | 直接用于产出物 |
三、Skill 的工作原理:渐进式披露
Skill 采用 Progressive Disclosure(渐进式披露) 设计,通过三层加载机制高效管理上下文窗口:
objectivec
┌──────────────────────────────────────────────────────────────┐
│ Level 1:Metadata(元数据) │
│ 内容:name + description(约 50-100 词) │
│ 加载:Agent 初始化时注入,始终常驻上下文 │
│ 作用:告知 Agent"有哪些 Skill、各自能做什么" │
└──────────────────────────────┬───────────────────────────────┘
│ 用户请求到达,进行匹配判断
▼
┌──────────────────────────────────────────────────────────────┐
│ Level 2:Body(主体指令) │
│ 内容:SKILL.md 的 Markdown 部分(工作流程、使用指南) │
│ 加载:Skill 被判定"激活"后,才加载到上下文 │
│ 作用:指导 Agent 如何执行具体任务 │
└──────────────────────────────┬───────────────────────────────┘
│ Agent 执行过程中按需使用
▼
┌──────────────────────────────────────────────────────────────┐
│ Level 3:Bundled Resources(捆绑资源) │
│ 内容:scripts / references / assets │
│ 加载:Agent 根据任务需要,选择性读取或执行 │
│ 作用:提供具体的工具、知识和素材(无大小限制) │
└──────────────────────────────────────────────────────────────┘
核心设计要点:
- 未激活 Skill 的 L2/L3 永远不会进入上下文窗口
description是唯一的匹配依据,其质量直接决定激活准确率- L3 的脚本可在不加载到上下文的情况下直接执行,效率极高
四、Skill 的激活机制:语义匹配
当用户请求到达时,Agent 需要将请求意图与各个 Skill 的 description 进行匹配,决定是否激活。这是 Skill 系统的核心路由环节。
4.1 匹配的维度
Agent 从三个维度判断 Skill 是否应该激活:
| 维度 | 判断依据 | 示例 |
|---|---|---|
| 功能域匹配 | 用户请求是否涉及 description 描述的功能范围 | 用户说"做 PPT"匹配 pptx skill |
| 任务类型匹配 | 是否是 description 中明确列出的任务类型 | "添加批注"匹配 docx skill 的"添加 comments" |
| 上下文匹配 | 当前对话上下文是否需要该 Skill 的专业能力 | 上传了 .xlsx 文件后,用户说"分析数据"匹配 xlsx skill |
4.2 语义匹配的实现方案
方案一:基于 LLM 的意图路由
将 Skill 列表和用户请求输入 LLM,由模型判断激活哪些 Skill。
markdown
【系统提示词】
你是 Skill Router。可用技能如下:
1. pptx: 处理 PowerPoint 演示文稿(.pptx),包括创建、编辑、
重新设计、格式化、美化,以及将其他格式转换为 PPT
2. xlsx: 处理 Excel 电子表格,包括数据分析、公式计算、
图表生成、格式设置
3. pdf: 处理 PDF 文档,包括创建、编辑、文本提取、表单填写
用户请求: {user_input}
请判断应激活哪些技能,返回 JSON:
{
"activated_skills": ["skill-name"],
"confidence": 0.95,
"reason": "用户明确要求创建PPT演示文稿"
}
| 优点 | 缺点 |
|---|---|
| 理解能力强,能处理复杂、模糊、间接的表达 | 增加一次 LLM 调用,有延迟 |
| 可天然支持多 Skill 激活判断 | 成本较高 |
| 能通过 few-shot 提升准确率 | 需要精心设计 prompt |
方案二:Embedding 相似度匹配
预计算 Skill description 的向量,通过余弦相似度快速匹配。
python
def route_by_embedding(user_query, skills, threshold=0.75):
"""基于 Embedding 的 Skill 路由"""
import numpy as np
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('all-MiniLM-L6-v2')
# 预计算 Skill description 向量(可缓存)
skill_embeddings = {
skill.name: model.encode(skill.description)
for skill in skills
}
# 用户请求向量化
query_vec = model.encode(user_query)
# 计算相似度,召回 Top-K
results = []
for name, emb in skill_embeddings.items():
sim = cosine_similarity(query_vec, emb)
if sim > threshold:
results.append((name, sim))
return sorted(results, key=lambda x: x[1], reverse=True)
| 优点 | 缺点 |
|---|---|
| 计算极快(毫秒级),无 LLM 调用开销 | 对否定句、条件句理解有限 |
| 成本低,适合高频场景 | 难以处理需要推理的复杂匹配 |
| 可预计算缓存 | 需要维护向量数据库 |
方案三:混合路由策略(推荐)
结合规则、Embedding 和 LLM 三层,兼顾速度与精度。
python
def hybrid_route(user_query, file_ext=None, skills=None):
"""
三层混合路由策略
Layer 1: 规则匹配(最快)
Layer 2: Embedding 相似度(快速召回)
Layer 3: LLM 判断(兜底)
"""
activated = []
# ========== Layer 1: 规则匹配 ==========
if file_ext == ".pptx":
return ["pptx"] # 文件类型明确,直接路由
if file_ext == ".xlsx":
return ["xlsx"]
# 关键词硬规则
if any(kw in user_query for kw in ["幻灯片", "演示文稿", "PPT"]):
return ["pptx"]
# ========== Layer 2: Embedding 召回 ==========
candidates = route_by_embedding(user_query, skills, threshold=0.70)
if candidates and candidates[0][1] > 0.85:
return [name for name, _ in candidates[:2]]
# ========== Layer 3: LLM 兜底 ==========
return llm_route(user_query, skills)
三层架构图:
yaml
用户请求 + 文件扩展名
│
▼
┌──────────────────┐
│ Layer 1: 规则匹配 │ ◄── 文件后缀、明确关键词、硬规则
│ 延迟:< 1ms │
└────┬───────────┬─┘
│匹配成功 │未匹配
▼ ▼
直接返回 ┌──────────────────┐
│ Layer 2: Embedding│ ◄── 向量相似度计算,Top-K 召回
│ 延迟:1-10ms │
└────┬──────────┬──┘
│高置信度 │低置信度
▼ ▼
返回结果 ┌──────────────────┐
│ Layer 3: LLM 判断 │ ◄── 复杂语义理解
│ 延迟:100-500ms │
└────────┬─────────┘
▼
返回结果
4.3 多 Skill 协作
复杂任务可能需要多个 Skill 按序协作:
json
{
"primary_skill": "pptx",
"supporting_skills": ["xlsx", "pdf"],
"execution_order": ["xlsx", "pdf", "pptx"],
"reason": "需先从 Excel 提取数据,再参考 PDF 报告,最终生成 PPT 汇报"
}
典型协作场景:
| 用户请求 | 激活 Skill | 协作顺序 |
|---|---|---|
| "把 Excel 数据做成 PPT" | xlsx → pptx |
先读取数据,再生成幻灯片 |
| "分析 PDF 里的表格并导出 Excel" | pdf → xlsx |
先提取内容,再结构化输出 |
| "基于数据库生成 Word 报告" | backend-building → docx |
先查询数据,再生成文档 |
关键设计哲学:
- 上下文是稀缺资源:未激活的 Skill 不占空间
- 描述是匹配的唯一入口:写好 description 至关重要
- 按需加载是无上限的:再长的参考资料、再复杂的脚本都不影响上下文
- 渐进式披露保护性能:大多数请求在 L1/L2 就能解决,极少走到 L3