Spring AI 2.0 实战:用 Java 构建企业级 AI 应用骨架

Spring AI 2.0 实战:用 Java 构建企业级 AI 应用骨架 过去两年Java 开发者面对的最大尴尬可能是 AI 应用开发几乎成了 Python 圈的“专属话题”。LangChain、LlamaIndex、各种 Agent 框架一搜全是 Python 教程。但对大多数做企业系统的团队来说Java 仍然是后端主力Spring 仍然是工程化的首选。于是问题变成能不能用 Java、用我们熟悉的 Spring 编程习惯把大模型接进现有业务系统这个问题的答案就是 Spring AI。尤其是大量教程把重点放在“调用模型聊天”时真正让 Spring AI 2.0 值得花时间去学的是它一整套贴近企业级工程化的能力多模型接入、Tools工具调用、MCP模型上下文协议、Skills技能封装、Agent智能体编排。这篇文章不打算复述官方文档而是想把这些概念串起来用一条“从零到可落地”的路径帮你在一周内建立起自己的 Java AI 应用骨架。先说结论Spring AI 适合的不是“想追热点的人”而是“手里有真实业务、需要把 LLM 能力嵌入现有系统的后端工程师”。如果你能接受“模型不稳定、工具调用有边界”这件事并且愿意花时间做工程化验证那么读这篇文章你会少走很多弯路。1. Java Spring AI 2.0 为什么值得你花一周学习很多 Java 开发的直觉是AI 应用的爆发期Java 是不是没有太多机会实际上并不是。Python 工具链强在研究和快速验证但在企业落地时Java 有更成熟的类型系统、更规范的工程结构、更完善的运维生态。真正的冲突点在于过去 Java 接入 LLM 要么自己封装 HTTP 接口要么套一层低质量的工具类缺少统一抽象。Spring AI 的定位就是把 Spring 中最成熟的能力复用到 AI 场景。它相当于为开发者在“大模型 API”和“业务系统”之间搭了一座桥。你可以像写 JdbcTemplate 一样使用 ChatClient像声明 Bean 一样注册工具方法像配置数据源一样配置多家模型服务商。理解了这个定位你就能理解为什么很多团队开始把 Spring AI 作为 Java 侧接入 LLM 的默认选项。这篇文章适合以下读者想在企业项目里接入大模型但不知道如何设计统一封装层已经能调通模型 API但觉得代码杂乱、多模型切换成本高在面试或技术选型时被问到 MCP、Agent想建立完整的认知框架准备把 Java 后端能力订单、权限、数据、文档开放给 AI 使用。标题里提到的“多模型、Tools、MCP、Skills、Agent”本质上是一条层层递进的技术路线先接模型再让模型能调用方法然后通过标准协议接入外部工具最后让模型自主编排任务。接下来我会用一个“订单助手”场景贯穿全文逐步把这些能力叠加起来。2. Spring AI 2.0 核心概念速览2.1 ChatClient类似 JdbcTemplate 的 AI 会话入口在 Spring AI 中ChatClient是最常用的编程入口。你可以把它理解成 AI 场景下的RestTemplate通过它统一管理提示词、模型调用、结构化输出和工具注册。早期版本的 Spring AI 会要求你直接操作ChatModelBean而现在更推荐通过ChatClient.Builder构建客户端对象。这种设计带来的核心价值是统一。你的业务代码不需要关心底层是 OpenAI、通义千问还是本地 Ollama 模型只需要依赖ChatClient这个抽象即可。对团队而言这意味着模型切换不会污染业务逻辑。2.2 Tools让模型调用你的 Java 方法模型本身只能“说”不能“做”。如果用户问“我的订单发货没有”模型并不知道订单数据在哪里。Tools 机制允许你注册一个 Java 方法比如getOrderStatus(userId)模型在回答过程中如果判断需要查订单就会发起工具调用Spring AI 会自动执行方法并把结果返回给模型继续推理。这个过程听起来很“黑科技”但本质上是模型生成结构化调用参数框架替你把参数传给 Java 方法再把结果塞回上下文。它解决了“模型与业务数据隔离”的问题。2.3 MCP标准化外部工具接入协议如果说 Tools 是“把自家方法给模型用”那么 MCP 就是“把整个工具生态给模型用”。MCPModel Context Protocol是一个开放协议它定义了模型与外部工具、数据源之间的通信方式。一个 MCP Server 可以暴露订单系统、文件系统、数据库、Figma 设计稿、蓝湖标注等能力Spring AI 应用作为 MCP Client 去连接这些服务。MCP 的意义在于互操作性。过去每个框架都有一套自己的工具接入方式MCP 出现后工具提供方只需要实现一次服务端所有支持 MCP 的客户端都能使用。这也是为什么越来越多的开发者搜索“蓝湖 MCP”“Figma MCP”去扩展模型能力。2.4 Skills沉淀专业能力的可复用模块Skills 在 Spring AI 中并没有像 Tools 那样统一的标准更多是一种工程实践。你可以把某类任务相关的提示词模板、Few-Shot 示例、工具组合、输出约束封装成一个“技能模块”供多个 Agent 复用。例如“售后规则解释”是一个 Skill“订单查询”是另一个 Skill。Skills 与 MCP 的区别需要特别注意Skills 偏重于“某个领域问题的解决方式”MCP 偏重于“连接到某个系统能力的协议”。Skill 常常会主动使用 MCP 暴露的工具二者是互补关系。2.5 Agent让模型自主编排工具的智能体Agent 是最终形态。它不再是一问一答而是面对一个目标自己拆解步骤决定先用哪个工具、再调用哪段逻辑。比如“帮我处理这个售后工单”Agent 可能需要先查订单、再查物流、最后生成处理意见。Spring AI 本身没有强制要求你用某种 Agent 框架你可以基于 ChatClient Tools 自建轻量 Agent 循环。概念解决的核心问题通俗理解ChatModel屏蔽不同模型 API 差异统一插座ChatClient简化提示词和推理调用会话入口Tools让模型调用业务方法给模型装上手MCP标准化外部资源接入给模型开放网络和生态Skills复用专业任务能力沉淀领域经验Agent模型自动编排工具不只是回答而是执行3. 环境准备与项目初始化3.1 基础环境要求从 Spring AI 当前主流实践看推荐使用以下基础环境JDK 17 及以上Spring Boot 3.2 及以上Maven 3.6 或 Gradle 7.5一个模型 API KeyOpenAI、DeepSeek、通义千问等本机安装 Ollama 可以用来做本地模型测试。需要说明的是Spring AI 版本更新非常快具体版本号请以 Maven Central 官方 release 为准。本文示例代码以“稳定版 API”为基线如果后续 2.0 版本出现调整请按官方迁移文档微调即可整体思路不变。3.2 创建一个 Spring Boot 项目推荐直接在 start.spring.io 生成项目也可以手动创建 Maven 工程。关键是把 Spring AI 的 BOM 和启动器加入pom.xml。下面是一个最小依赖示例!-- pom.xml -- parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.4.1/version relativePath/ /parent properties java.version17/java.version spring-ai.version1.0.0/spring-ai.version /properties dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version${spring-ai.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-ollama/artifactId /dependency /dependencies这段配置做了三件事引入 Spring Boot 父工程、统一管理 Spring AI 版本、按需加入 OpenAI 和 Ollama 的模型启动器。如果你使用国内云厂商模型可以考虑引入spring-ai-starter-model-dashscope或者关注Spring AI Alibaba项目它提供了阿里云百炼平台的适配。3.3 配置模型服务商在src/main/resources/application.yml中配置 API Key 和默认模型参数spring: application: name: order-ai-demo ai: openai: api-key: ${OPENAI_API_KEY} chat: options: model: gpt-4o temperature: 0.7 ollama: base-url: http://localhost:11434 chat: options: model: qwen2.5:7b这里使用环境变量${OPENAI_API_KEY}而不是写死在配置里是工程化实践的基本要求。如果你的 Key 不适合放环境变量至少也要放到配置中心或本地 Git 忽略文件避免误提交。4. 跑通第一个对话从依赖到验证4.1 注入 ChatClientSpring AI 的自动配置会为我们创建ChatClient.Builder。在服务中注入它构建一个ChatClient实例// 文件路径src/main/java/com/example/orderai/service/OrderAssistantService.java package com.example.orderai.service; import org.springframework.ai.chat.client.ChatClient; import org.springframework.stereotype.Service; Service public class OrderAssistantService { private final ChatClient chatClient; public OrderAssistantService(ChatClient.Builder builder) { this.chatClient builder.build(); } public String ask(String question) { return chatClient.prompt(question) .call() .content(); } }chatClient.prompt(question)可以理解成准备发送提示词.call()执行模型调用.content()返回模型生成的文本。这个模式会在后面多次出现。4.2 增加一个 HTTP 接口用于验证为了让教程更贴近实际项目我加一个简单的 Controller 来暴露服务// 文件路径src/main/java/com/example/orderai/controller/ChatController.java package com.example.orderai.controller; import com.example.orderai.service.OrderAssistantService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; RestController public class ChatController { private final OrderAssistantService orderAssistantService; public ChatController(OrderAssistantService orderAssistantService) { this.orderAssistantService orderAssistantService; } GetMapping(/chat) public String chat(RequestParam(q) String question) { return orderAssistantService.ask(question); } }启动项目后访问curl http://localhost:8080/chat?q用一句话解释什么是订单履约只要配置正确就能返回模型生成的文本。这一步跑通说明整个 Spring Boot Spring AI 链路已经没有任何问题。4.3 结构化输出让模型返回实体对象实际项目中我们常常不希望模型返回一大段“散文”而是像接口一样返回结构化的 JSON。Spring AI 支持把模型输出直接映射成 Java 对象。例如定义一个用户信息实体// 文件路径src/main/java/com/example/orderai/model/UserInfo.java package com.example.orderai.model; public record UserInfo(String name, String email, String region) { }在服务中调用entity方法public UserInfo extractUser(String content) { return chatClient.prompt(请从以下文本中提取用户姓名、邮箱和地区返回 JSON。\n content) .call() .entity(UserInfo.class); }这里的entity(UserInfo.class)是 Spring AI 提供的结构化输出便捷写法。市面上很多教程还在手动拼接 JSON 再反序列化Spring AI 已经把这个过程统一了。使用结构化输出时要注意实体类字段命名要简单明确避免过于复杂的嵌套结构否则模型输出容易偏离预期。5. 多模型切换一个应用接入多家大模型5.1 为什么需要多模型依赖单一模型的风险很大可能是价格问题、可能是区域网络问题也可能是模型能力不满足某个场景。企业级应用通常会准备多家模型平时用性价比高的模型复杂推理场景切换到更强的模型。Spring AI 的价值就是让这种切换不影响业务代码。5.2 配置多家模型提供方前面application.yml中其实已经配置了 OpenAI 和 Ollama 两家。要方便切换最直接的方式就是使用Qualifier选择不同的ChatModelBeanService public class MultiModelService { private final ChatModel openAiChatModel; private final ChatModel ollamaChatModel; public MultiModelService( Qualifier(openAiChatModel) ChatModel openAiChatModel, Qualifier(ollamaChatModel) ChatModel ollamaChatModel) { this.openAiChatModel openAiChatModel; this.ollamaChatModel ollamaChatModel; } public String chatWithModel(String modelType, String question) { ChatModel model ollama.equals(modelType) ? ollamaChatModel : openAiChatModel; return ChatClient.builder(model) .build() .prompt(question) .call() .content(); } }Bean 名字不一定总是openAiChatModel和ollamaChatModel具体取决于自动配置的命名规则。如果遇到 Bean 找不到的问题可以先打印所有ChatModel类型的 Bean 确认实际名称。5.3 动态模型路由的演进方向更优雅的做法是通过配置中心动态切换默认模型比如把spring.ai.openai.chat.options.model放到 Apollo 或 Nacos 中运维调整配置后无需重启应用。这种能力在 Spring Boot 原生体系里已经比较成熟Spring AI 没有必要重复造轮子。6. Tools让大模型调用你的 Java 方法6.1 Tools 解决的问题现在我们把“订单助手”推进到业务场景。用户问“帮我查一下订单号 10086 的物流状态”。模型并不知道这个订单存在也不应该凭想象回答。这时我们需要把订单系统的查询能力暴露给模型。6.2 定义 Tool 方法Spring AI 中给一个方法加上Tool注解该方法就可以被模型调用// 文件路径src/main/java/com/example/orderai/tools/OrderTools.java package com.example.orderai.tools; import org.springframework.ai.tool.annotation.Tool; import org.springframework.stereotype.Component; Component public class OrderTools { Tool(description 根据订单号查询物流状态) public String getLogisticsStatus(String orderId) { // 实际项目中这里会调用订单服务或查询数据库 if (10086.equals(orderId)) { return 订单已发货当前到达杭州转运中心预计明天送达; } return 未查询到订单信息订单号可能不存在; } }注意Tool注解里的description非常关键。模型看到的不是方法名和参数而是这段描述。描述越清晰模型越可能正确使用这个工具。6.3 注册并调用在构建ChatClient时把工具注册进去// 文件路径src/main/java/com/example/orderai/config/ChatClientConfig.java package com.example.orderai.config; import com.example.orderai.tools.OrderTools; import org.springframework.ai.chat.client.ChatClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class ChatClientConfig { Bean public ChatClient chatClient(ChatClient.Builder builder, OrderTools orderTools) { return builder .defaultTools(orderTools) .build(); } }然后调用public String ask(String question) { return chatClient.prompt(question) .call() .content(); }当用户问“订单 10086 到哪里了”模型会返回一个工具调用指令Spring AI 自动执行OrderTools.getLogisticsStatus(10086)再把结果喂回模型最终生成自然语言回答。这个过程对业务代码是透明的。这里真正容易踩坑的地方是工具方法不应该有副作用。设计 Tools 时尽量只做“查询类”操作。如果需要执行写操作要增加权限校验、操作确认、操作日志避免模型在不可控场景下触发危险方法。7. MCP把模型接入开放工具生态7.1 为什么 MCP 是趋势从网上大量热词可以看出MCP 正在成为 AI 应用开发的关键词蓝湖 MCP、Figma MCP、MATLAB MCP、免费联网 MCP 等说明各种工具都在抢着把自己的能力变成 MCP Server。对开发者来说如果我们的应用支持 MCP Client就能直接使用这些第三方能力而不需要为每个工具单独写对接代码。7.2 MCP 的核心工作方式MCP 分为 Server 和 Client 两个角色。MCP Server 暴露的是“工具Tools”“资源Resources”和“提示词Prompts”MCP Client 连接 Server并从模型调用请求中转发工具调用。在 Spring AI 中应用充当 Client 角色。你可以连接同一个进程内的 MCP Server也可以通过 SSEServer-Sent Events连接远程 Server。配置方式大致如下spring: ai: mcp: client: enabled: true具体配置项不同版本差异较大如果项目文档里已经定义了McpClient等自动配置就按官方示例注册。这里建议你先跑通一个官方的 MCP Demo再接入自己的项目。7.3 自己写一个 MCP Server如果你不想依赖第三方也可以用 Java 写一个简单 MCP Server。Spring AI MCP Server 的 API 在版本演进中变化较快示例代码请以官方仓库为准。这里提供一个伪代码式的结构说明// 示意代码非完整可运行版本 McpServer server McpServer.using(transport) .tools(new MyToolProvider()) .sync();实际项目中把一个已有的业务服务暴露成 MCP Server意味着其他 AI 应用也能通过标准协议使用这个能力。这是企业内部 AI 平台化的重要方向。7.4 MCP 与 Tools 怎么选对比项ToolsMCP接入成本低直接在代码里加注解高一些需要建立 Server/Client使用范围当前应用内部跨应用、跨团队共享典型场景订单、权限、数据库等内部方法设计稿、办公文档、公共数据源协议标准无统一标准有开放协议实际工程中二者不是二选一。内部稳定的方法用 Tools跨系统公共能力优先考虑 MCP。8. Skills 与 Agent从单次对话到任务执行8.1 Skills专业能力的可复用封装Skills 没有统一的 API但一种常见做法是定义一组包含系统提示词、工具集合和示例反馈的 Bean让不同请求复用。比如“售后话术”这个 Skill可以封装成// 文件路径src/main/java/com/example/orderai/skill/AfterSaleSkill.java package com.example.orderai.skill; public class AfterSaleSkill { public static final String SYSTEM_PROMPT 你是订单助手的售后专家。回答需要遵守以下规则 1. 先确认订单状态和物流信息再给出处理方案。 2. 如果用户情绪激动先安抚情绪。 3. 不能承诺超出实际故障范围的赔偿。 ; }在调用时把它作为系统提示词public String handleAfterSale(String question) { return chatClient.prompt() .system(AfterSaleSkill.SYSTEM_PROMPT) .user(question) .call() .content(); }这么做最大的价值在于治理。提示词不是散落在代码各处的字符串而是有名字、有归属、可评审的资产。8.2 Agent从“回答”到“执行”当你同时具备 Tools、MCP、Skills就可以构建一个轻量 Agent。最简单的 Agent 逻辑是模型根据用户目标决定调用哪些工具Spring AI 自动执行并循环直到生成最终答案。前面 Tools 示例中模型已经具备了自动调用工具的能力所以在小范围内也可以把它理解为 Agent。但真正的 Agent 还需要具备任务拆解和状态管理能力。一个常见的轻量 Agent 编排思路如下public String executeAgent(String userGoal) { String finalAnswer chatClient.prompt(userGoal) .call() .content(); // 实际工程中可能需要多轮工具调用、校验结果、汇总报告 return finalAnswer; }更复杂的 Agent 可以引入“计划-执行-反思”循环先让模型生成执行计划再逐步调用工具最后检查结果是否满足目标。Spring AI 生态中有不少 Agent 框架和案例但建议先不要一上来就上重型框架先基于 ChatClient Tools 跑通一个最小任务流。8.3 Agent 落地时最容易忽略的问题Agent 看起来很强大但落地时最容易出问题的是不可控性。模型可能会选择错误的工具、传错参数、或者陷入死循环。因此生产中至少要加三层防护工具调用超时与最大轮次限制关键操作需要人工确认完整记录调用轨迹方便追踪。这些点如果能在一开始就设计好后面上线会省很多力气。9. Spring AI 2.0 常见问题与排查方法问题现象可能原因排查方式解决方案启动时 Bean 创建失败Spring AI 版本与 Spring Boot 版本不匹配检查启动日志中的 NoSuchBeanDefinitionException统一 spring-ai-bom 版本确保 Spring Boot 版本符合要求调用模型返回 401API Key 无效查看日志中的响应状态码检查环境变量或配置中心中的 Key工具方法没有被调用Tool 描述不清晰或方法未注册打印模型返回的 tool calls 日志优化 description确认 ChatClient 已注册该工具模型返回大量 JSON 解析异常结构化输出实体字段复杂查看原始模型输出简化实体类增加 few-shot 示例流式输出超时或断连网络不稳定或客户端超时设置过短查看网络与代理配置调大超时时间做好重试Agent 多次调用工具后仍然不结束缺少最大轮次限制观察日志中工具调用次数加入 loop 上限与停止条件在实际排查时建议先打开 Spring AI 的调试日志logging: level: org.springframework.ai: DEBUG看到完整的提示词、模型响应、工具调用结果后大多数问题都会变得很直观。10. 工程化实践与一周学习路线10.1 工程化实践建议版本先行创建项目时先锁定spring-ai-bom版本避免依赖冲突。配置外置所有模型 Key、模型名称、温度参数都放到配置中心或环境变量。工具瘦身不要一股脑把所有方法都注册成 Tools只暴露模型真正需要的能力减小误用风险。提示词资产化把系统提示词、Few-Shot 示例抽成独立模块纳入代码评审。安全边界涉及写操作的工具必须做权限校验和二次确认。成本控制为每个请求记录 token 消耗设置模型调用配额。可观测性保存请求与响应摘要方便追溯模型输出错误和工具调用链。10.2 一周学习路线建议天数学习主题主要任务第 1 天Spring AI 基础构建项目跑通 ChatClient 调用理解 ChatModel 抽象第 2 天提示词与结构化输出设计系统提示词练习 entity 映射第 3 天多模型接入配置两家模型服务商分析切换逻辑第 4 天Tools 工具调用将订单查询方法注册为 Tool验证自动调用第 5 天MCP 接入跑通官方 MCP 示例尝试连接一个第三方服务第 6 天Skills 封装把售后话术封装成可复用 Skill第 7 天轻量 Agent基于 Tools 与 Skill 构建一个“订单售后助手”这个路线强调“每天都能运行出结果”而不是只读文档。建议每完成一天就写一小段实践笔记。这样做的好处是一周后你不仅记住了概念还能用它回答“MCP 和 Tools 有什么区别”“Agent 怎么落地”这类面试和工作中的实际问题。10.3 给你的进一步建议如果你已经掌握了基础链路下一步可以重点关注三个方向第一关注 Spring AI Alibaba 等国内生态项目。它们对国内模型、函数计算、图数据库等场景有更本地化的适配特别是spring ai alibaba graph这类项目可以用于构建知识图谱与 RAG 结合的企业应用。第二研究 Agent 的工程化问题。不要只停留在“模型能调用工具”这个层面而是考虑状态持久化、多轮记忆、任务队列、人机协同。这些才是 Agent 能真正走进生产环境的关键。第三尝试让 MCP 成为团队的公共能力层。如果你的团队有多个 AI 应用沉淀一套内部 MCP Server比每个项目单独对接外部系统更高效。Java 生态在 AI 应用开发中的位置正在从“旁观者”变成“基础设施提供者”。Spring AI 2.0 能走多远取决于模型能力更取决于我们能不能用工程思维把模型、工具和业务有机连接起来。这篇文章的代码示例只是起点建议你直接复制到本地项目跑一遍遇到问题就按第 9 节排查然后再逐步叠加更复杂的能力。把它收藏在阅读列表里等真正开始做项目时你会回来感谢现在的自己。