Perplexity 首次公开了内部 Skill 设计指南

> 我之所以把这篇写得更长,是因为我没有闲暇时间把它缩短。
>
> —— 十七世纪法国思想家 布莱兹·帕斯卡(Blaise Pascal)

帕斯卡的这句名言,现在成了 Perplexity 开发者的核心准则。

Perplexity 认为,开发高质量 Agent Skill 所需的直觉和实践方法,与构建传统软件完全不同。在 Perplexity 内部,工程师们提交的 Skill 代码经常会被打回重写,因为许多在编写传统代码时非常有用的模式,在创建 Skill 时反而成了错误的范式。

例如,如果你参考 PEP20(也就是著名的「Python 之禅」),你会发现写好 Python 代码和写好 Skill 完全是两回事。在这 20 条智慧格言中,至少有一半在编写 Skill 时是完全错误甚至具有误导性的。

下面是其中的五条:

Perplexity 首次公开了内部 Skill 设计指南

为了帮助开发者,Perplexity 公开了他们内部使用的设计指南。这份指南是 Perplexity 全体工程师在开发和评审 Skill 时使用的核心文档。

## 什么是 Skill?

当你编写一个 Skill 时,不是在编写普通的软件,而是在为模型及其运行环境构建「语境」(Context)。

在 Perplexity 的体系中,一个 Skill 包含四个维度:

### Skill 是一个目录

Skill 不仅仅是一个单独的`SKILL.md`文件。在很多情况下,一个 Skill 包含多个文件。在以你的 Skill 命名的目录下,通常会有以下结构:

`skill-name/├── SKILL.md           # 前置元数据和指令├── scripts/           # Agent 运行的代码(而不是让它现场发明代码)├── references/        # 厚重的参考文档,根据条件加载├── assets/            # 模板、架构和数据└── config.json        # 用户首次运行时的设置`
这种「枢纽与辐辏」(hub-and-spoke)模式能让 Skill 保持非常聚焦且精炼。你可以非常创意地利用文件夹结构。有时,特别复杂的 Skill 能够从多层分级结构中受益,这有助于模型更好地定位。

假设一个 Skill 需要涵盖 300 个主题,你可以将其归纳为 20 个领域。即便对当今最先进的模型来说,直接从 300 个主题中选出正确的那一个也是一项尚未解决的挑战。相比之下,让模型先锁定 20 个领域中的一个,再从该领域下的 15 个主题中做选择,难度会大幅降低。

### Skill 是一种格式

Skill 本身就是一种格式。核心的根文件`SKILL.md`必须同时具备名称(name)和描述(description)。而且,这个 Skill 的名称必须与其所在的目录名称完全匹配。

**名称要求**:

* • 必须全部小写
* • 不能有空格
* • 可以使用连字符

**描述部分是「路由触发器」(routing trigger)**。这是一个容易出错的地方:描述并不是为了记录 Skill 做了什么的内部文档,它其实是写给模型的指令,告诉模型在什么时候加载这个 Skill。

所以,你经常会看到描述里写的是「Load when…」(当……时加载),而不是「This Skill does…」(这个 Skill 的功能是)。这一点非常关键,因为大多数系统实现都会将这段描述直接注入到模型的上下文中。

在前置元数据(frontmatter)中,还有两个重要字段:

* •`depends:`:允许你创建层级化的 Skill 依赖关系
* •`metadata:`:用于评审和评估

不同的智能体系统甚至可以定义属于自己的前置元数据字段。作为一种替代方案,Skill 特有的元数据也可以打包在辅助的 JSON 或 YAML 配置文件中。如果你正在构建的系统需要为每个 Skill 提供不同的运行时行为,又不想让那些琐碎的细节「污染」模型的上下文,这种做法就很合适。

最后,也可以通过在读取时剥离(stripping)前置元数据来达到类似效果。Perplexity Computer 就采用了这种方法,让配置信息可以保留在根文件`SKILL.md`中。这需要在解析逻辑上非常细致,你可能还会根据需要实现「条件剥离」,以便保留某些对模型上下文有用的字段。

### Skill 是可调用的

Skill 是可调用的。智能体会在运行时加载 Skill。需要注意的是,Skill 并不总是被捆绑在上下文中。在默认情况下,大多数智能体系统会根据具体的需要,渐进式地展开(unfold)这些 Skill。

在 Computer 的实现中,这个过程包含以下几个步骤:

1. 1. 系统调用`load_skill(name=”…”)`
2. 2. 系统将 Skill 目录复制到隔离的执行沙箱中
3. 3. 系统根据`depends:`标签,递归地自动加载所有依赖项
4. 4. 系统剥离前置元数据,因此智能体最终只能看到正文内容和附加文件

不同的智能体系统可以选择不同的方式来展示 Skill 内容。例如,有些系统可能完全不展示文件层级,让模型通过文件系统操作自行去发现。而另一些系统可能会向模型提供整个文件树的映射(可能会有截断或深度限制)。为了保持上下文的简洁,Computer 默认在调用上下文中省略了完整的文件层级,不过这一点可以针对单个 Skill 进行覆盖设置。

### Skill 是渐进式的

Skill 具有渐进性。在 Computer 中,上下文成本分为三个阶段产生:

Perplexity 首次公开了内部 Skill 设计指南

Computer 会为每一个可用的 Skill 构建一个包含名称和描述的索引。这个索引的预算极其紧张,每个 Skill 只有大约 100 tokens 左右(越短越好)。之所以要求如此严苛,是因为每一位用户在每一次会话中,都要为这个索引支付成本。它会在对话最开始时就被注入到系统提示词中。模型通过查看这些 Skill 名称和描述,来决定是否要调用`load_skill()`。

进入这个索引的门槛非常高。你的 Skill 必须非常有用,且描述必须极其稠密和精炼,因为所有人都在随时为它支付成本。

当智能体系统加载了某个 Skill 后,就会引入完整的`SKILL.md`正文。理想情况下,正文内容不要超过 5,000 tokens。即便在这一层,你也要确保每一句话都有意义。因为一旦加载了某个 Skill,后续的对话都要一直承担这份成本,直到触及上下文压缩的边界。很多对话会同时加载 3 到 5 个不同的 Skill,成本会成倍增加。包含大量废话的 Skill 几乎肯定会干扰其他 Skill 的表现,并削弱智能体的整体能力。简而言之,如果你的 Skill 被加载了却没能起作用,那就是在浪费上下文空间。

渐进式的最后一层是脚本或特例(例如子技能或特定的格式化要求)。这里是存放无限制的条件分支逻辑的地方。智能体只有在真正需要时才会使用它们,这意味着这里的准入门槛要低得多。

总的来说,在索引层,每一个 token 都至关重要。加载后的 Skill 正文层要求稍微宽松一些。而运行时层则是最宽松的,成本可以是从 0 到 20,000 tokens 不等。这就是你可以考虑以渐进方式扩展模型上下文的地方。

## 你什么时候需要 Skill?

Perplexity 的 Agent 团队经常被问到一个问题:某个领域或用例是否真的需要一个 Skill?

通常没有一个绝对的答案。最有效的方法是:先在没有 Skill 的情况下让 Agent 运行几个核心查询(Hero Queries),观察它的表现。

### 需要 Skill 的情况

如果你想通过一句话的提示词无法改变 Agent 的行为,就需要 Skill:

**纠正错误或不一致**

当 Agent 在没有特殊语境的情况下会出错,或者你需要在多次运行中保持极高的一致性。

**特定的知识或流程**

知识是耐用的,但不在模型的训练数据中(比如企业特定的工作流)。

**审美品味**

比如 Perplexity 的设计负责人 Henry Modisett 编写了几个设计相关的 Skill。之所以每一行指令都存在,是因为 Henry 对网页和 PDF 的字体、感觉有非常独特的品味,这些判断力是模型无法仅从训练数据中学到的。

### 不需要 Skill 的情况

**模型已知的任务**

比如写一连串 Git 命令。这对人类是好文档,但对模型来说是差 Skill,因为它已经知道怎么做了。

**系统提示词的重复**

没必要把全局上下文里已有的内容再写一遍。

**变化太快的信息**

如果某些信息的变化速度超过了你的维护速度,就不该写进 Skill,否则会导致模型产生误判。

## 每一个 Skill 都是一份「税」

Perplexity 建议开发者对 Skill 中的每一句话进行测试:

> 如果没有这条指令,Agent 会出错吗?

如果答案是否定的,那这句话就不该存在。因为每一个 Skill 都是一份「税」,每个会话、每个用户都在为此支付 token 成本。

帕斯卡那句关于「没时间写短信」的名言在这里非常适用。写一个短小的 Skill 是很难的,如果你 5 分钟就写完了一个 Skill 并提交申请,那它多半是不合格的。

早期的研究也表明,如果你想用大模型来自动生成 Skill,效果通常很差。模型目前还无法可靠地编写出能让自己受益的过程性知识。

## 如何构建一个 Skill

你需要把自己的观点注入到 Skill 中。具体步骤如下:

### 第 0 步:编写评测(Evals)

先写评测,再写内容。你可以从真实的用户查询、已知的失败案例、或者是容易与邻近领域混淆的情况中寻找素材。

负面案例(即告诉模型什么时候「不该」加载)往往比正面案例更有力量。

### 第 1 步:写好描述(Description)

这是 Skill 中最难写的一行。它不是说明文档,而是「触发开关」:

* • 必须以「Load when…」(当……时加载)开头
* • 目标在 50 个单词以内
* • 描述用户的意图,而不是总结工作流程

### 第 2 步:编写正文(Body)

给 AI 写工作流和给同事写文档完全不同:

**跳过显而易见的事**:不要写具体的命令序列(比如`git log`、`git checkout`)

**给出原则而非死板命令**:比如写「将提交樱桃拾取(cherry-pick)到干净的分支上,保留意图并解决冲突」,AI 会完成得更好

**专注于「坑」(Gotchas)**:这是信号量最高的内容。随着 Agent 不断犯错,这里的负面例子会自然增长

### 第 3 步:利用层级结构

当涉及脚本、参考资料或特定工具时,请充分利用 Skill 的层级结构:

Perplexity 首次公开了内部 Skill 设计指南

对于任何具有条件性或分支逻辑的内容,请将其从主 Skill 文件中拆分出来,放入子文件夹。同时,多层级结构也可以用于处理极其复杂的 Skill。在这种情况下,你需要仔细考虑是将功能实现为一个庞大的单体,还是拆分为一组具有依赖关系的 Skill 集合。

### 第 4 步:迭代

在分支上进行多轮迭代。你可以先在没有该 Skill 的主分支上运行,构建你的核心查询集,并运行大量评测。任何评审你代码的人都会感激你提交了一个带有完整评测集的变更集。评审连续的细微改动是非常困难的(除非是增加一个新的注意事项),所以请尽量减少这种情况。

你可能会对文字描述进行许多细微的改动。描述中微小的词语变化可能会对路由产生巨大的影响(包括对其他 Skill 的溢出效应),因此请在进入第 5 步之前完成这些工作。

### 第 5 步:发布

正式发布。

## 如何维护一个 Skill

编写完 Skill 之后,你还需要对其进行维护。

### 「坑」(Gotchas)的飞轮效应

从这一步开始,你的「注意事项」(Gotchas)列表会不断增长或变化。我们经常看到工程师在没有经过评测的情况下就修改描述(Description)。如果你在 Skill 合并之后还在频繁修改描述,那说明你偏离轨道了。如果你要修改决定路由逻辑的部分,必须有评测集来支持这些变更。

Skill 应该是「只增不减」的。随着时间推移,Gotchas 部分积累的价值最高:

* •**智能体在某处失败了**:增加一个 Gotcha(注意事项)
* •**智能体错误加载了该 Skill**:收紧描述并增加负面评测案例
* •**智能体在该加载时没加载**:增加关键词和正面评测案例
* •**系统提示词发生了变化**:检查是否存在冲突或重复

在内部测试或生产环境中发现单个失败案例并增加一个注意事项是很简单的。这是一个负面示例,它并没有改变显式的指导,但它能让模型知道:这里有一个已知的坑。随着你从 80/20 进步到 99.9% 甚至 99.99% 的成功率,这个 Gotcha 列表会自然增长。你应该把大部分内容追加到 Gotchas 部分,而不是增加更长的指令或修改描述。

### 评测套件(Eval Suites)

在 Perplexity,我们会运行多种评测套件:

* •**加载与文件读取评测**:检查加载 Skill 的准确率和召回率,以及是否有「禁区」检查。这确保了新 Skill 不会破坏现有的边界。
* •**渐进式加载评测**:检查智能体是否正确读取了附件文件。比如一个金融 Skill,它是否在需要时读取了专门的格式化要求文件?
* •**端到端任务评测**:运行完整的智能体循环,并使用 LLM 作为裁判,根据定义良好的标准进行评分。

在不同模型上运行这些评测至关重要。Computer 支持多种模型(GPT、Claude Opus、Claude Sonnet)。你需要在不同的模型上运行评测,以确保行为一致,因为 Sonnet 和 GPT 在处理 Skill 时的表现非常不同。

## 最后的思考与总结

你构建的 Skill 越多,你就会越擅长。如果你还没有尝试使用 Skill 来自动化你日常重复性的任务,请立即开始。

构建 Skill 不仅能优化产品,它们在自动化业务流程方面也非常出色。如果你能描述出自己每周、每天甚至每季度要做的任何事情,你都应该写一个 Skill 来买回你自己的时间。

无论是自动化事故复盘,还是审核代码合并请求(PR),任何任务都可以先由智能体技能来完成第一遍,这将为你节省大量时间。

当然,也要记住 Skill 并不总是容易写的,也并不总是必要的。少即是多。以下是一些核心要点:

1. 1.**先写评测,再写 Skill**:包含负面示例,以及防止相邻领域技能误加载的限制
2. 2.**描述是最难的部分**:以「Load when…」开头的每一句话都在消耗注意力成本
3. 3.**「坑」(Gotchas)是极高价值的内容**:从小处开始,随着智能体犯错而不断丰富
4. 4.**警惕「超距作用」**:记住,添加一个新 Skill 很容易破坏原有的 Skill 表现,即便你没有碰过旧的代码

在编写和维护 Skill 时,请利用好所有可用的工具。如果你想了解更多,可以参考 Agent Skills 网站上的案例。通过不断练习,你可以构建出真正高效、精准的智能体技能。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片