调用API是在用工具,搭建Skills是在设计意图
本文最后更新于 2026-05-10,文章内容可能已经过时。
调用API是在用工具,搭建Skills是在设计意图——Perplexity这份手册,把开发者的升级路径写明白了
Perplexity的Agent Skills开发手册里有这么一句话:
"Skills需要新的开发者思维(Skills require a new developer mindset)。"
大多数开发者扫一眼就跳过了。毕竟,这种话听起来像是产品文案里的套话——哪家公司不说自己"需要新思维"?
但我把这份手册反复读了几遍之后,发现这句话背后藏着三个真实的设计陷阱。不是理论上的,是那种你照着老习惯写完代码、部署上线、然后发现Skill从来不被触发、或者模型开始自己编答案的那种陷阱。
这篇文章就是把这三个陷阱拆开来给你看。
---
第一个陷阱:你以为你在写触发条件,其实你在写一段自我介绍
传统API的世界是确定性的
在普通的API调用逻辑里,触发入口是开发者定义的。逻辑大概长这样:
# 传统API调用方式
def handle_user_input(user_input):
if "天气" in user_input:
return call_weather_api(parse_city(user_input))
elif "翻译" in user_input:
return call_translation_api(user_input)
else:
return default_response()
规则是你写的,条件是你定的,什么情况下调哪个API,完全在你的掌控之内。这套逻辑是闭合的、可预测的,出了问题你能顺着代码一行一行找。
Skills的世界是意图驱动的
但在Perplexity的Skills体系里,触发逻辑不是你写的——是模型读懂的。
Agent在决定"要不要调用这个Skill"的时候,它看的不是你的if-else,而是你在description字段里写的那段话。模型会把用户的自然语言意图,和你写的description做语义匹配,然后自己决定"这个Skill该不该上"。
# Skills的注册方式(伪代码)
skill = {
"name": "weather_query",
"description": "当用户询问某个城市或地点的天气情况时使用此技能,
包括当前天气、未来几天预报、温度、降雨概率等。",
"parameters": {
"city": {"type": "string", "description": "城市名称"}
}
}
你的代码入口,从main()变成了一段自然语言。
这意味着什么?
意味着description写烂了,Skill永远不会被调用——而且这个Bug比代码Bug更难debug。
举个真实场景:假设你写了一个查询股票价格的Skill,description是这样的:
"查询金融数据。"
用户问:"帮我看看今天苹果股价怎么样?"
模型很可能不会触发这个Skill。因为"金融数据"这个描述太模糊,模型无法确信这个Skill能回答"股价"这类问题。它可能直接用自己的知识库给你一个过时的答案,甚至编一个。
正确的写法应该是:
"当用户询问股票价格、涨跌幅、市值或某只股票的实时行情时,使用此技能。支持A股、港股、美股的股票代码或公司名称查询。"核心转变:你不再写触发条件,你要写Skill的自我描述,让模型读懂"我能干什么、什么时候该叫我"。
---
第二个陷阱:你的错误信息现在有两个读者——用户和AI
传统的错误处理链路
在传统开发里,错误处理是这样的:API调用失败→抛出异常→开发者捕获→返回错误码→前端展示友好提示。链路清晰,责任分明。
# 传统错误处理
try:
result = call_external_api(params)
return {"status": "success", "data": result}
except APIException as e:
return {"status": "error", "code": e.code, "message": "服务暂时不可用"}
这里的message是写给用户看的,目标是"让用户理解出了什么问题"。
Skills失败后,模型会自己做决定
但在Skills体系里,失败之后发生的事情超出了你的控制范围。
模型在拿到你的错误返回之后,会自行决定下一步:它可能重试、可能切换到另一个Skill、也可能——这是最危险的情况——直接用自己的知识库编一个答案。
Perplexity手册里对这一点有明确要求:你必须在返回结构里定义fallback语义,告诉模型"失败时你应该怎么理解这个结果"。
这意味着你的error_message字段,不再只是给用户看的提示,而是给模型读的提示词。
# Skills的错误返回(伪代码)
def handle_skill_error(error_type):
if error_type == "city_not_found":
return {
"status": "error",
# 给用户看的
"user_message": "未找到该城市的天气数据",
# 给模型读的——告诉它下一步该怎么办
"model_instruction": "城市名称可能有误,请向用户确认具体城市名称,
不要自行猜测或使用历史数据作为当前天气。"
}
你需要同时写两个版本的错误信息:一个让用户明白发生了什么,一个让模型知道它下一步应该怎么行动。
为什么这很重要?
因为如果你不告诉模型失败时该怎么做,模型会自己找出路。而模型找出路的方式,有时候是"幻觉"——它会用一种自信的语气告诉用户一个完全错误的答案,用户还以为是你的Skill返回的结果。
你的错误处理逻辑,现在是AI行为的一部分。---
第三个陷阱:你设计的不是函数,是在对话流里漂流的能力单元
传统API是无状态的
传统API调用是无状态的。每次请求都是独立的,上下文管理是开发者自己的事。你要传什么参数,就在请求里显式地带上什么参数,API不会"记得"你上次说了什么。
Skills活在对话的上下文里
但Skills的每次调用,都处于一段对话的"中间"。模型会把前文的信息带进来,自动填充Skill的输入参数。
来看一个具体的场景:
用户:上海今天天气怎么样?
>
Agent:上海今天晴,气温28℃……
>
用户:那明天呢?
第二句话里,用户根本没提"上海"。但模型会从上下文里理解,city参数应该是"上海",然后用这个值去调用你的天气Skill。
听起来很智能,对吧?但问题来了:
用户:帮我查一下刚才那个城市的天气。
你的Skill的city参数,该从哪里来?
如果你在设计Skill的时候没有考虑这种情况——没有在description里说明"city参数可以从上下文中获取"——模型可能会:
1. 直接报错说"缺少城市参数"
2. 随便猜一个城市
3. 向用户重新确认(这是最好的情况,但体验很差)
Perplexity手册里有一个隐含要求:Skill的参数设计必须考虑"模型可能用上下文自动填充哪些字段",并在description里明确说明哪些参数可以从对话历史推断,哪些必须用户显式提供。这是一个思维方式的根本转变:你不是在设计一个函数签名,你是在设计一个能在对话流里自主定位自己输入的能力单元。
---
综合对比:三个维度,一张表看清楚
| 维度 | 传统API调用 | Perplexity Skills | | 触发逻辑 | 开发者用代码定义(if-else、路由规则) | 模型根据用户意图 + Skill描述动态匹配 |
| 错误处理 | 抛异常→捕获→返回错误码,读者是用户 | 返回fallback语义,同时服务用户和模型 |
| 状态管理 | 无状态,每次调用独立,参数显式传入 | 有隐式状态,模型从对话上下文自动填充参数 |
三个维度,每一个都要求你把"开发者视角"切换成"模型协作者视角"。
---
实战建议:写完一个Skill,用这3个问题自查
✅ Skills开发者思维检查清单
问题一:如果模型只读了我的description,它能准确判断"什么时候该调我"吗?检查方法:把description单独拿出来,给一个没看过你代码的同事读,让他判断"这个Skill适合回答哪类用户问题"。如果他说不清楚,模型也说不清楚。
问题二:我的错误返回,有没有告诉模型"失败后该怎么做"?检查方法:想象模型拿到你的error response之后,它的下一步行动是什么。如果答案是"不知道",你需要补一个model_instruction字段。
检查方法:设计一个多轮对话场景,在第三轮或第四轮调用你的Skill,看看参数还能不能正确填充。
---
横向视角:这不只是Perplexity的问题
这套思维不是Perplexity独有的。
如果你用过Claude的Function Calling,你会发现function description字段的设计哲学完全一致——写得好不好,直接决定模型会不会调用这个函数。GPT的Tool Calling同理。MCP(Model Context Protocol)在工具定义规范里,也在走同一条路:把工具的"自我描述"作为一等公民来设计。
这是Agent时代的一个底层共识:当AI成为调用方,开发者的工作重心从"写调用逻辑"转移到"写能力说明书"。
你写的不再是代码逻辑,而是AI能力的使用说明书。
---
如果你想直接上手测试这套设计逻辑,或者对比GPT / Claude的Function Calling在这三个维度上的实际表现——
👉 [api.884819.xyz](https://api.884819.xyz) 聚合了主流模型的API接入,可以用同一套代码框架横向对比不同Agent能力的设计逻辑。新用户注册即送体验token,国产模型(Deepseek / 千问等)完全免费,没有月租,按量付费,省去多平台注册的麻烦。
---
这篇我们拆的是Perplexity Skills的设计哲学——触发逻辑、错误处理、状态管理,三个维度各有一个认知陷阱。
但有一个问题我一直没回答:如果同样的"新开发者思维",放到Anthropic的MCP协议里,设计逻辑会不会完全不同?
下一篇,我们把MCP的工具定义规范拿来和Perplexity Skills并排放——看看两家对"AI调用能力"这件事,到底在哪里达成了共识,又在哪里产生了根本分歧。MCP有一个设计决策,我第一次看到的时候觉得"这不对吧",但越想越觉得它比Skills更彻底。
敬请期待。
---
本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。#AI开发 #Perplexity #AgentSkills #FunctionCalling #MCP #大模型应用 #8848AI #AI工程师