Java中使用Spring Boot+Ollama实现本地AI的MCP接入

目录结构

  • 完善spring boot
    • pom.xml添加依赖
    • application.yml
    • MCP 工具配置 mcp-servers.json
    • 配置类
    • 编写API

在我的上一篇文章搭建好本地的聊天机器人后,准备接入MCP进一步增强AI的能力,以实现类似手机AI的功能
在这里插入图片描述

参考的是第二篇文章链接其内容比较精炼,有些细节被忽略了,导致踩坑不少,可能是因为版本原因,最终我没能使用他的方案运行成功,转而使用了另一个方案,原文连接
为什么使用Qwen3
在这里插入图片描述

完善spring boot

pom.xml添加依赖

在这里插入图片描述

在实际添加过程中,第一个依赖我用的不一样,原文给的我无法加载,第二个依赖我并不能成功加入,我使用的依赖如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>Qwen3</artifactId><version>0.0.1-SNAPSHOT</version><name>Qwen3</name><description>Qwen3</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.1</version></parent><properties><java.version>17</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-ollama-spring-boot-starter</artifactId><version>1.0.0-M6</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId><version>1.0.0-M6</version></dependency></dependencies><repositories><repository><id>spring-milestones</id><url>https://repo.spring.io/milestone</url></repository><repository><id>spring-snapshots</id><url>https://repo.spring.io/snapshot</url><snapshots><enabled>true</enabled></snapshots></repository></repositories><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>17</source><target>17</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><mainClass>com.example.qwen3.Qwen3Application</mainClass></configuration></plugin></plugins></build></project>

MCP客户端和服务端分别作用
在这里插入图片描述
我两者都添加了

application.yml

yml完全改掉了,毕竟

spring:ai:ollama:base-url: http://localhost:11434chat:enabled: true# 聊天模型model: qwen3:4boptions:temperature: 0.7top_p: 0.9num_predict: 5120   # 单次回复最大长度,根据自己电脑性能来定embedding:enabled: true# 向量模型(通常用小点的模型效率高)model: qwen3:4boptions:num-batch: 5120mcp:client:enabled: truename: mcp-clientversion: 1.0type: SYNCrequest-timeout: 30sstdio:servers-configuration: classpath:/mcp-server-settings.jsonlogging:level:org.springframework.ai.mcp.tool: DEBUGserver:port: 8181

MCP 工具配置 mcp-servers.json

我想使用本地文件操作以实现
在这里插入图片描述
它需要安装Node.js 和 npm
自测一下确实安装过了
在这里插入图片描述
并且

在红框路径新建mcp-servers.json文件,注意红色下划线处要改成自己的桌面路径
在这里插入图片描述

{"mcpServers": {"filesystem": {"command": "F:\\Environment\\nodejs\\npx.cmd","args": ["-y","@modelcontextprotocol/server-filesystem","C:\\Users\\lenovo\\Desktop\\temp"]}}
}

“filesystem” 是 MCP server 的名字

“command”: “npx.cmd” → Windows 下用 npx 启动(Linux/macOS 下就是 “npx”)

“@modelcontextprotocol/server-filesystem” 是官方提供的文件系统 MCP server

“C:\Users\lenovo\Desktop\temp” 表示允许 AI 访问的目录范围

配置类

package com.example.qwen3.config;import io.modelcontextprotocol.client.McpSyncClient;
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.List;@Configuration
public class McpConfig {@Beanpublic SyncMcpToolCallbackProvider syncMcpToolCallbackProvider(List<McpSyncClient> mcpSyncClients) {return new SyncMcpToolCallbackProvider(mcpSyncClients);}}

编写API

在这里插入图片描述

package com.example.qwen3.controller;import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.api.OllamaOptions;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
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;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;import java.time.Duration;@RequestMapping("/mcp")
@RestController
public class McpController {private final OllamaChatModel chatModel;private final SyncMcpToolCallbackProvider syncMcpToolCallbackProvider;public McpController(OllamaChatModel chatModel, SyncMcpToolCallbackProvider syncMcpToolCallbackProvider) {this.chatModel = chatModel;this.syncMcpToolCallbackProvider = syncMcpToolCallbackProvider;}@GetMapping("/mcpChat")public String generate(@RequestParam(value = "prompt") String prompt) {ChatClient chatClient = ChatClient.builder(chatModel).defaultTools(syncMcpToolCallbackProvider.getToolCallbacks()).build();return chatClient.prompt().user(prompt).call().content();}@GetMapping(value = "/mcpChatStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<ChatResponse> generateStream(@RequestParam(value = "prompt") String prompt) {// 先执行一次完整的调用以确保工具被执行ChatClient chatClient = ChatClient.builder(chatModel).defaultTools(syncMcpToolCallbackProvider.getToolCallbacks()).defaultOptions(OllamaOptions.builder().model("qwen3:4b").build()).build();// 执行工具调用(非流式)String result = chatClient.prompt().user(prompt).call().content();// 然后返回流式响应(基于已执行的结果)return chatClient.prompt().user(prompt + "\n\n基于上述操作,请总结执行结果:").stream().chatResponse();}// 方案5:简化版本 - 直接使用工作版本的逻辑@GetMapping(value = "/mcpChatStreamFixed", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> mcpChatStreamFixed(@RequestParam("prompt") String prompt) {ChatClient chatClient = ChatClient.builder(chatModel).defaultTools(syncMcpToolCallbackProvider.getToolCallbacks()).build();// 使用已知工作的逻辑,但改为流式输出return Mono.fromCallable(() -> {// 先执行完整的对话(包括工具调用)return chatClient.prompt().user(prompt).call().content();}).flatMapMany(result -> {// 然后将结果分块流式返回return Flux.fromArray(result.split("")).delayElements(Duration.ofMillis(50)); // 每个字符延迟50ms}).subscribeOn(Schedulers.boundedElastic());}@GetMapping("/test")public String test(@RequestParam(value = "prompt") String prompt) {return "input=" + prompt;}
}

我在想要实现流式问答部分卡了很久,原因是在流式响应中,工具调用和工具执行的时机与非流式不同,导致工具调用被跳过或执行顺序有问题。
所以要么就是一次性输出内容,比如

http://localhost:8181/mcp/mcpChat?在temp目录下创建文件e1.txt,内容为我是mcpChat创建的文件

要么是先执行操作,再流式输出对于上一次操作的总结

http://localhost:8181/mcp/mcpChatStream?在temp目录下创建文件e2.txt,内容为我是mcpChat创建的文件

或者单纯流式
本地模型速度还是太慢了,实测大概需要5分钟才能创建好一个文件,基本没有实用性可言

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/94816.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/94816.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#正则表达式与用法

&#x1f31f; C# 常用正则表达式与用法C# 使用正则需要引用命名空间&#xff1a;using System.Text.RegularExpressions; 常用方法&#xff1a;Regex.IsMatch(input, pattern) → 返回 bool&#xff0c;用于验证Regex.Match(input, pattern) → 返回 Match 对象&#xff0c;可…

从0开始学习Java+AI知识点总结-27.web实战(Maven高级)

一、分模块设计与开发&#xff1a;让项目结构更清晰1.1 为什么需要分模块&#xff1f;单模块开发的痛点在小型项目中&#xff0c;单模块&#xff08;所有代码放在一个工程&#xff09;或许能满足需求&#xff0c;但项目规模扩大后会出现两大核心问题&#xff1a;维护成本高&…

Ferris Wheel (贪心 | 双指针)

题目&#xff1a;思路&#xff1a;本题注意题目的条件即可&#xff0c;题意说一个摩天轮可以坐一个人或者两个人&#xff0c;那么显然我们就可以贪心一下具体的&#xff0c;我们可以让最小的去匹配最大的&#xff0c;如果此时大于 x&#xff0c;那么显然我们根本无法使得 最大的…

课程视频怎么加密?在线教育机构常用的6个课程加密方法

知识付费时代&#xff0c;课程视频是教育机构的核心资产。但是不难发现&#xff0c;课程视频的安全却得不到保障。各大购物平台搜索课程名称&#xff0c;便出现了许多盗版课程。如何有效防止课程被翻录和二次传播&#xff0c;成为急需解决的关键问题。今天这期分享点干货&#…

SOME/IP-SD中”服务器服务组播端点”、“客户端服务组播端点”与“IPv4组播选项的区分

<摘要> AUTOSIP-SD协议中组播端点&#xff08;Multicast Endpoint&#xff09;在不同上下文中的角色与表述差异。准确理解“服务器服务组播端点”、“客户端服务组播端点”与“IPv4组播选项”中配置的端点之间的关系&#xff0c;是正确实现组播事件分发机制的关键。这涉及…

计算机是如何运行的

目录 一&#xff0c;计算机是如何组成的 1.1&#xff0c;CPU中央处理单元 1.1.1&#xff0c;CPU的构成和属性 1.1.2&#xff0c;如何判断cpu的好坏 1.1.3&#xff0c;指令 1.1.4&#xff0c;CPU的缓存 1.2&#xff0c;操作系统 1.2.1&#xff0c;进程 1.2.2&#xff0…

JavaScript性能优化:实战技巧与高效策略

JavaScript性能优化实战技术文章大纲性能优化的重要性解释为什么性能优化对用户体验和业务指标至关重要列举常见性能问题的影响&#xff08;如跳出率、转化率下降&#xff09;代码层面的优化减少全局变量使用&#xff0c;避免内存泄漏使用事件委托减少事件监听器的数量避免频繁…

解决.env.production 写死 IP 的问题:Vue + config.json 运行时加载方案

背景&#xff1a;前端常用 .env.production 在构建时写死 API 地址 场景&#xff1a;运维部署时经常不知道目标主机 IP/域名 问题&#xff1a;每次 IP 变动都要重新编译 → 增加运维成本 引出需求&#xff1a;只修改 IP 就能完成部署&#xff0c;不需要重新打包 目录一、解决方…

如何从三星手机转移到另一部三星手机

三星Galaxy S系列因其出色的设计、令人惊叹的显示屏、惊艳的摄像头、更好的扬声器以及创新的指纹传感器而受到大多数用户的欢迎&#xff0c;获得了良好的声誉。让用户感到满意的是&#xff0c;三星Galaxy S10拥有更美观的设计、令人惊叹的显示屏、令人惊叹的摄像头、更好的扬声…

聚焦建筑能源革新!安科瑞 “光储直柔” 方案护航碳中和目标实现

1、背景在 “双碳” 目标引领下&#xff0c;能源结构转型与建筑能效提升成为重要课题。清华大学江亿院士提出的 “光储直柔” 新型配电系统&#xff0c;为建筑领域绿色发展提供了创新方向。光储直柔得到了业界广泛认同和积极响应&#xff0c;国家、各部委、地区陆续出台相关政策…

Shell 中 ()、(())、[]、{} 的用法详解

文章目录Shell 中 ()、(())、[]、{} 的用法详解一、先明确&#xff1a;四类符号的核心功能定位二、逐个拆解&#xff1a;用法、示例与避坑点1. ()&#xff1a;子 Shell 执行&#xff0c;隔离环境核心用法1&#xff1a;子 Shell 执行命令&#xff0c;隔离变量核心用法2&#xff…

开发避坑指南(41):Vue3 提示框proxy.$modal.msgSuccess()提示文本换行解决方案

需求 由于接口返回的提示信息过长&#xff0c;接口已经在返回提示中加入换行标签了&#xff0c;但是使用proxy.modal.msgSuccess(res.msg)提示没有换行&#xff0c;那么Vue3中proxy.modal.msgSuccess(res.msg)提示没有换行&#xff0c;那么Vue3 中 proxy.modal.msgSuccess(res.…

[Sync_ai_vid] 唇形同步推理流程 | Whisper架构

链接&#xff1a;https://github.com/bytedance/LatentSync/blob/main/docs/syncnet_arch.md docs&#xff1a;LatentSync LatentSync是一个端到端唇语同步项目&#xff0c;能够生成语音与唇形完美匹配的逼真视频。 该项目通过使用*音频条件化3D U-Net*&#xff08;一种生成式…

uniapp中 ios端 scroll-view 组件内部子元素z-index失效问题

发现子组件中的弹窗在ios手机上会被限制在scroll-view里面&#xff0c;安卓手机上不受限制&#xff0c;网上找了好久原因 scroll-view组件内部设置了 -webkit-overflow-scrolling: touch 样式&#xff0c;导致z-index失效&#xff08;safari 3D变换会忽略z-index的层级问题&…

PyTorch图像预处理完全指南:从基础操作到GPU加速实战

引言 图像预处理是模型性能的"隐形基石"&#xff0c;在计算机视觉任务中直接决定模型能否提取有效特征。科学的预处理流程能让基础模型性能提升15%以上&#xff0c;而GPU加速预处理可使数据准备阶段耗时降低60%以上。本文将聚焦PyTorch预处理核心技术&#xff0c;从基…

【前端教程】 CSS浮动布局解析与优化:从基础实现到工程化改进

浮动(float)是CSS中实现页面布局的经典技术,虽然现代布局更多使用Flexbox和Grid,但理解浮动的工作原理仍是前端开发者的基础素养。本文以一个三栏浮动布局的代码为例,从布局原理解析、潜在问题诊断、工程化优化三个维度,带你深入理解浮动布局的精髓与优化思路。 一、原代…

DVWA靶场通关笔记-暴力破解(Impossible级别)

目录 一、查看源码 二、功能分析 三、SQL注入分析 1、使用PDO预处理语句和参数绑定 2、mysqli_real_escape_string转义 3、stripslashes去除反斜杠 四、暴力破解分析 1、token防止暴力破解机制 2、登录失败随机延迟机制 3、登陆失败报错信息相同 4、登陆失败的账户…

IAR工程如何生成compile_commands.json文件(能生成但是clangd不能生成“.cache文件”)

最近一直在使用vscodeclangd的方式编写代码&#xff0c;感觉使用clangd查找函数调用、函数声明、类型定义等等都比使用vscode自带的c/c插件好用太多了。现在我有一个功能是IAR版本的&#xff0c;那么有没有办法生成clangd使用的compile_commands.json文件呢&#xff1f;答案是&…

QT5.14.2、CMake 扩展openCV

一、准备工具Qt5.14.2c11cmake3.24.0opencv3.4.16二、使用cmake可扩展opencv 首先解压cmake、opencv 两个下载的压缩包&#xff0c;如下&#xff1a;运行cmake-gui.exe打开后有弹窗选择&#xff0c;然后进入QT的安装路径下找 mingw73_64文件下的 C和C的执行文件这个截图是我扩展…

【3D入门-指标篇下】 3D重建评估指标对比-附实现代码

3D重建评估指标对比表 每个指标的具体代码位于文章末尾指标计算方法数值范围评估重点优缺点适用场景Chamfer Distance (C1)从预测网格到真实网格的平均距离[0, ∞)几何形状准确性优点&#xff1a;直观、计算高效缺点&#xff1a;对噪声敏感整体形状评估Chamfer Distance (C2)从…