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
英文地址,請注明出處:http://en.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)從…