news 2026/10/20 6:11:03

实战案例:Spring AI + MCP Server 优化电商订单处理流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
实战案例:Spring AI + MCP Server 优化电商订单处理流程

1. 电商订单处理为什么需要 Spring AI 与 MCP Server 协同

订单处理这条链路,做过电商后端的同学都清楚,它从来不是「创建订单 → 扣库存 → 发货」这么线性。真实场景里,一笔订单要经过风控校验、优惠券核销、库存预占、支付确认、履约拆单、物流回传等七八个环节,每个环节背后可能是一个独立服务。传统写法是把这些调用硬编码在业务代码里,OrderService里塞满if-else和try-catch,一旦某个下游接口改了参数或者加了新规则,就得改代码、重新发版。

我接触过的一个中型电商项目,日均订单十万笔左右,大促峰值能冲到五十万。原来的订单服务是同步串行调用,创建订单接口平均响应 8 到 12 秒,超时和库存不一致的问题每天都有几十单。后来他们把订单校验、库存查询、状态流转这几块拆出来,用 Spring AI 做智能决策层,用 MCP Server 做工具能力的统一暴露层,整个链路才顺过来。

这里要先说清楚两个概念,不然后面配置看不懂。

Spring AI 是 Spring 生态里用来对接大模型的框架,它提供了一套统一的ChatClient、ToolCallback、Advisor抽象,让你在 Spring Boot 项目里用几行代码就能把大模型接进来,并且把本地方法注册成模型可以调用的「工具」。它的核心价值不是让你调个 API 聊天,而是让模型能够根据用户意图,自主决定调用哪个业务方法、传什么参数。

MCP Server 则是 Model Context Protocol 的服务端实现。MCP 是一套让模型和外部工具、数据源通信的协议标准,你可以把它理解成「模型世界的 USB 接口」。MCP Server 把订单查询、库存扣减、状态更新这些能力包装成标准化的 tool,任何支持 MCP 的客户端(包括 Spring AI 应用、Claude Code、Cline 等)都能直接调用,不用为每个客户端单独写适配。

两者结合后的分工是这样的:Spring AI 负责「理解意图 + 编排决策」,MCP Server 负责「暴露能力 + 执行动作」。用户说一句「帮我查一下订单 20240512001 现在到哪了,如果还没发货就取消掉」,Spring AI 解析出意图,决定先调queryOrder,再根据返回状态决定是否调cancelOrder,而这两个方法实际都注册在 MCP Server 上。

这套架构适合谁?我认为三类团队收益最明显:一是订单链路已经拆成微服务、但调用关系混乱的团队;二是想引入 AI 能力做智能客服、智能订单助手的团队;三是希望把内部业务能力标准化输出、让多个 AI 客户端复用的团队。如果你还在单体应用阶段,订单逻辑就几百行,那暂时不用上这套,杀鸡用牛刀。

下面我按「前置准备 → 配置 → 代码 → 联调验证 → 排错」的顺序,把整个流程拆开讲,每一步都给可复制的内容。

2. TaoToken 前置准备:拿到 Base URL、API Key 与模型 ID

在写 Spring AI 代码之前,得先有一个能调用大模型的服务端点。Spring AI 本身不提供模型,它只是客户端框架,你需要一个兼容 OpenAI 协议的服务地址。这里我用 TaoToken 来做演示,因为它同时提供模型对话、Coding Plan 和 API Key 管理,配置起来比较直接。

第一步,打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,注册并登录。登录后在控制台左侧找到「API Keys」入口,对应地址是 https://taotoken.net/console/api-keys 。点「创建密钥」,给它起个名字比如spring-ai-order-demo,创建完立刻复制保存,因为页面刷新后就看不到完整 Key 了。

第二步,确认你要用的模型 ID。在「模型对话」页面 https://taotoken.net/model-chat 里,可以看到当前可用的模型列表。做订单意图解析和工具调用,建议选支持 function calling 的模型,比如claude-sonnet-4-5或者gpt-4o这类。把模型 ID 记下来,后面配置里要用。

第三步,确认 Base URL。Spring AI 的 OpenAI 兼容配置里,base-url填https://taotoken.net/api,注意这里不要加任何 UTM 参数,就是干净的 API 地址。完整的 API 文档在 https://taotoken.net/doc ,里面有各语言的调用示例,遇到参数不确定的时候可以对照。

如果你打算长期跑编码类 Agent 任务,比如让模型自动改代码、跑测试,那可以看一下 Coding Plan 页面 https://taotoken.net/coding-plan ,它针对高频调用场景做了额度优化,比按量付费更划算。不过订单处理这种业务场景,按量调用就够了,不用一上来就买套餐。

拿到这三样东西后,建议先在本地用 curl 验证一下 Key 是否可用,避免后面 Spring AI 报错时排查方向跑偏:

curl https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-你的Key" \ -d '{ "model": "claude-sonnet-4-5", "messages": [{"role": "user", "content": "回复 OK"}] }'

如果返回里有choices字段和正常内容,说明 Key 和网络都没问题。如果返回 401,那就是 Key 错了或者没带上Bearer前缀;如果返回连接超时,检查一下本地网络能不能访问taotoken.net。

这一步做完,前置条件就齐了:Base URL、API Key、Model ID 三件套。接下来进入 Spring AI 项目配置。

3. 可复制配置:Spring AI 接入 MCP Server 的完整片段

这一节是全文最核心的部分,我把pom.xml依赖、application.yml配置、MCP Server 的mcp.json定义、以及 Spring AI 的工具注册代码全部给出来,你直接复制改改就能跑。

先看 Maven 依赖。Spring AI 的版本迭代比较快,我这里用 1.0.0 稳定版,MCP 相关的能力在spring-ai-starter-mcp-client里:

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-client</artifactId> <version>1.0.0</version> </dependency> </dependencies>

然后是application.yml,这里把 TaoToken 的 Base URL、Key、模型 ID 都配上,同时配置 MCP Server 的连接方式。注意base-url结尾不要带/v1,Spring AI 会自动补:

spring: ai: openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: claude-sonnet-4-5 temperature: 0.2 mcp: client: enabled: true name: order-mcp-client version: 1.0.0 type: SYNC request-timeout: 30s stdio: connections: order-server: command: java args: - -jar - ./mcp-order-server/target/order-mcp-server.jar

这里api-key用环境变量注入,不要硬编码在 yml 里,生产环境尤其注意。temperature设 0.2 是因为订单场景要的是稳定输出,不需要模型发挥创意。

接下来是 MCP Server 端的工具定义。我用一个mcp.json来描述暴露给模型的能力,这个文件放在 MCP Server 项目根目录:

{ "mcpServers": { "order-server": { "command": "java", "args": ["-jar", "order-mcp-server.jar"], "env": { "DB_URL": "jdbc:mysql://localhost:3306/order_db", "DB_USER": "order_user" }, "tools": [ { "name": "queryOrder", "description": "根据订单号查询订单详情,返回状态、金额、商品列表", "inputSchema": { "type": "object", "properties": { "orderId": { "type": "string", "description": "订单号" } }, "required": ["orderId"] } }, { "name": "checkStock", "description": "查询指定 SKU 的可用库存数量", "inputSchema": { "type": "object", "properties": { "skuId": { "type": "string" }, "quantity": { "type": "integer" } }, "required": ["skuId"] } }, { "name": "updateOrderStatus", "description": "更新订单状态,支持 CREATED/PAID/SHIPPED/CANCELLED", "inputSchema": { "type": "object", "properties": { "orderId": { "type": "string" }, "status": { "type": "string" } }, "required": ["orderId", "status"] } } ] } } }

这个mcp.json就是 MCP 协议里的服务描述文件,客户端读到它就知道有哪些工具、参数是什么。注意tools数组里的inputSchema用的是 JSON Schema 标准,模型会根据这个 schema 生成调用参数。

最后是 Spring AI 侧的工具注册代码。如果你用的是 MCP 客户端模式,Spring AI 会自动把 MCP Server 暴露的工具注册成ToolCallback,你只需要在ChatClient里开启工具调用:

@Configuration public class OrderAiConfig { @Bean public ChatClient orderChatClient(ChatClient.Builder builder, ToolCallbackProvider mcpToolProvider) { return builder .defaultSystem("你是电商订单助手,负责解析用户意图并调用工具完成订单查询、库存校验和状态流转。调用工具前先确认参数完整。") .defaultToolCallbacks(mcpToolProvider) .build(); } }

如果你不想走 MCP,想直接在 Spring AI 里用@Tool注解注册本地方法,也可以这样写:

@Component public class OrderTools { private final OrderRepository orderRepository; public OrderTools(OrderRepository orderRepository) { this.orderRepository = orderRepository; } @Tool(description = "根据订单号查询订单详情") public Order queryOrder(@ToolParam(description = "订单号") String orderId) { return orderRepository.findById(orderId) .orElseThrow(() -> new IllegalArgumentException("订单不存在: " + orderId)); } @Tool(description = "更新订单状态") public boolean updateOrderStatus( @ToolParam(description = "订单号") String orderId, @ToolParam(description = "目标状态") String status) { return orderRepository.updateStatus(orderId, status); } }

然后在ChatClient里加上.defaultTools(new OrderTools(orderRepository))即可。两种方式选一种,MCP 适合跨客户端复用,@Tool适合单体项目快速接入。

配置到这里就完整了。三件套对应关系再强调一遍:Base URL 是https://taotoken.net/api,Key 是你从 API Keys 页面拿的sk-开头字符串,Model ID 是claude-sonnet-4-5这类。这三个任何一个错了,后面都会报错。

4. 验证请求:一次订单从创建到履约的完整联调

配置写完,得实际跑一遍才知道通不通。我设计了一个完整的验证动作:模拟用户下单,让 Spring AI 解析意图,依次调用checkStock、queryOrder、updateOrderStatus,最后确认订单状态从CREATED流转到SHIPPED。

先写一个测试 Controller:

@RestController @RequestMapping("/api/order") public class OrderAiController { private final ChatClient orderChatClient; public OrderAiController(ChatClient orderChatClient) { this.orderChatClient = orderChatClient; } @PostMapping("/assist") public String assist(@RequestBody AssistRequest request) { return orderChatClient.prompt() .user(request.getMessage()) .call() .content(); } }

启动应用后,用 curl 发一条自然语言指令:

curl -X POST http://localhost:8080/api/order/assist \ -H "Content-Type: application/json" \ -d '{ "message": "订单 20240512001 现在什么状态?如果还没发货,帮我确认下 SKU-8899 的库存,够的话就发货。" }'

预期行为是这样的:模型先调用queryOrder拿到订单状态,发现是PAID(未发货),然后调用checkStock查SKU-8899库存,库存充足则调用updateOrderStatus把状态改成SHIPPED,最后返回一段自然语言总结。

实际返回大概长这样:

订单 20240512001 当前状态为 PAID,已确认 SKU-8899 库存充足(可用 120 件), 已将订单状态更新为 SHIPPED,履约流程已触发。

如果你在日志里看到类似下面的工具调用记录,说明 MCP 链路是通的:

Tool call: queryOrder({"orderId": "20240512001"}) Tool result: {"status": "PAID", "amount": 299.00, ...} Tool call: checkStock({"skuId": "SKU-8899", "quantity": 1}) Tool result: {"available": 120} Tool call: updateOrderStatus({"orderId": "20240512001", "status": "SHIPPED"}) Tool result: {"success": true}

这里有个细节要注意:模型决定调用哪些工具、按什么顺序调用,是它自己根据 system prompt 和工具描述推理出来的。所以description写得越清楚,模型调用越准。我见过有人把description写成「查询订单」,结果模型经常传错参数;改成「根据订单号查询订单详情,返回状态、金额、商品列表」之后就稳定多了。

验证通过的标准有三个:一是 HTTP 返回 200 且内容合理;二是日志里能看到完整的工具调用链;三是数据库里订单状态确实变了。三个都满足,说明 Spring AI + MCP Server 的协同链路完全打通。

如果你想验证更复杂的场景,比如「批量查询今天所有未发货订单,库存不足的自动取消」,可以把指令改成这个,观察模型是否会循环调用工具。这种多轮工具调用是 MCP 架构的真正价值所在。

5. 本篇常见错误排查:401、local proxy failed 与 choices 解析异常

这一节把我踩过的坑和社区里高频出现的报错整理出来,对照着排查能省不少时间。

报错一:401 Unauthorized

org.springframework.ai.openai.api.OpenAiApiException: 401 Unauthorized {"error":{"message":"Invalid API key","type":"invalid_request_error"}}

原因通常是三个:Key 复制时漏了字符、环境变量TAOTOKEN_API_KEY没生效、或者Authorization头没带上Bearer前缀。排查方法:先在终端echo $TAOTOKEN_API_KEY确认变量有值,再用第 2 节的 curl 命令直接测 Key。如果 curl 通但 Spring AI 不通,那就是 yml 里api-key的引用写错了,检查是不是写成了${TAOTOKEN_API_KEY:}这种带默认值的格式导致取到空串。

报错二:local proxy failed / Connection refused

java.net.ConnectException: Connection refused: no further information Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException

这个报错一般出现在 MCP Server 的 stdio 连接上。Spring AI 启动时会去拉起mcp.json里配置的command,如果order-mcp-server.jar路径不对、或者 jar 没打包成功,就会连接失败。排查步骤:先手动执行java -jar ./mcp-order-server/target/order-mcp-server.jar,看能不能正常启动;如果报no main manifest attribute,说明打包时没配spring-boot-maven-plugin的repackage目标。另外路径建议用绝对路径,相对路径在不同工作目录下容易出问题。

报错三:reading choices 解析异常

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.List<...>` from Object value at [Source: (String)"..."; line: 1, column: 1] (through reference chain: ...ChatCompletionMessage["choices"])

这个报错说明返回的 JSON 结构和 Spring AI 期望的不一致。常见原因是 Base URL 配错了,比如写成了https://taotoken.net/api/v1/v1,多了一层/v1,导致请求打到了错误的路由上,返回的是 HTML 错误页而不是 JSON。正确写法就是https://taotoken.net/api,Spring AI 内部会拼/v1/chat/completions。另一个可能是模型 ID 写错了,服务端返回了错误结构,检查model字段是不是和模型对话页面里列出的完全一致。

报错四:OAuth / token 过期类错误

{"error":"invalid_token","error_description":"The access token expired"}

如果你用的是 Coding Plan 或者带 OAuth 的接入方式,token 是有有效期的。这种情况重新在控制台生成一个 Key 替换即可。注意不要把 OAuth token 和 API Key 混用,两者格式和用途不同。

报错五:工具调用参数为空

模型返回了工具调用意图,但参数是空的或者类型不对。这通常是inputSchema写得不严谨,比如quantity定义成string但模型传了数字。解决办法是把 schema 写严格,required字段列全,类型明确。另外 system prompt 里加一句「调用工具前确认所有必填参数已提供」也能明显改善。

排查这类问题的通用思路是:先看 HTTP 层通不通(curl),再看 Spring AI 配置对不对(yml),最后看 MCP 工具描述准不准(mcp.json)。三层逐层排除,基本都能定位到。

6. 把订单能力标准化输出:下一步怎么走

走到这里,你已经有了一个能跑通的 Spring AI + MCP Server 订单处理链路。但真正落地到生产,还有几件事值得做。

第一件是把 MCP Server 的工具集扩展完整。我上面只给了queryOrder、checkStock、updateOrderStatus三个,实际业务里还需要createOrder、applyCoupon、splitOrder、refundOrder等。每加一个工具,就在mcp.json的tools数组里加一段 schema,然后在 MCP Server 里实现对应方法。工具描述要写得像给新人看的接口文档,模型才能用对。

第二件是加一层权限和审计。MCP Server 暴露的工具是模型可以直接调的,像updateOrderStatus、refundOrder这种写操作,一定要加权限校验和操作日志。我的做法是在 MCP Server 里加一个ToolInterceptor,每次工具调用前检查当前会话的权限范围,调用后把orderId、toolName、params、result写进审计表。这样出了问题能追溯。

第三件是监控模型调用质量。订单场景对准确性要求高,模型偶尔会理解错意图。建议在 Spring AI 侧加一个Advisor,记录每次请求的 prompt、工具调用链、最终响应,定期抽样人工检查。如果发现某类指令经常出错,就回去优化 system prompt 或工具描述。

关于接入方式的选择,再补充一点:如果你只是自己项目里用,Spring AI 的@Tool注解方式最省事,不用额外部署 MCP Server。但如果你希望这套订单能力被多个 AI 客户端复用,比如同时给 Spring AI 应用、Claude Code、Cline 用,那就值得把 MCP Server 独立部署。MCP 的价值就在于「一次定义,多处调用」。

最后给一个实用建议:先在测试环境把整条链路跑通,用真实订单数据验证工具调用的准确性,确认没问题再上生产。生产环境的 Key 单独申请一个,和测试环境隔离,方便做额度控制和问题定位。API Key 管理在 https://taotoken.net/console/api-keys ,接入文档在 https://taotoken.net/doc ,遇到配置问题先翻文档,大部分坑里面都有说明。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 6:08:24

文章转口播视频全流程:半自动流水线搭建指南

把一篇已经排好版的文章&#xff0c;变成一条能直接发出去的口播短视频&#xff0c;这条流水线我前前后后折腾了两周&#xff0c;总算是跑通了。先说结论&#xff1a;完全可行&#xff0c;但它真不是你想象中那种“丢一篇文章进去、一条成片出来”的全自动机器。这条路上真正耗…

作者头像 李华
网站建设 2026/10/20 6:08:09

具身智能运动规划:从路径规划到真机部署的实战解析

1. 具身智能运动规划到底在解决什么问题先抛一个自己的观点&#xff1a;具身智能这个词这两年火得一塌糊涂&#xff0c;但我们拆开来看&#xff0c;大部分讨论其实停留在"大脑"层面&#xff0c;怎么做感知、怎么做决策、怎么多模态融合。真正让它从实验室走到工厂流水…

作者头像 李华
网站建设 2026/10/20 6:07:16

社区医院信息平台SpringBoot+Vue+MyBatis全栈实战解析

这些年做全栈项目&#xff0c;我经手过不少类似“社区医院信息管理系统”的东西&#xff0c;有拿来练手的、毕业设计用的&#xff0c;也有真实准备上线给基层医疗机构用的。说实话&#xff0c;这类项目看着是典型的CRUD&#xff0c;但一旦把预约挂号、医生接诊、病历处方、药品…

作者头像 李华
网站建设 2026/10/20 6:07:14

LibUsbDotNet 实战:C# 上位机 USB 设备枚举、批量传输与避坑指南

简介&#xff1a;这份资源面向具备一定C#基础的.NET开发者与USB上位机开发初学者&#xff0c;围绕libusbDotNet库讲解如何在C#中完成USB设备的枚举、打开、读写与异常处理&#xff0c;帮助解决.NET环境下访问USB设备接口不便的问题。压缩包共236个文件&#xff0c;约4.05MB&…

作者头像 李华
网站建设 2026/10/20 6:07:13

机器人标定十年演进:从手动示教到在线自标定的实战指南

1. 这十年&#xff0c;机器人标定到底变在哪做机器人集成和产线调试久了&#xff0c;你会发现一个残酷的事实&#xff1a;机器人标定永远是项目现场最容易被低估、又最容易让整个系统翻车的环节。十年前的产线里&#xff0c;“标定”这个词基本等同于老师傅拿着千分尺、顶针和激…

作者头像 李华
网站建设 2026/10/20 6:07:13

从1.4万Token到200:AI编程助手系统提示词迁移实战与成本优化

1. 从 1.4 万 Token 到 200 Token&#xff1a;这次迁移到底在省什么第一次看到"系统提示词从 1.4W 砍到 200"这个数字对比时&#xff0c;我的反应和大多数人一样——要么是标题党&#xff0c;要么是砍掉了核心能力。毕竟在 AI 编程助手这个领域&#xff0c;系统提示词…

作者头像 李华