深度解析【Perplexity】 公开内部手册:Agent Skills 是什么?如何设计、优化和维护?(附完整结构模板)
Perplexity Agent Skills 设计指南 Perplexity公开了构建Agent Skills的内部手册,揭示了从设计到优化的完整流程。核心要点包括: Skill与Tool的区别:Skill是包含指令集、文档和脚本的能力域组合,而Tool是单一功能调用。 物理结构:采用hub-spoke模式,SKILL.md作为核心文件,references目录存放按需加载的辅助文档。 关键字段
深度解析【Perplexity】 公开内部手册:Agent Skills 是什么?如何设计、优化和维护?(附完整结构模板)
作者:技术博主 | 更新时间:2026-05-11 | 阅读时长:约 20 分钟
来源:Perplexity Research《Designing, Refining, and Maintaining Agent Skills at Perplexity》
标签:AgentAgent SkillsMCPPerplexityLLM智能体工具调用Claude Code
🔥 一句话定位:Perplexity 把内部构建 Agent Skills 的玩法彻底公开了。如果你正在做 Agent,这份手册比大多数教程都实战得多——它不讲原理,直接讲:description 怎么写才能被正确路由,gotcha 列表怎么维护,progressive loading 怎么设计,以及怎么跑 eval。本篇带你逐条拆解。

目录
- 一、什么是 Agent Skill?和 MCP Tool 有什么区别
- 二、Skill 的物理结构:hub-spoke 模式
- 三、Frontmatter 是 Skill 的"大脑":四个关键字段
- 四、最高频踩坑:description 不是注释,是路由触发器
- 五、Progressive Loading:上下文窗口管理的核心机制
- 六、Gotcha 列表:从 80% 到 99.9% 成功率的关键
- 七、Eval 体系:Perplexity 怎么测试 Skill 质量
- 八、构建 Skill 的实战流程:从 0 到上线
- 九、最容易忽视的警告:行动的距离效应
- 十、完整 Skill 结构模板
一、什么是 Agent Skill?和 MCP Tool 有什么区别
在开始之前,需要先把概念说清楚,因为很多人把 Agent Skill 和 MCP Tool 混淆了。
MCP Tool(工具调用):
模型调用一个函数/API,得到结果
例:search(query) -> 返回搜索结果
粒度:细,单个功能
状态:无状态
Agent Skill:
模型加载一套"指令集 + 文档 + 脚本"的组合
告诉模型:在这类任务里,应该怎么思考、用什么工具、注意什么
粒度:粗,完整的能力域
状态:有层级、有依赖关系
两者的关系:
Skill 经常封装多个 MCP Tool 的调用逻辑
Skill 是"如何做事的说明书"
Tool 是"做事的手"
Perplexity 的定义很直接:Skill 是可被调用的(invocable)。Agent 在运行时动态加载 Skill,大多数情况下 Skill 并不常驻 context——它们根据具体需要被逐步展开(progressively disclosed)。
这一点极其重要,后文会反复强调。
二、Skill 的物理结构:hub-spoke 模式

一个 Skill 在文件系统上是一个目录,结构如下:
my-skill/ <- 目录名 = Skill 名(必须完全匹配)
├── SKILL.md <- 核心:hub 文件,模型激活后先读这个
├── scripts/
│ └── helper.py <- 可选:可执行脚本
└── references/
├── FORMATTING.md <- 辅助文档(spoke)
├── edge-cases.md <- 辅助文档(spoke)
└── finance.md <- 辅助文档(spoke)
hub-spoke 设计的本质:
SKILL.md(hub):
- 模型激活 Skill 后,优先完整读取
- 包含:核心指令、常见场景、gotcha 列表、辅助文件索引
- 不应该太长(过长会塞满 context)
references/*.md(spoke):
- 按需加载,只有任务需要时才读入
- 每个文件专注单一主题(格式规范 / 特殊案例 / 工具文档)
- 文件越小越好,减少不必要的 context 消耗
类比:
SKILL.md 是一本书的目录 + 摘要
references/* 是各章节正文
模型根据任务需要,只翻到它需要的那一章
目录命名规则:
Skill 名称必须与所在目录名完全对应,必须全部小写,不能有空格,可以使用连字符。
✅ 正确命名:
my-skill/
us-tax-advisor/
code-review-python/
❌ 错误命名:
My Skill/ # 有大写有空格
mySkill/ # 驼峰
my_skill/ # 下划线(部分实现不支持)
三、Frontmatter 是 Skill 的"大脑":四个关键字段
每个 SKILL.md 的开头都是 YAML frontmatter。这几行代码决定了整个 Skill 如何被系统发现和调用:
---
name: us-tax-advisor
description: >
Load when the user asks about U.S. income tax, IRS rules,
deductions, filing deadlines, or tax forms (1040, W-2, etc.).
Also load for questions about tax optimization strategies
or state tax calculations.
depends:
- base-financial-tools
metadata:
version: "2.1"
owner: "tax-team"
eval_suite: "tax-v2-suite"
---
# U.S. Tax Advisor Skill
## Core Instructions
...
四个字段逐一解析:
name:唯一标识符
必须与目录名完全一致,是 Skill 在系统内的"身份证"。
description:路由触发器(最重要!)
下一节单独深讲,这是最容易踩坑的地方。
depends:依赖关系
depends: 字段允许创建层级化的 Skill 依赖,系统会在加载当前 Skill 前先加载依赖项。
# 示例:高级税务 Skill 依赖基础金融工具 Skill
depends:
- base-financial-tools
- us-legal-terminology
这使得 Skill 可以形成树状依赖图:
- 专用 Skill 站在通用 Skill 的肩膀上
- 避免重复在每个 Skill 里定义相同的基础内容
- 修改基础 Skill 自动传播到所有依赖它的子 Skill
metadata:供 eval 和 review 使用
metadata: 字段用于 review 和 evaluation,不会注入模型的 context,也可以在辅助 JSON/YAML 文件中维护,适合需要在运行时控制不同行为而不污染模型 context 的情况。
四、最高频踩坑:description 不是注释,是路由触发器
Perplexity 的文档在这里用了非常强烈的措辞:
“这是一个常见的失败点(common failure point)”
description 不是关于 Skill 是什么的内部文档,而是告诉模型何时加载该 Skill 的指令。所以你会频繁看到 “Load when…”,而不是 “This Skill does…”。这很重要,因为大多数实现会将 description 直接注入模型的 context。
这个区别在实践中产生巨大差异:
# ❌ 错误写法:描述功能(内部文档视角)
description: >
This skill handles U.S. income tax calculations, including
federal and state tax rules, deductions, and IRS compliance.
# ✅ 正确写法:路由触发器(模型决策视角)
description: >
Load when the user asks about U.S. income tax, IRS rules,
tax forms (1040, W-2, Schedule C), deductions, filing deadlines,
or state tax calculations. Also load for tax optimization and
audit-related questions.
两种写法的本质区别:
错误写法:告诉模型"这个工具能做什么"
-> 模型可能在任何和税相关的话题时都尝试加载
-> 也可能在应该加载时因为措辞不匹配而漏掉
正确写法:告诉模型"在什么情况下激活我"
-> 精确的触发条件
-> 明确的关键词映射
-> 边界条件清晰(also load for / NOT for)
Description 的写作要点:
1. 以 "Load when" 开头(明确告知这是触发条件)
2. 枚举关键词和短语(覆盖用户可能使用的各种表达)
3. 包含边界条件(什么时候应该加载,什么时候不应该)
4. 控制长度(所有 Skill 的 description 会同时存在 context 中,
每个 description 大约 50-100 tokens 的预算)
示例模板:
---
description: >
Load when [主要触发场景].
Also load for [扩展场景].
NOT for [明确排除的场景,避免误触发].
---
五、Progressive Loading:上下文窗口管理的核心机制

这是 Agent Skill 设计哲学的核心。
会话开始时,Agent 扫描 skills 目录,只读取每个 SKILL.md 的 YAML frontmatter,正文不解析。只有当 Agent 判断某个 Skill 与当前任务相关,才读取完整的 SKILL.md 正文。
三个加载层级(Three Loading Tiers):
Tier 1:Frontmatter(会话启动时常驻 context)
所有 Skill 的 name + description
极小,约 50-100 tokens/Skill
模型用这些来决策"是否需要激活某个 Skill"
Tier 2:SKILL.md 正文(激活 Skill 后加载)
核心指令、核心场景、gotcha 列表
按需加载,只有决定使用该 Skill 时才读入
Tier 3:references/*.md(任务需要时按需加载)
条件性内容、专项文档
任务执行中根据具体情况决定是否读入
例:只有在生成财务报告时,才加载 FORMATTING.md
Progressive Loading 的实践意义:
没有 Progressive Loading:
加载 50 个 Skill,每个 SKILL.md 平均 2000 tokens
-> 光 Skill 文档就占用 100K tokens context
-> 这些 context 大多数时候是无效噪音
有 Progressive Loading:
Tier 1:50 个 Skill 的 description,约 5K tokens
Tier 2:激活 1-3 个 Skill,约 3-6K tokens
Tier 3:按需加载辅助文档,约 1-3K tokens
总计:~10K tokens 活跃 context,且全部相关
对 SKILL.md 写作的直接影响:
如果 SKILL.md 里有任何部分是条件性的或内容极重,应该将其移出 SKILL.md(hub),放入辅助文件(spoke)。将条件性或分支逻辑放入辅助文件,以便按需加载。
# SKILL.md 里应该放什么:
✅ 核心指令(所有场景都需要的)
✅ 关键概念定义
✅ 最常见的 2-3 个用例
✅ Gotcha 列表(反例集合)
✅ 辅助文件索引(告诉模型有哪些文件,何时读)
# 不应该放在 SKILL.md 里:
❌ 完整的法规原文(-> references/regulations.md)
❌ 大量代码示例(-> references/examples.md)
❌ 条件分支逻辑(-> references/special-cases.md)
❌ 不常用的边缘情况处理
六、Gotcha 列表:从 80% 到 99.9% 成功率的关键

这是 Perplexity 手册里最有工程价值的一节。
Gotcha 是极高信号含量的内容,因为它们往往引导模型了解"什么事不该做"。你可以在 Agent 每次失败时追加一条,Gotcha 列表会有机生长。
Gotcha 的本质是:负例知识库。
指令(正例):
"回答税务问题时,总是引用最新的 IRS 规则"
Gotcha(负例):
"不要混淆联邦税率和州税率
错误案例:用户问加州收入税,
Agent 错误地使用了联邦税率表"
"在 2024 年之前,个人 IRA 供款上限是 6500 美元
不要使用 2023 年之前的旧数字(6000 美元)"
Gotcha 的增长策略:
从 80-20 到 99.9% 甚至 99.99% 的成功率,很容易不断增长 gotcha 列表。每次看到负例,就追加到 gotcha 部分。不要增加更长的指令或修改 description,追加 gotcha 即可。
Skill 生命周期:
第一周(80% 成功率):
SKILL.md 核心指令 + 3-5 条 gotcha
第一个月(90% 成功率):
+ 10-20 条 gotcha(来自真实失败案例)
三个月后(99%+ 成功率):
+ 50-100 条 gotcha(覆盖大量边缘情况)
通常不需要重写核心指令
只是不断增加负例
关键认知:不要用 Gotcha 替代正向指令
❌ 错误做法:
核心指令写得很简单
把所有情况都用 gotcha 来约束
✅ 正确做法:
核心指令覆盖 80% 的常规场景
Gotcha 覆盖异常情况、历史 Bug、特殊限制
比例参考:
核心指令:500-1000 tokens
Gotcha 列表:200-500 tokens
辅助文件:按需,任意大小
七、Eval 体系:Perplexity 怎么测试 Skill 质量
Perplexity 运行多种 eval 套件来检验不同方面的质量。Skill 加载评测(Skill loading evals)检查 Skill 加载本身的精准率、召回率和禁止项——Agent 会在应该路由时加载 Skill 吗?这些 eval 还确保新 Skill 不会破坏已有 Skill 的边界。另外还有检查正确渐进加载的 eval——Agent 可能加载了 Skill,但它是否读取了辅助文件?以及端到端任务完成 eval。
把这套 eval 体系翻译成可复用的框架:
三层 Eval 体系:
Layer 1:Skill 路由 Eval
测试点:
Precision(精准率):触发了不应该触发的 Skill?
Recall(召回率):应该触发的 Skill 漏触发了?
Forbidden checks:是否加载了被明确排除的 Skill?
测试数据:
正例集:应该触发此 Skill 的查询
负例集:不应该触发此 Skill 的查询
边界案例:模糊地带的查询
示例 eval case:
Input: "如何计算 W-2 表格上的联邦税"
Expected: tax-advisor Skill 被加载
Forbidden: legal-advisor Skill 不应被加载
Layer 2:Progressive Loading Eval
测试点:
Skill 激活后,是否正确读取了辅助文件?
Finance 查询是否触发了 FORMATTING.md 的加载?
条件分支是否被正确路由到对应的辅助文件?
Layer 3:端到端任务完成 Eval
测试点:
最终回答的正确率
输出格式是否符合要求
是否触发了 Gotcha 中记录的已知失败模式
实际测试代码示例:
from typing import Callable
class SkillEvalSuite:
"""简单的 Skill 路由评测框架"""
def __init__(self, agent_fn: Callable):
self.agent = agent_fn
self.results = []
def add_case(self, query: str, expected_skills: list,
forbidden_skills: list = None, label: str = ""):
self.results.append({
"query": query,
"expected": expected_skills,
"forbidden": forbidden_skills or [],
"label": label,
})
def run(self) -> dict:
tp = fp = fn = 0
failures = []
for case in self.results:
loaded_skills = self.agent.get_loaded_skills(case["query"])
# 召回率计算
for skill in case["expected"]:
if skill in loaded_skills:
tp += 1
else:
fn += 1
failures.append(f"MISS: {case['label']} -> {skill}")
# 精准率计算
for skill in case["forbidden"]:
if skill in loaded_skills:
fp += 1
failures.append(f"FALSE POSITIVE: {case['label']} -> {skill}")
precision = tp / (tp + fp) if (tp + fp) > 0 else 1.0
recall = tp / (tp + fn) if (tp + fn) > 0 else 1.0
return {
"precision": precision,
"recall": recall,
"f1": 2 * precision * recall / (precision + recall + 1e-9),
"failures": failures,
}
# 使用示例
suite = SkillEvalSuite(agent)
suite.add_case(
query="我需要申报 2024 年的联邦所得税",
expected_skills=["us-tax-advisor"],
forbidden_skills=["legal-advisor", "investment-advisor"],
label="basic-tax-query",
)
suite.add_case(
query="推荐一下理财产品",
expected_skills=["investment-advisor"],
forbidden_skills=["us-tax-advisor"],
label="investment-query",
)
results = suite.run()
print(f"Precision: {results['precision']:.2%}")
print(f"Recall: {results['recall']:.2%}")
print(f"F1: {results['f1']:.2%}")
for f in results["failures"]:
print(f" {f}")
八、构建 Skill 的实战流程:从 0 到上线
结合 Perplexity 手册和工程经验,整理出一套可复用的流程:
Step 1:明确边界(最重要的一步)
在写任何文件之前,先回答这三个问题:
1. 这个 Skill 解决什么具体问题?
(不是"税务问题",而是"用户询问 U.S. 联邦所得税计算")
2. 这个 Skill 的边界在哪里?
(它不负责什么?哪些话题应该由其他 Skill 处理?)
3. 触发条件是什么?
(用户会用哪些词语或短语触发这个 Skill?)
只有这三个问题都清晰了,才开始写文件。
Step 2:写 SKILL.md(从薄到厚)
---
name: skill-name
description: >
Load when [具体触发条件].
Also load for [扩展场景].
depends: []
---
# Skill Name
## Overview
一句话概述这个 Skill 的职责。
## Core Instructions
- [指令1]
- [指令2]
- [指令3]
## Common Scenarios
### Scenario 1: [最常见场景]
[具体处理方式]
### Scenario 2: [次常见场景]
[具体处理方式]
## Gotchas
<!-- 从这里开始,随着失败案例增长 -->
- [已知失败模式1]
- [已知失败模式2]
## Reference Files
- `references/FORMATTING.md`: Load when generating formatted reports
- `references/edge-cases.md`: Load for unusual or borderline scenarios
Step 3:跑初始 Eval(建立基线)
# 在有任何真实用户数据之前,手动构建初始测试集
# 至少覆盖:
# 10个 正例(应触发)
# 10个 负例(不应触发)
# 5个 边界案例
baseline = suite.run()
print(f"初始基线 F1: {baseline['f1']:.2%}")
# 目标:初始就达到 F1 > 80%
Step 4:上线监控 + 追加 Gotcha
生产环境中的维护循环:
发现失败 -> 记录具体案例
-> 追加到 SKILL.md 的 Gotcha 部分
-> 重跑 eval,确认修复
-> 检查是否影响其他 Skill(行动的距离效应)
Step 5:定期审计(防止 Skill 退化)
每季度检查:
□ Precision/Recall 是否有下降趋势?
□ 新增的 Skill 是否破坏了已有 Skill 的边界?
□ Gotcha 列表是否过长?(过长说明核心指令需要重构)
□ 辅助文件是否过大?(过大需要进一步拆分)
九、最容易忽视的警告:行动的距离效应
Perplexity 手册特别提到一个非直觉的警告:
很容易因为添加新 Skill 而破坏已有的 Skill,即便你没有改动它(注意行动的距离效应)。
这是因为所有 Skill 的 description 共享同一个 context,它们之间存在竞争关系:
示例:添加新 Skill 破坏旧 Skill
已有 Skill:
us-tax-advisor:
description: "Load when user asks about tax..."
新增 Skill:
financial-planning:
description: "Load when user asks about finances,
tax strategies, investments..."
↑ 这里包含了 "tax" 相关词汇!
后果:
用户问 "如何优化我的税务负担?"
本来应该路由到 us-tax-advisor
现在 financial-planning 也可能被触发
两个 Skill 同时加载,产生冲突或浪费 context
解决方案:
新 Skill 的 description 要明确排除与已有 Skill 重叠的触发词
添加新 Skill 后,对所有相关旧 Skill 重跑 eval
实践原则:
每次新增或修改任何 Skill 后:
1. 先跑新 Skill 的 eval(确认它按预期工作)
2. 再跑所有相关 Skill 的 eval(确认没有破坏已有边界)
3. 特别关注 description 有词汇重叠的 Skill 组
十、完整 Skill 结构模板
这是根据 Perplexity 手册整理的可直接复用的模板:
目录结构
your-skill/
├── SKILL.md <- 必须,hub 文件
├── scripts/
│ └── helper.py <- 可选,可执行脚本
└── references/
├── FORMATTING.md <- 格式规范(按需加载)
├── edge-cases.md <- 边界案例(按需加载)
└── domain-guide.md <- 领域知识(按需加载)
SKILL.md 完整模板
---
name: your-skill-name
description: >
Load when [主要触发场景:用 "Load when" 开头,枚举关键词].
Also load for [扩展场景].
NOT for [明确排除,避免与其他 Skill 冲突].
depends:
- base-skill-name # 可选,有依赖时填写
metadata:
version: "1.0"
owner: "your-team"
eval_suite: "your-skill-eval-v1"
---
# Your Skill Name
## Overview
[一句话职责说明,不超过两行]
## Core Instructions
[核心操作指令,覆盖 80% 常规场景]
1. [指令1]
2. [指令2]
3. [指令3]
## Common Scenarios
### [场景1:最常见]
**触发词**:[用户可能使用的词语]
**处理方式**:[具体步骤]
### [场景2:次常见]
**触发词**:[用户可能使用的词语]
**处理方式**:[具体步骤]
## Gotchas
<!-- 每次发现失败案例时追加,不要修改核心指令 -->
- **[已知错误1]**:[描述模型容易犯的错误,提供正确做法]
- **[已知错误2]**:[描述模型容易犯的错误,提供正确做法]
## Reference Files
<!-- 告诉模型有哪些辅助文件,以及何时加载 -->
- `references/FORMATTING.md`:生成格式化报告时加载
- `references/edge-cases.md`:遇到边界案例时加载
- `references/domain-guide.md`:需要深入领域知识时加载
快速检查清单
发布前必须确认:
□ name 与目录名完全一致(全小写,连字符)
□ description 以 "Load when" 开头,而不是 "This Skill does"
□ description 包含用户常用的触发关键词
□ description 明确排除了与相邻 Skill 重叠的场景
□ SKILL.md 正文不超过 2000 tokens(超出部分移入 references/)
□ 条件性内容已移入 references/ 辅助文件
□ 至少有 5 条 Gotcha(来自真实测试)
□ 已构建初始 eval 集(10 正例 + 10 负例)
□ F1 > 80%(初始基线)
□ 已对所有相关 Skill 重跑 eval(确认没有副作用)
核心洞见:Agent Skill 开发的思维转变
Perplexity 这份手册最深刻的价值,是它揭示了一个思维方式的转变:
传统软件开发的思维:
我写代码,代码按规则执行
bug = 代码逻辑错误
修复 = 修改代码
Agent Skill 开发的思维:
我写指令,模型根据指令推理
bug = 模型的推理偏差
修复 = 给模型更好的信息(Gotcha + 边界条件)
关键认知:
不要试图用更长的指令覆盖所有情况
而是要构建"正例 + 反例"的完整知识体
让模型从真实的成功和失败案例中学习
就像培训一个新员工:
不是给他一本厚厚的规则手册
而是不断告诉他:"这种情况要这样做,上次那个错误不要再犯"
这也是为什么 Gotcha 列表比核心指令更有价值——它记录的是真实发生的失败,而不是设计者想象中可能发生的问题。
💬 你在构建 Agent 时用的是 MCP 工具调用还是 Skill 这种结构化指令集? 欢迎评论区分享经验!
原文地址:https://research.perplexity.ai/articles/designing-refining-and-maintaining-agent-skills-at-perplexity
🙏 如果这篇帮到你,一键三连(点赞 + 收藏 + 关注)!
参考资料
- Perplexity Research《Designing, Refining, and Maintaining Agent Skills at Perplexity》:https://research.perplexity.ai/articles/designing-refining-and-maintaining-agent-skills-at-perplexity
- Agent Skills 规范文档:https://agentskills.io/specification
- Microsoft Agent Skills Progressive Disclosure Pattern:https://deepwiki.com/microsoft/agent-skills/5.3-progressive-disclosure-pattern
- DEV Community《Building Agent Skills from Scratch》:https://dev.to/onlyoneaman/building-agent-skills-from-scratch-lbl
本文为原创技术解析,基于 Perplexity 官方文章。最后更新:2026-05-11
更多推荐




所有评论(0)