工具调用(亦称函数调用)。
AI 大模型中的 Function Call(函数调用), 它是一个极其重要的功能,它极大地扩展了大语言模型的能力边界,使其从单纯的文本生成器升级为能够感知、决策并操作外部世界的智能代理。
其优势与价值如下:
访问实时信息: 获取股票、天气、新闻、航班等最新数据。
操作外部系统: 发送邮件、创建日历事件、控制 IoT 设备、操作数据库。
执行精确计算/转换: 调用计算器、货币转换器等。
检索私有/专有数据: 连接企业内部数据库、知识库、CRM 系统。
增强可靠性: 将需要精确性的任务(如计算、数据查询)交给专门工具处理,减少模型“幻觉”。
构建智能代理(Agents):
Function Call是实现AI Agent自动规划和执行复杂任务序列(如“查天气-订机票-发通知”)的基础技术。简化开发: 开发者只需定义好函数接口,模型能理解如何调用,无需复杂的自然语言解析。
提升用户体验: 用户可以用自然语言无缝触发复杂的后端操作。
1. 调用工具查询日期和天气
1.1. 定义 Tool 工具
import org.springframework.ai.tool.annotation.Tool;
@Slf4j
public class DateTimeTools {
@Tool(description = "获取当前日期和时间")
String getCurrentDateTime() {
return LocalDateTime.now().toString();
}
}1.2. ChatClient 使用工具调用
并不是所有 AI 大模型都支持工具调用功能的
/**
* 流式对话
* @param message
* @return
*/
@GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
public Flux<String> generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message,
@RequestParam(value = "chatId") String chatId) {
// 流式输出
return chatClient.prompt()
.tools(new DateTimeTools()) // Function Call
.user(message) // 提示词
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
.stream()
.content();
}
1.2.1. 定义多个 Tool 工具
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
@Slf4j
public class WeatherTools {
@Tool(description = "获取当日的天气情况,时间参数需为 ISO-8601 格式")
String getWeather(String time) {
log.info("## time: {}", time);
// TODO 调用第三方接口,获取当日天气情况
return "今天天气晴朗,最低温度 18℃,最高温度 38℃";
}
}
/**
* 流式对话
* @param message
* @return
*/
@GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
public Flux<String> generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message,
@RequestParam(value = "chatId") String chatId) {
// 流式输出
return chatClient.prompt()
.tools(new DateTimeTools(), new WeatherTools()) // Function Call
.user(message) // 提示词
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
.stream()
.content();
}1.3. ChatModel 使用工具调用
@RestController
@RequestMapping("/v13/ai")
public class ToolCallingController {
@Resource
private DeepSeekChatModel chatModel;
/**
* 流式对话
* @param message
* @return
*/
@GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
public Flux<String> generateStream(@RequestParam(value = "message") String message) {
// 将 DateTimeTools 注册到工具集中
ToolCallback[] tools = ToolCallbacks.from(new DateTimeTools());
// 构建聊天选项配置,设置工具回调功能
ChatOptions chatOptions = ToolCallingChatOptions.builder()
.toolCallbacks(tools)
.build();
// 构建提示词
Prompt prompt = new Prompt(new UserMessage(message), chatOptions);
// 流式输出
return chatModel.stream(prompt)
.mapNotNull(chatResponse -> {
// 获取响应内容
DeepSeekAssistantMessage deepSeekAssistantMessage = (DeepSeekAssistantMessage) chatResponse.getResult().getOutput();
// 推理内容
String reasoningContent = deepSeekAssistantMessage.getReasoningContent();
// 推理结束后的正式回答
String text = deepSeekAssistantMessage.getText();
return StringUtils.isNotBlank(reasoningContent) ? reasoningContent : text;
});
}
}2. MCP 协议
通过标准化接口,让AI模型能像使用 “USB接口” 一样,连接各类外部资源,如数据库、第三方 API、文件系统等等,从而突破静态训练数据的限制,实现动态任务执行。
下面列举一些 MCP 的应用场景:
2.1. MCP 架构
MCP 采用经典的 “客户端-服务端” 架构
https://img.quanxiaoha.com/quanxiaoha/175210541772851

Host 主机:通常为 AI 应用,比如 Cursor,Trae 等代码编辑器或其他应用。主机负责接收用户的问题与指令,再调用 AI 大模型,当大模型觉得需要调用外部工具时,Host 主机会主动调用 MCP 客户端。
MCP 客户端:客户端通常内置于主机中,负责与 MCP 服务端建立连接、发送请求和接收请求。我们可以把 MCP 客户端理解为公司 “前台小姐姐”,为外来人员提供服务,有啥事都可以咨询她,由她将任务转交给不同部门去处理。
MCP 服务端:MCP 服务器可以看做是一个 “工具箱” 或 “数据源”,供 MCP 客户端来调用,例如访问文件系统、数据库查询、操作浏览器等等。MCP 服务器负责执行具体的操作,如调用工具或访问数据,再将结果返回给 MCP 客户端。
多个 MCP 服务器可以同时运行,当大模型觉得自己无法完成某项任务时,就可以让这些 MCP 服务器来协助。
举个栗子,我们向主机提问 “我的 E:/ 盘下,有哪些文件?”,比如 Cursor 编辑器,整体的处理流程大致如下:
我们向 Cursor 提问;
Cursor 调用大模型来分析我们的问题,由大模型决定是否需要访问本地文件系统;
若需要,主机内置的 MCP 客户端被激活,与本地文件系统的 MCP 服务器建立连接;
MCP 客户端向 MCP 服务端发送请求,想要获取
E:/盘下的文件列表;本地文件系统 MCP 服务器执行访问操作,获取文件列表,并将结果返回给 MCP 客户端;
MCP 客户端再将结果发送给 AI 大模型;
AI 大模型再以自然语言的方式,告诉我们最终结果;
2.2. 和 Fucntion Call 的区别
定义上:MCP 是一种标准化协议,为 AI 大模型与外部系统之间的交互,提供了规范化的接口,有点类似于 “USB 接口” ,能够连接不同的外接设备,如键盘、鼠标、音箱等等。它能让不同的系统之间能够高效的数据传输与工具调用;而 Function Call 是大语言模型本身提供的一种能力,通过预定义函数,当用户提问后,AI 大模型理解用户的提示词,并判断是否需要调用这些预定义的函数。
技术实现上:MCP 采用了 “客户端-服务端” 架构,标准化处理 MCP 客户端与 MCP 服务端之间的通信,包括请求、响应等等。此架构能够更好的应用复杂的网络环境,和多元化的场景需求;而 Function Call 实现相对简单,它在大模型运行时环境直接执行,但需要开发者提前将函数定义好,并提交给 AI 大模型。
功能与应用场景:MCP 能够处理复杂、异步的任务,例如,你可以将公司内部的系统,封装成 MCP 服务提供调用;而 Function Call 则更适合处理简单、低延迟的任务,例如获取天气数据、实时翻译等。
整合方式:MCP 服务一般由第三方提供好,我们只需要对接即可,无需额外编写代码;而 Function Call 则需要自己编写预定义函数,并提交给 AI 大模型。
3. 整合 MCP Client: 调用高德地图 MCP 服务
让 AI 大模型推荐最近 1000m 内,好评率较高的烧烤店
3.1. MCP.so 介绍
MCP.so(官网:https://mcp.so/zh)是全球领先的MCP(Model Context Protocol,模型上下文协议)服务器资源平台,专注于提供 MCP 服务的导航、托管与调试功能。其核心定位是成为连接 AI 模型与外部工具/数据源的标准化枢纽,推动AI应用开发的效率与可扩展性,目前已收录 1万+ 的 MCP 服务。
进入 MCP.so 官网后,在 Featrued 精选菜单下,可以找到高德地图官方提供的 MCP Server,它包含的工具包括:
生成专属地图:将出行规划导入高德地图,生成专属地图;
导航到目的地:根据用户传入经纬度,启动导航;
打车:根据用户输入起终经纬度坐标,发起打车请求;
地理编码:将详细的结构化地址转换为经纬度坐标;
逆地理编码:将一个高德经纬度坐标转换为行政区划地址信息;
IP 定位:IP 定位根据用户输入的 IP 地址,定位 IP 的所在位置;
天气查询:根据城市名称或者标准adcode查询指定城市的天气;
骑行路径规划:用于规划骑行通勤方案,规划时会考虑天桥、单行线、封路等情况。最大支持 500km 的骑行路线规划;
周边搜索:根据用户传入关键词以及坐标,搜索出规定半径范围内的 POI 地点;
TIP: 关于高德地图 MCP Server 更多功能,可阅读官方文档:https://lbs.amap.com/api/mcp-server/summary。
3.2. 申请 API Key
在使用高德 MCP 服务之前,需要登录到高德开发平台:https://lbs.amap.com/,创建 Apikey
3.3. 依赖
<!-- MCP Client -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
</dependency>3.4. 配置
在 MCP.so 网站中,点击进入高德地图 MCP 服务的详情页中,复制配置。
在 /resources 目录下,新建一个 mcp-servers-config.json 配置文件,文件名可以随意命名:
{
"mcpServers": {
"amap-maps": {
"command": "cmd",
"args": [
"/c",
"npx",
"-y",
"@amap/amap-maps-mcp-server"
],
"env": {
"AMAP_MAPS_API_KEY": "填写你申请的高德地图 API Key"
}
}
}
}解释一下:
根对象
mcpServers: 定义一组 MCP 服务器配置;服务标识
amap-maps: 服务名称,表示这是针对 高德地图(AMap) 的配置。command: 指定要运行的基本命令。这里使用的是cmd(Windows 命令提示符)。args: 是一个数组,包含传递给命令的参数。在这个例子中:/c表示执行后面的命令然后终止。npx是 Node.js 的一个工具,用于执行npm包中的命令。注意,需要确保你的电脑已安装好 Node.js。-y是 npx 的一个选项,表示如果遇到提示(比如是否安装包)都自动回答yes。@amap/amap-maps-mcp-server是要通过npx运行的包,即高德地图的 MCP 服务包。env: 是一个环境变量对象,用于设置运行时的环境变量。AMAP_MAPS_API_KEY: 需要填写用户申请的高德地图API Key。
编辑 application.yml 配置文件,添加配置项如下:
spring:
ai:
mcp:
client:
stdio:
servers-configuration: classpath:/mcp-servers-config.json # 指定 MCP 服务的配置文件路径
toolcallback:
enabled: true # 开启 MCP 客户端的工具回调(Tool Callback)功能3.5. 配置 ChatClient
编辑 ChatClientConfig 配置类,将 MCP 工具配置上
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ChatClientConfig {
@Resource
private ChatMemory chatMemory;
/**
* 初始化 ChatClient 客户端
* @param chatModel
* @return
*/
@Bean
public ChatClient chatClient(DeepSeekChatModel chatModel, ToolCallbackProvider tools) {
return ChatClient.builder(chatModel)
.defaultToolCallbacks(tools) // MCP
.defaultAdvisors(
new SimpleLoggerAdvisor(), // 添加 Spring AI 内置的日志记录功能
MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();
}
}
3.6. 调用
@RestController
@RequestMapping("/mcp/ai")
public class McpChatClientController {
@Resource
private ChatClient chatClient;
/**
* 流式对话
* @param message
* @return
*/
@GetMapping(value = "/generateStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<AIResponse> generateStream(@RequestParam(value = "message") String message,
@RequestParam(value = "chatId") String chatId) {
// 流式输出
return chatClient.prompt()
.user(message) // 提示词
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
.stream()
.chatResponse()
.mapNotNull(chatResponse -> {
Generation generation = chatResponse.getResult();
String text = generation.getOutput().getText();
return AIResponse.builder().v(text).build();
});
}
}3.6.1. 场景1:IP 定位
36.57.99.213 这个 IP 的具体位置在哪里3.6.2. 场景2:天气情况
合肥今天的天气怎么样3.6.3. 场景3:推荐附近高评分门店
我的坐标是东经117°12′24.754″,北纬31°56′0.982″,附近 1000m 有什么好评率较高的烧烤店,推荐一下。需要附带上门店的图片,以 markdown 图片格式展示出来4. 搭建自定义 MCP Server:获取 QQ 信息
4.1. 新建 MCP Server 项目
4.2. 依赖
<!-- Spring AI 依赖管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- MCP Server WebFlux -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
</dependencies>4.3. MCP Server 三种部署模式
4.4. 配置
server:
port: 8000 # 启动端口号
spring:
ai:
mcp:
server:
type: sync # 处理模式,SYNC 同步或 ASYNC 异步
name: mcp-server-qq # MCP Server 名称
version: 1.0.0 # MCP Server 版本号
# 奶思猫 API 密钥(替换为你自己的)
api-key: xxx根据 QQ 号查询 QQ 信息,需要调用奶思猫第三方平台的 API, 需要先申请 API Key。如何申请可参考《前后端分离博客2期》的《6.2节》
4.5. 配置 RestTemplate
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(10000); // 连接超时时间:10秒
factory.setReadTimeout(10000); // 读取超时时间:10秒
return new RestTemplate(factory);
}
}4.6. 定义 Tool
新建一个 /tools 包,并通过 @Tool 注解声明一个 “根据 QQ 号获取 QQ 信息” 工具方法,模式和之前定义 Function Call 差不太多
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Component
@Slf4j
public class QQTool {
@Resource
private RestTemplate restTemplate;
@Value("${api-key}")
private String apiKey;
@Tool(description = "根据 QQ 号获取 QQ 信息")
public String getQQInfo(String qq) {
log.info("## 获取 QQ 信息, qq: {}", qq);
// 请求第三方接口
String url = String.format("https://api.nsmao.net/api/qq/query?qq=%s&key=%s", qq, apiKey);
String result = restTemplate.getForObject(url, String.class);
log.info("## 返参: {}", result);
return result;
}
}
4.7. 注册工具
在启动类,注册工具回调(Tool Callbacks)
import com.quanxiaoha.mcp.server.qq.tools.QQTool;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
/**
* 注册工具回调(Tool Callbacks)
* @param qqTool
* @return
*/
@Bean
public ToolCallbackProvider qqTools(QQTool qqTool) {
return MethodToolCallbackProvider.builder()
.toolObjects(qqTool)
.build();
}
}5. 对接自定义 MCP Server
5.1. 添加配置
添加连接自定义 MCP Server 的相关配置项
spring:
ai:
mcp:
client:
type: sync # 客户端使用同步通信模式
request-timeout: 20s # 设置单次请求超时时间
sse: # SSE (Server-Sent Events) 流式响应配置
connections: # 定义 SSE 连接端点
qq-mcp-server: # 自定义连接名称(可任意命名)
url: http://localhost:8000 # MCP 服务实际地址
5.2. 调用
@RestController
@RequestMapping("/mcp/ai")
public class McpChatClientController {
@Resource
private ChatClient chatClient;
/**
* 流式对话
* @param message
* @return
*/
@GetMapping(value = "/generateStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<AIResponse> generateStream(@RequestParam(value = "message") String message,
@RequestParam(value = "chatId") String chatId) {
// 流式输出
return chatClient.prompt()
.user(message) // 提示词
.stream()
.chatResponse()
.mapNotNull(chatResponse -> {
Generation generation = chatResponse.getResult();
String text = generation.getOutput().getText();
return AIResponse.builder().v(text).build();
});
}
}870361626 这个 qq 号的信息展示一下,头像需要以 Markdown 格式图片格式返回5.3. mcp-servers-config.json 对接多个 MCP Server
高德地图 MCP 服务,是直接定义在 json 文件中的,那么这种方式如何对接多个 MCP 服务呢?接下来,我们将尝试再添加一个新的 MCP 服务 —— @modelcontextprotocol/server-filesystem。
5.3.1. 介绍
@modelcontextprotocol/server-filesystem 是 Model Context Protocol (MCP) 生态中的官方参考服务器之一,专注于为大型语言模型(LLM)提供安全、标准化的文件系统访问能力。其核心作用是将本地文件系统的操作(如读取、搜索文件)封装为 AI 可调用的工具,从而增强模型对实时数据的处理能力。
5.3.2. 添加 MCP 服务配置
编辑 mcp-servers-config.json 文件,在 /mcpServers 节点下,额外添加 filesystem 的 MCP 服务配置:
{
"mcpServers": {
"amap-maps": {
"command": "cmd",
"args": [
"/c",
"npx",
"-y",
"@amap/amap-maps-mcp-server"
],
"env": {
"AMAP_MAPS_API_KEY": "725178d06255921fee4111576572ab13"
}
},
"filesystem": {
"command": "cmd",
"args": [
"/c",
"npx",
"-y",
"@modelcontextprotocol/server-filesystem",
"D:\\",
"E:\\"
]
}
}
}
TIP: 上述配置项中,D:\\ 和 E:\\ 表示授权能够访问的路径。
评论区