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/

相关推荐
sindyra1 小时前
享元模式(Flyweight Pattern)
java·开发语言·设计模式·享元模式·优缺点
这是程序猿1 小时前
设计模式入门:Java 单例模式(Singleton)详解,从入门到实战
java·单例模式·设计模式
codingPower1 小时前
ApplicationListener 和 SpringApplicationRunListener 深度解析对比
java·开发语言·spring boot
ch.ju1 小时前
Java Programming Chapter 2-Recursion of function
java·开发语言
铁皮哥1 小时前
【后端开发】RabbitMQ、RocketMQ、Kafka 怎么选?我从业务场景重新梳理了一遍
java·linux·数据库·分布式·kafka·rabbitmq·rocketmq
AC赳赳老秦1 小时前
数据库操作自动化:用 OpenClaw 对接 Navicat/DBeaver,实现数据备份、脱敏、日常操作自动化
java·运维·数据库·python·oracle·自动化·openclaw
程序员小白条1 小时前
AI 编程辅助,从入门到真香
java·开发语言·数据库·人工智能·面试·职场和发展
ErizJ1 小时前
Go|腾讯面经总结
开发语言·后端·golang
曹牧1 小时前
Java:“Syntax error on token “do“, Identifier expected”
java·开发语言