在 Perplexity 设计、精炼和维护 Agent 技能

了解 Perplexity 如何编写、审查和维护 Agent 技能,以及我们的工程师用来构建它们的指南。

作者Perplexity Engineering

Perplexity 的前沿 Agent 产品建立在打包于模块化 Agent 技能中的专业知识和领域专长基础之上。我们在技术环境中维护着一个精心策划的技能库。这些技能涵盖了驱动 Perplexity Computer 的许多通用实用工具;金融、法律和医疗等领域的垂直特定能力;以及用于满足用户需求的大量细分模块。某些技能被调用的频率较低,但被调用时却至关重要 时。为了确保始终如一的卓越用户体验,Perplexity 的 Agent 团队将技能质量视为与代码质量同等重要的优先事项。

开发高质量技能所需的直觉和最佳实践与构建传统软件所需的那些截然不同。Agent 团队会审查来自优秀工程师在工作过程中开发的许多拉取请求。结果几乎总是会有大量的修订意见和建议。这是因为许多有用的代码编写模式在技能创作中会变成反模式。

例如,如果您采用 PEP20 – Python 之禅中的一些警句,很快就会清楚,编写高质量的 Python 代码与编写高质量的技能是不同的。在这些 20 条智慧箴言中,至少有一半在编写技能时是完全错误的或具有严重的误导性。以下是其中五条:

Python 之禅

技能之禅

简单胜过复杂

技能是一个文件夹,而不是一个文件。复杂性即特性。

显式胜过隐式

激活即隐式模式匹配。渐进式披露。

稀疏胜过稠密

上下文极其昂贵。每个 Token 的最大信号量。

特殊情况也不足以打破规则

陷阱本身就是特殊情况(它们是最高价值的内容)。

如果实现易于解释,这可能是一个好主意

如果它易于解释,模型就已经知道了。删掉它。

Python 禅与撰写 Skills 的文章指南之间的五个对比。

本指南是 Perplexity 的工程师在开发和审查技能时使用的文件。我们也向公众发布本指南,以便我们的发现和经验能使更广泛的社区受益。无论您是日常设计生产技能的工程师,还是希望在您最擅长的领域开发自己技能的 Computer 用户,亦或是两者兼而有之,本指南都适合您。

什么是技能?

当您编写技能时,您编写的并非普通软件(尽管技能现在是 Agent 系统主要逻辑引擎的一部分)。相反,您是在为模型及其环境构建上下文。技能具有不同的约束和不同的设计原则。如果您像编写代码一样编写技能,您将会失败。

技能至少包含四个方面,特别是在我们 Perplexity 构建它们的情况下。

技能即目录

技能不仅是一个单独的 SKILL.md 文件。在许多情况下,技能包含多个文件。在以您的技能命名的目录下,您可能会有:

SKILL.md:元数据和指令

scripts/:Agent 运行的代码,而非重新发明

references/:大型文档,有条件地加载

assets/:模板、模式和数据

config.json:首次运行用户设置

这种中心辐射型模式使您能够保持技能的高度专注和紧凑,并且可以以非常创造性的方式利用文件夹结构。有时,特别复杂的技能受益于多级层次结构,以帮助模型更好地导航。假设一项技能需要跨越 300 个主题的知识,这些主题可分为 20 个领域。即使对于当今最优秀的前沿模型,在 300 个主题中可靠地选择正确的主题也是一个尚未解决的挑战。对于模型而言,在 20 个领域中锁定一个区域,比在 15 个主题中选择要容易得多。

作为多级层次结构提供价值的一个例子,我们的团队在过去纳税季中,在驱动 Computer 美国所得税能力的技能中采用了三级主题嵌套。鉴于税法的复杂性,这种层次结构绝对不可或缺:在我们早期的测试中,向模型呈现一个包含美国国内税收法典所有 1,945 个章节的单个文件夹,其表现比根本不加载该技能还要差。将信息组织成逻辑细分部分对于确保高精度读取操作是不可或缺的。

然而,这种层次结构并非免费。增加层次结构的级别需要增加信息架构层面的策划,以管理由此产生的间接成本。我们设计了快速参考指南、自定义搜索实用工具以及其他工具,以支持模型以最小的间接成本定位信息。在这种情况下,进行艰苦的策划工作最终产生了积极的最终结果:一项使模型在执行税务相关任务时比仅使用通用工具更加出色的技能。

使用 Computer 的税务相关 Skills 制作的 Schedule C 税务计算器。

技能即格式

技能即格式。核心根文件 SKILL.md 必须同时具有名称和描述。此外,技能需要精确映射到技能所在的目录名称。名称必须全部为小写字符,不能有空格,可以使用连字符。描述是路由触发器。这是一个常见的失败点:描述不是关于技能功能的内部文档。它相当于向模型发出的关于何时加载技能的指令。因此,您会经常看到“Load when”(何时加载),而不是“This Skill does”(此技能的功能)。这一点很重要,因为大多数实现将描述注入到模型上下文中的方式。

在元数据中,还有“depends:”,它允许您创建分层技能依赖关系,以及“metadata:”,用于审查和评估。不同的 Agent 系统甚至可以定义自己的元数据字段,以特定于这些系统的方式使用。作为替代方案,技能特定的元数据可以打包在辅助 JSON 或 YAML 配置文件中。当构建需要为每个技能促进不同类型的运行时行为的 Agent 系统,而不使用琐事污染模型上下文时,这是理想的选择。最后,类似的行为可以通过在读取时剥离技能元数据来实现。Computer 采用了这种方法,允许在根 SKILL.md 文件中保留配置。解析逻辑需要特别注意细节,如果某些字段在模型上下文中是有用的,您可能希望实现条件性剥离。

技能是可调用的

技能是可调用的。Agent 在运行时加载技能。重要的是,技能并不总是被捆绑在上下文中。默认情况下,大多数 Agent 系统会根据特定需求逐步展开技能。

在我们实现 Computer 技能的方式中,至少有三个层级的上下文成本。以下是该过程:

Computer 调用 load_skill(name="...")

Computer 将技能目录复制到隔离的执行沙盒中

Computer 递归地自动加载“depends:”标签中的依赖项

Computer 然后剥离元数据,Agent 因此只能看到主体和附加文件

不同的 Agent 系统可以选择以不同方式暴露技能内容。例如,某些系统可能根本不暴露文件层次结构,而是留给模型通过文件系统操作去发现层次结构。其他系统可能选择向模型提供整个文件树的映射,并限制一定的截断和/或深度。为了保持上下文清洁,Computer 从调用上下文中省略了完整的文件层次结构;然而,这可以在每个技能的基础上进行覆盖。

技能是渐进式的

技能是渐进式的。在 Computer 中,有三种不同的上下文成本层级,我们在不同的阶段都会产生这三种成本:

层级

加载内容

预算

支付时间

索引

名称:每个非隐藏技能的描述

每个技能约 100 个 Token

每次会话,每个用户,始终付费

加载

完整的 SKILL.md 主体

约 5,000 个 Token

约 5,000 个 Token

运行时

scripts/、references/、assets/、子技能、FORMATTING.md、SPECIAL_CASES.md 中的文件

无限制

仅在 Agent 读取它们时

Skill 上下文的三个层级:索引、完整的 Skill 加载,以及运行时参考文件。

Computer 构建了一个技能索引,其中包含每个可用技能的名称和描述。其预算约为每个技能 100 个 Token(越短越好)。之所以如此紧凑,是因为您在每次会话中、为每个用户都在支付这一成本。这在对话的最开始就被注入到系统提示中。模型可以访问一组已命名的技能和描述,以便它可以决定是否调用“load_skill()”。进入此索引的门槛极高。您的技能必须非常有用,并且描述需要极其密集和简洁,因为每个人始终都在支付这一成本。

在 Agent 系统加载技能后,会有一个完整的 SKILL.md 主体。理想情况下,主体文本不超过 5,000 个 Token。即使这样,您也希望每一个句子都发挥作用,因为一旦您加载了技能,其余的对话都必须为此支付成本,直到您达到压缩边界。许多问题会加载 3 到 5 个不同的技能,从而使这一成本成倍增加。包含大量无关内容的技能几乎肯定会降低其他技能的效果以及整体的 Agent 能力。简而言之,如果您的技能加载了却不能做正确的事情,那就是浪费上下文。

渐进式的最后阶段是脚本或特殊情况,如子技能或格式化。这是您想要放入无限制的条件分支逻辑的地方。Agent 只会在需要时才使用它,这意味着您放入这里的内容门槛要低得多。

在索引中,每一个 Token 都很重要。已加载的技能主体则较为宽松,运行时最为宽松。这可以是 20,000 个 Token 或零个 Token。这是您可能考虑以渐进方式扩展模型思考的层级。

什么时候需要技能?

Agent 团队经常被要求就给定领域或用例是否真正需要技能发表意见。我们很少能仅凭基本原则给出确定性的答案。真正找出答案的唯一方法是从没有该技能的 Agent 开始,运行几个英雄查询,然后判断 Agent 是否表现良好。

当您需要技能时

有很多任务是在已训练模型的分布范围内。只有当您想以某种您无法通过例如提示语中的一句话实现的方式改变该行为时,才需要应用技能。因此,当 Agent 在没有特殊上下文的情况下会出错,或者如果存在某种不一致或非确定性,而您需要跨运行保持极其一致时,就需要技能。

可能是您的知识是持久的,但不在训练数据中。可能存在截止日期或企业特定的工作流,或者可能是品味问题。例如,我们在 Computer 中有几个由 Henry Modisett(我们的设计主管)编写的与设计相关的技能。那些技能中存在的每一个 Token 的原因,是因为 Henry 在设计网站和 PDF 时有很好的品味。Henry 指定了使用哪些字体以及不使用哪些字体,这些字体如何感觉,以及其他模型仅从训练数据中无法学习的判断事项。

当您不需要技能时

我们看到许多技能中,工程师编写了一系列需要按顺序执行的 git 命令。这是不必要的,因为模型已经知道如何做到这一点,这意味着这虽然是很好的文档,但却是一个糟糕的技能。

我们看到一些例子,技能重述了系统提示中的指令。您不需要为此编写技能。大多数请求相关的知识应该包含在全局上下文中,而不是包含在有条件加载的技能中。

如果有某些变化速度超过了您的维护能力的东西,您就不需要技能。例如,如果您正在访问某个远程 MCP 端点,而其工具或这些工具的版本经常变化,您不应该将它们注入到技能中。如果您这样做,最终只会导致漂移,模型会犯错误。

每个技能都是一种税

这里有一个您可以应用于技能中每个句子的有用测试:“如果没有这个指令,Agent 会出错吗?”如果句子不需要在那里,它就承担不起在那里的代价,因为每个人每次都在支付这一成本。当您决定是否添加技能时,请记住这种税,即每次会话和每个用户都会消耗 Token。

以下这句名言,在法语中听起来更好,大致翻译为“我写这封信之所以如此冗长,是因为我没有时间让它变得简短。”

« Je n’ai fait celle-ci plus longue que parce que je n’ai pas eu le loisir de la faire plus courte. » — Blaise Pascal, Lettres Provinciales, 1657

就像 Pascal 一样,您需要为每个技能投入时间。编写一个简短的技能是困难的。如果您的技能很容易编写,它可能太长了或者根本不该存在。一个好的技能应当尽其所能简短。

如果您发现自己试图一次性生成技能并五分钟内提交 PR,结果几乎肯定是不达标的。事实上,早期的研究已经表明,如果您正在使用 LLM 编写技能,LLM 可能不会从中受益:“自生成的技能平均而言没有提供任何益处,这表明模型无法可靠地编写它们从消费中获益的过程性知识。”

如何构建技能

换句话说,您需要将您的意见注入到您编写的任何技能中。请遵循以下步骤。

第 0 步:编写评估

先写一些评估。您可以从以下来源获取评估案例:

真实用户查询:从生产环境或您的智囊团中采样

已知失败:Agent 失败是因为技能不存在

相邻混淆:靠近您的领域边界但路由到了另一个技能

至少,您应该确保正在测试技能是否在需要时加载。理想情况下,您可以从生产环境中采样其中一些。您还可以考虑已知的错误情况:也许您着手编写技能的全部原因是因为您注意到某个特定的失败,或者也许您正在进行重构,并且在由一个技能覆盖的两个相近领域中存在一些混淆。

从类似的负面和正面示例开始。负面示例极其强大,有时比正面示例更重要。

第 1 步:描述

这是 Skill 中最难翻译的一句话。它是一个路由触发器,而不是文档。要把名称和描述写对,你不需要关心 Skill 的内容。你只需要关心 Skill 是否在正确的位置加载并注入,且没有越界副作用,因为这是一号故障模式。每当你添加一个额外的 Skill 时,都会让每个 其他 Skill 稍微变差一些,所以你需要确保把回归降到最低。

再次强调,糟糕的描述会描述技能做什么或为什么它有用。好的描述会说明 Agent 何时应该加载该技能。例如,假设您有用于监视拉取请求的东西。不要写技能做什么。写工程师在沮丧且希望您确保他们的 PR 有效时所说的话,比如“babysit”(照看)、“watch CI”(监视 CI)或“make sure this lands”(确保它成功合并)。

这是一个快速核对清单:

以“Load when...”开头

目标字数 50 字或更少

描述用户意图,理想情况下来自真实查询

不要总结工作流

真实查询是您可以在 80-20 原则中覆盖的内容。通常,两三个例子效果很好。添加正好且仅您所需的内容并不容易。

第 2 步:编写主体

接下来,编写技能本身的内容。请注意,这不是第 0 步或第 1 步。

向 LLM 传达工作流与向同事甚至向您的运行时系统传达工作流完全不同。当学习一个新的软件工具时,工程师可能需要阅读文档,从有经验的人那里获得演示,并学习如何使用该工具。同时,对于几乎任何已经存在至少一年的软件工具,您只需要提及它的名称,LLM 就拥有了它所需的所有信息。

编写主体时,跳过显而易见的事情。许多工程师有丰富的编写列出某人需要运行的每个命令的 readme.md 文件的经验。当您编写技能时很容易回到那种习惯,因为这感觉就像在写文档,但如果您这样做,您的技能将是垃圾。因此,不要写出一系列命令。

例如,您不需要写:“git log # find the commit; git checkout main; git checkout -b <clean-branch>; git cherry-pick <commit>;”

相反,写:“将提交 Cherry-pick 到一个干净的分支上。解决冲突,保留意图。如果它不能顺利落地,解释原因。”

模型对后者处理得比前者的过度规定性命令序列要好得多,尤其是在出现问题时。不要强制性或过度规定,那很脆弱,而要灵活,多种方法都可以奏效。同样,对人类有用的文档对于模型来说通常是糟糕的。

接下来,专注于陷阱或负面示例。这些是极高信号的内容,因为它们通常在指导模型什么不该做方面提供指导。如果您在 Agent 每一次绊倒时添加一行,您就会通过运行它来学习,陷阱会自然增长。

最后,如果有任何部分是有条件的或内容极重的,请将其从作为枢纽的 SKILL.md 中取出,放入其中一个分支中。将其放入可以渐进加载的辅助文件中,我们接下来将深入探讨。

第 3 步:使用层次结构

当您有脚本、参考资料或使用特定工具时,请利用技能层次结构:

scripts/ Agent 在每次运行时都会重新发明的确定性逻辑

给它代码去组合,而不是去重建

references/ 仅在满足条件时加载的大型文档

“如果 API 返回非 200,请阅读 api-errors.md”

assets/ Agent 复制并填充的输出模板

report-template.md,输出模式

config.json 首次运行用户设置

询问 Slack 频道,保存,下次复用

Skill 中脚本、参考资料、资源和配置的建议用途。

对于任何有条件的或从主技能分支出来的内容,将其分解到一个文件夹中。此外,请记住,多级层次结构可用于特别复杂的技能。对于这些,您需要仔细考虑功能应该是单体实现,还是作为技能集合实现(也许带有 depends: 的基于加载关系)。

第 4 步:迭代

接下来,在分支上进行大量的迭代。在没有技能的主分支上开始,进行一些迭代,构建您的英雄查询集,并运行一堆评估。任何审查您技能代码的人都会感谢您提交了一个完整且带有评估集的变更集。审查连续的增量变更(除新陷阱外)非常困难,所以尽量减少它。

您可能会做许多微小的文字更改。描述中的微小文字更改可能对路由产生超乎寻常的影响(包括对其他技能的溢出效应),因此在第 5 步之前完成所有这些工作。

第 5 步:发布

发布它。

如何维护技能

既然您已经编写了技能,就必须维护它。

陷阱飞轮

从这一点开始,您的陷阱列表往往会增长或发生很大变化。我们经常看到工程师做出的 PR 是未经评估的,例如,更改了描述。如果您的技能合并后您还在更改描述,那么您就走偏了。如果您正在对决定是否路由您的技能的内容进行更改,您需要编写一些支持这些更改的评估。

技能主要是追加式的。陷阱部分随着时间的推移积累了最大的价值:

Agent 在某事上失败 → 添加一个陷阱

Agent 加载了非目标的技能 → 收紧描述并添加负面评估

Agent 未能在应该加载时加载技能 → 添加关键字和正面评估

系统提示更改 → 检查是否有竞争或重复

在内部测试或生产中注意到单个失败案例并添加陷阱很容易。这是一个负面示例,因此它并没有真正改变明确的指导,但它让模型知道,“嘿,有一个已知的失败。”

随着您从 80-20 阶段向 99.9% 或 99.99% 的成功率迈进,这个陷阱列表很容易增长。当您看到这些负面示例时,您应该主要追加到陷阱部分。您不应该添加更长的指令或更改描述。

评估套件

在 Perplexity,我们运行许多评估套件来检查不同的事情。有技能加载和技能文件读取,它检查技能加载本身的精确度、召回率和禁止检查。当应该路由您的技能时,Agent 会路由吗?这些确保新技能不会破坏现有的边界。

还有一些评估可以检查适当的渐进加载。Agent 可能会加载技能,但它是否读取了辅助文件或多个文件?例如,如果您有用于金融查询的金融技能,它是否读取了特殊的 FORMATTING.md 文件?

还有针对技能的评估,测试领域内的端到端任务完成情况。我们运行完整的 Agent 循环,并使用 LLM 评判员根据定义明确的标准进行评分。

最后,针对不同的模型运行这些评估很重要。Computer 支持至少三种不同的编排模型系列:GPT、Claude Opus 和 Claude Sonnet。您希望针对这些不同的 Agent 编排器运行您的技能加载和领域技能,以确保您不会得到不同的行为。Sonnet 和 GPT 在处理技能时的表现非常不同。

最终想法和要点

您构建的技能越多,您构建它们的能力就越强。如果您还没有使用技能来自动化或尝试使您日常处理的任务更具可重现性,请立即开始。

构建技能的行为使您能更好地构建更多的技能,而且它们在自动化业务流程方面非常出色。如果您能描述您每周在例会前、每个 Sprint 结束时所做的任何事情,或者作为工程师日常、每周甚至每季度所做的任何事情,您都应该编写一个技能来换回您的时间。

您可以自动化复盘吗?您可以审查拉取请求吗?任何您能做的任务,您至少可以让第一步成为 Agent 技能。这将为您节省大量时间。

话虽如此,请记住技能并不容易,甚至不总是必要的。少即是多。还有几个要点:

在技能之前编写评估。包括相邻但不同的技能的负面示例和禁止加载项。

描述是困难的部分。“Load when...” (每个字都消耗注意力)。

陷阱是极高价值的内容。从小处着手,随 Agent 失败而增长。

请记住,添加新技能很容易破坏其他预先存在的技能,即使您没有触动它(谨防远程动作)。

每次编写和维护技能时,都要使用所有可用的工具。如果您想了解更多,Agent 技能网站有大量好的示例,我们的内部存储库和公共生态系统也包含许多设计良好的技能示例。

引用

BibTeX
@online{perplexity2026DesigningRefiningAndMaintainingAgentSkillsAtPerplexity,
  author = {{Perplexity} and Marshall Kiely and Daisy Lee and Jerry Ma and Lauren Kolm},
  title = {{Designing, refining, and maintaining agent skills at Perplexity}},
  date = {2026-05-01},
  url = {https://perplexity.coolkeypoint.com/hub/blog/designing-refining-and-maintaining-agent-skills-at-perplexity}
}