可能你们也发现了,很多人都会把 Function Call 和 MCP 放在一起讲。但是讲着讲着,噼里啪啦一堆信息,看完之后大家虽然知道这两个东西是什么,却很难理解它们之间到底是什么关系,更不知道为什么要放在一起讲。
所以今天我想换一种方式,从技术演进的角度出发,看看为什么必须先从 Function Call 讲起,以及 Function Call 是怎么一步步发展到 MCP 的。
2023 年,OpenAI 在第一届 DevDay 上发布了新的开发接口能力:Assistants API 。
它的目标很明确:帮助开发者更容易地在自己的应用中构建基于大语言模型的 AI 助理。这个 API 最初集成了三个核心工具:
- 文件搜索(File Search) :支持模型检索用户上传的文档内容;
- 代码解释器(Code Interpreter) :让模型可以执行代码、分析数据、画图表等等;
- 函数调用(Function Call) :也就是今天的重点之一,让模型可以调用开发者定义的函数,执行各种任务,比如系统集成、自动化操作、调用外部 API 等。
这三个工具集成在一起,让 OpenAI 从一个聊天机器人平台,变成了一个真正能构建智能、灵活、可扩展 AI 应用的强大平台。

那openai为什么非得让模型"调用工具"?那肯定是为了解决实际的问题。我们来看一下当时大语言模型在应用中面临的几个关键限制:
第一个问题:没法访问实时信息。
语言模型是靠提前训练好的静态数据来学习的,也就是说,它不知道现在的天气、今天的新闻、股市的最新行情......这些实时的数据它根本没法获取。
第二个问题:不能主动操作系统。
你以前用模型写代码,是不是这样的流程:你提问、模型生成代码、你复制粘贴到 IDE、跑出来报错、你又把错误贴回去继续问......
整个过程中,模型其实啥也没"动手做",它只是一直在"纸上谈兵"。
第三个问题:缺乏结构化输出能力。
大模型生成的是自然语言,也就是非结构化文本。你要让它往表格里填数据、往数据库里塞内容,或者满足特定格式,往往就得写各种正则表达式、设计很复杂的 prompt ------ 又麻烦、又不稳定。
为了解决这些问题,OpenAI 引入了 Function Call(函数调用) 的机制。
这个机制的引入,让大语言模型从一个"只会聊天的助理",变成了一个能实际动手做事的智能体。它不再只是理解和生成自然语言,而是能和外部系统协作,执行真正的任务,大大提升了 AI 在实际应用中的实用性和智能化水平。

这个表非常直观地展示了 有无 Function Call 的差别,我们一起来看一下。
首先,第一个实时数据访问 。
以前模型是无法获取实时信息
但引入 Function Call 后,我们可以通过调用外部 API,让模型实时访问这些数据,能力一下子上了一个台阶。
第二个是 执行实际操作 。
原来模型不能主动去"动手",没法真正完成一个闭环任务。
有了 Function Call,模型就能调用你预设的函数,比如让它发邮件、查数据库、调用机器人动作......这些事它都可以自己搞定。
第三点 输出结构化数据 。
没有 Function Call 的时候,模型输出的是自然语言,这种非结构化的文本你要喂进系统还得二次解析,非常麻烦。
但 Function Call 能让模型直接生成 JSON 这种结构化格式,清晰、标准、易于处理,特别适合对接数据库、系统接口、表单等各种业务场景。
现在我们已经知道什么是function call,为什么要有function call了,那function call 是怎么起作用的呢
简单来说,Function Call(函数调用) 就是让大模型在理解用户意图后,能够主动调用预先定义好的函数,去获取数据或完成实际操作。
用openai官方原图讲解一下:

我们假设,现在想让模型能够实时回答我们天气问题。那就需要模型能调用获取天气的工具。所以我们应该给模型提供好获取天气的工具。
-
定义函数的 Call model
普通用户肯定不会给模型工具,所以这是在用户使用之前,由开发人员完成的。
pyimport requests def get_weather(latitude, longitude): response = requests.get(f"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}¤t=temperature_2m,wind_speed_10m&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m") data = response.json() return data['current']['temperature_2m']
开发人员要先确定需要调用哪些外部工具。在获取天气这个例子里就是定义了一个
get_weather
的函数,用来获取天气信息。这一步是大模型之外的东西,和模型无关。接下来,开发人员会根据业务需求,会用一种叫 JSON Schema 的格式给模型预定义好函数,明确每个参数的名字、类型、说明等等。这一步开发人员需要把刚才那些外部工具列好清单,并"告诉"模型怎么用这些工具。
pyfrom openai import OpenAI import json client = OpenAI() tools = [{ "type": "function", "name": "get_weather", "description": "Get current temperature for provided coordinates in celsius.", "parameters": { "type": "object", "properties": { "latitude": {"type": "number"}, "longitude": {"type": "number"} }, "required": ["latitude", "longitude"], "additionalProperties": False }, "strict": True }] input_messages = [{"role": "user", "content": "What's the weather like in Paris today?"}] response = client.responses.create( model="gpt-4.1", input=input_messages, tools=tools, )
-
到了用户真正使用的时候,也就是图中的第1步,用户会给模型发消息。
但同时,预定义好的函数列表也会一起发给模型。换句话说,模型拿到的输入是两部分组成的:
一部分是用户的自然语言请求,另一部分是已经设定好的可以调用的函数列表。
-
模型拿到这些信息之后,会理解用户提问的意图,看有没有需要用到某个工具,该用哪个工具、怎么调用。
比如在这个例子中,模型判断用户是在问天气,于是决定调用 get_weather 这个函数。
py[{ "type": "function_call", "id": "fc_12345xyz", "call_id": "call_12345xyz", "name": "get_weather", "arguments": "{\"latitude\":48.8566,\"longitude\":2.3522}" }]
-
到了第③步,就该真正去执行这个函数了,也就是调用外部的 get_weather,拿到结果。这一步是模型之外的外部系统自己调用的。
pytool_call = response.output[0] args = json.loads(tool_call.arguments) result = get_weather(args["latitude"], args["longitude"])
-
然后就是第④步,把刚才外部系统执行的结果,加上前面模型第二步回答的信息,一起返回给模型,模型根据这个输入生成最终的回复。
在没有 Function Call 的时代,我们用大模型的方式是这样的:
👉 用户的问题直接作为 prompt 喂给模型,让它生成答案。
但现在有了 Function Call,变成了:
👉 把用户的问题 + 工具列表 组合成一个结构化的 prompt,一起送给模型。模型判断是不是该用工具,再决定怎么用。
你可能会问:"说这么复杂,不就是让模型会自己选调用函数吗,那我们为什么不用提示词工程直接教模型怎么选工具,不就行了吗?"
其实一开始大家确实是用提示词(prompt engineering)来"硬教"模型怎么选工具的,比如通过 few-shot 的例子告诉模型:
如果用户说"查天气",你就调用 get_weather;
用户说"订酒店",你就调用 book_hotel。
但是这么做有几个非常大的问题:
❶ 没有标准格式,模型难以泛化
每个开发者定义工具的方式都不一样:
参数怎么传?结果怎么返回?用什么关键词触发?全靠自己规定。
模型面对这些"非统一格式"的工具,根本无法稳定理解和调用。
❷ 不能作为训练数据系统性学习
提示词是写死的,是人类"教"的,模型没法从海量调用中去学习"工具是什么""怎么选""怎么调用"。
但 Function Call 的设计就不同,它有统一的 JSON Schema 标准格式,结构化地告诉模型每个工具的参数、类型、说明是什么,模型可以拿这个去训练、去学习。
❸ 无法自动执行和结构化交互
即便模型猜对了工具,也还是只生成一段自然语言,不具备真正的结构化调用能力。
而 Function Call 返回的是规范的结构数据(比如 JSON),不仅便于系统执行,还能自动调用真正的函数接口,形成闭环。
所以说,Function Call 不是为了"让 prompt 更好写",
而是从根本上让模型和工具之间建立一套"通用语言"和"标准接口",让模型能可靠、稳定地与外部系统交互。
你可以理解为:
🧠 Function Call 是"教模型自己学会怎么选工具,并且能真正用起来"。
大模型在这里不是在"看提示词",而是在"学协议",是要具备长期理解和调用能力的。这种统一格式,才是让模型能力真正"落地"的关键。

有没有发现什么问题?
OpenAI作为行业标杆,Function Call 机制最早由 OpenAI 提出,但是他没有牵头把 Function Call 作为一个开放标准推广。
这就导致了其他厂商可以选择用,也可以自己定义,比如你叫Functioncall我可以叫tooluse。函数参数的 JSON 格式、调用方式、错误处理机制都不统一。每家模型厂商各搞一套,缺乏通用性。
💥 开发者的痛点来了:
• 如果我今天接的是 GPT-4 明天想接 Claude、Gemini、Yi-1.5,怎么办?
• 它们的工具调用接口各不相同,那我的程序就要重新适配每一个模型的 Function Call 协议。
• 这不仅增加了开发成本,还严重影响了大模型在实际工程中的通用性。
这时候,Anthropic像你伸出援手,Anthropic说不订标准是吧,你不订我来定。 MCP就出现了
说个题外话,Anthropic发家史,OpenAI研究部门副总裁叫达里奥·阿莫迪,安全政策部门副总裁叫丹妮拉·阿莫迪,都姓阿莫迪,没错他俩是兄妹。随着gpt系列的发展,这俩兄妹觉得openai已经在堆算力了,就是模型结构简单,只要算力足够大训练足够多就可以效果好,已经失去了算法的魅力了。然后他俩就离职创业去了,顺带拐走了openai 7 个高级员工,一起创立了Anthropic,研发了现在同样大名鼎鼎的claude。
MCP 让工具调用有统一语言
MCP(Model Component Protocol) 是一种为大语言模型(LLM)设计的通用接口协议,目标是:
📦 让不同模型之间调用"工具"或"组件"时的格式统一起来。
大家都知道,电脑需要连接各种外设 ,比如打印机、摄像头、U盘等等。在没有统一接口标准的时代,每个设备都有自己的接口和驱动程序,连接起来既复杂又麻烦。但后来,USB-C 的出现解决了这个问题,它提供了一个标准化的接口,几乎所有设备都能通过这个接口连接和通信,简单又高效。
那么,MCP 在 AI 世界里的作用,就像是 USB-C 接口一样,提供了一个标准化的方式,来让大模型与外部的工具、数据源和服务进行连接和使用。
MCP 的架构主要包括三个部分:Host(主机) 、Client(客户端) 和 Server(服务器) 。
看一下这张图,你可以看到两种类型的服务器:
- 远程服务,比如各种网络应用接口;
- 本地数据资源,比如数据库。

-
Host(主机)------AI 应用的"大脑"
职责:接收用户的输入,处理请求,并通过 Client 与外部资源进行通信。
举个例子,就是我们平时用的智能助手,或者集成开发环境(IDE)中的 AI 插件,都是"主机"角色。
-
Client(客户端)------沟通的"桥梁"
职责:和server一一对应,将 Host 的请求转发给 Server,并将 Server 的响应返回给 Host。
客户端就像是一个中介,它帮助主机和服务器之间传递信息,确保两者可以顺利对接。
-
Server(服务器)------提供工具和数据的"仓库"
职责:接收来自 Client 的请求,执行相应的操作,并将结果返回。
我们图里列的链接到网盘,连接到数据库,连接到网络啊等服务。
对比Function call和MCP流程,其实对比起来逻辑上就多了个client。模型和外部服务直接需要通过client通信。
