Function Calling 与 MCP 深度对比:从原理到实践,一文讲透区别与关系
Function Calling 与 MCP 深度对比:从原理到实践,一文讲透区别与关系
一、问题场景
“我用 Claude API 的 Tool Use 功能已经很顺手了,为什么还要学 MCP?”
“Function Calling 和 MCP 到底是什么关系?它们是竞争还是互补?”
“团队要统一 AI 工具调用方案,应该选 Function Calling 还是 MCP?”
这三个问题,是近半年来我被问得最多的问题。很多开发者在接触 MCP(Model Context Protocol)之后,第一反应是困惑——Anthropic 不是已经有 Tool Use 了吗?OpenAI 不是已经有 Function Calling 了吗?为什么又冒出来一个 MCP?
本文将从三个维度彻底讲清楚这个问题:
- 概念层:Function Calling 和 MCP 各自是什么?解决什么问题?
- 关系层:它们在不同层面的分工——就像 HTTP 和 Web 应用的关系
- 实战层:同一个工具分别用 Function Calling 和 MCP 实现,直观对比差异
读完这篇文章,你不仅能清晰理解两者的关系,还能知道在实际项目中如何选型和组合使用。
二、原理分析
2.1 Function Calling 是什么?
Function Calling 是大模型的原生能力,让模型能够识别用户意图并决定"我应该调用哪个函数"。
当用户问"北京今天天气怎么样?",模型本身不知道实时天气。但如果你定义了一个 get_weather 函数并告诉模型,模型就能推断出需要调用这个函数,并生成调用参数 {“city”: “北京”}。
各家厂商的 Function Calling 实现:
| 厂商 | 名称 | 定义格式 |
|---|---|---|
| OpenAI | Function Calling / Tools | JSON Schema |
| Anthropic | Tool Use | JSON Schema(input_schema) |
| Function Declaration | OpenAPI / JSON Schema |
核心流程(以 Claude Tool Use 为例):
① 开发者定义 Tool 描述(名称 + 描述 + JSON Schema) ② 将 Tool 定义随请求一起发送给模型 ③ 模型推理后返回 tool_use 块(含函数名和参数) ④ 开发者在自己的代码中执行函数 ⑤ 将执行结果以 tool_result 块返回给模型 ⑥ 模型基于结果生成最终自然语言回复关键点:Function Calling 只负责"决定调用什么 + 生成调用参数",不负责执行。函数执行完全由开发者的代码完成。
2.2 MCP 是什么?
MCP(Model Context Protocol)是协议标准,定义了 AI 应用与外部工具/数据源之间的通信方式。
MCP 采用 Client-Server 架构:
- MCP Client:AI 应用端(Claude Desktop、Cursor、你的应用)
- MCP Server:工具提供端(你开发的工具服务)
- 通信协议:JSON-RPC 2.0,通过 stdio 或 HTTP+SSE 传输
MCP 定义了三种 Server 能力(原语):
- Tools:可执行的函数,模型可以调用
- Resources:可读取的数据,作为模型推理的上下文
- Prompts:预定义的提示词模板
MCP 的核心价值:一次编写,到处使用。你写的 MCP Server 可以被 Claude Desktop、Cursor、Continue 等所有支持 MCP 的 Client 使用,无需为每个平台适配。
2.3 核心区别:不同层面的东西
Function Calling 和 MCP 不是竞争关系,它们在不同的抽象层面工作:
┌──────────────────────────────────────────┐ │ 用户问题 │ │ "北京今天天气怎么样?" │ ├──────────────────────────────────────────┤ │ AI 模型(Claude / GPT) │ │ ┌────────────────────────────────┐ │ │ │ Function Calling / Tool Use │ │ ← 模型能力层 │ │ "我需要调用 get_weather" │ │ │ └────────────────────────────────┘ │ ├──────────────────────────────────────────┤ │ MCP 协议层 │ ← 协议标准层 │ Client → tools/call → Server │ ├──────────────────────────────────────────┤ │ MCP Server │ ← 工具实现层 │ def get_weather(city): ... │ └──────────────────────────────────────────┘类比理解:
| 类比 | 对应关系 |
|---|---|
| Function Calling = 汽车的"方向盘" | 模型通过它来操控外部工具 |
| MCP = 汽车的"方向盘接口标准" | 确保任何车都能用同一套方向盘 |
| 你的 Tool 实现 = 具体的"转向系统" | 接收方向盘指令并执行 |
Function Calling 是模型的大脑(决定做什么),MCP 是神经系统(怎么传递信号),Tool 实现是手脚(实际执行)。
2.4 一张表讲清所有区别
| 维度 | Function Calling | MCP |
|---|---|---|
| 本质 | 模型能力 | 通信协议 |
| 层级 | 应用层(模型推理) | 传输层(Client-Server 通信) |
| 标准化 | 各家私有格式 | 开放协议标准(JSON-RPC 2.0) |
| 谁实现 | AI 厂商(OpenAI/Anthropic/Google) | 任何人(开源社区 + 你) |
| 作用范围 | 单次 API 调用内 | 跨应用、跨平台、跨模型 |
| 执行方式 | 开发者代码自己执行函数 | MCP Client 自动调度执行 |
| 可复用性 | 绑定特定模型 API | 编写一次,到处使用 |
| 工具发现 | 每次请求手动传入 | Client 自动发现(tools/list) |
| 生命周期 | 单次请求-响应 | 持久化进程/服务 |
| 典型场景 | 在代码中调用模型并处理 Tool | 构建可被多个 AI 应用共享的工具生态 |
2.5 它们的关系:互补而非替代
MCP 离不开 Function Calling:
MCP 本身只是定义了"如何发现和调用工具",但"决定调用哪个工具"这个智能推理步骤,仍然需要模型的 Function Calling 能力。MCP 解决的是"管道"问题,Function Calling 解决的是"判断"问题。
Function Calling 离不开 MCP(的好处):
没有 MCP 时,用 Function Calling 搭建工具体系是这样的:
- 写 Tool 定义(JSON Schema)
- 写 Tool 执行逻辑
- 每次 API 调用时手动传入 Tool 定义
- 在回调中手动匹配 tool_use 并执行
有 MCP 后变成:
- 写一次 MCP Server
- 所有支持 MCP 的应用直接使用
- 无需手动传入 Tool 定义(Client 自动发现)
- 无需手动执行回调(Client 自动调度)
一句话总结:MCP 是 Function Calling 的"工程化基础设施"——它让 Function Calling 变得标准化、可复用、跨平台。
三、实践验证
用一个具体的天气查询工具,分别用纯 Function Calling 和 MCP Server 两种方式实现,直观对比差异。
3.1 方式一:纯 Function Calling(Claude API)
""" 纯 Function Calling 方式 —— 所有逻辑写在一个文件里 每次调用都要手动传入 Tool 定义 + 手动执行回调 """fromanthropicimportAnthropic client=Anthropic()# 1. 定义 Tooltools=[{"name":"get_weather","description":"获取指定城市的天气信息","input_schema":{"type":"object","properties":{"city":{"type":"string","description":"城市名称"}},"required":["city"]}}]# 2. 定义执行函数(和 Tool 定义分离)defget_weather(city:str)->dict:# 模拟天气查询return{"city":city,"temp":25,"condition":"晴"}# 3. 发起请求response=client.messages.create(model="claude-sonnet-4-6",max_tokens=1024,tools=tools,# 每次请求都要传messages=[{"role":"user","content":"北京天气怎么样?"}])# 4. 手动处理 tool_use 回调ifresponse.stop_reason=="tool_use":forblockinresponse.content:ifblock.type=="tool_use":ifblock.name=="get_weather":city=block.input["city"]result=get_weather(city)# 5. 手动发送 tool_resultresponse=client.messages.create(model="claude-sonnet-4-6",max_tokens=1024,tools=tools,# 又要传一遍messages=[{"role":"user","content":"北京天气怎么样?"},{"role":"assistant","content":[block]},{"role":"user","content":[{"type":"tool_result","tool_use_id":block.id,"content":str(result)}]}])print(response.content[0].text)痛点:
- Tool 定义和执行逻辑分离,维护时容易不同步
- 每次 API 调用都要传 tools 参数(浪费 Token)
- tool_use 回调需要手动匹配和处理
- 换个应用(如 Cursor)就得重写一遍
3.2 方式二:MCP Server(工具定义 + 执行一体化)
server.py
""" MCP Server 方式 —— 工具定义和执行逻辑内聚在一起 一次编写,Claude Desktop、Cursor、Continue 等都能直接用 """importjsonfrommcp.serverimportServerfrommcp.server.stdioimportstdio_server server=Server("weather-server")# Tool 定义和执行逻辑在一起,内聚且同步@server.list_tools()asyncdefhandle_list_tools():return[{"name":"get_weather","description":"获取指定城市的天气信息,包括温度和天气状况","inputSchema":{"type":"object","properties":{"city":{"type":"string","description":"城市名称"}},"required":["city"]}}]@server.call_tool()asyncdefhandle_call_tool(name:str,arguments:dict):ifname=="get_weather":city=arguments["city"]result={"city":city,"temp":25,"condition":"晴"}return[{"type":"text","text":json.dumps(result,ensure_ascii=False)}]asyncdefmain():asyncwithstdio_server()as(read_stream,write_stream):awaitserver.run(read_stream,write_stream,server.create_initialization_options())if__name__=="__main__":importasyncio asyncio.run(main())Claude Desktop 配置:
{"mcpServers":{"weather-server":{"command":"python","args":["C:/path/to/server.py"]}}}优势:
- Tool 定义和实现在一起,修改时不会遗漏
- Client 通过 tools/list 自动发现,Token 零开销
- tool_use 回调由 MCP Client 自动调度
- 一次编写,跨应用复用
3.3 对比总结
| 方面 | 纯 Function Calling | MCP Server |
|---|---|---|
| 代码量 | ~50 行(含回调处理) | ~30 行 |
| Tool 定义与实现 | 分离,易不同步 | 内聚,同步更新 |
| 跨应用复用 | 每次重写 | 一次编写到处使用 |
| Token 开销 | 每次请求传 tools | 零(自动发现) |
| 回调处理 | 手动匹配 | 自动调度 |
| 部署 | 代码内嵌 | 独立进程/服务 |
面试加分点:
- Function Calling 是模型能力,MCP 是协议标准,两者在不同抽象层
- MCP 的 stdio Transport 天然隔离,无需处理端口冲突
- tools/list 实现工具发现,避免了每次请求手动传入
- MCP 生态已有 1000+ 开源 Server,可以不用重复造轮子
- MCP 支持 Tool/Resource/Prompt 三种原语,比纯 Function Calling 覆盖更多场景
四、选型指南
4.1 什么时候用纯 Function Calling?
- 只有 1-2 个简单工具,不值得起一个 MCP Server
- 一次性的原型验证
- 工具逻辑和业务代码强耦合
- 不需要跨应用复用
4.2 什么时候用 MCP?
- 工具有多个使用场景/应用
- 工具逻辑复杂,值得独立维护
- 团队协作(工具可共享给同事)
- 需要工具发现和动态注册能力
- 构建企业内部工具体系
4.3 最佳实践:两者结合
在生产环境中,推荐架构是:
┌─────────────────────┐ │ 你的 AI 应用 │ │ (Claude API 调用) │ ← Function Calling 做推理 ├─────────────────────┤ │ MCP Client SDK │ ← MCP 做通信 ├─────────────────────┤ │ 企业 MCP Server │ │ ┌─────┐ ┌─────┐ │ │ │用户API│ │订单API│ │ ← 业务工具实现 │ └─────┘ └─────┘ │ └─────────────────────┘模型用 Function Calling 决定"该查什么",MCP 负责把请求路由到正确的 Server 并执行,两者各司其职。
五、总结
Function Calling 和 MCP 的关系可以用一句话概括:Function Calling 是模型的"决策大脑",MCP 是工具的"通信高速公路"。
它们不是竞争关系,而是不同层面的互补。Function Calling 回答"该做什么",MCP 回答"怎么做到"。
推荐学习路径:
- 先用 Function Calling 跑通一个 API 调用,理解模型如何决定调用工具
- 把同一个工具改写为 MCP Server,体验一次编写到处使用的便利
- 探索 MCP 生态,在 github.com/modelcontextprotocol/servers 学习优秀实践
- 构建企业的 MCP 工具体系,让所有 AI 应用共享同一套工具基础设施
延伸阅读:
- Anthropic Tool Use 文档
- MCP 官方规范
- MCP Python SDK
- OpenAI Function Calling 文档
理解这两者的关系,你就站在了 LLM 应用开发的最前沿。
