Function Call、Tool、MCP:大模型工具调用三件事
·
Function Call、Tool、MCP:大模型工具调用三件事
一、大模型缺什么
| 大模型能做的 | 大模型不能做的 |
|---|---|
| 回答学过的东西 | 查实时天气 |
| 理解你给的文章 | 调你的 API |
| 翻译、润色 | 操作你的文件 |
它缺“手”和“眼”,需要工具帮忙。
二、Function Call:让大模型学会“下命令”
大模型不直接说人话,而是输出一段 JSON,告诉程序:“我要调用哪个函数,参数是什么”。
| 普通对话 | Function Call |
|---|---|
| “您可以打开天气 App 看北京天气” | {"function":"get_weather","city":"北京"} |
格式谁定的: 大模型厂商内置好的,你不用教它。
填什么内容: 大模型根据你给的“工具菜单”和用户的话,自己匹配工具、提取参数。
三、Tool:自带描述和干活逻辑的方法
Tool 就是一个方法,包含两部分:
| Tool 里有什么 | 作用 | 给谁看 |
|---|---|---|
| 描述部分(名称、功能描述、参数定义) | 告诉大模型“我能干嘛、需要什么参数” | 大模型 |
| 执行逻辑(方法体里的代码) | 真正干活的代码,调 API、跑脚本 | 程序自己 |
用 Java 写一个本地 Tool:
@Tool(name = "get_weather", description = "查询指定城市的实时天气")
public String getWeather(@ToolParam(description = "城市名称") String city) {
return 天气API.query(city); // 执行逻辑
}
| 组成部分 | 代码里写的 | 作用 |
|---|---|---|
| 名称 | get_weather |
大模型在 JSON 里填这个名字 |
| 描述 | “查询指定城市的实时天气” | 大模型据此判断能不能用 |
| 参数 | city,城市名称 |
大模型知道要传什么 |
| 执行逻辑 | 调天气 API | 大模型不关心,程序自己跑 |
四、完整流程:本地 Tool
一句话:大模型点菜(JSON),程序炒菜(执行方法),大模型上菜(润色)。
五、为什么执行完还要回传大模型
程序拿到的是原始数据,不会“说人话”。
| 原始数据 | 用户期待的回复 |
|---|---|
{"temp":25,"weather":"晴"} |
“北京今天晴天,25度,体感舒适。” |
| 角色 | 负责 |
|---|---|
| Tool 执行逻辑 | 动手拿数据 |
| 大模型 | 动脑判断 + 动嘴润色 |
六、Tool 多了的麻烦
早期每接一个第三方服务,都要手写一个 Tool。
| 服务 | 开发者要做什么 |
|---|---|
| 天气 | 手写 Tool 封装 API |
| GitHub | 手写 Tool |
| 地图 | 手写 Tool |
本质问题:我们在替服务方写 Tool。
七、MCP:让第三方自己提供 Tool
7.1 核心思路
第三方服务按统一标准封装接口,我们直接连,不用替它写 Tool。
类比:
- MCP 之前:买电器送裸线,自己接插头
- MCP 之后:电器出厂自带标准插头,直接插
7.2 两方各自做什么
| 角色 | 做什么 | 用什么 |
|---|---|---|
| 第三方服务方 | 把自己的 API 封装成 MCP 服务 | MCP 官方提供的 SDK |
| 我们 | 配置连接地址,直接调用 | 配置文件里写 URL |
7.3 SDK 是什么,在哪用
SDK(软件开发工具包)是 MCP 官方提供的一套现成工具包,给第三方服务方用的。第三方用这个 SDK,可以把自己的服务(比如 GitHub API)快速变成一个标准的 MCP 服务端,暴露一个 URL 出来。
SDK 是第三方用的,不是我们用的。 我们的 Java 程序不需要引入 MCP SDK,只需要配一个 URL。
7.4 我们怎么写代码:两种方式
| 方式 | 做法 | 适用场景 |
|---|---|---|
| 本地手动封装 | 自己写 @Tool 方法,方法体里调第三方 API |
第三方没提供 MCP 接口 |
| MCP 配置连接 | 在配置文件里写 URL,框架自动拉取 | 第三方提供了 MCP 服务端 |
如果第三方提供了 MCP 服务,我们选第二种,零代码。
八、MCP 配置实战
8.1 配置文件
假设有三个第三方服务都提供了 MCP 接口:
spring:
ai:
mcp:
client:
connections:
github:
type: STREAMABLE_HTTP
url: https://github-mcp.example.com/mcp
weather:
type: STREAMABLE_HTTP
url: https://weather-mcp.example.com/mcp
email:
type: STREAMABLE_HTTP
url: https://email-mcp.example.com/mcp
有多少个 MCP 工具,就配多少个 connections 节点。 不需要为每个工具写 Java 类。
8.2 框架启动时自动做了什么
1. 读取配置文件里的 MCP 连接列表
2. 逐个连接 MCP 服务端
3. 从每个服务端拉取它提供的工具描述
4. 把这些工具描述合并到本地 Tool 列表中
5. 把完整的工具列表发给大模型
你不需要手动写任何代码去拉取、合并、发送。框架全自动完成。
8.3 大模型该怎么调还怎么调
大模型眼里,所有工具都一样,不区分是本地的还是 MCP 远程的。它照样输出 Function Call:
{"function": "github_search", "arguments": {"query": "AI agent"}}
框架收到后自动判断:这个工具来自 MCP,走 MCP 协议远程调用,拿到结果回传大模型润色。
8.4 调用流程
九、有无 MCP 对比
| 对比项 | 没有 MCP | 有 MCP |
|---|---|---|
| 接一个工具要写多少代码 | 一个完整的 @Tool 类 |
一行 YAML 配置 |
| 接十个工具 | 十个 @Tool 类 |
十段 YAML 配置 |
| 工具更新维护 | 改代码,重新部署 | 第三方自己更新,我们不用动 |
| 工具列表发给大模型 | 手动收集 | 框架自动合并本地 Tool + MCP 工具 |
| 调用逻辑 | 框架自动 | 框架自动(跟本地 Tool 一样) |
十、演变总结
| 阶段 | 核心 |
|---|---|
| 起点 | 大模型没手没脚 |
| Function Call | 大模型能下命令(输出 JSON) |
| Tool | 方法含描述和执行逻辑,描述给大模型看,逻辑自己跑 |
| MCP | 第三方自己封装,我们配置 URL 直接用 |
十一、速记卡
Function Call = 大模型下命令的语法
Tool = 描述(给大模型看)+ 执行逻辑(自己跑)
MCP = 第三方用官方 SDK 封装服务,我们配 URL 直接连
本地 Tool 和 MCP 工具的关系:
大模型眼里都一样
框架自动合并,一起发给大模型
调用流程不变
SDK 给谁用:
第三方服务方用,用来封装 MCP 服务端
我们不用,我们只配 URL
更多推荐

所有评论(0)