Function Call、Tool、MCP:大模型工具调用三件事
Function Call、Tool、MCP:大模型工具调用三件事
- 一、大模型缺什么
- 二、Function Call:让大模型学会“下命令”
- 三、Tool:自带描述和干活逻辑的方法
- 四、完整流程:本地 Tool
- 五、为什么执行完还要回传大模型
- 六、Tool 多了的麻烦
- 七、MCP:让第三方自己提供 Tool
- 7.1 核心思路
- 7.2 两方各自做什么
- 7.3 SDK 是什么,在哪用
- 7.4 我们怎么写代码:两种方式
- 八、MCP 配置实战
- 8.1 配置文件
- 8.2 框架启动时自动做了什么
- 8.3 大模型该怎么调还怎么调
- 8.4 调用流程
- 九、有无 MCP 对比
- 十、演变总结
- 十一、速记卡
一、大模型缺什么
| 大模型能做的 | 大模型不能做的 |
|---|---|
| 回答学过的东西 | 查实时天气 |
| 理解你给的文章 | 调你的 API |
| 翻译、润色 | 操作你的文件 |
它缺“手”和“眼”,需要工具帮忙。
二、Function Call:让大模型学会“下命令”
大模型不直接说人话,而是输出一段 JSON,告诉程序:“我要调用哪个函数,参数是什么”。
| 普通对话 | Function Call |
|---|---|
| “您可以打开天气 App 看北京天气” | {"function":"get_weather","city":"北京"} |
格式谁定的:大模型厂商内置好的,你不用教它。
填什么内容:大模型根据你给的“工具菜单”和用户的话,自己匹配工具、提取参数。
三、Tool:自带描述和干活逻辑的方法
Tool 就是一个方法,包含两部分:
| Tool 里有什么 | 作用 | 给谁看 |
|---|---|---|
| 描述部分(名称、功能描述、参数定义) | 告诉大模型“我能干嘛、需要什么参数” | 大模型 |
| 执行逻辑(方法体里的代码) | 真正干活的代码,调 API、跑脚本 | 程序自己 |
用 Java 写一个本地 Tool:
@Tool(name="get_weather",description="查询指定城市的实时天气")publicStringgetWeather(@ToolParam(description="城市名称")Stringcity){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_HTTPurl:https://github-mcp.example.com/mcpweather:type:STREAMABLE_HTTPurl:https://weather-mcp.example.com/mcpemail:type:STREAMABLE_HTTPurl: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