SpringBoot+LangChain4j+Ollama+MCP实现智能天气工具调用示例

场景

SpringBoot+LangChain4j+Ollama实现Function Calling工具调用-仿智能客服示例:

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/160409823

基于上述基础,学会简单的Tools的使用,下面学习MCP相关概念和入门案例。

一、MCP 核心概念

MCP(Model Context Protocol) 是由 Anthropic 推出的开放协议,旨在为大型语言模型(LLM)与外部工具、数据源之间建立统一的交互标准。

它采用 客户端-服务器 架构,核心角色如下:

角色 说明
MCP Host 宿主应用(如 Claude Desktop、VS Code 插件)
MCP Client 在 Host 内部,与 Server 进行 1:1 协议连接,负责发现工具、发起调用、接收结果
MCP Server 轻量级服务,通过 MCP 暴露工具(Tools)、资源(Resources)、提示模板(Prompts)

两大传输模式:

SSE(Server-Sent Events)

旧版规范,客户端通过 GET /sse 建立长连接,获取一个 sessionId,后续请求发往 POST /mcp/message?sessionId=xxx。

存在空闲超时、断连重连等问题。

Streamable HTTP

2025 新规范,统一端点 /mcp,每次请求独立,天然避免长连接超时,稳定性更好。

本文示例 基于旧版 SSE,因其学习资源更多、兼容早期 Spring AI 实现。

二、核心知识点速查

JSON-RPC 2.0:MCP 的底层消息格式,请求带 id,支持通知(无 id)。

工具动态发现:Client 初始化时发送 tools/list 请求,Server 返回工具清单及 JSON Schema。

工具调用流程:LLM 决定调用工具 → Client 发送 tools/call → Server 执行并返回结果 → Client 将结果回填给 LLM。

模型要求:必须支持 原生 Function Calling(如 gpt-4o-mini、qwen2.5:7b-instruct、llama3.1:8b-instruct-fp16)。

Ollama 兼容性:

建议通过 OpenAI 兼容端点 /v1 调用,即使用 OpenAiChatModel 并设置 baseUrl = http://localhost:11434/v1

可显著提升函数调用稳定性。

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi

实现

三、MCP Server搭建

环境准备

组件 版本/说明
JDK 17+
Spring Boot 3.4.5
LangChain4j 1.0.0-beta3
MCP Server Spring AI 1.1.4 实现的天气查询服务(暴露 /sse/mcp/message
Ollama 本地运行,模型 qwen2.5:7b-instruct(需支持 Function Calling)

MCP Server

三大核心原语:

MCP Server可以向外暴露三种不同类型的"能力":

Tools (工具):

这是最常用的功能,指AI模型可以调用的函数。模型会根据你的描述,生成结构化的参数来调用你定义的工具。

例如,一个 get_weather 工具可以接收城市名并返回天气信息。

Resources (资源):

以只读方式暴露给LLM的结构化数据,模型可以像读取文件一样访问这些数据。

Prompts (提示模板):

提供预定义的提示词模板,让客户端可以获取并使用,保证AI交互的一致性。

协议与架构:

MCP采用客户端-服务器架构,通过标准化的JSON-RPC 2.0进行通信。

协议交互流程:

一次完整的交互通常分为三个阶段:

连接建立(客户端请求并验证服务器能力)、工具发现(客户端发送 tools/list 请求获取工具列表)

和工具调用(客户端发送 tools/call 请求执行具体工具)

如何暴露工具:从注解到手动注册

在Java生态中,定义工具并将其暴露给AI有几种不同的方式,核心是告诉框架你的函数及其参数规范。

向AI应用暴露MCP工具主要有以下机制:

Spring AI @Tool 注解、Spring AI @McpTool 注解 (Spring AI 1.1.0-M1+、Spring AI FunctionCallback 接口

本文使用@Tool 注解的方式。

实战演练:搭建你的第一个MCP天气服务器

下面以"天气查询服务器"为例,基于Spring Boot生态,搭建一个MCP Server。

使用Spring Boot + Spring AI Starter (推荐)

这是最标准、最快捷的方式,Spring AI提供了专门的Starter来简化开发

第一步:引入核心依赖

在你Server项目的pom.xml中,添加以下依赖:

复制代码
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
            <version>1.1.4</version>
        </dependency>

(此Starter会自动引入其他必需的库,如Spring Web、Jackson等)

完整pom:

复制代码
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version>
    </parent>

    <groupId>com.badao.ai</groupId>
    <artifactId>weather-mcp-server</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Spring AI MCP Server Starter (WebMVC 版) -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
            <version>1.1.4</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

第二步:配置应用基础信息

在application.yml中,设置你的服务器名称和版本:

复制代码
server:
  port: 8081
spring:
  ai:
    mcp:
      server:
        protocol: SSE
        name: weather-mcp-server
        version: 1.0.0

注意这里的protocol,指定协议方式为SSE

第三步:定义一个工具

创建一个Service类,并使用@Tool注解标记你的业务方法。

复制代码
package com.badao.ai.mcpserver;

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

@Service
public class WeatherService {

    @Tool(name = "getWeather", description = "查询指定城市的天气信息")
    public WeatherResult getWeather(
            @ToolParam(description = "城市名称,例如:北京") String city) {
        // 模拟天气数据,实际可接入真实API
        System.out.println("调用了getWeather");
        return new WeatherResult(city, "晴", "25°C", "湿度:60%");
    }

    public record WeatherResult(
            String city,
            String weather,
            String temperature,
            String details
    ) {}
}

@Tool和@ToolParam注解中的description非常重要,它们是LLM理解工具功能和参数含义的唯一途径,

描述越清晰准确,模型调用工具的成功率就越高。

第四步:注册工具

在你的Spring Boot启动类或一个配置类中,将你的WeatherService注册为工具提供者:

复制代码
package com.badao.ai;

import com.badao.ai.mcpserver.WeatherService;
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 SpringAiDemoApplication {

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

    // 方式一:启动时注册,自动扫描 @Tool 注解
    @Bean
    public ToolCallbackProvider weatherTools(WeatherService weatherService) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(weatherService)
                .build();
    }
}

四、MCP Client搭建

环境准备

1、确保 MCP 天气服务器在 http://localhost:8081 运行。

访问:

http://localhost:8081/sse

如果返回 event:endpoint 和 sessionId,这就是旧版 (SSE)。且启动成功。

2、确保 Ollama 服务在 http://localhost:11434 运行,并且已拉取 qwen2.5:7b-instruct。

拉取并运行支持工具的模型:

复制代码
ollama pull qwen2.5:7b-instruct

确认你的 Ollama 模型是否支持工具调用:

复制代码
​
curl http://localhost:11434/api/chat -d '{
  "model": "qwen2.5:7b-instruct",
  "messages": [
    {"role": "user", "content": "青岛天气如何?"}
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "getWeather",
        "description": "获取城市天气",
        "parameters": {
          "type": "object",
          "properties": {
            "city": { "type": "string", "description": "城市名" }
          },
          "required": ["city"]
        }
      }
    }
  ],
  "stream": false
}'

​

如果返回类似以下内容,说明模型支持工具调用:

复制代码
{
  "message": {
    "role": "assistant",
    "content": "",
    "tool_calls": [
      {
        "function": {
          "name": "getWeather",
          "arguments": { "city": "青岛" }
        }
      }
    ]
  }
}

如果返回的 content 是普通文本(没有 tool_calls),说明该模型不支持工具调用。

依赖(pom.xml)

复制代码
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.5</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>mcp-client-standalone</artifactId>
    <version>1.0</version>

    <properties>
        <java.version>17</java.version>
        <langchain4j.version>1.0.0-beta3</langchain4j.version>
    </properties>

    <dependencies>
        <!-- Spring Boot Web 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- MCP 客户端依赖 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-mcp</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>
        <!-- Spring Boot Starter,提供 @AiService 支持 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-spring-boot-starter</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>
    </dependencies>

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

应用配置(application.yml)

复制代码
​
server:
  port: 8082

langchain4j:
  ollama:
    chat-model:
      base-url: http://localhost:11434
      model-name: qwen2.5:7b-instruct   # 需要支持 Function Calling
      log-requests: true
      log-responses: true
      timeout: 60s # 为 Ollama 模型调用设置 60 秒的超时

​

注意这里的本地的ollama调用要加超时时间,否则无法看到预想的效果!

核心配置类(ManualAssistantConfig.java)

复制代码
​
package com.badao.ai.config;

import com.badao.ai.service.WeatherAssistant;
import dev.langchain4j.mcp.McpToolProvider;
import dev.langchain4j.mcp.client.DefaultMcpClient;
import dev.langchain4j.mcp.client.McpClient;
import dev.langchain4j.mcp.client.transport.McpTransport;
import dev.langchain4j.mcp.client.transport.http.HttpMcpTransport;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.tool.ToolProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
import java.util.List;

@Configuration
public class ManualMcpConfig {

    @Bean
    public WeatherAssistant weatherAssistant() {
        // 1. 创建 Ollama 聊天模型
        ChatLanguageModel model = OpenAiChatModel.builder()
                .baseUrl("http://localhost:11434/v1")    // Ollama 的 OpenAI 兼容端点
                .apiKey("ollama")                        // 任意非空字符串
                .modelName("qwen2.5:7b-instruct")        // 你的模型名
                .timeout(Duration.ofSeconds(60))
                .build();

        // 2. 配置 MCP 传输层(连接远程 Weather Server)
        McpTransport transport = new HttpMcpTransport.Builder()
                .sseUrl("http://localhost:8081/sse")  // 指向 MCP Server 的 SSE 端点
                .logRequests(true)
                .logResponses(true)
                .build();

        // 3. 创建 MCP 客户端
        McpClient mcpClient = new DefaultMcpClient.Builder()
                .transport(transport)
                .build();

        // 4. 通过 McpToolProvider 将远端工具转换为本地可调用的 ToolProvider
        ToolProvider toolProvider = McpToolProvider.builder()
                .mcpClients(List.of(mcpClient))
                .build();

        // 5. 手动组装 AiService(系统提示 + 模型 + 工具)
        return AiServices.builder(WeatherAssistant.class)
                .chatLanguageModel(model)
                .toolProvider(toolProvider)
                .build();
    }
}

​

定义 AI 服务接口

复制代码
package com.badao.ai.service;

public interface WeatherAssistant {
    String chat(String userMessage);
}

控制器(ChatController.java)

复制代码
package com.badao.ai.controller;

import com.badao.ai.service.WeatherAssistant;
import org.springframework.web.bind.annotation.*;
import java.util.Map;

@RestController
public class ChatController {
    private final WeatherAssistant weatherAssistant;

    public ChatController(WeatherAssistant weatherAssistant) {
        this.weatherAssistant = weatherAssistant;
    }

    @PostMapping("/chat")
    public Map<String, String> chat(@RequestBody Map<String, String> request) {
        String userMessage = request.get("message");
        String response = weatherAssistant.chat(userMessage);
        return Map.of("response", response);
    }
}

五、 运行与验证

启动 MCP 天气服务器(端口 8081,确保 /sse 端点可访问)。

启动 Ollama,确保 qwen2.5:7b-instruct 已下载。

启动本客户端(端口 8082)。

调用接口:

复制代码
​
curl -X POST http://localhost:8082/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "青岛天气?"}'

​

此时查看mcp server的日志,确实被调用

六、常见问题排查

1、启动报 IllegalConfigurationException

未找到 ChatLanguageModel Bean 采

用手动配置类 ManualAssistantConfig,不依赖 @AiService 自动扫描

2、调用接口返回模拟调用文本

模型不支持 Function Calling 或未使用 /v1 端点

用 Postman 测试模型是否返回 tool_calls,改用 OpenAiChatModel

3、Unexpected status code: 404

SSE 会话失效,客户端向旧端点发请求 重启客户端或改用 Streamable HTTP

4、SSE 连接超时 正常现象,

SSE 空闲关闭 忽略警告或切换到 Streamable HTTP

5、依赖版本混乱导致 ClassNotFoundException 或 IllegalConfigurationException现象:

启动时提示 Please specify either chatLanguageModel or streamingChatLanguageModel,

或报 Cannot resolve symbol 'StreamableHttpMcpTransport'。

根本原因:

混用了 langchain4j 不同模块的 beta 版本(如 mcp 使用 1.1.0-beta7,而 ollama 使用 1.0.0-beta3),内部 API 不兼容。

某些版本缺少特定的类(例如 StreamableHttpMcpTransport 在 1.0.0-beta3 中不存在,需要 1.1.0-beta7 以上)。

未正确添加 langchain4j-spring-boot-starter 依赖,导致 @AiService 注解无法被识别。

解决方案:

统一所有 LangChain4j 模块的版本,最终确定使用 1.0.0-beta3,该版本各模块齐备且兼容。

直接引入 langchain4j-mcp 和 langchain4j-open-ai,避免使用多余的 Starter 造成冲突。

7、参考资料

https://docs.langchain4j.dev/tutorials/mcp/

相关推荐
苏三说技术8 分钟前
Claude Code从失控到起飞,只用了这些技巧
后端
长栎1 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode1 小时前
Redis 在生产项目的使用
前端·后端
用户559822481221 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode1 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战1 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha2 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn2 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端
用户762352425912 小时前
ShardingJDBC
后端
行者全栈架构师2 小时前
IDEA 中 Maven 项目的 15 个红色报错快速解决方法
java·后端