一句话区别:Function Calling 解决"模型怎么表达它想调用某个工具",MCP 解决"工具从哪来、怎么被发现、怎么跨应用复用"。两者不是替代关系,而是上下游——MCP 负责把工具标准化地暴露出来,客户端再把这些工具翻译成各家模型能理解的 Function Calling 格式送进去。

所以真正的问题不是"选哪个",而是"你现在卡在哪一层"。工具只给自己写的一个脚本用,直接用 Function Calling 就够了;工具要在多个客户端之间复用,才需要引 MCP 这层协议。
本文先讲清两者的分工边界,再给一个能跑起来的最小落地示例,最后列出四个高频失败分支与验证办法。
先看结论
只接一个模型、工具列表固定不变 → 用 Function Calling,代码最少。一次工具调用要经过"声明工具、模型表达意图、执行、回传"四步,Function Calling 只规范了第二步。工具要跨多个客户端复用,或者除了函数还想给模型提供数据资源与提示词模板 → 用 MCP 协议。
一个容易忽略的事实:用了 MCP 之后,Function Calling 并没有消失,它仍在底层工作。MCP server 暴露工具,客户端负责把它们翻译成当前模型的工具调用 schema,模型返回的调用请求再回到 server 执行。这两层各管一段。
协议细节想对照原文看的,可以翻 MCP 协议文档 一节一节核。
一、先分清两层:谁负责什么
把一次工具调用拆开看,链路是这样的:
用户提问 → 客户端把工具列表塞进请求 → 模型输出调用意图 → 客户端执行工具 → 结果回传模型 → 模型作答
Function Calling 管的是中间那一步"模型输出调用意图"的格式:模型不再返回一段自然语言,而是返回一个带函数名和参数的结构化对象。
MCP 管的是两端:工具列表怎么被客户端发现(服务端声明),以及工具怎么被执行(服务端实现)。
| 维度 | Function Calling | MCP 协议 |
|---|---|---|
| 解决的问题 | 模型如何表达调用意图 | 工具如何被发现与复用 |
| 规范归属 | 各模型厂商自定 | 开放协议,跨厂商 |
| 是否跨客户端复用 | 否,换模型要改代码 | 是,一次实现多处接入 |
| 除函数外还能提供 | 通常没有 | 资源、提示词模板 |
| 引入成本 | 低 | 中,需跑一个服务端 |
理解这张表,选型就清楚了:Function Calling 是能力,MCP 是管道。

二、Function Calling:最小可用形态
先看不用 MCP 时,工具调用长什么样。
import json
from openai import OpenAI
TOOLS = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
client = OpenAI()
def run(question: str) -> str:
messages = [{"role": "user", "content": question}]
resp = client.chat.completions.create(
model="gpt-4o-mini", messages=messages, tools=TOOLS
)
msg = resp.choices[0].message
if not msg.tool_calls:
return msg.content
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = {"city": args["city"], "temp": 26, "unit": "C"}
messages.append(msg)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result, ensure_ascii=False),
})
final = client.chat.completions.create(model="gpt-4o-mini", messages=messages)
return final.choices[0].message.content
这段代码做的是:声明一个工具的 JSON Schema 传给模型;如果模型返回了调用请求,就解析参数、执行本地函数、把结果作为 tool 角色消息追加回对话;最后再请求一次拿到最终回答。
这段代码的局限也很明显:工具定义写死在业务代码里,换个模型要改 schema 细节,换个应用要重写一遍。这正是 MCP 要解决的接入方式问题。
三、MCP:把工具变成可复用的服务
MCP 把工具从业务代码里搬到一个独立进程,用统一协议对外声明。
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather")
@mcp.tool()
def get_weather(city: str) -> dict:
"""查询指定城市的当前天气"""
return {"city": city, "temp": 26, "unit": "C"}
if __name__ == "__main__":
mcp.run(transport="stdio")
这段做的是:创建一个 MCP 服务端,用装饰器把一个普通 Python 函数注册成工具,函数签名与文档字符串会自动转成工具描述,最后以 stdio 方式启动。客户端连接后就能拿到工具列表并调用它。
好处是同一个服务端可以被不同客户端接入——桌面应用、编辑器插件、你自己写的脚本都能连。工具只写一次。
代价也要说清:
- 多一个进程要维护,调试链路变长;
- 工具数量会挤占上下文,几十个工具的 schema 加起来很可观;
- 协议本身不解决鉴权与审计,谁能在什么范围内调用,仍要自己在服务端实现。

四、四个失败分支与验证清单
4.1 失败分支一:模型返回的参数过不了 schema 校验
模型有时会漏字段或类型不对。修复办法是在执行前用校验库过一遍,失败时把错误信息作为工具结果回传,让模型自己纠正——这比直接抛异常有效得多。
from pydantic import BaseModel, ValidationError
class WeatherArgs(BaseModel):
city: str
def safe_call(raw: dict) -> str:
try:
args = WeatherArgs(**raw)
except ValidationError as exc:
return f"参数不合法,请修正后重试:{exc.errors()}"
return json.dumps(get_weather(args.city), ensure_ascii=False)
这段做的是:用数据模型校验入参,校验失败时把具体错误作为字符串返回给模型,让它自行修正。预期结果(未在本机执行,依据 pydantic 的标准行为)是缺字段时返回可读错误而不是崩掉。
4.2 失败分支二:工具名冲突
多个 MCP 服务端提供同名工具时,客户端无法区分。修复办法是给工具名加前缀命名空间,并在接入前列出全部工具名检查一遍。
4.3 失败分支三:一次工具调用超时卡住整条链路
外部接口慢会让整条链路挂住。修复办法是在服务端实现里设超时并返回明确错误,让模型知道这次调用没成功,而不是无限等待。
4.4 验证清单
- 检查:
mcp.run()启动后客户端能否列出工具 - 检查:工具描述里是否写清了用途与参数含义
- 运行:问一个必须调用工具才能回答的问题
- 预期:模型返回调用请求,工具执行后给出最终答案
- 失败:模型不调用工具 → 描述写得不够具体,补清用途与边界
- 失败:执行报错 → 先单独运行函数本身,确认与协议无关
- 修复:调整描述或补参数校验后重新连接
- 验证:连续问三个不同问题,确认工具调用稳定触发
总结
MCP 和 Function Calling 是上下游而非二选一:Function Calling 让模型会表达调用意图,MCP 让工具能被发现、被复用。工具只在一个应用里用就直接 Function Calling,需要跨客户端复用再上 MCP,别为了用协议而用协议。
三条要点带走:
- 用了 MCP 之后 Function Calling 仍在底层工作,两层各管一段;
- 工具描述决定模型会不会调用,写清用途比写清参数更重要;
- 参数校验失败时把错误回传给模型,比抛异常更能自我纠正。
下一步建议先用 Function Calling 跑通一个工具,把链路摸清之后再迁到 MCP 服务端。配置细节记不住时,翻 IDE 配置 MCP 教程 最快。
常见问题
Q:有了 MCP 还需要 Function Calling 吗?
A:需要。MCP 负责工具从哪来,Function Calling 负责模型怎么表达调用意图,客户端会把 MCP 的工具翻译成模型的调用格式。
Q:只有两三个工具,值得上 MCP 吗?
A:如果只在一个应用里用,直接用 Function Calling 更省事。工具需要在多个客户端之间复用时才体现出 MCP 的价值。
Q:MCP 协议能解决权限和安全问题吗?
A:协议本身不解决。服务端跑在你自己的环境里,谁能调用、能访问哪些数据,仍要在服务端自己实现鉴权与审计。
Q:工具越加越多会有什么后果?
A:工具 Schema 会占满上下文,模型选择工具的准确率也会下降。建议按场景分组接入,同一时刻只暴露必要的那几个。
延伸学习
想把工具调用这块补齐,可以按这个顺序来:
- 读一篇相关笔记 Function Calling 笔记,把模型调用外部工具的机制弄清;
- 想动手练,AI 开发实战课程 是边学边写的形式;
- 想看另一个客户端怎么接,可以看 Claude Code 接 MCP。

TRAE-AI编程



