Tool Calling和本地MCP服务的调用
Tool Calling
我们在使用AI的时候有着一个联网搜索的按键,当我们需要进行网上的搜索的时候就需要借助Tool Calling,所以简单而言,Tool Calling是大模型使用的工具类。
ToolCalling也被称呼为Function Calling,它允许大模型与一组API或工具进行交互,将大模型的智能与外部工具或API进行无缝连接,增强大模型的功能,注意大模型是不直接调用工具的,它是让应用程序去执行大模型的工具,大模型等待程序返回结果,然后返回给用户。
所以我们是对大模型的调用功能进行打通,主要执行某种工具让大模型进行函数的调用。
如果我们不使用ToolCalling的话,我们的实时问题也就无法正常的解决,如下图
首先我们使用ChatModel进行工具的调用,当我们直接使用一个工具类进行返回的时候,根据官方的文档我们就可以看得到默认情况下是直接进行返回,我们可以使用returnDirect参数的定义来设置是否直接返回。
我们想要让大模型进行工具的使用,所以我们首先需要进行工具类的配置如下:
package ai.utils;
import org.springframework.ai.tool.annotation.Tool;
public class DataTimeTools {/** returnDirect=true的话,默认直接被大模型拿走* false的话将返回的结果进行修饰拼装再进行返回*/@Tool(description = "获取时间",returnDirect = false)public String getTime(){return "现在时间是:" + new java.util.Date();}
}
我们原先在帮助文档里面就可以看到,我们的大模型是否进行简单的处理就是需要returnDirect的参数控制。当我们配置类结束之后我们就可以控制台的编写,首先就是把工具放到工具类当中,然后使用ChatOptions让大模型了解到我们使用的工具类,然后将提示词进行编写入大模型,最后就可以得到结果。
package ai.controller;
import ai.utils.DataTimeTools;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.tool.ToolCallingChatOptions;
import org.springframework.ai.support.ToolCallbacks;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ToolCallingController {@Resource(name="qwen")private ChatModel chatModel;
@GetMapping("/toolcall/call")public String chat(@RequestParam(name = "msg",defaultValue = "现在几点")String msg) {// 创建工具,工具注册到工具集合中ToolCallback[] tools = ToolCallbacks.from(new DataTimeTools());// 将工具集配置进ChatOptions当中ToolCallingChatOptions build = ToolCallingChatOptions.builder().toolCallbacks(tools).build();
Prompt prompt = new Prompt(msg, build);
return chatModel.call(prompt).getResult().getOutput().getText();
}
}
我们通过访问地址就可以得到经过大模型修饰过的返回结果:
如果我们使用的是ChatClient我们依旧可以正常使用和Chatmodel一样
@GetMapping("/toolcall/chatClient")
public Flux<String> stream(@RequestParam(name = "msg", defaultValue = "现在几点") String msg) {ToolCallback[] tools = ToolCallbacks.from(new DataTimeTools());// 将工具集配置进ChatOptions当中ToolCallingChatOptions build = ToolCallingChatOptions.builder().toolCallbacks(tools).build();Prompt prompt = new Prompt(msg, build);return qwenChatClient.prompt(prompt).stream().content();
}
MCP模型上下文协议
MCP是什么?
在早期Spring AI(1.0.0-M6)的版本的时候,FunctingCalling几乎要被MCP取代,因为简单来说Tool Calling的编写工具类并没有办法给多个微服务进行调用,同样如果我们想要多写几个工具包的话,我们同样也需要进行大量的代码编写,所以从多种的角度来说的话,如何进行二者的兼顾呢,为了解决这个问题,我们为了解决多个微服务之间的问题,我们就可以使用MCP协议,简单来说就是我们通过自己的服务去调用同一个大模型服务,通过遵守MCP协议这样我们就可以通过一套协议就可以使用多家的工具包,所以就出现了MCP,几乎可以取代Tool Calling。
理解MCP很简单,就是统一的Type-C协议,只要是这个接口就可以使用进行充电和传递数据,MCP就是可以这样。我们如果想使用MCP,我们有两种方式,SSE,STDIO这两种方式的区别在于STDIO支持标准输入和输出流进行通信,主要用于本地集成、命令行工具等场景,SSE支持使用 HTTP POST请求进行服务器到客户端流式处理,以实现客户端到服务器的通信。
MCP的官方网站:MCP Servers
本地MCP调用
首先我们先进行本地的MCP使用,也就是说我们自己进行撰写。
首先我们先引入依赖和修改yml文件
!-- <!– Web 启动器(Spring Boot Web 核心依赖) –>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>--><!--注意,spring-boot-starter-web和spring-ai-starter-mcp-server-webflux是不能够同时使用的,使用第一个就会直接使用内置的tomcat最终导致mcpservice失败。--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-webflux</artifactId></dependency>
spring.ai.mcp.server.type=async
spring.ai.mcp.server.name=custom-define-mcp-server
spring.ai.mcp.server.version=1.0.0
现在我们需要进行工具类的编写,这个时候就可以进行方法的使用了package ai.Service;
import org.springframework.ai.tool.annotation.Tool;
import java.util.Map;
public class WeatherService {@Tool(description = "获取天气信息")public String getWeather(String city){Map<String,String> map = Map.of("北京","晴天","上海","阴天","深圳","雷阵雨");return map.getOrDefault(city,"未知城市");}
}
我们还需要一个配置类,来进行表示MCP的服务
package ai.config;
import ai.Service.WeatherService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class McpServerConfig {@Beanpublic ToolCallbackProvider toolCallbackProvider(WeatherService weatherService) {return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();}
}
我们启动之后就会发现启动的就是Netty服务器
我们如果想要正常使用这个服务端的话,首先我们要进行依赖的导入,我们如果想要调用需要另一个微服务进行。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-mcp-client</artifactId>
</dependency>
这个时候我们的配置文件就需要有这样的改动,注意端口号要是你服务端开启的端口进行调用。
spring.ai.mcp.server.type=async
spring.ai.mcp.server.url=http://localhost:8080
spring.ai.mcp.server.timeout=5000
然后重点在于Client配置的参数引入:
@Bean
public ChatClient chatClient(ChatModel chatModel, ToolCallbackProvider tools) {return ChatClient.builder(chatModel).defaultToolCallbacks(tools.getToolCallbacks()).build(); }
对于控制层的代码,我们就和正常调用是一样的