当前位置: 首页 > news >正文

SpringAI调用MCP服务的实现思路

在这里插入图片描述

1. 核心架构与抽象

Spring AI 的核心是提供一套统一的 API 来与各种 AI 模型和服务交互,其关键抽象是 ChatClient 和 PromptCallback 等。对于 MCP,它需要解决两个问题:

发现(Discovery):如何连接到 MCP 服务器并获取其提供的所有工具(tools)和资源(resources)列表。

适配(Adaptation):如何将这些远程的工具和资源转换成 Spring AI 能够理解和调用的格式,特别是如何将它们作为 FunctionCallback 集成到 AI 对话中。

SpringAiMcpClient 库完美地扮演了这个适配器的角色。

2. 实现原理与关键步骤

整个过程可以分解为以下几个关键步骤:

步骤一:建立连接与传输层

Spring AI MCP 客户端使用 SSE(Server-Sent Events) 或 Stdio 作为传输层与 MCP 服务器通信。你需要在配置中指定 MCP 服务器的地址(对于 SSE)或启动命令(对于 Stdio)。

application.yml

spring:ai:mcp:clients:my-mcp-server: # 自定义客户端实例名type: sseurl: http://localhost:8000/sse# 或者使用 stdio# type: stdio# command: "npx -y @modelcontextprotocol/server-example"

步骤二:初始化与服务器握手

应用启动时,SpringAiMcpClient 会自动执行 MCP 协议规定的初始化流程:

与服务器建立连接。

发送 initialize 请求,交换客户端和服务器的能力信息。

服务器回复 initialized 通知。

客户端发送 tools/list 请求,获取服务器提供的所有工具(函数)的列表及其 JSON Schema 定义。

客户端发送 resources/list 请求,获取服务器提供的所有资源的列表。

步骤三:动态注册为 Function Callback

这是最核心的一步。Spring AI 获取到工具列表后,会为每一个 MCP 工具动态地创建一个 FunctionCallback 实例。

函数定义(Function Definition):使用从服务器获取的 JSON Schema 来构建 Function 对象,包含了函数名、描述和参数schema。

函数执行(Function Execution):当 LLM 决定调用某个函数时,Spring AI 会找到对应的 FunctionCallback。这个回调函数内部会通过 MCP 协议向服务器发送 tools/call 请求,并将 LLM 生成的参数传递过去。

结果返回:MCP 服务器执行工具,返回结果。Spring AI 将该结果返回给 LLM,让 LLM 基于结果生成最终的回复给用户。

步骤四:集成到 AI 对话中

这些动态生成的 FunctionCallback 会被聚合到一个 FunctionCallbackRegistry 中。当你使用 ChatClient 并开启函数调用功能时,这些 MCP 工具就会自动成为可用的选项。

@Bean
public ChatClient chatClient(ChatModel chatModel, List<FunctionCallback> toolFunctionCallbacks) {// 所有 MCP 工具生成的 FunctionCallback 都会被自动注入到这里return ChatClient.builder(chatModel)// .defaultFunctions() // 也可以选择默认启用所有函数.build();
}

现在,当你发起一个对话时,如果用户的提问涉及到 MCP 工具(例如:“查看下本地的天气”),LLM 就会自主选择调用相应的 MCP 工具函数,完成服务调用。

3. 代码示例:调用多个服务

假设你的 MCP 服务器提供了两个工具:get_weather(获取天气)和 search_files(搜索文件)。

1. 配置 (application.yml)

yaml
spring:ai:mcp:clients:weather-server:type: sseurl: http://localhost:8000/ssefile-server:type: stdiocommand: "node /path/to/my-file-server.js"chat:model: openai:gpt-4o-mini

2. Java 代码使用

你不需要为每个工具手动编写代码。Spring AI 会自动完成所有繁重的工作。

@RestController
public class McpController {private final ChatClient chatClient;public McpController(ChatClient chatClient) {this.chatClient = chatClient;}@GetMapping("/ask")public String ask(@RequestParam String question) {// 用户的问题可能同时涉及天气和文件搜索// LLM 会自动决定是否需要调用函数,以及调用哪一个或哪几个Prompt prompt = new Prompt(new UserMessage(question));ChatResponse response = chatClient.call(prompt);return response.getResult().getOutput().getContent();}
}

交互流程示例:

用户输入: “我旧金山今天的天气怎么样?然后再帮我找个文件名包含‘季度报告’的文档。”

LLM 推理: 这个问题需要两个步骤:先查天气,再搜文件。

Action 1: LLM 决定调用 get_weather 函数,参数 {“location”: “San Francisco”}。

Spring AI 通过 MCP 调用天气服务器的工具。

天气服务器返回 JSON 格式的天气数据。

Action 2: LLM 收到天气结果后,决定调用 search_files 函数,参数 {“query”: “季度报告”}。

Spring AI 通过 MCP 调用文件服务器的工具。

文件服务器返回文件列表。

最终回复: LLM 综合天气结果和文件列表,生成一段连贯的自然语言回复给用户:“旧金山今天晴,气温22度。我找到了3个包含‘季度报告’的文件:…”

总结

Spring AI 实现 MCP 多服务调用的方式可以概括为:

协议层:基于 MCP 协议(SSE/Stdio)与一个或多个服务器通信。

适配层:在启动时自动发现所有远程工具和资源。

抽象层:将每个远程工具动态封装成一个 Spring AI FunctionCallback。

执行层:在 AI 对话过程中,由 LLM 驱动,通过对应的 FunctionCallback 透明地执行 MCP 函数调用,并将结果返回给 LLM。

多服务:通过配置多个客户端实例,轻松集成多个不同的 MCP 服务器,所有这些服务器的工具都会统一注册到 Spring AI 的上下文中,供 LLM 选择使用。

这种方式极大地简化了集成工作,开发者只需关注配置和业务逻辑,无需编写大量的胶水代码,真正实现了“开箱即用”的多工具AI应用开发。


文章转载自:

http://oPHAEUpC.dysgr.cn
http://cfo4uDg9.dysgr.cn
http://SijDORay.dysgr.cn
http://GMMFY85l.dysgr.cn
http://3MAG3dqK.dysgr.cn
http://Jajv1BGT.dysgr.cn
http://yQiKjiwm.dysgr.cn
http://ewFxaSX2.dysgr.cn
http://PpDPfcPl.dysgr.cn
http://2pm3Exqg.dysgr.cn
http://gFSfAzJB.dysgr.cn
http://i5De7k0c.dysgr.cn
http://eTU5QniC.dysgr.cn
http://zhTHv895.dysgr.cn
http://6U8tM5R5.dysgr.cn
http://DA9zDaCg.dysgr.cn
http://6NoTPuJ4.dysgr.cn
http://BvZcUyFg.dysgr.cn
http://bwZAlefT.dysgr.cn
http://rrZVoG1H.dysgr.cn
http://kaSNNrYg.dysgr.cn
http://5rGhbcoV.dysgr.cn
http://aJEP8Se9.dysgr.cn
http://SB1oOH7H.dysgr.cn
http://IFyFWkBn.dysgr.cn
http://aLKb0TQS.dysgr.cn
http://zhZYywUr.dysgr.cn
http://HBenvlrz.dysgr.cn
http://52tzrbdo.dysgr.cn
http://Mx38FhlO.dysgr.cn
http://www.dtcms.com/a/373048.html

相关文章:

  • react16到react19更新及底层实现是什么以及区别
  • K-meas 聚类、KNN算法、决策树、随机森林
  • Day 17: 3D点云深度学习专项 - 理论深度与面试精通之路
  • React中的合成事件
  • 不连续页分配器补充
  • Hadoop NameNode内存泄漏与GC停顿问题排查与解决方案
  • 防火墙配置
  • Hydra-SSH 破解安全防范
  • Hadoop(十)
  • C++三种对象实例化在栈或堆的区别
  • 碰一碰系统源码于小程序打通技术开发整合方案,驱动AI技术开发源代码
  • 深入解析TCP核心机制:连接管理、流量与拥塞控制
  • 【混合开发】vue+Android、iPhone、鸿蒙、win、macOS、Linux之dist打包发布在Android工程asserts里
  • 医疗问诊陪诊小程序:以细节创新重塑就医体验的温度与效率
  • [20250908]Android Talkback 自定义合并
  • 【智能融合:增材制造多物理场AI建模与工业应用实战】
  • stm32——独立看门狗,RTC
  • LeetCode 3634.使数组平衡的最少移除数目
  • 106. 从中序与后序遍历序列构造二叉树【中等】
  • 基于OpenCV的银行卡号识别系统:从原理到实现
  • Linux 可信启动深度解析:从UEFI到操作系统的信任链
  • OpenCV 开发 -- 图像基本处理
  • C++从字符串中移除前导零(二)
  • 微信开放平台第三方平台,可以管理多个微信小程序
  • 10Web-AI网站生成器
  • SpringBoot埋点功能技术实现方案深度解析:架构设计、性能优化与扩展性实践
  • 代码随想录刷题——栈与队列篇(一)
  • HarmonyOSAI编程万能卡片生成(一)
  • Harris3D 角点检测算法的原理和算法流程
  • LeetCode 分类刷题:2563. 统计公平数对的数目