Function Calling
为什么需要 Function Calling?
大型语言模型(LLM),如 GPT,最初的任务是生成文本。但随着应用场景的扩展,传统的文本生成能力已经不能满足所有需求。用户不仅想要一个回答,他们可能还需要:
- 实时数据访问:例如最新的天气、股票行情或新闻。
- 多样化的任务处理:如数据库查询、网页搜索、复杂计算或访问外部服务。
- 与外部系统的互动:将语言模型和实际工作流连接起来,比如管理任务、自动化流程等。
自动发送邮件的一个小项目可以参考FunctionCall Mail Agent
因此,Function Calling(函数调用)作为一个重要机制应运而生,旨在弥补传统文本生成模型的不足,让模型不仅仅是一个“回答机器”,还能够成为一个“执行机器”。
工作流程
外部接口的定义——函数触发——数据返回与整合
早期思路:后端+LLM——前端【硬编码】
Function calling思路
- 广义的 Function Calling 是指让先向大模型提供可用函数的列表及说明,由大模型在对话过程中智能判断是否需要调用函数,并自动生成调用所需的参数,最终用文字返回符合约定格式的函数调用请求。
- 狭义的 Function Calling 特指大模型提供商在模型内部与 API 层面 做了支持的一种能力。它最早由 OpenAI 引入,在 模型层面,提供商需对大模型进行特别优化,使其具备根据上下文正确选择合适函数、生成有效参数的能力(比如 有监督微调、强化学习);在 API 层面:模型提供商需额外开放对 Function Calling 的支持(比如 GPT API 提供了 functions 参数)。
基于提示词的 Function Calling
System Prompt examples
# 你的角色
你是一个函数调用助手,我将提供多个函数的定义信息,包括函数名称、作用、参数及参数类型。
# 你的任务
- 根据用户的输入,判断是否需要调用某个函数
- 如果需要,请**严格按照以下格式**输出函数调用指令:
```json
{ "name": "函数名", "arguments": { "参数名": "参数值" } }
```
# 函数定义信息
1. **get_weather**
- 作用:查询指定城市的天气情况
- 参数:
-`city`(string):城市名称
2. **get_time**
- 作用:查询指定城市的当前时间
- 参数:
- `city`(string):城市名称
用户提问示例:“广州的天气怎么样?”
模型函数请求:{ "name": "get_weather", "arguments": { "city": "广州" }
存在的问题
- 输出格式不稳定
- 容易出现幻觉
- 高度依赖开发者构建提示词
- 上下文冗长,tokens消耗
基于API的Function Calling
- 用户发起提问:用户通过自然语言提出问题,例如:“广州今天天气如何?适合出门吗?”
- 后端第一次向大模型 API 发起请求,获取函数调用指令:后端向大模型 API 传入用户原始输入、函数描述和其他上下文信息,获取调用指令。函数描述包括函数名称、用途说明、参数结构等。
{
"messages": [
{
"role": "system",
"content": "你是一个助手,可以根据用户的请求调用工具来获取信息。"
},
{
"role": "user",
"content": "广州今天天气如何?适合出门吗?"
}
],
"functions": [
{
"name": "getWeather",
"description": "获取指定城市的天气",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称,比如北京"
},
"date": {
"type": "string",
"description": "日期,比如 2025-08-07"
}
},
"required": ["location", "date"]
}
}
]
}
- 模型生成调用指令:模型会智能判断是否需要调用函数,选择合适的函数,并基于上下文自动生成结构化的调用指令(函数名 + 参数)
# 调用指令示例(OpenAI Function Calling)
{
"function_call": {
"name": "getWeather",
"arguments": {
"location": "Guangzhou",
"date": "2025-07-17"
}
}
}
- 后端解析调用指令,并执行实际的函数调用:后端接收到模型返回的调用指令后,解析调用指令,得到函数名称和参数,执行对应的方法(如调用天气查询函数),并获取结果。
- 后端第二次向大模型 API 发起请求,将刚才的调用结果和其他上下文信息一起传给模型,生成最终的回复:后端将函数执行结果 + 其他上下文信息(包括用户原始输入)传给模型,模型判断此时已有足够的信息回答问题,不再需要调用函数了,于是直接生成最终结果。
存在问题
- 后端应用适配不同大模型时存在大量冗余开发:同一个功能,在OpenAI、Qwen、智谱GLM等中可能需要不同的封装
- 可选模型有限:真正原生支持Api Function Callin的模型数量较少,尤其在国内大模型生态中,支持度参差不齐
MCP
要解决的问题(为什么需要 MCP)
不是解决function call本身存在的问题
- 工具接入冗余开发:现在如果要在 LLM 应用里接入别人写的工具(比如天气查询函数、数据库查询函数),就必须把“工具代码 + 函数描述”整块复制进来。如果要接入 3 个工具,就要 copy 3 次。这样非常重复、低效。
- 工具复用困难:复制代码后可能跑不通,环境依赖不同、语言不一样(Python 工具拿到 Java 环境跑不了)。很多公司甚至不会把源码开放出来,那就更没法 copy。
如何解决问题(假设没有 MCP 协议)
思路一:本地服务式接入
工具代码不用 copy,而是作为一个独立“服务”运行在本地。AI 应用只需通过 进程间通信(管道/Socket)来调用它。 好处:不同语言也能跑,因为只需要在本地把它当服务起起来,不需要管源码。 比如工具是 Java 写的,你的应用是 Python 写的,你只需要起一个 Java 进程跑这个工具,再通过标准通信方式(JSON over socket)调用即可。
思路二:远程服务式接入
工具开发者自己部署工具,把它变成一个标准化 API 服务(HTTP / gRPC 等)。AI 应用调用这个远程服务就好,不用管实现语言,也不用 copy 代码。只要有统一的请求/响应格式,大家就能互通。
**不再 copy 代码,而是通过“服务”的方式来调用工具。**并且要实现“配置替代人工适配”,必须解决两件事:能自动获取工具的描述信息(不用人手动写)、能自动定位工具的调用入口并执行调用(不用人手动适配代码)。
技术需求(拆成两种场景)
本地服务式接入
- 标准化配置后,AI 应用可:
- 拉取工具包到本地运行。
- 自动获取工具描述信息。
- 通过进程间通信完成调用。
远程服务式接入
- 标准化配置后,AI 应用可:
- 访问远程工具服务。
- 自动获取工具描述信息。
- 通过远程调用完成调用。
技术方案思路
- 工具与 AI 应用必须 解耦。
- 工具与 AI 应用之间交互必须 标准化:
- 通信协议统一:本地进程通信 / 远程服务调用。
- 接口定义统一:所有工具接口需声明必要信息。
- 数据格式统一:请求 / 响应使用统一格式(如 JSON)。
- 配置方式统一:工具接入时只需标准化配置。
- 工具端要求:必须提供标准化接入方式。
- 应用端要求:必须内置标准化加载逻辑。
系统架构设计
MCP是什么
2024 年 11 月由 Anthropic提出(官方文档)的,全称为Model Context Protocol (MCP)。
MCP is an open protocol that standardizes how applications provide context to large language models (LLMs). Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools. MCP enables you to build agents and complex workflows on top of LLMs and connects your models with the world.
MCP provides:
- A growing list of pre-built integrations that your LLM can directly plug into
- A standardized way to build custom integrations for AI applications
- An open protocol that everyone is free to implement and use
- The flexibility to change between different apps and take your context with you
如何理解呢?
- 应用程序:集成了 LLM 的具体应用。包括各家大模型的在线对话网站、集成了大模型的IDE(如 Claude desktop)、各种 Agent(比如 Cursor 就是一个 Agent)、以及其他接入了大模型的普通应用。
- 上下文:指的是模型在决策时可访问的所有信息,如当前用户输入、历史对话信息、外部工具(tool)信息、外部数据源(resource)信息、提示词(prompt)信息等等(这里重点只讲工具)。
MCP 核心架构
MCP follows a client-server architecture where an MCP host — an AI application like Claude Code or Claude Desktop — establishes connections to one or more MCP servers. The MCP host accomplishes this by creating one MCP client for each MCP server. Each MCP client maintains a dedicated one-to-one connection with its corresponding MCP server.The key participants in the MCP architecture are:
- MCP Host: The AI application that coordinates and manages one or multiple MCP clients
- MCP Client: A component that maintains a connection to an MCP server and obtains context from an MCP server for the MCP host to use
- MCP Server: A program that provides context to MCP clients
For example: Visual Studio Code acts as an MCP host. When Visual Studio Code establishes a connection to an MCP server, such as the Sentry MCP server, the Visual Studio Code runtime instantiates an MCP client object that maintains the connection to the Sentry MCP server. When Visual Studio Code subsequently connects to another MCP server, such as the local filesystem server, the Visual Studio Code runtime instantiates an additional MCP client object to maintain this connection, hence maintaining a one-to-one relationship of MCP clients to MCP servers.Note that MCP server refers to the program that serves context data, regardless of where it runs. MCP servers can execute locally or remotely. For example, when Claude Desktop launches the filesystem server, the server runs locally on the same machine because it uses the STDIO transport. This is commonly referred to as a “local” MCP server. The officialSentry MCP server runs on the Sentry platform, and uses the Streamable HTTP transport. This is commonly referred to as a “remote” MCP server.
整体模式就是**“客户端-服务器架构”**:
- MCP Host:协调和管理一个或多个 MCP Server 的应用程序,比如 Claude Desktop、Claude Code、VS Code;
- MCP Client:一个组件,用于维护与 MCP Server的连接,并从 MCP Server获取上下文,供 MCP Host使用,由 Host 自动创建,用来和某个 Server 建立、保持连接;
- MCP Server:一个为 MCP Client 提供上下文的程序,比如 Sentry、文件系统、数据库等。
MCP 的传输协议
MCP supports two transport mechanisms:
- Stdio transport: Uses standard input/output streams for direct process communication between local processes on the same machine, providing optimal performance with no network overhead.
- Streamable HTTP transport: Uses HTTP POST for client-to-server messages with optional Server-Sent Events for streaming capabilities. This transport enables remote server communication and supports standard HTTP authentication methods including bearer tokens, API keys, and custom headers. MCP recommends using OAuth to obtain authentication tokens.
The transport layer abstracts communication details from the protocol layer, enabling the same JSON-RPC 2.0 message format across all transport mechanisms.
Stdio 传输
Stdio 传输本质上是本地进程间通信(IPC)的一种形式,它最常用的底层机制就是管道(pipe)。stdio(standard I/O)是进程的标准输入/输出接口。本质上通过标准输入和标准输出这两个数据流来传输数据、通过管道来连接两个进程的标准输入/输出接口,使得一个进程的输出直接传给另一个进程输入,实现进程间数据传输(基于字节流的全双工通信通道)。
ps aux | grep python
当然在操作系统里,常见的 IPC(进程间通信)方式有很多,比如:Socket(本地 TCP/Unix Domain Socket)、命名管道(FIFO)、共享内存、消息队列、文件映射、Stdio(标准输入/输出);那为什么 MCP 选了 Stdio:
- 无论是 Linux、MacOS 还是 Windows,每个进程一启动就天然有 stdin/stdout/stderr 三个文件描述符。开发者不用额外做 socket 绑定、端口管理,避免了复杂性和防火墙、权限等问题。
- AI 应用只要启动一个 MCP Server 进程,就可以直接通过 stdin/stdout 跟它对话,不需要额外监听端口,也不需要暴露网络接口 → 安全性更高。
- 如果用 Socket(尤其是 TCP),可能会意外暴露接口到外部,带来安全风险。Stdio 完全是父进程和子进程的私有通信通道,不经过操作系统的网络栈,天然更安全。
- MCP 的数据格式是 JSON-RPC over Stdio。这意味着数据其实就是一条条 JSON 文本,从 stdout 打出来就能直接看懂,非常适合开发和调试。
- Stdio 是 LSP(Language Server Protocol) 社区已经验证过的成功模式。LSP 也走 Stdio → IDE(客户端)启动语言服务器(子进程),通过 Stdio 传 JSON-RPC 消息。
HTTP + SSE 传输(旧方案,2024.10)
客户端通过 HTTP POST 向服务端发请求,服务端通过 SSE 通道返回响应结果。SSE(Server-Sent Events服务器发送事件),是一种服务器单向推送数据给客户端的技术,基于 HTTP 协议。
Why Notifications Matter This notification system is crucial for several reasons:
- Dynamic Environments: Tools may come and go based on server state, external dependencies, or user permissions
- Efficiency: Clients don’t need to poll for changes; they’re notified when updates occur
- Consistency: Ensures clients always have accurate information about available server capabilities
- Real-time Collaboration: Enables responsive AI applications that can adapt to changing contexts This notification pattern extends beyond tools to other MCP primitives, enabling comprehensive real-time synchronization between clients and servers.
客户端先向服务端发起一个普通的 HTTP 请求。服务端保持这个连接不断开,以 text/event-stream 作为响应类型,源源不断地往里写数据。客户端收到数据后会触发相应的事件回调(比如浏览器前端实时更新界面)。支持服务端主动、流式地推送消息。
Streamable HTTP 传输(新方案,2025.03)
HTTP + SSE 传输方案的升级版,Streamable HTTP 并不是一个标准协议名,而是一个通用描述,指的是基于 HTTP 协议的“可流式传输”技术。它的核心思想是:在一个 HTTP 连接里,服务端可以持续不断地发送数据给客户端,客户端边接收边处理,类似“流”一样。与传统 HTTP 请求响应“一次性完成”不同,Streamable HTTP 保持连接不关闭,数据分片持续传输。常见实现方式包括:
- HTTP/1.1 长连接 + 分块传输编码(Chunked Transfer Encoding)
- HTTP/2 流式数据
- HTTP/3 QUIC 流式传输
为什么 HTTP + SSE 要升级成 Streamable HTTP ?
- 数据格式限制问题:SSE 的 Content-Type: text/event-stream 只支持文本格式;Streamable HTTP 的Content-Type支持任意格式,如 JSON、HTML、二进制等,更适合 AI 场景(可能要传 JSON + 音频 + 图片)
- 跨平台兼容问题:SSE 支持的客户端主要是浏览器端和少量语言库;而 Streamable HTTP 支持多种客户端。
- 性能问题:SSE 是基于 HTTP/1.1 长连接,Streamable HTTP 可以基于 HTTP/2/3 ,支持多路复用和双向流。且 HTTP/2/3 的流控制和优先级机制使得高吞吐和低延迟成为可能;SSE 消息只能文本格式,Streamable HTTP 支持其他采用更紧凑的编码方式(比如二进制分包、压缩等)。
MCP 工作流程
最后
后续会继续发布,你也可以自己试一下:
- 其实,MCP 协议和 Function Calling 之间绝不是“技术递进”的关系。
- 多看 MCP 协议官方文档:https://modelcontextprotocol.io/docs/getting-started/intro
- 通过官方 SDK,尝试编写一个 MCP Server 并启动服务;初始化一个后端应用,创建 MCP Client,完成 Client - Server 完整交互流程的开发。MCP SDK 地址:https://modelcontextprotocol.io/docs/sdk
- 找一个开源的支持了 MCP 协议的 Agent 框架,追溯其中涉及到 MCP Client 、MCP Server 逻辑的所有代码;以接入高德地图 MCP Server 为例,参考文档:https://lbs.amap.com/api/mcp-server/gettingstarted(来自ModelScope 的 MCP Server 市场:https://modelscope.cn/mcp)
特别感谢 @bilibili 堂吉诃德拉曼查的英豪,在学习和整理过程中,她的视频给予了我很多启发。
推荐大家去多多支持她的视频作品!🎬✨
Comments | NOTHING