Spring AI 系列之三十五 - Spring AI Alibaba-Graph框架之MCP

之前做個幾個大模型的應用,都是使用Python語言,后來有一個項目使用了Java,并使用了Spring AI框架。隨著Spring AI不斷地完善,最近它發布了1.0正式版,意味著它已經能很好的作為企業級生產環境的使用。對于Java開發者來說真是一個福音,其功能已經能滿足基于大模型開發企業級應用。借著這次機會,給大家分享一下Spring AI框架。

注意由于框架不同版本改造會有些使用的不同,因此本次系列中使用基本框架是 Spring AI-1.0.0,JDK版本使用的是19,Spring-AI-Alibaba-1.0.0.3-SNAPSHOT
代碼參考: https://github.com/forever1986/springai-study

目錄

  • 1 示例演示
    • 1.1 初始化
    • 1.2 構建圖和節點
    • 1.3 演示效果

上一章演示了Graph框架的并行執行流程,并剖析了其中ParallelNode的實現邏輯。這一章來講一下Graph如何訪問MCP。

1 示例演示

代碼參考lesson26子模塊中的graph-mcp子模塊

示例說明:通過構建一個Graph圖,其中定義一個訪問MCP節點

在這里插入圖片描述

1.1 初始化

1)本次MCP服務采用前面lesson10子模塊的sse-server子模塊作為MCP Server,啟動該服務

在這里插入圖片描述

2)在lesson26子模塊下,新建graph-mcp子模塊,其pom引入如下:

<dependencies><!-- 引入智譜的model插件 --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-zhipuai</artifactId></dependency><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-graph-core</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-client-webflux</artifactId></dependency><!-- 需要引入gson插件 --><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.6</version></dependency>
</dependencies>

3)新建application.properties配置文件

# 聊天模型
spring.ai.zhipuai.api-key=你的智譜API KEY
spring.ai.zhipuai.chat.options.model=GLM-4-Flash-250414
spring.ai.zhipuai.chat.options.temperature=0.7# 指定mcp-servers的URL
spring.ai.mcp.client.type=SYNC
spring.ai.mcp.client.sse.connections.server1.url=http://localhost:8081spring.ai.graph.nodes.node2servers.mcp-node=server1

4)新建McpNodeProperties讀取配置spring.ai.graph.nodes開頭

import org.springframework.boot.context.properties.ConfigurationProperties;import java.util.Map;
import java.util.Set;/*** 為了方便解析配置多少個MCP服務*/
@ConfigurationProperties(prefix = McpNodeProperties.PREFIX)
public class McpNodeProperties {public static final String PREFIX = "spring.ai.graph.nodes";private Map<String, Set<String>> node2servers;public Map<String, Set<String>> getNode2servers() {return node2servers;}public void setNode2servers(Map<String, Set<String>> node2servers) {this.node2servers = node2servers;}
}

1.2 構建圖和節點

1)新建McpClientToolCallbackProvider類,用于讀取toolcall

import com.demo.lesson26.mcp.config.McpNodeProperties;
import org.apache.commons.compress.utils.Lists;
import org.glassfish.jersey.internal.guava.Sets;
import org.springframework.ai.mcp.McpToolUtils;
import org.springframework.ai.mcp.client.autoconfigure.properties.McpClientCommonProperties;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.definition.ToolDefinition;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Set;@Service
public class McpClientToolCallbackProvider {private final ToolCallbackProvider toolCallbackProvider;private final McpClientCommonProperties commonProperties;private final McpNodeProperties mcpNodeProperties;public McpClientToolCallbackProvider(ToolCallbackProvider toolCallbackProvider,McpClientCommonProperties commonProperties, McpNodeProperties mcpNodeProperties) {this.toolCallbackProvider = toolCallbackProvider;this.commonProperties = commonProperties;this.mcpNodeProperties = mcpNodeProperties;}/*** 通過配置的spring.ai.graph.nodes的名稱,獲取從Spring AI中獲取到的toolCall*/public Set<ToolCallback> findToolCallbacks(String nodeName) {// 獲取配置文件中spring.ai.graph.nodes開頭的數據Set<ToolCallback> defineCallback = Sets.newHashSet();Set<String> mcpClients = mcpNodeProperties.getNode2servers().get(nodeName);if (mcpClients == null || mcpClients.isEmpty()) {return defineCallback;}List<String> exceptMcpClientNames = Lists.newArrayList();for (String mcpClient : mcpClients) {// my-mcp-clientString name = commonProperties.getName();// mymcpclientserver1String prefixedMcpClientName = McpToolUtils.prefixedToolName(name, mcpClient);exceptMcpClientNames.add(prefixedMcpClientName);}// 從Spring AI的MCP客戶端獲取到的toolCall,放到defineCallback,以方便注冊到MCPNode中的chatClientToolCallback[] toolCallbacks = toolCallbackProvider.getToolCallbacks();for (ToolCallback toolCallback : toolCallbacks) {ToolDefinition toolDefinition = toolCallback.getToolDefinition();String name = toolDefinition.name();for (String exceptMcpClientName : exceptMcpClientNames) {if (name.startsWith(exceptMcpClientName)) {defineCallback.add(toolCallback);}}}return defineCallback;}
}

2)構建McpNode節點

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import com.demo.lesson26.mcp.tool.McpClientToolCallbackProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallback;
import reactor.core.publisher.Flux;import java.util.HashMap;
import java.util.Map;
import java.util.Set;/*** 自定義MCP節點*/
public class McpNode implements NodeAction {private static final Logger logger = LoggerFactory.getLogger(McpNode.class);private static final String NODENAME = "mcp-node";private final ChatClient chatClient;public McpNode(ChatClient.Builder chatClientBuilder, McpClientToolCallbackProvider mcpClientToolCallbackProvider) {// 獲取mcp-node前綴定義的工具,注冊到chatClient中Set<ToolCallback> toolCallbacks = mcpClientToolCallbackProvider.findToolCallbacks(NODENAME);for (ToolCallback toolCallback : toolCallbacks) {logger.info("Mcp Node load ToolCallback: " + toolCallback.getToolDefinition().name());}this.chatClient = chatClientBuilder.defaultToolCallbacks(toolCallbacks.toArray(ToolCallback[]::new)).build();}@Overridepublic Map<String, Object> apply(OverAllState state) {String query = state.value("query", "");Flux<String> streamResult = chatClient.prompt(query).stream().content();String result = streamResult.reduce("", (acc, item) -> acc + item).block();HashMap<String, Object> resultMap = new HashMap<>();resultMap.put("mcpcontent", result);return resultMap;}
}

3)設置配置類McpGaphConfiguration構建圖:

import com.alibaba.cloud.ai.graph.GraphRepresentation;
import com.alibaba.cloud.ai.graph.KeyStrategy;
import com.alibaba.cloud.ai.graph.KeyStrategyFactory;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.action.AsyncNodeAction;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy;
import com.demo.lesson26.mcp.node.McpNode;
import com.demo.lesson26.mcp.tool.McpClientToolCallbackProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;@Configuration
@EnableConfigurationProperties({ McpNodeProperties.class })
public class McpGaphConfiguration {private static final Logger logger = LoggerFactory.getLogger(McpGaphConfiguration.class);@Autowiredprivate McpClientToolCallbackProvider mcpClientToolCallbackProvider;@Beanpublic StateGraph mcpGraph(ChatClient.Builder chatClientBuilder) throws GraphStateException {KeyStrategyFactory keyStrategyFactory = () -> {HashMap<String, KeyStrategy> keyStrategyHashMap = new HashMap<>();// 用戶輸入keyStrategyHashMap.put("query", new ReplaceStrategy());keyStrategyHashMap.put("mcpcontent", new ReplaceStrategy());return keyStrategyHashMap;};// 構建圖StateGraph stateGraph = new StateGraph(keyStrategyFactory).addNode("mcp", AsyncNodeAction.node_async(new McpNode(chatClientBuilder, mcpClientToolCallbackProvider))).addEdge(StateGraph.START, "mcp").addEdge("mcp", StateGraph.END);// 添加 PlantUML 打印GraphRepresentation representation = stateGraph.getGraph(GraphRepresentation.Type.PLANTUML,"mcp flow");logger.info("\n=== mcp UML Flow ===");logger.info(representation.content());logger.info("==================================\n");return stateGraph;}
}

4)新建啟動類:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Lesson26MCPApplication {public static void main(String[] args) {SpringApplication.run(Lesson26MCPApplication.class, args);}}

1.3 演示效果

http://localhost:8080/graph/mcp

在這里插入圖片描述

結語:本章演示了Graph中如何訪問MCP服務,可見其架構的可擴展性,在Spring AI Alibaba中有一個com.alibaba.cloud.ai.graph.node.McpNode的MCP訪問節點實現,但是該節點只是一個固定MCP訪問,即需要傳入方法和參數,并沒有配置大模型。如果你構建的Graph中只是簡單調用MCP服務,則可以直接使用com.alibaba.cloud.ai.graph.node.McpNode節點。前面通過幾章對Graph框架進行了比較詳細的講解,這是因為在實際應用中,一個應用一般都是一個流程,而非一撮而就,所以使用Graph場景非常多。下一章將講Spring AI Alibaba的nl2sql,這個是一個基于Graph構建的生成SQL的實際案例,你就可以見識到復雜的工作流。

Spring AI系列上一章:《Spring AI 系列之三十四 - Spring AI Alibaba-Graph框架之并行執行》

Spring AI系列下一章:《Spring AI 系列之三十六 - Spring AI Alibaba-nl2sql》

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/92087.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/92087.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/92087.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

FastAPI后端工程化項目記錄

以下是一個使用fastapi上傳視頻的接口&#xff0c;記錄一下工程化后端程序的業務邏輯 重點是代碼如何抽離 項目結構優化 project/ ├── .env # 環境變量配置 ├── app/ │ ├── __init__.py │ ├── main.py # 主應用入口 │ …

令牌桶限流算法

你提供的 Java 代碼實現的是令牌桶限流算法&#xff08;Token Bucket Algorithm&#xff09;&#xff0c;這是目前最常用、最靈活的限流算法之一。它允許一定程度的“突發流量”&#xff0c;同時又能控制平均速率。下面我將&#xff1a;逐行詳細解釋 TokenBucketLimiter 類的每…

基于springboot的寵物商城設計與實現

管理員&#xff1a;登錄&#xff0c;個人中心&#xff0c;用戶管埋&#xff0c;寵物分類管理&#xff0c;寵物信息管理&#xff0c;留言反饋&#xff0c;寵物論壇&#xff0c;系統管理&#xff0c;訂單管理用戶&#xff1a;寵物信息&#xff0c;寵物論壇&#xff0c;公告信息&a…

Python day36

浙大疏錦行 Python day36. 復習日 本周內容&#xff1a; 如何導入模塊以及庫項目的規范拆分和寫法官方文檔的閱讀MLP神經網絡的訓練在GPU上訓練模型可視化以及推理

【gaussian-splatting】用自己的數據復現高斯潑濺(一)

1.環境準備1.1.下載diff-gaussian-rasterization這里本來沒啥說的&#xff0c;直接從github上下載就行了&#xff0c;但是我踩坑了&#xff0c;下的版本不對&#xff0c;后續運行報錯參數個數對不上&#xff0c;特在此給大家避坑&#xff0c;注意一定要下帶3dgs版本的diff-gaus…

中國移動h10g-01_S905L處理器安卓7.1當貝純凈版線刷機包帶root權限_融合終端網關

下載固件之前請先將主板上的屏蔽罩取下&#xff0c;查看處理器型號 是否為S905L型號&#xff0c;然后再下載固件進行刷機&#xff1b; 本頁面的固件是采用雙公頭數據線進行刷機的哈&#xff1b; 安卓4.4.2版本固件下載地址&#xff1a;點此進行下載 安卓7.1版本固件下載地址…

夜天之書 #110 涓滴開源:Cronexpr 的故事

在年初的一篇關于商業開源的博文當中&#xff0c;我介紹了在開發商業軟件的過程中&#xff0c;衍生出開源公共軟件庫的模式。在那篇博文里面&#xff0c;我只是簡單羅列了相關開源庫的名字及一句話總結。近期&#xff0c;我會結合商業開源實踐的最新進展&#xff0c;對其中一些…

完整的登陸學生管理系統(配置數據庫)

目錄 要求 思路 1. 登錄模塊&#xff08;LoginFrame.java&#xff09; 2. 學生信息管理模塊&#xff08;StudentFrame.java&#xff09; 3. 數據層&#xff08;StudentDAO.java&#xff09; 4. 業務層&#xff08;StudentService.java / UserService.java&#xff09; 5…

譯 | 在 Python 中從頭開始構建 Qwen-3 MoE

文章出自&#xff1a;基于 2個Expert 的 MoE 架構分步指南 本篇適合 MoE 架構初學者。文章亮點在于詳細拆解 Qwen 3 MoE 架構&#xff0c;并用簡單代碼從零實現 MoE 路由器、RMSNorm 等核心組件&#xff0c;便于理解內部原理。 該方法適用于需部署高性能、高效率大模型&#x…

Spring Boot + ShardingSphere 分庫分表實戰

&#x1f680;Spring Boot ShardingSphere 實戰&#xff1a;分庫分表&#xff0c;性能暴增的終極指南&#xff01; ? 適用場景&#xff1a;千萬級大表、高并發、讀寫分離場景 ? 核心框架&#xff1a;Spring Boot 3.x ShardingSphere-JDBC 5.4.1 ? 數據庫&#xff1a;MySQL…

MaxKB 使用 MCP 連接 Oracle (免安裝 cx_Oracle 和 Oracle Instant Client)

一、背景 安裝cx_Oracle包和Oracle Instant Client來操作數據庫&#xff0c;比較繁瑣同時容易沖突&#xff0c;不同的 Oracle 版本都需要安裝不同的插件。這篇文章將介紹使用 MCP 協議的連接方法。 二、操作步驟 1、使用 1Panel 安裝 DBhub a) 數據庫類型選擇 Oracle 類型。…

基于Python的超聲波OFDM數字通信鏈路設計與實現

基于Python的超聲波OFDM數字通信鏈路設計與實現 摘要 本文詳細介紹了使用Python實現的超聲波OFDM(正交頻分復用)數字通信鏈路系統。該系統能夠在標準音響設備上運行&#xff0c;利用高于15kHz的超聲波頻段進行數據傳輸&#xff0c;采用48kHz采樣率。文章涵蓋了從OFDM基本原理、…

滑動窗口相關題目

近些年來&#xff0c;我國防沙治沙取得顯著成果。某沙漠新種植N棵胡楊&#xff08;編號1-N&#xff09;&#xff0c;排成一排。一個月后&#xff0c;有M棵胡楊未能成活。現可補種胡楊K棵&#xff0c;請問如何補種&#xff08;只能補種&#xff0c;不能新種&#xff09;&#xf…

Java 工具類的“活化石”:Apache Commons 核心用法、性能陷阱與現代替代方案

在上一篇文章中&#xff0c;我們回顧了 Apache Commons 的經典組件。但作為 Java 世界中資歷最老、影響最深遠的工具庫&#xff0c;它的價值遠不止于此。許多開發者可能只使用了它 10% 的功能&#xff0c;卻忽略了另外 80% 能極大提升代碼質量的“隱藏寶石”。本文將提供一個更…

數據結構——圖及其C++實現 多源最短路徑 FloydWarshall算法

目錄 一、前言 二、算法思想 三、代碼實現 四、測試 五、源碼 一、前言 前兩篇學習的Dijkstra算法和Bellman-Ford算法都是用來求解圖的單源最短路徑&#xff0c;即從圖中指定的一個源點出發到圖中其他任意頂點的最短路徑。Dijkstra算法不能求解帶有負權重的圖的最短路徑&…

解決微軟應用商店 (Microsoft store) 打不開,無網絡連接的問題!

很多小伙伴都會遇見微軟應用商店 (Microsoft store)打開后出現無網絡的問題&#xff0c;一般出現這種問題基本都是因為你的電腦安裝了某些銀行的網銀工具&#xff0c;因為網銀工具為了安全會關閉Internet 選項中的最新版本的TLS協議&#xff0c;而微軟商店又需要最新的TLS協議才…

Android—服務+通知=>前臺服務

文章目錄1、Android服務1.1、定義1.2、基本用法1.2.1、定義一個服務1.2.2、服務注冊1.2.3、啟動和停止服務1.2.4、活動和服務進行通信1.3、帶綁定的服務示例1.3.1、定義服務類1.3.2、客戶端&#xff08;Activity&#xff09;綁定與交互?1.3.3、AndroidManifest.xml 注冊?1.3.…

從基礎功能到自主決策, Agent 開發進階路怎么走

Agent 開發進階路線大綱基礎功能實現核心模塊構建環境感知&#xff1a;傳感器數據處理&#xff08;視覺、語音、文本等輸入&#xff09;基礎動作控制&#xff1a;API調用、硬件驅動、簡單反饋機制狀態管理&#xff1a;有限狀態機&#xff08;FSM&#xff09;或行為樹&#xff0…

《動手學深度學習》讀書筆記—9.6編碼器-解碼器架構

本文記錄了自己在閱讀《動手學深度學習》時的一些思考&#xff0c;僅用來作為作者本人的學習筆記&#xff0c;不存在商業用途。 正如我們在9.5機器翻譯中所討論的&#xff0c;機器翻譯是序列轉換模型的一個核心問題&#xff0c;其輸入和輸出都是長度可變的序列。為了處理這種類…

DocBench:面向大模型文檔閱讀系統的評估基準與數據集分析

本文由「大千AI助手」原創發布&#xff0c;專注用真話講AI&#xff0c;回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我&#xff0c;一起撕掉過度包裝&#xff0c;學習真實的AI技術&#xff01; 一、數據集概述與核心目標 DocBench 是由研究團隊于2024年提出的首個…