你可能写过 Function Calling,但 Perplexity 说那还不够
你可能写过 Function Calling,但 Perplexity 说那还不够
你有没有遇到过这种感觉:明明觉得自己懂了,但某一句话让你突然卡住——
Perplexity 在推出 Agent Skills 的时候,官方文档里有这样一句话:
"Building with Agent Skills requires a fundamentally different developer mindset."
"全新的开发者思维"。
不是"新的 API",不是"更多参数",而是思维方式。
我第一次看到这句话的时候,下意识想跳过它——毕竟每家公司发布新功能都喜欢说"革命性"。但后来我真的去拆了 Agent Skills 的实现逻辑,才意识到:这句话不是营销话术,它在描述一个真实的认知断层。
而这个断层,很多已经用过 Function Calling 的开发者,反而更难察觉。
---
一个反差场景:同样是"查航班",代码看起来差不多
先看两段代码,功能相同——查询航班信息:
① 传统函数调用写法(命令式)def handle_user_message(user_input: str):
# 开发者显式判断:什么情况下调用工具
if "航班" in user_input or "flight" in user_input.lower():
departure, destination = extract_cities(user_input)
date = extract_date(user_input)
if departure and destination and date:
result = search_flight_api(departure, destination, date)
return format_flight_result(result)
else:
return "请提供出发地、目的地和日期"
else:
return llm_chat(user_input)
② Agent Skill 写法(声明式)
{
"name": "search_flight",
"description": "当用户询问航班信息、机票价格、航班时刻表,或者需要查询两地之间的飞行路线时使用。用户可能只提供了部分信息,可以主动追问缺失字段。",
"parameters": {
"type": "object",
"properties": {
"departure": {
"type": "string",
"description": "出发城市或机场,如果用户未提供可以追问"
},
"destination": {
"type": "string",
"description": "目的地城市或机场"
},
"date": {
"type": "string",
"description": "出行日期,格式 YYYY-MM-DD,支持相对表达如'明天''下周五'"
}
},
"required": ["departure", "destination"]
}
}
表面上看,两段代码的信息量差不多。但如果你仔细盯着看 30 秒,会发现一个根本性的不同:
第一段代码里,if "航班" in user_input 这行是开发者写的。第二段代码里,没有任何 if。
这不是代码风格的差异。这是控制权的转移。
---
第一个差异:谁在决定"要不要调用"
用一个类比来说清楚这件事。
传统函数调用,像餐厅点菜:你看菜单,你决定点什么,服务员照单执行。控制权在你手里,每一个动作都是你显式发出的指令。 Agent Skill,像主厨套餐:你告诉主厨"我今天想吃得清淡一点,不吃辣",然后主厨根据当天食材、你的偏好、季节,自己决定上什么菜。你声明了偏好和约束,但具体执行由主厨判断。在 Agent Skills 的架构里,开发者的角色从"写调用逻辑"变成了"声明能力边界"。
你不再写 if 用户问了航班 then 调用 search_flight。你只需要告诉 AI:search_flight 这个工具存在,它能做什么,在什么场景下适用。AI 自己决定什么时候用它。
这个转变听起来很美好——少写很多 if-else。但它同时意味着:你失去了对调用时机的直接控制。
对于习惯了"确定性编程"的开发者来说,这是一种真实的不适感。
---
第二个差异:输入不是参数,是"意图碎片"
传统函数调用里,参数是清晰的:
search_flight(departure="北京", destination="上海", date="2025-08-01")
类型明确,边界清晰,缺了哪个字段直接报错。
但在 Agent Skill 的世界里,输入来自用户的自然语言,而自然语言天然是模糊的、残缺的、跨轮次拼凑的。
用户可能这样说话:
- 第一轮:"我想去上海"
- 第二轮:"下周五"
- 第三轮:"从北京出发,最便宜的那种"
这三轮对话,合在一起才构成一次完整的 search_flight 调用所需的参数。AI 需要在多轮上下文中拼凑出"意图",然后决定何时参数足够充分、可以触发工具调用。
这意味着什么?
description 字段比代码本身更重要。
回头看上面那段 JSON,注意 description 里的这句话:
"用户可能只提供了部分信息,可以主动追问缺失字段。"
这不是注释,这是行为规范。AI 靠这段文字来理解:这个工具允许在信息不完整时调用,允许向用户追问。
如果你把 description 写成 "查询航班信息"——五个字,AI 可能在完全不相关的场景下触发它,也可能在最该用的时候没用。
在 Agent Skill 开发里,description 就是接口文档,是给 AI 看的 API 说明书。写得模糊,就等于接口文档缺失。
我见过一个真实的踩坑案例:某个团队给一个"发送邮件"的 Skill 写的 description 是 "发送消息给用户"。结果 AI 在用户说"帮我通知一下张总"的时候,触发了邮件发送——但用户其实想要的是在内部 IM 里发消息。
debug 了半天,最后发现根本不是代码问题,是 description 太模糊,AI 做了"合理但错误"的推断。
改成 "当用户明确要求发送电子邮件时使用,不适用于即时消息、短信或其他通信形式" 之后,问题消失了。
---
第三个差异:失败不是报错,是"对话继续"
这是三个差异里认知冲击最大的一个。
传统函数调用失败了,你知道该怎么处理:
try:
result = search_flight_api(departure, destination, date)
except FlightAPIException as e:
return {"error": e.message, "code": e.status_code}
返回错误码,调用方处理,流程终止或走 fallback 分支。干净,确定,可预期。
但在 Agent Skill 里,调用失败之后发生的事情,不是你控制的。
AI 可能会:
- 自动重试,换一组参数再试一次
- 换策略,改用另一个 Skill 来达到同样目的
- 向用户追问,"我查不到这个航班,你确认日期是对的吗?"
- 降级处理,告诉用户"暂时无法查询,建议你直接访问航空公司官网"
这些行为,都是 AI 根据上下文自主决策的,不是开发者写的 catch 块。
"失败不是报错,是对话继续。"
这句话意味着:你需要设计的不是 try-catch,而是失败后的语义预期。
具体来说,你要在 Skill 的设计里回答这些问题:
- 这个 Skill 失败了,AI 应该告诉用户什么?
- 有没有备用方案可以声明?
- 失败后继续追问用户,还是直接给出替代建议?
这要求开发者从"写程序逻辑"切换到"写 AI 行为预期"——你描述的是期望的结果,而不是实现的步骤。
---
三个差异,一张表扫完
| 维度 | 传统函数调用 | Agent Skill | | 触发方式 | 开发者写if 条件,显式触发,100% 确定性 | AI 根据上下文语义自主判断,开发者只声明能力 |
| 输入形态 | 类型明确的参数,边界清晰,缺失即报错 | 自然语言意图碎片,可能残缺、模糊、跨轮拼凑 |
| 失败处理 | 抛异常/返回错误码,调用方处理,流程可控 | AI 自主重试/换策略/追问用户,开发者设计语义预期 |
---
思维转变的本质:从命令式到声明式
这三个差异,指向同一个底层变化:
从命令式(告诉机器怎么做)→ 声明式(告诉机器能做什么)。这不是第一次有这种转变。SQL 就是声明式的——你告诉数据库"我要什么数据",不告诉它"怎么查"。React 的状态管理也是声明式的——你描述 UI 应该是什么样,不写 DOM 操作步骤。
Agent Skill 把这个思维延伸到了工具调用层面。你声明工具的能力边界,AI 负责编排调用。
但和 SQL、React 不同的是:Agent Skill 的"执行引擎"是一个语言模型,它的行为受 description 文本影响,而不是受语法规则约束。 这让"声明"本身变成了一门需要刻意练习的技能。
---
实操建议:在你的项目里做第一步迁移
如果你现在有一个用传统函数调用实现的 Agent,想迁移到 Agent Skill 思维,这里是三条可以立刻执行的建议:
第一条:把每个工具的 description 当成产品文档来写不要写"查询天气",要写"当用户询问某个城市当前或未来几天的天气状况时使用,支持城市名和地区名,不适用于历史天气查询"。多写 20 个字,能省掉很多莫名其妙的 debug 时间。
💡 想直接上手试?
如果你还没有 Perplexity API,或者想用更低成本跑通 Agent Skill 的完整链路,可以通过 [api.884819.xyz](https://api.884819.xyz) 接入——支持多模型统一调用,文中的 Demo 代码在这里可以直接跑,新用户注册即送体验 token,不用单独申请多个 Key。第二条:为每个 Skill 设计两条路径:成功路径和失败语义
成功路径是你平时就会想的。失败语义是大多数人忽略的:这个 Skill 失败了,AI 应该怎么向用户解释?有没有降级方案?把这个写进 description 或者系统提示里。
第三条:上线前做"意图测试",不只是"功能测试"传统测试:输入正确参数,验证输出。
Agent Skill 测试:输入模糊的自然语言,观察 AI 是否在正确时机触发了正确的 Skill,在不该触发时没有触发。
这种测试需要你准备一批"边界用例":什么情况下应该触发,什么情况下不应该,什么情况下应该追问用户。
---
一个最小可运行的 Demo
下面是一个完整的 Agent Skill 声明示例,可以直接接入支持 OpenAI Function Calling 格式的接口:
tools = [
{
"type": "function",
"function": {
"name": "search_flight",
"description": (
"当用户询问航班信息、机票价格、航班时刻表时使用。"
"用户可能只提供部分信息(如只说了目的地),此时可以主动追问出发地和日期。"
"不适用于火车、汽车等非航空出行方式的查询。"
),
"parameters": {
"type": "object",
"properties": {
"departure": {
"type": "string",
"description": "出发城市,如'北京''上海',不确定时可追问用户"
},
"destination": {
"type": "string",
"description": "目的地城市"
},
"date": {
"type": "string",
"description": "出行日期,格式 YYYY-MM-DD,支持'明天''下周五'等相对表达"
}
},
"required": ["departure", "destination"]
# date 不是必填,允许 AI 在日期未知时先触发,再追问
}
}
}
]
注意 date 没有放进 required——这是一个刻意的设计决策,允许 AI 在用户只说了出发地和目的地时就触发工具,然后在对话中追问日期,而不是强制用户一次性提供所有信息。
---
写在最后
这三个差异,其实只是 Agent 开发思维转变的第一层。
还有一个更难的问题我们没聊:当多个 Skill 同时被触发,AI 怎么决定执行顺序?开发者能干预吗?如果两个 Skill 的 description 出现了语义重叠,AI 会怎么选?
下一篇,我会拿一个真实的多 Skill 协作案例拆开来看——一个查航班、订酒店、规划行程三个 Skill 同时激活的场景,那才是 Agent 工程化真正烧脑的地方。
如果你看完这篇已经有了"想动手试试"的冲动,那就对了。先把你现有项目里的一个工具,重新写一版 description——你会发现,这件事比写代码难得多,也有趣得多。
---
本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。#AI开发 #AgentSkills #FunctionCalling #AI工程化 #Perplexity #8848AI #大模型应用 #AI教程