一文搞懂 Function Calling、MCP、A2A 和 Skills
关注公众号,回复666,获取AI全路径学习资料
系列文章:
之前我们已经单独介绍了MCP、Fuction Calling、A2A乃至(Claude)Skills。
但是很多粉丝依旧觉得有些懵逼,我想了想原因,大概是单点知识不具备连贯性,要把他们完全搞懂,可能还是要从全局出发、从目的出发。
追本溯源,这个东西还是得从智能体(Agent)开始。因为,MCP、Fuction Calling、A2A 这三者与Agent直接相关,属于智能体与外界交互的三种方式:
Fuction Calling
首先是Fuction Calling,他是一种让大模型在推理过程中,能够主动选择并调用外部函数的能力:
具体的交互逻辑为:在对话中,LLM根据用户的问题(今天北京的天气如何?)判断是否需要调用函数。如果需要,它会输出一个结构化的JSON请求,其中包含了要调用的函数名和参数,然后再调用我们的程序:
具体的流程,直接看GPT官方的定义即可:
# 这是给模型看的工具定义,不是真正的代码
tools = [{
"type": "function",
"name": "get_weather",
"description": "Retrieves current weather for the given location.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and country e.g. Bogotá, Colombia"
},
......
},
}
}]
每次调用API时都需要传递tools参数,这里直接调用GPT接口(发起请求):
# 每次调用API时都需要传递tools参数,调用GPT接口发起请求
response = client.responses.create(
model="gpt-5",
messages=[...],
tools=tools # ← 这个每次都要带
)
这里也可以看出来,模型具有哪些工具调用能力,全部是我们预定义好的,模型会根据用户输入,选择使用哪个工具:
# 用户输入
user_query = "今天北京天气怎么样?"
# 模型会分析:
# - 用户问的是"天气" → 匹配到 get_weather 的 description
# - 提到了"北京" → 对应 location 参数
# - 决定调用 get_weather 函数
只不过,模型事实上并不会直接调用工具,他只会返回结构化的调用指令,这里返回这个东西是模型专门任务训练的结果:
{
"function_call": {
"name": "get_weather",
"arguments": "{\"location\": \"北京\", \"unit\": \"celsius\"}"
}
}
真正根据返回JSON数据调用脚本的是我们后台程序,并且这里需要将调用结果给到模型:
# 把天气结果返回给模型
# result是返回的结果
final_response = llm.chat(
model="gpt-5",
messages=[
{"role": "user", "content": "今天北京天气怎么样?"},
{"role": "assistant", "function_call": model_response["function_call"]},
{"role": "function", "name": "get_weather", "content": json.dumps(result)}
]
)
逻辑很清晰,如果意图识别没有工具(函数)调用,则直接调用大模型返回给用户,如果判断有工具调用,那么就拿着首次模型返回的参数,拿到结果后二次调用模型,再将最终结果返回给用户。
这里有几个点要特别注意:如果你的工具接口挂了,容错做得不好的话,那么模型就不会回答用户了。
另外还有几个问题,理解后几乎就能了解Fuction Calling的本质,乃至为什么他用得不太频繁的原因:
第一,如果Tools工具过多(数组过多),这个也是要占用上下文长度的,所以真实使用会做很多小处理;
第二,Fuction Calling 使用好坏非常依赖于模型本身对意图识别的能力,模型判断要不要调用一个函数,主要是根据description参数来的。这里看上去风险挺大的,因为一定会出现模型调用出问题的情况,只不过模型容错能力强,多拿了数据也未必会影响回答;
在这个基础下,我们再来说MCP:
MCP
Function Calling 本身没有问题,但频繁使用后会有很多痛点,比如:
不同基座模型都有类似Function Calling的概念,但具体叫法或者参数上可能有差异; 整个Tools预定义的过程,硬编码痕迹很重,但他其实比较适合注册机制; ...;
Function Calling解决的是:单个模型怎么“按你定义的 JSON 协议”去调你自己的API的问题。
而MCP就是为了解决这些问题而生的,所以MCP的但是其实是帮Function Calling “擦屁股”的...
MCP 是由 Anthropic 提出的一种开源协议,旨在标准化LLM与外部资源和工具的连接方式。可以把它想象成 AI 世界的 “USB标准” 或 “应用商店”。
只不过,这里有个非常关键的点要注意:
现在主流厂商大多都实现了各自的 Function Calling; MCP 目前主要是 Anthropic 这条线在推,是工具协议层;
换句话说就是:并不是所有模型厂商都跟进了MCP,如果基座模型没做,那么应用层就得自己套壳包装,如果不被支持的情况下,要使用MCP其实有两个前提:
第一是在模型侧需要用 Function Calling; 第二是在客户端自己把 MCP 工具转成 Function Calling 描述再喂给模型;
最直接的说法就是OpenAI就是不支持MCP,人家要自己玩,所以想用的话还得做个中间代理!
而我们会屈就的核心原因不是因为MCP本身很屌,而是社群一直在倒推基座模型厂商,现阶段由于社区活跃度,MCP的插件(Server端)已经很多了,如果我们想省事不想自己去做这个工具代码实现,那么就要做这个中间桥接层:
这里首先来个天气查询,Server端的伪代码:
start_mcp_server("weather-mcp-server"):
# 1)声明一个工具:get_weather
register_tool(
name = "get_weather",
description = "查询指定城市今天的天气情况",
input_schema = {
"type": "object",
"properties": {
"city": { "type": "string", "description": "城市名称,例如:Beijing" }
},
"required": ["city"]
},
output_schema = {
"type": "object",
"properties": {
"city": { "type": "string" },
"temperature": { "type": "number" },
"condition": { "type": "string" } # 晴、多云、小雨...
}
}
)
# 2)真正被调用时要做的事
on_tool_call("get_weather", args):
city = args.city
# 这里调用真实天气接口,或者你的内部系统
raw = http_get("https://api.weather.com", { "q": city })
return {
"city": city,
"temperature": raw.temp,
"condition": raw.text
}
Server端的代码我们其实是不关心的,这里写出来只是为了让大家更了解一点,我们需要关注的是Client端的配置,如果是OpenAI的话,需要将之匹配到桥阶层,有两件事要做:
调用天气 MCP Server,拉取工具定义; 把工具定义 转换成 OpenAI 的 tools(Function Calling)格式,并在模型发起 tool_call 时,代为转发给 MCP Server;
这里的代码就很简单了,几乎全部由MCP Server端完成了:
# 启动你的应用服务时:
# 1)创建 MCP Client,连接到天气 MCP Server
mcp_client = MCPClient.connect("weather-mcp-server")
# 2)从 Server 询问:你有哪些工具?
mcp_tools = mcp_client.list_tools()
# 例如返回:
# [
# {
# name: "get_weather",
# description: "查询指定城市今天的天气情况",
# input_schema: { ...上面的 JSON Schema... }
# }
# ]
接下来就是把 MCP 工具转成 OpenAI 的 tools:
# 3)把 MCP 的工具描述转换成 OpenAI 的 tools 数组
openai_tools = []
for each tool in mcp_tools:
openai_tools.append({
"type": "function",
"function": {
"name": tool.name, # "get_weather"
"description": tool.description, # "查询指定城市今天的天气情况"
"parameters": tool.input_schema # 直接复用或稍作转换
}
})
# 之后你在调用 OpenAI 时,就可以直接把 openai_tools 作为 tools 传入
再之后的流程跟Function Calling 很类似,我们这里就不赘述了。
A2A
到了 Agent to Agent 这里,情况马上变得简单又麻烦了,简单好像就是一次调用;麻烦的话是两个直接的通信可以很复杂,而且可控性得不到保障。
这里以之前的天气调用为例,基本的流程是模型 → 工具,到A2A这里就不这么完了,他需要模型 → 模型 → 工具。
而且在复杂场景下,这样做是有好处的,必定不同Agent擅长的方向不一样,对应着底层的提示词就不一样,单Agent的话因为任务简单也不会有Tools过多导致的问题:
为了更方便的说明,我们这里再举个例子:这里有两个Agent,一个天气Agent、一个旅游Agent,而旅游Agent需要天气情况。
他的触发词可能是:五一想去成都玩三天,要不要带厚一点的衣服?
在这个场景下会出现三个角色:
天气API:最底层天气查询API; 天气MCP:天气工具MCP Server服务,他最终会调用底层天气API,也会被天气Agent调用; 天气Agent:需要时候,他会调用天气MCP获得天气情况;
这里唯一的不同是天气Agent会对外暴露一个接口,输入是 城市 + 日期范围,输出一段天气(或者旅游建议)。
换句话说,天气Agent给出去的信息是自己根据天气信息,认为对面需要的跟天气相关信息,但未必是天气本身,其实将天气Agent当大模型调用就好
而具体的调用方式就比较原始了,又要回归最初的Function Calling了,将天气Agent对外释放的API,当成旅游Agent一个Tool,只是Agent的调用对参数要求没那么高,可以传更多的上下文:
{
"city": city,
"start_date": start_date,
"end_date": end_date,
"question": "是否适合旅游?要怎么穿衣?"
}
# 天气Agent返回
{
"summary": "五一期间成都气温 15–25℃,白天舒适,早晚偏凉。",
"advice": "白天薄长袖+长裤,晚上建议加一件外套。",
"risk": "5月2日有小雨,记得带雨伞。"
}
所以读到这里大家就很清晰了,真他嘛的AI名词多,其实全部是Function Calling!!!
最后我们说下Claude Skills:
Skills
Anthropic 对Skill的定义是:一个文件夹,里面装着说明文档、脚本和资源,Claude 在执行任务时会先扫一圈所有 Skills,觉得哪个对当前任务有用,就把完整内容拉进上下文来用。
我这边翻译翻译是:
Skill = 一份可反复调用的专业SOP+说明书,由模型自己按需加载
可以把 Skill 想成:给“AI 员工”写的一本 岗位说明书 + 培训手册;不用每次在 Prompt 里“从零复述”:
Skills长什么样?
每个Skill有一段非常短的描述(meta),比如:
品牌写作技能:教你如何按照 XX 公司品牌规范写公众号文章和活动文案。
Claude 在接到一个任务时,会先用这些 meta 做 “技能检索”:看看当前任务跟哪些 Skills 相关、只选命中的那几个;
最后,只有确认相关的 Skills,才会把完整的 instructions.md、例子、甚至附带脚本拉进上下文。
所以,你可以给模型装很多技能,上下文不会撑爆,他主打一个“按需加载”。
抽象一下,一个Skill看起来大概是这样(不是官方格式):
brand_style_skill/
meta.json # 很短的技能简介 & 什么时候用
instructions.md # 详细的写作规范、SOP、负面示例
examples/ # 正反例、few-shot 样本
scripts/ # 可选:比如检查用词的小脚本
assets/ # 品牌色、Logo 使用规范等资源
meta.json 里的东西会被优先加载:
{
"name": "brand_style_cn",
"description": "按照 XX 品牌规范撰写中文营销文案,保持语气、结构和禁用词一致。",
"good_for": [
"公众号推文",
"电商详情页",
"活动落地页"
]
}
当你说:帮我写一篇双十一活动主推文案,品牌是 XX。
Claude 在内部大致会做两件事:
看当前任务内容 → 觉得“品牌写作”相关; 在所有 Skills 的 meta 里找到 brand_style_cn → 决定:加载这个 Skill 的完整说明;
之后,Skill 里的各种“套路”就会生效,比如:
标题要包含的要素; 开头 100 字要解决什么问题; 哪些词属于品牌禁用词; 有哪些可复用的模块化段落结构; ...;
Skills的定位
上述的描述太孤立,所以在说明Skill的定位前,我们先总结一下:
Function Calling出现的目的是为了让模型在受控的自由下去调用第三方服务; 而后MCP是为了“偷懒”而生,核心主旨是让大家多创造插件生态(MCP Server); A2A的话反而跟前两者不是一个赛道,他属于复杂架构的拆解;
所以,A2A赛道不一样,就不参与后续讨论,我们这里回归最初的起点Function Calling,前面说过他有两个问题:
第一,Tools多了影响Token上下文,所以需要很多小策略;
第二,Function Calling的准确性很依赖于意图识别,如果调错了,会比较麻烦;
在这两点以外还有第三点:每次Function Calling的数据中途,我们都要处理工具返回数据,这其实挺烦的;
之前上述工作完全是我们自己手动处理的,但基座模型厂商可能觉得“他们也有责任”,所以Anthropic又提出了Skill概念,协助解决上述Function Calling一部分问题,比如:
Skill 主要关注数据如何用的问题,而其中按需加载的部分是值得Function Calling参考的策略
从关系上说是这么回事:
Function Calling / MCP 提供“手”,Skills 提供“干这类活的整套套路”,两者是“上下游”的关系
Skills 可以内部用 Function Calling 和 MCP,Function Calling/MCP 不知道什么叫 Skill
Skills = 业务服务 + 调用这些接口的代码 + 使用说明
为了让大家理解的更清晰,我们这里加个说明:
流程说明
在一个老板 BI Agent里配置了,一批 Tools/MCP 工具:
get_sales_report get_marketing_spend get_cashflow_status
两个 Skills:
boss_bi_dashboard_cn:教模型如何用上面几个工具,按老板视角解释数字、写结论,里面有详细的 KPI 口径、话术、注意事项; excel_analysis_skill:教模型如何用 code execution 对上传的 Excel 做分析;
这时候触发条件来了:帮我看看今年 Q3 的营收和投放,简单说说是不是该收一收预算?这里具体的流程是:
一、先走Skill检索
模型首先会理解,这是一个老板视角的财务分析 + 决策建议,接下来模型会遍历Skills里所有的meta,发现 boss_bi_dashboard_cn 的描述里有类似:
用于解读公司经营指标、营收、成本、预算,输出老板视角决策建议
所以它会激活这个 Skill,读取 instructions.md,把这份“说明书 + SOP”拉进当前上下文。此时,Tools/MCP 还没被调用,模型完成了:从很多工具定义 + 一堆 Skills里,选出一个最合适的技能包。
二、Skill里面决定工具调用
boss_bi_dashboard_cn 的 instructions.md 可能会写类似这样的话:
如果用户问的是某个时间段的“营收 + 投放”,
先调用 get_sales_report 拿营收数据,
再调用 get_marketing_spend 拿投放数据;
然后根据「同比 / 环比 / ROAS」给出老板能看懂的判断;
输出结论时,要用以下结构:
一句话结论
2–3 个关键数字
建议动作
风险提示
Claude 读了这份说明后,就知道下一步应该:
先查 KPI → 需要工具; 然后就是具体工具调用:
get_sales_report({"period": "2024-Q3"})
get_marketing_spend({"period": "2024-Q3"})
到这里Function Calling / MCP 出场了。
三、数据处理 + SOP
这里走Function Calling的逻辑拿到最终反馈数据即可(这里不展开):
{
"sales": 12345678,
"growth_rate": 0.12,
"gross_margin": 0.31
}
然后就是数据使用,这个instructions.md里面已经说得很清楚了:
输出结构怎么写;
哪些数字要重点强调;
语气要偏老板视角,少讲实现,多讲结论和动作;
有哪些“常见坑”要避开;
# 输出案例
结论:Q3 的营收仍在增长,但投放效率明显走低,建议适度收缩预算、把钱放到 ROAS 更高的渠道上。
......
后面是建议 + 风险......
从这里看就比较清晰了,Skills在意图识别和数据使用上做了不少工作。
结语
从最基础的 Function Calling,到旨在统一工具的 MCP,再到实现复杂协作的 A2A,乃至封装业务逻辑的 Skills,这一系列令人蛋疼的名词,其演进脉络始终清晰:它们为AI智能体更好与现实世界交互而生:
Function Calling 是底层原子能力,是弥合用户无限意图与模型与现实交互的基础; MCP 做的是“工具/数据的统一协议 + 生态”,方便别人写好一个 Server,更多客户端直接复用,而不是一个个项目 copy 粘贴; A2A 不是“更高级的 Function Calling”,而是“系统怎么拆成一群 Agent,并用结构化方式彼此调用”的架构问题; Skills 也不是来抢工具活的,而是帮你沉淀“怎么用工具 + 怎么用数据”的那套 SOP;
理了一圈后,就发现这些名词其实没那么玄乎,其实依旧是模型 + 工具 + 数据 + 说明书这套组合。
好了,篇幅不小了,希望这篇文章对大家有用!
点击上方卡片关注叶小钗公众号,查看下方二维码,添加我个人微信:
往期推荐
《LangChain、 Dify、 n8n、 Coze:四大AI框架怎么选?》