本文最后更新于 2026-05-10,文章内容可能已经过时。

我以为我会调用它,结果文档说:你只需要注册它,然后等

我原本以为这会是一次普通的API接入。

写个函数,传个参数,拿到返回值——这套流程我闭着眼睛都能写。但当我翻开Perplexity Agent Skills的官方文档,第一页就出现了一句让我愣了三秒的话:

"Skills are not called by you. They are invoked by the intent router when the system determines your skill is the best match for the user's request."

你不调用它。你只是注册它,然后等它被调用。

这和我的直觉完全相反。但当我花了一个下午把整套流程跑通之后,我意识到:这才是Agent的正确打开方式,而我之前的思维模型,其实一直停留在"高级版API调用"的层次。

这篇文章记录我的完整复现过程,包括踩过的坑、反直觉的设计,以及这套架构背后真正有意思的工程逻辑。

---

第一章:Perplexity为什么要公开这份手册?

Perplexity不是第一次做技术文档,但这次的Agent Skills搭建文档和以往不同。

它公开的不是一个新的API端点,而是内部技能调度机制的完整协议。换句话说,Perplexity把自己产品里那套"决定什么时候用搜索、什么时候用计算、什么时候用外部工具"的核心逻辑,以一种可扩展的方式对外暴露了。

在此之前,Perplexity在用户眼里就是一个"更好的搜索引擎"——你问问题,它给答案,顺便附上引用来源。但这个定位有个天花板:它只能回答你的问题,不能帮你执行任务

Agent Skills解决的正是这个问题。它允许开发者把自己的能力模块(比如查数据库、调外部API、执行代码)注册到Perplexity的意图路由系统里。当用户的请求触发了匹配的意图,系统会自动调用你注册的Skill,把结构化结果融合进最终回答。

这个定位,和普通的"插件系统"有本质区别:插件是你主动选择调用的工具,Skill是系统自动决策是否调用的能力。理解这一点,是后面所有内容的前提。

---

第二章:我照着文档跑的过程

环境准备

开始之前需要确认几件事:

  • Python 3.10+(文档里的示例代码用了3.10的类型注解语法)
  • 一个有效的Perplexity API Key(需要在官网申请,目前Skills功能要求Pro级别的API访问权限)
  • httpxpydantic 这两个库是必须的,官方示例依赖它们
pip install httpx pydantic

第一步:定义你的Skill Schema

Skills系统的入口是一个JSON Schema,用来描述你的技能"能做什么"、"需要什么输入"。

这是我写的最简版本——一个查询本地天气数据的Skill:

{

"name": "get_local_weather",

"description": "Retrieves current weather conditions for a specified city. Use this when users ask about weather, temperature, or climate conditions.",

"parameters": {

"type": "object",

"properties": {

"city": {

"type": "string",

"description": "The name of the city to query weather for"

},

"unit": {

"type": "string",

"enum": ["celsius", "fahrenheit"],

"default": "celsius"

}

},

"required": ["city"]

}

}

注意description字段——这不是写给人看的注释,而是意图路由用来判断是否调用你的Skill的核心依据。写得越精确,匹配率越高。我第一次写得太笼统("Gets weather data"),结果路由几乎从不触发这个Skill。

第二步:实现Handler函数

Schema定义了"能做什么",Handler负责"真正去做"。

from pydantic import BaseModel

from typing import Optional

import httpx

class WeatherInput(BaseModel):

city: str

unit: Optional[str] = "celsius"

class WeatherOutput(BaseModel):

temperature: float

condition: str

humidity: int

city: str

async def get_local_weather_handler(inputs: WeatherInput) -> WeatherOutput:

# 这里接入你自己的天气API

async with httpx.AsyncClient() as client:

response = await client.get(

"https://your-weather-api.example.com/current",

params={"city": inputs.city, "unit": inputs.unit}

)

data = response.json()

return WeatherOutput(

temperature=data["temp"],

condition=data["condition"],

humidity=data["humidity"],

city=inputs.city

)

第三步:注册到Skills系统

这一步是我卡得最久的地方。

文档里的注册接口看起来很简单,但有个细节没有明确说明:注册请求必须包含一个endpoint_url字段,指向你Handler的公网可访问地址。这意味着你在本地开发阶段,必须用ngrok或者类似工具把本地服务暴露出去。

我第一次跑的时候直接填了localhost:8000,返回200但Skills从来不触发——因为Perplexity的服务器根本访问不到你的本地端口。

import httpx

async def register_skill(api_key: str, skill_schema: dict, endpoint_url: str):

async with httpx.AsyncClient() as client:

response = await client.post(

"https://api.perplexity.ai/skills/register",

headers={

"Authorization": f"Bearer {api_key}",

"Content-Type": "application/json"

},

json={

"schema": skill_schema,

"endpoint": endpoint_url,

"version": "1.0"

}

)

return response.json()

成功注册后,你会拿到一个skill_id,保存好,后续调试要用。

---

第三章:核心反直觉点——和普通API调用哪里完全不一样?

跑通之后,我花了很长时间在脑子里整理"哪里和我预期不一样"。总结下来有三个核心反直觉点。

反直觉点①:触发机制——你是被动的

普通API调用的心智模型:
用户输入 → 你的代码判断 → 你主动调用API → 拿到结果 → 处理输出
Skill的心智模型:
用户输入 → 意图路由分析 → 系统决定调不调你 → 你的Handler被动响应 → 结果被融合进回答

这个差异比看起来要大得多。在普通API模式下,你是控制流的主人,你决定什么时候调什么。在Skills模式下,你是一个注册在案的能力提供者,调度权在系统手里。

这对开发者的心态要求完全不同:你不能假设你的Skill一定会被调用,也不能假设它不会被调用。你只能保证:当它被调用时,它能正确响应。

反直觉点②:输入结构——不是原始Query

很多人(包括我)第一反应是:用户说了一句话,这句话会原封不动传给我的Handler。

错。

传进来的是这样的结构:

{

"intent": "weather_query",

"confidence": 0.94,

"extracted_params": {

"city": "上海",

"unit": "celsius"

},

"original_query": "上海今天天气怎么样",

"context": {

"conversation_history": [...],

"user_locale": "zh-CN"

}

}

意图路由已经帮你做了语义解析,把用户的自然语言转成了结构化参数。你的Handler拿到的是已经处理过的输入,而不是原始文本。

这有好处:你不需要自己做NLP,参数提取这件苦差事系统帮你做了。但也有坏处:如果路由的语义解析出了偏差,你的Handler拿到的就是错误的输入,而你完全不知道用户原本说了什么(除非你去读original_query字段)。

反直觉点③:错误处理——失败是沉默的

这是最坑的一个。

在普通API调用里,出错了会抛异常,你能立刻感知到。但Skills系统的错误处理逻辑是这样的:

如果你的Skill返回错误,系统不会把错误暴露给用户,而是静默降级——要么用其他Skill重试,要么直接用基础搜索能力回答,然后假装什么都没发生。

从用户体验角度,这很合理:用户不需要看到技术错误。但对开发者来说,这意味着你的Skill失败了,你可能完全不知道

我在调试阶段有一次Handler代码有bug,本地测试一直没发现,因为在Skills系统里它一直被降级处理掉了,用户(也就是我自己)拿到的是一个"看起来正常"的搜索结果。

解决方案是:必须主动接入日志系统,在Handler里把每次调用的输入输出都记录下来,不能依赖Skills系统的反馈来感知错误。

---

第四章:这套设计背后的逻辑

为什么要这样设计?这不是Perplexity的任性,而是有明确的工程考量。

多技能并发调度

当一个用户请求可能涉及多个能力时,系统需要同时评估所有注册的Skills,选出最合适的一个(或几个)并发调用。如果是"你主动调用"的模式,这种并发协调就变成了开发者的责任——每个人都要自己实现调度逻辑,重复造轮子。

把调度权收归系统,开发者只需要专注"我的Skill能做什么、做得好不好",调度这件事交给专门的路由层来做。

意图置信度阈值

路由系统不是非黑即白的。官方文档提到,只有当意图匹配的置信度超过一定阈值(文档中给出的参考值是0.85),对应的Skill才会被触发。

这个设计避免了"误触发"——用户随便说了一句话,结果触发了一堆不相关的Skills,浪费资源还影响体验。

降级兜底链路

沉默降级不只是"出错了不报错",而是一套完整的兜底链路:Skill失败 → 尝试其他匹配的Skill → 全部失败 → 回退到基础搜索。

这保证了系统的可用性下限,但也要求开发者把"我的Skill不可用"当作一种正常状态来设计,而不是假设它永远在线。

---

第五章:值得上手的前提——你现在需要什么才能跑起来?

准备清单

  • API权限:目前Skills功能需要向Perplexity申请,普通API Key不够用,需要确认你的账户级别
  • 公网可访问的Handler端点:本地开发用ngrok,生产环境需要部署到有公网IP的服务器
  • Python 3.10+,安装httpxpydanticfastapi(如果你用FastAPI搭Handler服务)
  • 一个具体的用例:不要为了用Skills而用Skills,先想清楚"我想让Perplexity帮用户做什么额外的事"

当前限制(诚实说)

  • Skills目前支持的返回类型有限,复杂的二进制数据(图片、文件)还不支持
  • 意图路由的调试工具很弱,官方没有提供可视化的"为什么这次没触发你的Skill"的解释
  • 文档更新滞后于实际API,部分字段的行为和文档描述有出入,需要自己测

接入建议

如果你在国内访问Perplexity官方API端点有延迟或连通性问题,可以走 [api.884819.xyz](https://api.884819.xyz) 做中转接入——格式和OpenAI SDK完全兼容,改一行base_url就行:

from openai import OpenAI

client = OpenAI(

api_key="your-8848-api-key",

base_url="https://api.884819.xyz/v1"

)

这个入口的好处是:你可以用同一个SDK同时调Perplexity、GPT系列、Claude、Deepseek做横向对比测试,不用切来切去。新用户注册即送体验token,国产模型(Deepseek、通义千问等)完全免费,没有月租,按量付费,注册地址:[api.884819.xyz](https://api.884819.xyz)。

值不值得现在就学?

诚实判断:如果你已经在做Agent相关的开发,值得花半天跑通这套流程,它会给你一个很好的参照——"被动注册+意图路由"这种调度思路,比你自己手写调度逻辑要优雅很多,值得借鉴。

如果你只是好奇,或者还没有具体的Agent开发需求,可以先收藏这篇文章,等需求具体了再回来。现在上手的主要成本是:文档不够完善,调试体验差,需要一定的踩坑耐心。

---

Perplexity这套Skills的意图路由,本质上是一个轻量级的函数分发器。它解决了一个很具体的问题:在多个能力模块之间,如何根据用户意图做出最优调度决策。

但这个问题不是Perplexity独有的。

下一篇我想聊聊:OpenAI的Function Calling、Anthropic的Tool Use、Perplexity的Skills——三套东西的设计哲学到底有什么本质差异? 如果你不依赖任何一家平台,想用开源方案自己复刻同样的调度逻辑,最少需要几行代码?这三套方案各自的适用边界在哪里?

这个横向对比,对已经跑通本篇的读者来说,应该是最有价值的下一步。

---

本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。

#AI开发 #Perplexity #Agent #API接入 #8848AI #大模型 #AI工具 #开发者