1. Tool Calling工具调用

1.1 定义

工具调用(也称为函数调用)是 AI 应用程序中的一种常见模式,允许模型与一组 API 或_工具_交互,从而增强其能力。

工具主要用于:

  • 信息检索:此类工具可用于从外部源(如数据库、Web 服务、文件系统或 Web 搜索引擎)检索信息。目标是增强模型的知识,使其能够回答原本无法回答的问题。例如,工具可用于检索给定位置的当前天气、检索最新新闻文章或查询数据库中的特定记录。
  • 执行操作:此类工具可用于在软件系统中执行操作,如发送电子邮件、在数据库中创建新记录、提交表单或触发工作流。目标是自动化原本需要人工干预或显式编程的任务。例如,工具可用于为客户预订航班、填写网页表单或基于自动化测试(TDD)实现 Java 类。

尽管我们通常将_工具调用_称为模型能力,但实际上是由客户端应用程序提供工具调用逻辑。模型只能请求工具调用并提供输入参数,而应用程序负责从输入参数执行工具调用并返回结果。模型永远无法访问作为工具提供的任何 API,这是一个关键的安全考虑因素。

简单来说,Tool Calling 就是LLM的外部utils工具类。
需要注意的是:

  • ToolCalling(也称为FunctionCalling)它允许大模型与一组API或工具进行交互,将 LLM 的智能与外部工具或 API无缝连接,从而增强大模型其功能。
  • LLM本身并不执行函数,它只是指示应该调用哪个函数以及如何调用。

1.2 作用

  • 访问实时数据
  • 执行某种工具类/辅助类操作,例如触发并调用第三方函数,比如发邮件/查询微信/调用支付宝/查看顺丰快递单据号等等......

1.3 工作流程

1.4 编码实战(不使用 ToolCalling)

1.4.1 新建Module

可以命名为 ToolCalling

1.4.2 修改POM文件

在依赖配置节点修改为以下配置:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--spring-ai-alibaba dashscope-->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.38</version>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

1.4.3 编写配置文件

在resources目录下新建application.properties配置文件,内容如下:

server.port=8013

# 设置全局编码格式
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8

spring.application.name=ToolCalling

# ====SpringAIAlibaba Config=============
spring.ai.dashscope.api-key=${DASHSCOPE_API_KEY}

1.4.4 编写主启动类

新建主启动类,并编写如下内容:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ToolCallingApplication {
    public static void main(String[] args){
        SpringApplication.run(ToolCallingApplication.class, args);
    }

}

1.3.5 编写业务类

新建子包controller,并在其中新建业务类 NoToolCallingController

import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
public class NoToolCallingController
{
    @Resource
    private ChatModel chatModel;

    /**
     * http://localhost:8013/notoolcall/chat
     * @param msg
     * @return
     */
    @GetMapping("/notoolcall/chat")
    public Flux<String> chat(@RequestParam(name = "msg",defaultValue = "你是谁现在几点") String msg)
    {
        return chatModel.stream(msg);
    }
}

1.3.6 测试

启动主启动类后,在浏览器中请求如下地址:

http://localhost:8013/notoolcall/chat

不使用 ToolCalling,则大模型无法感知时间。

1.5 编码实战(通过ChatModel实现)

1.5.1 新建Tool工具类

新建子包utils,并在其中创建工具类DateTimeTools

import org.springframework.ai.tool.annotation.Tool;

import java.time.LocalDateTime;

public class DateTimeTools{
    /**
     * 1.定义 function call(tool call)
     * 2. returnDirect
     *    true = tool直接返回不走大模型,直接给客户
     *    false = 默认值,拿到tool返回的结果,给大模型,最后由大模型回复
     */
    @Tool(description = "获取当前时间", returnDirect = false)
    public String getCurrentTime()
    {
        return LocalDateTime.now().toString();
    }
}

工具调用直接返回

1.5.2 编写业务类

在controller子包新建业务类 ToolCallingController

import com.atguigu.study.utils.DateTimeTools;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.ChatOptions;
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;
import reactor.core.publisher.Flux;


@RestController
public class ToolCallingController
{
    @Resource
    private ChatModel chatModel;


    @GetMapping("/toolcall/chat")
    public String chat(@RequestParam(name = "msg",defaultValue = "你是谁现在几点") String msg)
    {
        // 1.工具注册到工具集合里
        ToolCallback[] tools = ToolCallbacks.from(new DateTimeTools());

        // 2.将工具集配置进ChatOptions对象
        ChatOptions options = ToolCallingChatOptions.builder().toolCallbacks(tools).build();

        // 3.构建提示词
        Prompt prompt = new Prompt(msg, options);

        // 4.调用大模型
        return chatModel.call(prompt).getResult().getOutput().getText();
    }

}

1.5.3 测试

启动主启动类后,在浏览器中请求如下地址:

http://localhost:8013/toolcall/chat

1.6 编码实战(通过ChatClient实现)

由于chat client本身不会自动装配,直接定义无法使用,所以需要通过ChatClient.builder(chatModel).build()来构建。

1.6.1 编写配置类

新建子包config,并在其中新建配置类SaaLLMConfig

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SaaLLMConfig {
    @Bean
    public ChatClient chatClient(ChatModel chatModel){
        return ChatClient.builder(chatModel).build();
    }
}

1.6.2 修改业务类

将上文的业务类 ToolCallingController 进一步替换为如下

import com.atguigu.study.utils.DateTimeTools;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.ChatOptions;
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;
import reactor.core.publisher.Flux;


@RestController
public class ToolCallingController
{
    @Resource
    private ChatModel chatModel;

    @GetMapping("/toolcall/chat")
    public String chat(@RequestParam(name = "msg",defaultValue = "你是谁现在几点") String msg)
    {
        // 1.工具注册到工具集合里
        ToolCallback[] tools = ToolCallbacks.from(new DateTimeTools());

        // 2.将工具集配置进ChatOptions对象
        ChatOptions options = ToolCallingChatOptions.builder().toolCallbacks(tools).build();

        // 3.构建提示词
        Prompt prompt = new Prompt(msg, options);

        // 4.调用大模型
        return chatModel.call(prompt).getResult().getOutput().getText();
    }

    @Resource
    private ChatClient chatClient;

    @GetMapping("/toolcall/chat2")
    public Flux<String> chat2(@RequestParam(name = "msg",defaultValue = "你是谁现在几点") String msg)
    {
        return chatClient.prompt(msg)
                .tools(new DateTimeTools())
                .stream()
                .content();
    }
}

1.6.3 测试

启动主启动类后,在浏览器中请求如下地址:

localhost:8013/toolcall/chat2

将 DateTimeTools的 getCurrentTime方法上的@Tool注解修改为如下

@Tool(description = "获取当前时间", returnDirect = true)

将@Tool注解修改为以下,即returnDirect 设置为false

@Tool(description = "获取当前时间", returnDirect = false)

请求的结果和默认是一致的

1.7 注意事项

ToolCalling使用的前提是大模型支持function call才能正常调用。

2. MCP模型上下文协议(Model Context Protocol)

2.1 MCP 出现之前的局限性

之前每个大模型(如DeepSeek、ChatGPT)需要为每个工具单独开发接口(FunctionCalling),导致重复劳动。

2.2 MCP定义

MCP(模型上下文协议)是一种用于将 AI 应用程序连接到外部系统的开源标准。使用 MCP,Claude 或 ChatGPT 等人工智能应用程序可以连接到数据源(例如本地文件、数据库)、工具(例如搜索引擎、计算器)和工作流程(例如专门提示),使它们能够访问关键信息并执行任务。将 MCP 视为用于 AI 应用的 USB-C 端口。正如 USB-C 提供了连接电子设备的标准化方式一样,MCP 也提供了将 AI 应用程序连接到外部系统的标准化方式。

模型上下文协议(即 Model Context Protocol,MCP)是一个开放协议,它规范了应用程序如何向大型语言模型(LLM)提供上下文。MCP 提供了一种统一的方式将 AI 模型连接到不同的数据源和工具,它定义了统一的集成方式。在开发智能体(Agent)的过程中,我们经常需要将将智能体与数据和工具集成,MCP 以标准的方式规范了智能体与数据及工具的集成方式,可以帮助您在 LLM 之上构建智能体(Agent)和复杂的工作流。

简单地说,MCP协议就是Java界的SpringCloud Openfeign,只不过Openfeign是用于微服务通讯的,而MCP用于大模型通讯的,但它们都是为了通讯获取某项数据的一种机制。

2.3 作用

提供了一种标准化的方式来连接 LLMs 需要的上下文,MCP 就类似于一个 Agent 时代的 Type-C协议,希望能将不同来源的数据、工具、服务统一起来供大模型调用。

MCP 厉害的地方在于,不用重复造轮子。过去每个软件(比如微信、Excel)都要单独给 AI 做接口,现在 MCP 统一了标准,就像所有电器都用 USB-C 充电口,AI 一个接口就能连接所有工具。

形象化理解


 

官网地址: https://mcp.so/zh

2.4 MCP 架构知识

MCP遵循客户端-服务器架构,包含以下几个核心部分:

  • MCP 主机(MCP Hosts):发起请求的 AI 应用程序,比如聊天机器人、AI 驱动的 IDE 等。
  • MCP 客户端(MCP Clients):在主机程序内部,与 MCP 服务器保持 1:1 的连接。
  • MCP 服务器(MCP Servers):为 MCP 客户端提供上下文、工具和提示信息。
  • 本地资源(Local Resources):本地计算机中可供 MCP 服务器安全访问的资源,如文件、数据库。
  • 远程资源(Remote Resources):MCP 服务器可以连接到的远程资源,如通过 API 提供的数据。
     

2.4.1 MCP的两种模式

2.4.1.1 STDIO(标准输入/输出)

支持标准输入和输出流进行通信,主要用于本地集成、命令行工具等场景。

2.4.1.2 SSE (Server-Sent Events)

支持使用 HTTP POST 请求进行服务器到客户端流式处理,以实现客户端到服务器的通信。

2.4.1.3 二者对比

2.5 小总结

  • ToolCalling 工具类,为了让大模型使用Util工具。
  • RAG 知识库,为了让大模型获取足够的上下文。
  • MCP 协议,为了让大模型之间的相互调用。

2.5.1 MCP VS ToolCalling

之前每个大模型(如DeepSeek、ChatGPT)需要为每个工具单独开发接口(FunctionCalling),导致重复劳动(ToolCalling)

开发者只需写一次MCP服务端,所有兼容MCP协议的模型都能调用,MCP让大模型从"被动应答”变为”主动调用工具”(MCP)

调用一个MCP服务器就等价调用一个带有多个功能的Utils工具类,自己还不用受累携带(MCP)

2.6 编码实战(MCP-Server服务端实现)

2.6.1 新建Module

可以命名为LocalMcpServer

2.6.2 修改POM文件

在依赖配置节点修改为以下配置:

<dependencies>
        <!--注意事项(重要)
            spring-ai-starter-mcp-server-webflux不能和<artifactId>spring-boot-starter-web</artifactId>依赖并存,
            否则会使用tomcat启动,而不是netty启动,从而导致mcpserver启动失败,但程序运行是正常的,mcp客户端连接不上。
        -->
        <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>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.38</version>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

2.6.3 编写配置文件

在resources目录下新建application.properties配置文件,内容如下:

server.port=8014

# 设置全局编码格式
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8

spring.application.name=LocalMcpServer


# ====mcp-server Config=============
spring.ai.mcp.server.type=async
spring.ai.mcp.server.name=customer-define-mcp-server
spring.ai.mcp.server.version=1.0.0

2.6.4 编写主启动类

新建主启动类,并编写如下内容:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LocalMcpServerApplication {

    public static void main(String[] args){
        SpringApplication.run(LocalMcpServerApplication.class, args);
    }

}

2.6.5 编写业务类

新建子包service,并在其中新建业务类 WeatherService

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;

import java.util.Map;


@Service
public class WeatherService {
    @Tool(description = "根据城市名称获取天气预报")
    public String getWeatherByCity(String city)
    {
        Map<String, String> map = Map.of(
                "北京", "11111降雨频繁,其中今天和后天雨势较强,部分地区有暴雨并伴强对流天气,需注意",
                "上海", "22222多云,15℃~27℃,南风3级,当前温度27℃。",
                "深圳", "333333多云40天,阴16天,雨30天,晴3天"
        );
        return map.getOrDefault(city, "抱歉:未查询到对应城市!");
    }
}

2.6.6 编写配置类

新建子包config,并在其中新建配置类 McpServerConfig

import com.atguigu.study.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 {
    /**
     * 将工具方法暴露给外部 mcp client 调用
     * @param weatherService
     * @return
     */
    @Bean
    public ToolCallbackProvider weatherTools(WeatherService weatherService) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(weatherService)
                .build();
    }
}

2.7 编码实战(MCP-Client客户端实现)

 2.7.1 新建Module

可以命名为 LocalMcpClient

2.7.2 修改POM文件

在依赖配置节点修改为以下配置:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--spring-ai-alibaba dashscope-->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
        <!-- 2.mcp-clent 依赖 -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.38</version>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

2.7.3 编写配置文件

在resources目录下新建application.properties配置文件,内容如下:

server.port=8015

# 设置全局编码格式
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8

spring.application.name=LocalMcpClient

# ====SpringAIAlibaba Config=============
spring.ai.dashscope.api-key=${DASHSCOPE_API_KEY}

# ====mcp-client Config=============
spring.ai.mcp.client.type=async
spring.ai.mcp.client.request-timeout=60s
spring.ai.mcp.client.toolcallback.enabled=true
spring.ai.mcp.client.sse.connections.mcp-server1.url=http://localhost:8014

2.7.4 编写主启动类

新建主启动类,并编写如下内容:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LocalMcpClientApplication {

    public static void main(String[] args){
        SpringApplication.run(LocalMcpClientApplication.class, args);
    }

}

2.7.5 编写业务类

新建子包controller,并在其中新建业务类 McpClientController

import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;


@RestController
public class McpClientController
{
    @Resource
    private ChatClient chatClient;//使用mcp支持

    @Resource
    private ChatModel chatModel;//没有纳入tool支持,普通调用

    // http://localhost:8015/mcpclient/chat?msg=上海
    @GetMapping("/mcpclient/chat")
    public Flux<String> chat(@RequestParam(name = "msg",defaultValue = "北京") String msg)
    {
        System.out.println("使用了mcp");
        return chatClient.prompt(msg).stream().content();
    }

    @RequestMapping("/mcpclient/chat2")
    public Flux<String> chat2(@RequestParam(name = "msg",defaultValue = "北京") String msg)
    {
        System.out.println("未使用mcp");
        return chatModel.stream(msg);
    }
}

2.7.6 编写配置类

新建子包config,并在其中新建配置类 SaaLLMConfig

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SaaLLMConfig {
    @Bean
    public ChatClient chatClient(ChatModel chatModel, ToolCallbackProvider tools) {
        return ChatClient.builder(chatModel)
                .defaultToolCallbacks(tools.getToolCallbacks())  //mcp协议,配置见yml文件
                .build();
    }
}

2.7.7 测试

先启动MCP-Server端的主启动类,作为服务端等待调用

然后在浏览器输入如下地址

http://localhost:8015/mcpclient/chat?msg=上海

可以看到调用了MCP的大模型给出的回复。

http://localhost:8015/mcpclient/chat2?msg=上海

可以看到,本来我们是需要给定城市的天气信息,而大模型给我们返回的并不是我们想要的信息。

2.8 远程MCP增强案例-对接互联网通用MCP服务(百度地图)

对接互联网通用MCP服务(百度地图)

2.8.1 环境配置

下载最新版的NodeJS https://nodejs.org/zh-cn
注册百度地图账号+申请API-key https://lbsyun.baidu.com/

一定要注意此处全部勾选

可以设置为指定IP,Demo阶段建议简单设置为所有ip,生产环境请勿设置全开放。

2.8.2 编码实战

2.8.2.1 新建Module

可以命名为 ClientCallBaiduMcpServer

2.8.2.2 修改POM文件

在依赖配置节点修改为以下配置:

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--spring-ai-alibaba dashscope-->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
        <!-- 2.mcp-clent 依赖 -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.38</version>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
2.8.2.3 编写配置文件

在resources目录下新建application.properties配置文件,内容如下:

server.port=8016

# 设置全局编码格式
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8

spring.application.name=ClientCallBaiduMcpServer

# ====SpringAIAlibaba Config=============
spring.ai.dashscope.api-key=${DASHSCOPE_API_KEY}

# ====mcp-client Config=============
spring.ai.mcp.client.request-timeout=20s
spring.ai.mcp.client.toolcallback.enabled=true
spring.ai.mcp.client.stdio.servers-configuration=classpath:/mcp-server.json5
2.8.2.4 编写主启动类

新建主启动类,并编写如下内容:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ClientCallBaiduMcpServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ClientCallBaiduMcpServerApplication.class, args);
    }

}
2.8.2.5 编写配置类

新建子包config,并在其中新建配置类SaaLLMConfig

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SaaLLMConfig
{
    @Bean
    public ChatClient chatClient(ChatModel chatModel, ToolCallbackProvider tools)
    {
        return ChatClient.builder(chatModel)
                //mcp协议,配置见yml文件,此处只赋能给ChatClient对象
                .defaultToolCallbacks(tools.getToolCallbacks())
                .build();
    }
}
2.8.2.6 编写业务类

新建子包controller,并在其中新建业务类 McpClientCallBaiDuMcpController

import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
public class McpClientCallBaiDuMcpController {
    @Resource
    private ChatClient chatClient; //添加了MCP调用能力

    @Resource
    private ChatModel chatModel; //没有添加MCP调用能力

    /**
     * 添加了MCP调用能力
     * http://localhost:8016/mcp/chat?msg=查询北纬39.9042东经116.4074天气
     * http://localhost:8016/mcp/chat?msg=查询61.149.121.66归属地
     * http://localhost:8016/mcp/chat?msg=查询昌平到天安门路线规划
     * @param msg
     * @return
     */
    @GetMapping("/mcp/chat")
    public Flux<String> chat(String msg)
    {
        return chatClient.prompt(msg).stream().content();
    }

    /**
     * 没有添加MCP调用能力
     * http://localhost:8016/mcp/chat2?msg=查询北纬39.9042东经116.4074天气
     * @param msg
     * @return
     */
    @RequestMapping("/mcp/chat2")
    public Flux<String> chat2(String msg)
    {
        return chatModel.stream(msg);
    }
}
2.8.2.7 nodejs配置编码-Typescript接入

在resources目录下新建mcp-server.json5

{
  "mcpServers":
  {
    "baidu-map":
    {

      "command": "cmd",
      "args": ["/c", "npx", "-y", "@baidumap/mcp-server-baidu-map"],
      "env":  {"BAIDU_MAP_API_KEY": "此处替换为你申请的应用的AK"}
    }
  }
}
// 构建McpTransport协议

//cmd:启动 Windows 命令行解释器。
///c:告诉 cmd 执行完后面的命令后关闭自身。
//npx:npx = npm execute package,Node.js 的一个工具,用于执行 npm 包中的可执行文件。
//-y 或 --yes:自动确认操作(类似于默认接受所有提示)。
//@baidumap/mcp-server-baidu-map:要通过 npx 执行的 npm 包名
//BAIDU_MAP_API_KEY 是访问百度地图开放平台API的AK

使用说明:Baidu Map MCP Server

2.8.2.8 测试

启动主启动类后,在后台可以看到以下输出:

在浏览器中输入以下地址:

http://localhost:8016/mcp/chat?msg=查询北纬39.9042东经116.4074天气

http://localhost:8016/mcp/chat?msg=查询昌平到天安门路线规划

没有使用MCP的结果

http://localhost:8016/mcp/chat2?msg=查询北纬39.9042东经116.4074天气

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐