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

SpringAI1.0下的MCP的异步请求和同步请求的区别

代码简单解释

private final ChatClient chatClient;public OllamaMCPClien(ChatClient.Builder chatClientBuilder, List<McpSyncClient> mcpSyncClients) {// 使用 chatClientBuilder 构建 ChatClient 实例this.chatClient = chatClientBuilder// 设置默认的系统消息,指导 AI 的行为。// 这里明确告诉AI它是一个必须使用工具来回答问题的助手。// 强调了当用户提问时,应优先寻找并使用可用工具(如天气查询或回显),而不是直接回答。.defaultSystem("你就是一个执行器,你可以调取远程的MCP的工具来进行执行,必须要执行一个工具")// 注册 MCP 工具回调,它会发现并集成所有可用的MCP工具.defaultToolCallbacks(new SyncMcpToolCallbackProvider(mcpSyncClients))// 添加消息历史记忆功能,以支持多轮对话.defaultAdvisors(MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build()).build();
}

这里的代码演示的就是一段同步请求MCPServer的请求,当用户想要调取一个被MCPClient管理的Server的管理的列表的话,那么种类进行同步的请求的话会直接发送请求的阻塞,只有当用户请求的MCPServer的请求被响应之后才会继续进行服务的响应和处理,如果LLM没有找到服务进行处理的话,会直接被LLM处理结果然后直接返回给用户结果。

详细对比

我用一个比喻来解释:

  • 同步 (Synchronous):就像是打电话。你拨通电话问对方一个问题,你必须在线上一直等着,直到对方想好答案告诉你,然后你才能挂电话去做别的事情。在等待期间,你什么也做不了。
  • 异步 (Asynchronous):就像是发短信/邮件。你把问题发给对方,然后就可以马上去做自己的事情了。对方收到后,有空了会处理,处理完再把答案发给你。你随时可以查看有没有新消息,而不需要一直干等着。

现在我们把这个概念应用到你的 MCP 客户端和服务端上:


同步 (Synchronous) - McpSyncClient

在你的代码里,你正在使用 McpSyncClient,这是一个同步客户端。

  1. 工作方式:

    • OllamaMCPClien (AI) 决定调用一个远程工具时,它会通过 McpSyncClientMCP-SERVER 发起一个网络请求(比如 HTTP 请求)。
    • 发起请求的那个线程会被阻塞 (block),进入等待状态。
    • 这个线程会一直等待,直到 MCP-SERVER 上的工具执行完毕,并将结果通过网络返回。
    • 收到返回结果后,该线程才会被唤醒,继续执行后面的代码。
  2. 优点:

    • 简单直观:代码的执行流程是线性的,“调用->等待->返回”,非常容易理解和调试。
    • 实现简单:不需要处理复杂的回调函数、Future 或响应式编程模型。
  3. 缺点:

    • 性能和资源瓶颈这是最主要的区别。如果 MCP-SERVER 上的工具执行时间很长(例如,需要几秒钟甚至更久),那么 MCP-CLINE 这边的调用线程就会被长时间占用。在高并发场景下,如果大量请求都在等待慢速工具的返回,服务器的线程资源会很快被耗尽,导致系统吞吐量下降,无法响应新的请求。

异步 (Asynchronous) - (如果存在 McpAsyncClient)

如果有一个异步的实现(我们称之为 McpAsyncClient),它的工作方式会完全不同。

  1. 工作方式:

    • 当 AI 决定调用一个工具时,McpAsyncClient 会向 MCP-SERVER 发起请求。
    • 但是,它不会等待 MCP-SERVER 的响应。调用会立即返回,通常返回一个“凭证”,比如 CompletableFuture<T>Mono<T> (在使用 Spring WebFlux 的情况下)。
    • 发起调用的线程不会被阻塞,它可以立即去处理其他任务。
    • MCP-SERVER 处理完请求并返回结果时,会通过回调机制或者完成 CompletableFuture 来通知客户端。一个独立的线程(或线程池中的线程)会接着处理这个返回的结果。
  2. 优点:

    • 高吞吐量和高伸缩性:线程不会因为等待 I/O (网络、磁盘) 操作而被阻塞。少量的线程就可以处理大量的并发请求,系统资源利用率极高。
    • 更好的用户体验:对于需要调用多个工具或长耗时工具的场景,系统不会被单个请求卡死,整体响应性更好。
  3. 缺点:

    • 编程模型更复杂:你需要处理回调、Futures 或响应式流 (Reactive Streams)。代码不再是简单的线性执行,调试和排查问题也相对困难一些(比如所谓的 “Callback Hell”,尽管现代Java已经大大改善了这一点)。

总结

特性同步 (Synchronous)异步 (Asynchronous)
通信模型阻塞式,客户端必须等待服务端响应非阻塞式,客户端发送请求后无需等待
资源占用每一个请求在等待时都会占用一个线程少量线程可处理大量并发请求,资源利用率高
性能性能较低,容易因慢速任务而产生瓶颈性能高,适合I/O密集型和高并发场景
编程复杂度简单,代码逻辑直观复杂,需要处理回调或响应式编程
适用场景逻辑简单、快速返回的调用、低并发场景I/O密集型、高并发、长耗时任务的调用

对于你的 MCP 架构来说,因为涉及到微服务之间的网络通信,这本身就是一种 I/O 操作。如果你的工具都是毫秒级就能快速返回的,那么使用同步模型是完全可以接受的,因为它更简单。但如果你的工具可能涉及到复杂计算、访问数据库、调用第三方API等耗时操作,那么异步模型会是更健壮、性能更好的选择。

相关文章:

  • 领域驱动设计(DDD)【3】之事件风暴
  • 自定义OceanBase集群安装并使用OCP接管集群
  • K8s初始化容器与边车容器比对
  • HTTPS的加密方式介绍
  • 从语义到推荐:大语言模型(LLM)如何驱动智能选车系统?
  • 蚂蚁百宝箱快速创建智能体AI小程序
  • 【入门级-基础知识与编程环境:计算机的基本构成 (CPU、内存、I/O设备等)】
  • 【算法一周目】分而治之,归并如风:算法中的美学与哲理
  • IEC61850 一致性测试中的 UCA 测试
  • AI大模型学习之基础数学:高斯分布-AI大模型概率统计的基石
  • `toRaw` 与 `markRaw`:Vue3 响应式系统的细粒度控制
  • ad24智能pdf输出的装配图没有四个边角那里的圆孔
  • 学习C++、QT---03(C++的输入输出、C++的基本数据类型介绍)
  • GO语言---数组
  • `teleport` 传送 API 的使用:在 Vue 3 中的最佳实践
  • ffmpeg(七):直播相关命令
  • Python列表常用操作方法
  • 爱高集团引领转型浪潮:AI与区块链驱动香港科技资本新机遇
  • GitHub Copilot快捷键
  • 【AGI】突破感知-决策边界:VLA-具身智能2.0
  • 孟津网站建设/怎么利用互联网推广
  • 邳州哪家做百度推广网站/软文写作范例大全
  • 南昌城市旅游网站建设/哈尔滨关键词排名工具
  • 湖南关键词优化快速/海口关键词优化报价
  • 广州网站seo优化排名/郑州网站推广公司电话
  • 网站做链接代码/竞价代运营外包公司