Skill 设计与开发指南:Agent 的可复用能力单元
什么是 Skill
Skill 是 Agent 系统中的可复用业务能力单元。它不是简单的工具函数,而是封装了完整业务逻辑、Prompt 模板、工具调用链、错误处理的独立模块。一个 Skill 通常包含:SKILL.md(指令描述)+ 脚本/工具链 + 状态管理。
Skill vs Tool vs Plugin
| 维度 | Tool(工具) | Skill(技能) | Plugin(插件) |
|---|---|---|---|
| 粒度 | 单一函数调用 | 多步骤业务流程 | 外部系统集成 |
| 示例 | get_weather() | 旅行规划、文档生成 | Slack集成、GitHub连接 |
| 状态 | 无状态 | 有状态(Skill内上下文) | 视实现而定 |
| 编排 | 由Agent直接调用 | 有自己的编排逻辑 | 由框架管理 |
| 复用性 | 跨项目 | 跨场景 | 跨系统 |
Skill 的核心组成
my-skill/
├── SKILL.md # Skill 描述:能力边界、触发条件、使用说明
├── skill.py # 核心逻辑:编排、工具调用、错误处理
├── prompts/ # Prompt 模板
│ ├── system.md
│ └── examples.md
├── tools/ # Skill 专属工具
│ └── api_client.py
└── config.yaml # 配置:模型、超时、降级策略
SKILL.md 的写法
SKILL.md 是 Skill 的"说明书",Agent 通过它理解 Skill 的能力和触发条件:
# 旅行规划 Skill
## 触发条件
用户表达旅行意图时触发(关键词:旅行、旅游、出行、攻略)
## 能力边界
- ✅ 能做的:热门目的地推荐、行程规划、景点查询
- ❌ 不能做的:实际预订、支付、签证办理
## 输入要求
- 目的地(必填)
- 天数(可选,默认3天)
- 偏好(可选:美食/文化/自然)
## 输出格式
按天分段的结构化行程 + 景点简介 + 交通建议
## 降级策略
高德API不可用时 → 使用预置热门目的地数据
Skill 的设计原则
- 单一职责:一个 Skill 只做一件事,做透彻。不要做"万能 Skill"
- 显式边界:明确声明能力范围和不能做的事,避免 Agent 滥用
- 自描述:通过 SKILL.md 让 Agent 自动理解用法,无需硬编码路由
- 可降级:外部依赖失败时有备选方案,不阻断整体流程
- 可观测:记录每次调用的输入、输出、耗时、错误
- 可测试:每个 Skill 可以独立测试,不依赖完整的 Agent 系统
Skill 的注册与路由
Agent 发现和调用 Skill 有两种主流方式:
方式一:SKILL.md 注入 Prompt
将所有已注册 Skill 的 SKILL.md 内容注入 System Prompt,Agent 通过 Function Calling 决定调用哪个 Skill。适合 Skill 数量少(<10)的场景。
# System Prompt 片段
## 可用技能
${skills.map(s => s.mdContent).join('\n---\n')}
当用户需求匹配某技能时,调用 activate_skill(skill_name, params)
方式二:Router + Orchestrator 路由
一个轻量 Router 根据用户意图匹配 Skill,Orchestrator 管理 Skill 的生命周期。适合 Skill 数量多(10+)的生产环境。
# 意图路由
intent = router.classify(user_message)
if intent == "travel":
skill = skills["travel-planner"]
elif intent == "document":
skill = skills["docx-writer"]
result = orchestrator.run(skill, user_message, context)
Skill 的状态管理
Skill 可能需要维护调用间的状态:
- 无状态 Skill:每次调用独立,如天气查询、翻译
- 会话级状态:在一次对话中保持上下文,如旅行规划的中间步骤
- 持久化状态:跨会话保持数据,如用户偏好、历史记录
class TravelSkill:
def __init__(self):
self.sessions = {} # session_id → 行程草稿
async def run(self, session_id, input):
if session_id not in self.sessions:
self.sessions[session_id] = {"draft": None}
# 使用和更新 session state
Skill 开发的常见问题
问题一:Skill 之间互相调用导致循环
解决方案:禁止 Skill 间直接调用,统一由 Orchestrator 编排;或者限制最大调用深度(≤3层)。
问题二:SKILL.md 过长导致 Token 浪费
解决方案:SKILL.md 只写摘要(≤500 tokens),完整文档放独立文件,Agent 需要时再动态加载。
问题三:Skill 返回结果不可控
解决方案:定义标准输出 Schema,Skill 的所有返回值必须符合 Schema,加入输出校验层。
问题四:多个 Skill 的 Prompt 冲突
解决方案:Skill 的 System Prompt 用分隔符隔离;设置优先级,高优先级 Skill 的 Prompt 不被覆盖。