Function Calling 和 MCP 常被当作竞争关系,实际是两个层面的东西:前者是模型的原生能力(模型知道怎么"调用函数"),后者是生态的接入协议(函数从哪来、结果怎么回)。真正的选型题是:工具定义放在应用里,还是放到独立的服务进程里。
Function Calling:应用内一体化
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"schema": {...}
}
}]
resp = llm.chat(messages, tools=tools) # 工具定义随请求发送
result = execute(resp.tool_calls) # 应用自己执行
优点:零额外进程、延迟最低(无进程间通信)、全部逻辑在一处、调试直接看请求体。 适用:工具数量少(<20)、团队单一、工具与应用强耦合的业务逻辑。
短板:工具定义散落在各应用代码里,重复实现;换模型供应商时各家的 schema 细节差异要逐一适配;没有统一的生命周期管理。
MCP:独立服务化
工具从应用代码里剥离成独立 Server,应用通过协议消费:
优点:一次实现处处接入(Claude、IDE、自研 Agent 共用同一个 Server);语言无关(Server 用 Python,Host 用 Rust);进程隔离带来安全边界;生态复用——现成的 GitHub/数据库/浏览器 Server 拿来就用。 成本:多一层进程与协议开销;需要管理 Server 的启动、健康、权限;调试链路变长。
选型决策表
| 场景 | 建议 |
|---|---|
| 单应用、少量私有业务工具 | Function Calling,简单直接 |
| 工具需要被多个应用/团队复用 | MCP |
| 想直接用社区现成工具生态 | MCP(GitHub/Slack/DB Server 现成) |
| 极低延迟场景(流式对话中的工具) | Function Calling(省一跳) |
| 本地开发者工具(读文件、跑命令) | MCP(stdio 传输,天然本地化) |
混合才是常态
成熟的 Agent 系统通常两层并存:高频私有逻辑走 Function Calling 内联执行,通用能力(检索、代码执行、第三方 API)挂 MCP Server。模型不区分两者——它看到的都是"可调用的工具";差异只存在于应用的工程结构里。
一句话总结:Function Calling 决定模型能不能用工具,MCP 决定工具从哪里来。先有前者(能力),再长出后者(生态)——你的选型跟着工程结构走,而不是跟着新闻热度走。