Spring AI 2.0 GA 正式发布!
前言
最近缺项目经历想快速提升项目实战能力(包含多个AI项目),或者最近找工作,或者想学习AI的小伙伴,可以看看下面👇🏻的这个链接(或许真的能够帮到你)。
前两天在技术群里看到有人在问:“Spring AI 2.0到底啥时候发?都鸽了一个月了。”
底下跟着一串+1。
确实,从5月推到6月,中间还穿插了好几个RC版本,很多人等得有点着急。
但就在2026年6月12日,Spring团队终于在Spring I/O大会的最后一天宣布——Spring AI 2.0.0 GA正式发布,已同步上传至Maven Central。
RC2在6月9日发布,距离GA只隔了三天,节奏明显在加速。
从1.x一路跟过来的老开发应该知道,Spring AI 1.0 GA是2024年发布的,主要解决了“Java怎么调用大模型”的基础问题。
而这次2.0的定位完全不同——它不再是一个大模型客户端的SDK集合,而是Spring生态的AI原生运行时。
用官方的话说,这是一次“可持续演进的新基线”的重置。
今天这篇文章就跟大家一起聊聊Spring AI 2.0 GA版本,希望对你会有所帮助。
一、这波更新到底有多大?
Spring AI 2.0最根本的变化,不是加了几个新功能,而是整个地基都换了一遍。
从Spring Boot 3.x彻底迁移到Spring Boot 4.0 GA和Spring Framework 7.0,强制要求Java 21作为最低开发环境。
Jakarta EE 11也成了底层基石之一。
1.1 Java 21:虚拟线程不再是摆设
Java 21最大的亮点就是虚拟线程。
之前很多人都在喊“虚拟线程很强”,但实际项目中很少有场景能真正用上。
现在Spring AI 2.0把它变成了一等公民——处理IO密集型的模型调用,一个虚拟线程可以轻松抗下成千上万个并发会话。
据社区实测反馈,启用虚拟线程后,AI应用在IO密集型场景下的吞吐量能提升3到5倍。
你在application.yml里加一行配置就能享受这个红利,不用大改代码。
spring:
threads:
virtual:
enabled: trueGC更温柔,内存占用更克制。
连老MacBook Air都能轻量跑起来,这在以前是不敢想的。
1.2 Jackson 2 → Jackson 3
Jackson 3的升级改变了日期序列化的默认格式和属性顺序。
如果你有下游服务依赖解析Unix时间戳或固定字段顺序,升级前务必跑全量集成测试。
否则可能上线后发现前后端对不上了,排查到半夜才发现是Jackson的锅。
1.3 JSpecify空安全:编译期发现NPE
Spring AI 2.0的代码库全面使用JSpecify注解标注空安全。
你现在可以在编译阶段发现潜在的NPE,而不是等到运行时crash。
对于维护大型AI应用的团队来说,这省掉的调试时间不是一点半点。
1.4 Null Safety带来的连锁反应
在编写代码的时候,空安全的工作还触发了对配置属性处理方式的大幅重构。
Options现在通过Builder创建且一旦实例化就不可变,默认值有了统一的定义位置,取代了以前散落在各处的application.properties中的.options段。
二、ChatClient成为核心入口
在1.x时代,你要调AI,可以绕过ChatClient直接对着OpenAiChatModel撸代码。
但2.0的设计思路变了:ChatClient现在是面向AI应用开发的统一入口,ChatModel降级成了底层构件。
下面给出一个从零开始的完整示例,包含Maven配置、配置类、Service层和Controller层。
第一步:添加依赖(pom.xml)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.0</version>
<relativePath/>
</parent>
<properties>
<java.version>21</java.version>
</properties>
<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>2.0.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-milestones</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>第二步:配置文件(application.yml)
spring:
application:
name: ai-demo
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
model: gpt-4o
options:
temperature: 0.7
max-tokens: 2048
threads:
virtual:
enabled: true第三步:编写Service(使用ChatClient)
package com.example.ai.service;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.ToolCallingAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
@Service
public class AIChatService {
private final ChatClient chatClient;
public AIChatService(ChatClient.Builder chatClientBuilder) {
// 构建ChatClient,可以链式添加Advisors
this.chatClient = chatClientBuilder
// 添加对话记忆顾问(自动管理多轮上下文)
.advisors(new PromptChatMemoryAdvisor(new InMemoryChatMemory()))
// 添加工具调用顾问(处理Tool Calling)
.advisors(new ToolCallingAdvisor())
.build();
}
// 同步调用
public String chat(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.call()
.content();
}
// 流式调用
public Flux<String> streamChat(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.stream()
.content();
}
// 带系统提示词
public String chatWithSystem(String userMessage, String systemPrompt) {
return chatClient.prompt()
.system(systemPrompt)
.user(userMessage)
.call()
.content();
}
}第四步:编写Controller
package com.example.ai.controller;
import com.example.ai.service.AIChatService;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
@RestController
@RequestMapping("/api/chat")
public class ChatController {
private final AIChatService chatService;
public ChatController(AIChatService chatService) {
this.chatService = chatService;
}
@PostMapping("/sync")
public String syncChat(@RequestBody ChatRequest request) {
return chatService.chat(request.message());
}
@GetMapping(value = "/stream", produces = "text/plain;charset=UTF-8")
public Flux<String> streamChat(@RequestParam String message) {
return chatService.streamChat(message);
}
public record ChatRequest(String message) {}
}逐行逻辑拆解:ChatClient.Builder是自动配置好的Bean,你可以直接注入。
通过.advisors()可以挂载各种横切能力——PromptChatMemoryAdvisor自动管理多轮对话上下文,ToolCallingAdvisor接管工具调用循环。
这种链式调用的写法比1.x时代手动组装请求简洁得多,逻辑一目了然。
三、工具调用彻底重构
2.0中最核心的变化是工具调用机制的彻底重构。
在1.x中,每个ChatModel内部都内置了工具执行逻辑,导致模型与工具之间耦合很紧。
2.0的工程团队通过重构,把工具执行循环从各个ChatModel中完全抽离出来,统一由外部的ToolCallingAdvisor处理。
简单说:以前模型自己管自己怎么调用工具;现在模型只管说“我想用这个工具”,具体的执行、鉴权、审计、重试都由应用层代码说了算。
安全性和可观测性一下子上去了。
完整的工具调用示例(订单查询)
package com.example.ai.tool;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallingAdvisor;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
// 1. 定义工具类(可以是任意普通Java类)
@Component
public class OrderTools {
@Tool(description = "根据订单号查询订单详情,返回订单状态、金额、物流信息")
public OrderInfo queryOrder(@ToolParam(description = "订单号,格式为ORD-数字") String orderNumber) {
// 模拟数据库查询
if ("ORD-123456".equals(orderNumber)) {
return new OrderInfo(orderNumber, "已发货", 299.00, "顺丰快递 SF1234567890");
}
return new OrderInfo(orderNumber, "不存在", 0.0, null);
}
@Tool(description = "查询指定用户的订单列表")
public List<OrderInfo> listUserOrders(@ToolParam(description = "用户ID") String userId) {
// 模拟返回
return List.of(
new OrderInfo("ORD-123456", "已发货", 299.00, "SF123"),
new OrderInfo("ORD-789012", "待支付", 599.00, null)
);
}
// 返回值类型会用于生成JSON Schema,供LLM理解
public record OrderInfo(String orderNumber, String status, double amount, String trackingNumber) {}
}
// 2. Service中注册并调用
@Service
public class OrderAssistantService {
private final ChatClient chatClient;
public OrderAssistantService(ChatClient.Builder builder, OrderTools orderTools) {
// 将工具方法转换为ToolCallback
ToolCallback orderTool = ToolCallback.from(
"queryOrder",
(String orderNumber) -> orderTools.queryOrder(orderNumber)
);
ToolCallback listTool = ToolCallback.from(
"listUserOrders",
(String userId) -> orderTools.listUserOrders(userId)
);
this.chatClient = builder
.tools(orderTool, listTool) // 显式注册工具
.advisors(new ToolCallingAdvisor()) // 必须加这个顾问
.build();
}
public String ask(String userQuestion) {
return chatClient.prompt()
.user(userQuestion)
.call()
.content();
}
}
// 3. 测试调用
// 用户问:"帮我查一下订单ORD-123456的状态"
// Agent会:识别意图 → 调用queryOrder("ORD-123456") → 拿到结果 → 组织回答按需发现工具(ToolSearchToolCallingAdvisor)
// 适用场景:工具数量很多(几十上百个),不想一次性把定义全塞给模型
@Configuration
public class ToolDiscoveryConfig {
@Bean
public ToolSearchToolCallingAdvisor toolSearchAdvisor(VectorStore vectorStore) {
// 用VectorStore存储工具定义,模型根据用户问题动态检索相关工具
return ToolSearchToolCallingAdvisor.builder(vectorStore)
.similarityThreshold(0.75) // 相似度阈值
.topK(3) // 每次最多加载3个工具
.build();
}
}哪些东西被移除了?
internalToolExecutionEnabled标志toolNames()APISpringBeanToolCallbackResolver
正确的迁移方式:所有工具必须通过.tools(ToolCallback...)显式传递,不再依赖Bean名称自动注入。
四、Advisors链
把横切能力变成可插拔。
仔细想想,AI应用里最烦人的是那些横跨各个请求的“通用能力”——多轮对话的历史记忆、敏感词过滤、调用限流、性能监控……以前你要自己手写这些逻辑,往每个请求里硬塞。
2.0把ToolCallingAdvisor纳入了Advisor链,还带来了递归Advisor体系。
你可以把对话记忆、RAG检索、内容安全过滤、数据脱敏等能力打包成一个个独立的Advisor,在请求处理链上按顺序执行。
完整的Advisor配置示例
package com.example.ai.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.*;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ChatAdvisorConfig {
@Bean
public ChatClient chatClient(ChatClient.Builder builder,
VectorStore vectorStore,
ChatMemory chatMemory) {
// 构建RAG检索器
DocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.similarityThreshold(0.70)
.topK(4)
.build();
return builder
// 1. 对话记忆顾问(保留最近10轮对话)
.advisors(new PromptChatMemoryAdvisor(chatMemory, 10))
// 2. 内容安全过滤顾问(自定义实现)
.advisors(new ContentFilterAdvisor())
// 3. RAG检索增强顾问
.advisors(new QuestionAnswerAdvisor(retriever))
// 4. 工具调用顾问
.advisors(new ToolCallingAdvisor())
// 5. 日志监控顾问
.advisors(new LoggingAdvisor())
.build();
}
@Bean
public ChatMemory chatMemory() {
return new InMemoryChatMemory();
}
}自定义Advisor示例(敏感词过滤)
package com.example.ai.advisor;
import org.springframework.ai.chat.client.advisor.api.*;
import reactor.core.publisher.Mono;
public class ContentFilterAdvisor implements CallAroundAdvisor {
private static final List<String> SENSITIVE_WORDS = List.of("暴力", "色情", "赌博");
@Override
public AdvisorResult aroundCall(AdvisorContext context,
CallAroundAdvisorChain chain) {
String userMessage = context.userMessage();
for (String word : SENSITIVE_WORDS) {
if (userMessage.contains(word)) {
return new AdvisorResult("抱歉,您的输入包含敏感词汇,无法处理。");
}
}
return chain.call(context);
}
@Override
public int getOrder() {
return 0; // 优先级最高
}
}这种设计与Spring MVC的Interceptor思路如出一辙。
用惯了Spring的开发者上手几乎零学习成本,不用再去理解一套全新的Agent概念。
五、MCP变成一等公民
把Spring Bean变成AI能调的工具。
Model Context Protocol(MCP)在2.0中不再是需要依赖额外jar包的可选功能,而是直接收编到了Spring AI核心。
现在写一个MCP Server,跟写一个普通的Spring Bean一样简单。
完整的MCP Server示例
<!-- 添加MCP Server依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
<version>2.0.0</version>
</dependency># application.yml
spring:
ai:
mcp:
server:
name: enterprise-mcp-server
version: 1.0.0
protocol: STREAMABLE # 支持STREAMABLE/SSE/STDIO
type: SYNC
server:
port: 8080package com.example.mcp;
import org.springframework.ai.mcp.annotation.McpTool;
import org.springframework.ai.mcp.annotation.McpToolParam;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class EnterpriseMcpTools {
@McpTool(description = "根据员工ID查询员工信息")
public Employee getEmployee(
@McpToolParam(description = "员工ID,格式EMP-数字") String empId) {
// 调用HR系统
return employeeRepository.findById(empId);
}
@McpTool(description = "创建部门审批申请")
public ApprovalResult createApproval(
@McpToolParam(description = "申请人ID") String applicantId,
@McpToolParam(description = "审批类型:leave/expense/reimburse") String type,
@McpToolParam(description = "申请详情") String details) {
// 调用工作流引擎
return approvalService.submit(applicantId, type, details);
}
@McpTool(description = "查询实时库存")
public int getStock(
@McpToolParam(description = "商品SKU编码") String sku) {
return inventoryService.getStock(sku);
}
public record Employee(String id, String name, String department) {}
public record ApprovalResult(String approvalId, String status) {}
}启动应用后,访问http://localhost:8080/mcp就可以用MCP Inspector看到所有Tools、Resources和Prompts。
无需手动编写JSON Schema,无需搭建传输层基础设施,所有细节由框架自动处理。
MCP Client集成(消费外部MCP Server)
最近缺项目经历想快速提升项目实战能力(包含多个AI项目),或者最近找工作,或者想学习AI的小伙伴,可以看看下面👇🏻的这个链接(或许真的能够帮到你)。
如果你想让自己的Spring AI应用调用别人提供的MCP工具(比如Claude Desktop的Tools),可以配置MCP Client:
spring:
ai:
mcp:
client:
enabled: true
servers:
claude-tools:
url: http://localhost:9000/mcp
transport: streamable@Autowired
private McpClient mcpClient;
public void callExternalTool() {
// 自动发现远程MCP Server提供的工具
ToolCallback remoteTool = mcpClient.getTool("search_documents");
String result = remoteTool.execute("Spring AI 2.0 新特性");
}在企业应用中,这意味着你可以极低成本地把现有业务系统暴露给AI作为“工具”,也可以消费其他系统提供的AI能力。
六、结构化输出增强
Java强类型终于有了用武之地。
以前从AI返回的JSON里提取字段,全链路开发体验不太好——你要手写解析逻辑、手动异常处理、手动验证字段是否存在。
代码写起来啰嗦,跑起来还容易在边界条件上翻车。
2.0在ChatClient.entity()中增加了EntityParamSpec,直接在每次entity()调用时就能配置结构化输出。
完整示例:从自然语言提取订单实体
package com.example.ai.structured;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class StructuredOutputService {
private final ChatClient chatClient;
public StructuredOutputService(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
// 定义输出实体(使用Record,字段描述用于生成提示)
public record OrderExtract(
@JsonPropertyDescription("订单号,通常以ORD开头后跟数字")
String orderNumber,
@JsonPropertyDescription("客户姓名")
String customerName,
@JsonPropertyDescription("订单总金额,单位元")
BigDecimal totalAmount,
@JsonPropertyDescription("订单创建时间,格式yyyy-MM-dd HH:mm:ss")
LocalDateTime createTime,
@JsonPropertyDescription("订单状态:待支付/已支付/已发货/已完成")
String status,
@JsonPropertyDescription("商品清单")
List<OrderItem> items
) {}
public record OrderItem(
@JsonPropertyDescription("商品名称")
String productName,
@JsonPropertyDescription("购买数量")
int quantity,
@JsonPropertyDescription("单价")
BigDecimal unitPrice
) {}
public OrderExtract extractOrderFromText(String rawText) {
return chatClient.prompt()
.user("从以下文本中提取订单信息,按JSON格式返回:" + rawText)
// 关键:通过entity方法指定要解析的类型
.entity(OrderExtract.class, spec -> spec
.withNativeStructuredOutput(true) // 启用模型原生结构化输出(如GPT-4o的JSON模式)
.withValidation(true) // 对必填字段进行校验
);
}
}
// 调用示例
String raw = "用户张三在2026年6月15日下单了订单ORD-999,总金额1299元,包含2件商品:华为手机和充电器。";
OrderExtract order = service.extractOrderFromText(raw);
System.out.println(order.orderNumber()); // ORD-999
System.out.println(order.customerName()); // 张三
System.out.println(order.items().size()); // 2流式+结构化输出组合
public Flux<OrderExtract> streamExtractOrders(Flux<String> textStream) {
return chatClient.prompt()
.user(flux -> flux
.next(text -> text)
.then(asAssistant("提取订单信息")))
.stream()
.entity(new ParameterizedTypeReference<OrderExtract>() {});
}这个变化对Java开发者来说意义很大——你终于可以用熟悉的强类型去“拿捏”AI的输出,而不是在Map和JSON字符串里反复折腾。
代码更简洁,错误更少,维护成本更低。
七、MessageWindowChatMemory的消息驱逐优化
这是一条容易忽略但很重要的改进:当对话窗口达到容量上限需要驱逐旧消息时,系统会向前移动到最近的用户消息边界再切,而不是在对话中间拦腰截断。
这意味着不会出现一个完整的问答轮次被撕裂成两半的情况。
// 在2.0中,滑动窗口会在边界处切分
@Bean
public ChatMemory chatMemory() {
// 保留最近20条消息,但驱逐时会保持问答对完整
return MessageWindowChatMemory.withMaxMessages(20);
}
// 而在1.x中,可能在助手回答中间截断实际运行时的差异:假设对话是“用户问A → 助手答A1 → 用户问B → 助手答B1”,当窗口容量只能容纳3条时,2.0会完整保留“用户问A + 助手答A1”,丢弃用户问B(但维持语义完整性)。
1.x则可能在“助手答A1”中间切断,导致下轮对话失去上下文。
八、模型支持范围的理性收缩
在一些知乎深度解析贴和官方博文中都提到:Spring AI 2.0做了一件颇有争议的事——大幅收缩核心支持的模型提供商范围。
- OpenAI:从3种变体(Azure、HTTP、SDK)收缩到1种(SDK),但保留了兼容OpenAI API的模型接入路径
- Anthropic:从2种变体(HTTP、SDK)收缩到1种(SDK),同样可通过兼容Anthropic API的代理方式使用其他模型
- 另外保留了Amazon Bedrock、Google GenAI等核心支持
国内模型的独立支持路径有所收缩,比如智谱等厂商的专用支持路径被移除。
在工程角度,这样做是为了降低维护成本、把精力聚焦在主流模型上,但如果你需要特定国产模型,可能需要自己维护适配层或者通过兼容OpenAI/Anthropic API的代理方式解决。
兼容方案示例
// 使用兼容OpenAI API的通义千问
OpenAiChatModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.modelName("qwen-plus")
.build();spring:
ai:
openai:
api-key: ${DASHSCOPE_API_KEY}
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
chat:
model: qwen-plus九、如何从Spring AI 1.x平滑升级
如果你现在用的是Spring AI 1.x,可以直接跳到2.0的升级清单。
我把关键步骤和坑点整理如下。
9.1 前置条件
- Java 21+:低于21会直接启动失败
- Spring Boot 4.0/4.1:这是硬性要求,不能绕过
- Spring Framework 7.0
推荐升级路径:先升级Java到21+,再把Spring Boot从3.x升级到3.5(先解决废弃API警告),最后从3.5跳跃到4.0。
如果直接跨大版本升级,你可能会被编译时的API移除信息吓一跳。
9.2 破坏性变更代码调整清单
工具调用相关:
- 移除依赖
internalToolExecutionEnabled、toolNames()的代码 - 移除
SpringBeanToolCallbackResolver - 将所有工具改为通过
.tools(ToolCallback)显式注册
类名迁移:
MessageAggregator→ChatClientMessageAggregator
向量存储异常处理:
vectorStore.delete()不再静默失败,必须显式捕获VectorStoreException
Provider更换:
- Watson、QianFan(千帆)、MoonShot独立支持已移除,需要用兼容方案或自行适配
9.3 保持兼容但官方已弃用的部分
ToolCallAdvisor在2.0中已重命名为ToolCallingAdvisor,但作为被标记为过时的子类仍被保留并配有Builder工厂,短期内不会编译失败,只是会有弃用警告。
十、Spring AI 2.0 vs LangChain4j
这是很多Java开发者在选型时最纠结的地方。
我从几个维度做了对比。
| 维度 | Spring AI 2.0 | LangChain4j 1.13+ |
|---|---|---|
| 定位 | Spring AI官方项目,用Spring工程化思维统一AI开发 | 独立类库,不绑定应用框架,强调Java惯用法 |
| 基线 | 强制Java 21 + Spring Boot 4 / Spring 7 | JDK 17+(以官方文档为准),框架松耦合 |
| 包命名 | org.springframework.ai.* | dev.langchain4j.* |
| API风格 | 依赖注入、自动装配、Advisor横切 | 接口代理、链式调用、AiServices声明式 |
| 工具调用 | ToolCallingAdvisor统一外部处理 | 内置支持,灵活配置 |
| MCP | 原生集成,Spring注解驱动 | 需单独配置 |
| 学习曲线 | Spring开发者趋近于零 | 中等,需理解独立概念体系 |
| 采用率(JetBrains 2025) | 52% | 68% |
| 适用场景 | Spring Boot 4 + Java 21新项目、云原生Agent | 实验性项目、不想大版本升级的老项目、非Spring生态 |
LangChain4j功能覆盖面更广,不绑定Spring也意味着你的代码可以在任何应用框架上跑,适合那些不想被单一生态绑定的团队。
但从实际痛点出发,如果你的企业应用已经深度使用Spring全家桶,选Spring AI 2.0无疑是最平滑、最省力的路。
两者不是“谁替代谁”的关系,而是在各自的定位上服务不同类型的团队。
十一、优缺点和适用场景
11.1 五大核心优势
第一,Spring原生集成。 依赖注入、自动装配、application.yml配置、Actuator监控端点、可观测性体系——这些Spring开发者熟悉的东西,换到AI场景下依然全都在。你不需要学习一套全新的Agent概念,用Spring的方式写AI就能跑出不错的效果。
第二,Java 21 + Spring Boot 4完整支持。 虚拟线程、Record类型、Pattern Matching等新特性全都用得上,IO密集型AI场景下吞吐量有显著提升。
第三,工具调用与MCP原生集成。 工具执行循环外置化、MCP作为一等公民,这两项让AI与真实业务系统的交互能力上了一个台阶。
第四,Advisors可组合性强。 记忆、检索、过滤、限流、观测等横切能力可以像搭积木一样插拔,代码复用率高。
第五,结构化输出+空安全。 Java强类型系统终于能充分约束AI的输出,编译期就能发现很多问题,运行时翻车概率大大降低。
11.2 三点缺点
第一,升级门槛偏高。 Spring Boot 4 + Java 21的升级对老项目是较大的投入,短期收益不确定的话可能会犹豫。1.x长期支持(1.1.x支持到2025年11月,1.0.x支持到2025年5月)虽然仍在,但最终的迁移是绕不开的。
第二,国内模型支持路径在收缩。 RC1的官方文档中智谱等国内模型的专用支持路径被移除,通过兼容OpenAI/Anthropic API的方式使用或自行维护适配层是必要的准备。
第三,部分高级功能还在完善中。 多智能体协作框架、边缘计算运行时等仍在Roadmap上,企业级大规模Agent编排场景可能需要自己补充。
11.3 适用场景
| 场景 | 是否推荐 | 核心理由 |
|---|---|---|
| 全新Spring Boot 4 + Java 21项目 | ✅ 强烈推荐 | 基线完美匹配,工程化体验最佳 |
| 已深度使用Spring全家桶的团队 | ✅ 强烈推荐 | 学习成本趋近于零,现有基础设施可复用 |
| 需要MCP协议集成(跨Agent通信) | ✅ 推荐 | MCP作为一等公民,开箱即用 |
| 企业RAG/客服系统/智能助手类项目 | ✅ 推荐 | ChatClient + Advisor体系天然适合 |
| 老项目无法升级到Java 21 | ⚠️ 谨慎 | 基线不兼容,建议继续用1.x或考虑LangChain4j |
| 需要国产模型全量独立SDK支持 | ⚠️ 谨慎 | 可能需要额外适配层或迁移成本 |
| 快速原型/一次性演示 | ⚠️ 谨慎 | 架构相对重型,专用模型SDK可能更快 |
十二、写在最后
从2024年的1.0到2026年的2.0 GA,Spring AI用两年时间完成了从“模型客户端”到“AI原生运行时”的蜕变。
ChatClient统一入口、ToolCallingAdvisor接管工具执行、MCP原生集成、结构化输出进阶——每一项变化都不只是表面上的功能迭代,而是背后思维方式的深刻变化:把AI能力真正纳入Spring的工程化体系来治理,而不是作为附加的“外挂”。
它不再只是一个SDK,而是让Java开发者用自己最熟悉的方式去构建AI应用的完整方案。
如果你正好在做一个Java 21 + Spring Boot 4的新项目,或者正在重度使用Spring全家桶,Spring AI 2.0值得你立刻上手试试。
如果你的老项目还在Spring Boot 3.x上纠结,那不妨看看LangChain4j,或者等一等再规划迁移路径。
最后给你留个完整的pom配置和启动类,复制粘贴就能跑起来:
<!-- pom.xml 完整内容 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.0</version>
<relativePath/>
</parent>
<properties>
<java.version>21</java.version>
</properties>
<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>2.0.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-milestones</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>// 启动类
@SpringBootApplication
public class AiApplication {
public static void main(String[] args) {
SpringApplication.run(AiApplication.class, args);
}
}# application.yml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
model: gpt-4o
options:
temperature: 0.7在application.yml里配置好模型API Key,写个测试类注入ChatClient,就这么简单。
AI时代Java开发者并不比Python差,Spring AI 2.0就是最好的证明。
趁着GA刚出,赶紧去体验一把。
开源项目地址:https://github.com/spring-projects/spring-ai
官方文档:https://docs.spring.io/spring-ai/docs/2.0.x/reference/html/index.html
最近缺项目经历想快速提升项目实战能力(包含多个AI项目),或者最近找工作,或者想学习AI的小伙伴,可以看看下面👇🏻的这个链接(或许真的能够帮到你)。