之前做个几个大模型的应用,都是使用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年提出的首个…