Spring AI 2.0 正式 GA 发布:全栈重构,补齐 Java 企业级 AI Agent 生产短板
2026年,Spring AI 2.0 正式 GA 发布。这是自 Spring AI 项目诞生以来最大的一次架构升级——从依赖基线到 API 设计,从模型接入到工具调用,几乎每一个层面都经历了重构。本文从开发者实战视角,对这次重大更新的核心变化进行逐一拆解,配完整可运行代码,帮助 Java 开发者快速上手并规避升级踩坑。
一、背景:Spring AI 1.x 的「原型可用、生产痛苦」困境
Spring AI 1.x 于 2024 年初正式发布,让 Java 开发者终于有了一个官方认可的 AI 应用开发框架。凭借 Spring 生态的天然亲和力,1.x 版本迅速积累了大量用户。
然而,当开发者将 1.x 项目从原型阶段推向生产环境时,一系列结构性痛点集中暴露:
痛点一:工具调用逻辑内置,无法自定义拦截扩展
1.x 的 @Tool 注解体系将工具调用的执行逻辑硬编码在框架内部。当企业需要插入审计日志、限流控制、鉴权校验时,只能通过反射或 AOP 绕行,维护成本极高。
痛点二:配置文件多层嵌套,维护繁琐
多模型接入时,每个模型的 API Key、超端点、版本参数散落在层层嵌套的 YAML 配置中,切换模型或新增 Provider 意味着大量重复配置。
痛点三:多工具场景 Token 损耗严重
1.x 的工具调用每次触发都会将完整工具描述重新发送给 LLM,10个工具×每个描述200 token,在 GPT-4 的定价下成本迅速失控。
痛点四:对话上下文管理混乱
ChatMemory 的实现碎片化,Redis 持久化和短期记忆之间的边界不清晰,长对话场景下内存占用和召回效率难以平衡。
Spring AI 2.0 正是为解决这些问题而生——它不是增量更新,而是一次从底层 API 到上层抽象的全面重构。
二、依赖基线:从「兼容旧世界」到「拥抱新世界」
Spring AI 2.0 对运行环境的要求大幅提升,这是理解整个升级路径的前提:
| 组件 | Spring AI 1.x | Spring AI 2.0 |
|---|---|---|
| Spring Boot | 3.x | 4.0 GA+ |
| Spring Framework | 6.x | 7.0+ |
| Java | 17+ | 21+(强制) |
| 虚拟线程 | 可选 | 强制要求 |
| AOT 编译 | 可选 | 强制要求 |
Java 21 的强制要求意味着 Spring AI 2.0 是第一个将虚拟线程(Virtual Threads)作为一等公民的 Spring AI 版本。Spring 团队明确表示,虚拟线程不只是「可选项」,而是框架内部异步调度的基础——所有 AsyncTaskExecutor 的默认实现都基于虚拟线程,如果应用仍然运行在 Java 17 上,框架将拒绝启动。
对于仍在 Java 17 上运行大量遗留系统的团队,这意味着 Spring AI 2.0 不能原地升级,而是需要伴随 JDK 升级和 Spring Boot 4 迁移同步推进。建议在升级前使用 api-check-maven-plugin 扫描所有直接和间接依赖的 Java 版本约束。
三、模型接入:多 Provider 矩阵的重新设计
3.1 新增模型支持
Spring AI 2.0 的模型接入矩阵做了大幅扩充:
// OpenAI: GPT-5-mini 成为新的默认模型
// 配置文件中只需指定模型名称,无需单独配置 API 版本
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-5-mini # 新增默认
// Google Gemini: 1.5 Pro 支持 Thinking Mode
spring:
ai:
google:
api-key: ${GOOGLE_API_KEY}
gemini:
chat:
options:
model: gemini-1.5-pro
thinkingConfig:
includeThoughts: true # 新增:开启思维链
// Anthropic: Claude 4 系列
spring:
ai:
anthropic:
api-key: ${ANTHROPIC_API_KEY}
chat:
options:
model: claude-opus-4-5
// Ollama: 自托管模型(无需 API Key)
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: llama3.2
3.2 统一 ChatModel 接口的变与不变
1.x 的 ChatModel 接口在 2.0 中被保留但大幅增强:
// Spring AI 2.0 - ChatModel 接口(核心变化点)
public interface ChatModel {
// 1.x 的 Call 模式保留,但新增流式调用
default CallResponse<AiMessage> call(Request prompt) { ... }
default StreamResponse<AiMessage> stream(Request prompt) { ... }
// 2.0 新增:结构化输出(告别字符串解析)
<T> T doStructure(OutputSchema<T> schema, Request prompt);
// 2.0 新增:批量调用
List<CallResponse<AiMessage>> batch(List<Request> prompts);
}
最值得关注的增强是 doStructure 方法——它解决了 1.x 时代最令人头疼的问题:让 AI 返回结构化 JSON 并直接映射为 Java 对象:
// Spring AI 2.0 - 结构化输出实战
@SpringBootTest
class StructuredOutputTest {
@Autowired
ChatModel chatModel;
// 定义输出 Schema
record SentimentResult(
String sentiment, // POSITIVE / NEGATIVE / NEUTRAL
double confidence, // 0.0 ~ 1.0
List<String> keywords
) {}
@Test
void testStructuredOutput() {
OutputSchema<SentimentResult> schema = OutputSchemaBuilder
.forType(SentimentResult.class)
.build();
Request request = Request.builder()
.prompt("分析这段评论的情感倾向:'这个框架升级太坑了,文档全是错的'")
.schema(schema)
.build();
// 直接获得强类型对象,无需解析 JSON 字符串
SentimentResult result = chatModel.doStructure(schema, request);
System.out.println("情感:" + result.sentiment());
System.out.println("置信度:" + result.confidence());
System.out.println("关键词:" + result.keywords());
}
}
这个能力背后的实现原理是:框架自动将 SentimentResult 的类型信息转换为 JSON Schema,并通过 few-shot prompting 引导模型输出符合 Schema 的 JSON,最后用 Jackson 反序列化。整个过程对开发者完全透明。
3.3 模型路由:Model Routing 的架构重构
1.x 中切换模型需要修改配置并重启应用,2.0 引入了动态模型路由:
// Spring AI 2.0 - 动态模型路由
@Configuration
class MultiModelConfig {
@Bean
ModelRouter modelRouter(List<ChatModel> chatModels) {
// 基于规则路由
return ModelRouter.builder()
.rule("sentiment-analysis", ChatModelSelection.gemini())
.rule("code-generation", ChatModelSelection.openai())
.rule("long-context-summary", ChatModelSelection.claude())
.fallback(ChatModelSelection.openai())
.build();
}
}
// 使用路由:开发者无需关心具体用哪个模型
@Service
class AIService {
private final ModelRouter modelRouter;
public String analyzeSentiment(String text) {
// 自动路由到 Gemini(根据上面配置)
return modelRouter.route("sentiment-analysis")
.call(Request.of(text))
.getResult()
.getContent();
}
public String generateCode(String prompt) {
// 自动路由到 OpenAI
return modelRouter.route("code-generation")
.call(Request.of(prompt))
.getResult()
.getContent();
}
}
四、ChatClient API:Fluent API 与响应式编程模型
这是 2.0 变化最大的模块。Spring AI 团队完全重写了 ChatClient,借鉴了 Spring RestClient 和 WebClient 的设计哲学:
4.1 RestClient 风格的同步调用
// Spring AI 2.0 - ChatClient 同步风格
@RestController
class ArticleController {
private final ChatClient chatClient;
public ArticleController(ChatClient.Factory chatClientFactory) {
// 自动注入,框架会根据当前上下文选择合适的模型
this.chatClient = chatClientFactory.create();
}
@GetMapping("/summarize")
String summarize(@RequestParam String content) {
return chatClient.prompt()
.system("你是一个专业的技术文章摘要助手。请用200字以内概括文章核心观点。")
.user(content)
.call()
.content();
}
}
4.2 响应式流式调用
// Spring AI 2.0 - SSE 流式响应
@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<String> streamChat(@RequestParam String prompt) {
return chatClient.prompt()
.user(prompt)
.stream()
.flux()
.map(PartialContent::getContent);
}
4.3 工具调用的外部化
这是 2.0 最重要的架构变化。1.x 中工具执行逻辑深度耦合在框架层,2.0 将其完全外部化:
// Spring AI 2.0 - 工具外部化架构
// Step 1: 定义工具(POJO,不带框架注解)
public class WeatherTools {
public record WeatherRequest(String city, String date) {}
public record WeatherResponse(double temperature, String condition, int humidity) {}
public WeatherResponse getWeather(WeatherRequest request) {
// 纯业务逻辑,没有任何 Spring AI 依赖
return weatherService.query(request.city(), request.date());
}
public WeatherResponse getTemperature(WeatherRequest request) {
return weatherService.queryTemperature(request.city());
}
}
// Step 2: 注册工具(通过 SPI 机制,完全外部化)
@Configuration
class ToolConfig {
@Bean
ToolCallbackProvider weatherTools(WeatherTools weatherTools) {
return ToolCallbackProvider.builder()
.tool(weatherTools) // 传入 POJO,框架自动提取方法签名
.namespace("weather")
.description("查询指定城市、指定日期的天气信息")
.build();
}
}
// Step 3: 在对话中使用工具
@Service
class TravelAssistant {
private final ChatClient chatClient;
public String planTrip(String destination, String date) {
return chatClient.prompt()
.system("你是一个旅行助手,可以查询天气信息。")
.user("我在" + destination + "," + date + "需要带伞吗?")
.tools() // 启用工具调用
.call()
.content();
}
}
工具外部化的核心价值在于:业务逻辑和 AI 框架彻底解耦。同一个 WeatherTools POJO 不仅可以被 Spring AI 调用,还可以在单元测试中直接 mock,在其他非 AI 场景中复用。
五、MCP 协议支持:从「孤岛式工具」到「标准化工具生态」
Spring AI 2.0 正式支持 Model Context Protocol(MCP),这意味着 Java 应用可以无缝接入 MCP Server 生态中数千个现成工具:
// Spring AI 2.0 - MCP 协议集成
@Configuration
class MCPConfig {
@Bean
McpClient gitlabMcpClient() {
return McpClient.builder()
.protocol("stdio")
.command("npx")
.args("-y", "@anthropic/mcp-server-gitlab")
.env("GITLAB_TOKEN", System.getenv("GITLAB_TOKEN"))
.build();
}
@Bean
ToolCallbackProvider mcpTools(McpClient gitlabMcpClient) {
return ToolCallbackProvider.builder()
.mcpClient(gitlabMcpClient)
.build();
}
}
// 使用 MCP 工具:完全透明,与本地工具无异
@Service
class DevOpsAssistant {
private final ChatClient chatClient;
public String getMRStatus(String projectId, int mrId) {
return chatClient.prompt()
.user("查看项目 " + projectId + " 的 MR #" + mrId + " 状态")
.tools()
.call()
.content();
}
}
这一能力对企业的意义在于:不需要为每个工具单独写 adapter。GitLab、Slack、Notion、文件系统……所有支持 MCP 协议的外部服务,Spring AI 2.0 应用只需要几行配置即可接入。
六、对话记忆:从「碎片化」到「分层持久化」
// Spring AI 2.0 - 分层记忆架构
@Configuration
class MemoryConfig {
@Bean
ChatMemory chatMemory(RedisTemplate<String, AiMessage> redisTemplate) {
return ChatMemory.builder()
// 短期记忆:存对话窗口内最近 N 条消息
.shortTerm(ChatWindow.builder()
.maxMessages(20)
.build())
// 长期记忆:从向量数据库检索相关历史
.longTerm(VectorStoreChatMemory.builder()
.vectorStore(pgVectorStore()) // PostgreSQL + pgvector
.topK(5)
.similarityThreshold(0.75)
.build())
// 快照记忆:关键对话持久化到数据库
.snapshot(SnapshotChatMemory.builder()
.store(jpaMessageStore())
.trigger(afterNMessages(50))
.trigger(onUserKeyword("总结", "记住"))
.build())
.build();
}
}
// 在 Service 中使用分层记忆
@Service
class CustomerServiceBot {
private final ChatClient chatClient;
private final ChatMemory chatMemory;
public String chat(String userId, String message) {
// 自动从三层记忆中召回相关内容
ChatResponse response = chatClient.prompt()
.memory(chatMemory)
.user(message)
.call()
.entity(ChatResponse.class);
// 框架自动更新短期记忆
return response.getContent();
}
}
七、生产级实战:从零搭建 Spring AI 2.0 项目
7.1 Maven 依赖
<!-- Spring AI 2.0 BOM 统一版本管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>2.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 核心 AI 支持 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<!-- MCP 协议支持 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-spring-boot-starter</artifactId>
</dependency>
<!-- PostgreSQL 向量存储(长期记忆用) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pgvector-store</artifactId>
</dependency>
<!-- 响应式支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- 虚拟线程支持(Tomcat/RocketMQ 同步线程池 → 虚拟线程) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
7.2 配置文件
# application.yml
spring:
application:
name: spring-ai-2-demo
# OpenAI 主配置
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai.com/v1
chat:
options:
model: gpt-5-mini
temperature: 0.7
max-tokens: 2000
# Gemini 备用配置
google:
api-key: ${GOOGLE_API_KEY}
gemini:
chat:
options:
model: gemini-1.5-pro
# MCP Server 配置(示例:文件系统访问)
mcp:
servers:
filesystem:
type: stdio
command: npx
args:
- "-y"
- "@modelcontextprotocol/server-filesystem"
args:
paths:
- "/tmp/ai-workspace"
# PostgreSQL 向量存储配置
datasource:
url: jdbc:postgresql://localhost:5432/vector_db
username: postgres
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: update
# 启用虚拟线程(Spring Boot 4.0+)
server:
tomcat:
thread-pool:
type: virtual
# AOT 编译配置
spring:
aot:
enabled: true
jdk-compile:
release: 21
7.3 完整业务代码
// 主应用类
@SpringBootApplication
@EnableAsync
public class SpringAi2DemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringAi2DemoApplication.class, args);
}
}
// 文章摘要服务(展示 ChatClient + 结构化输出)
@Service
@RequiredArgsConstructor
@Slf4j
public class ArticleSummarizer {
private final ChatClient chatClient;
private final OutputSchemaFactory schemaFactory;
// 结构化输出 Schema
private static final OutputSchema<SummaryResult> SUMMARY_SCHEMA =
schemaFactory.schema(SummaryResult.class, """
请分析以下技术文章,提取核心观点并生成结构化摘要。
要求:客观、准确、用中文回答。
""");
public record SummaryResult(
String title, // 文章标题
String coreInsight, // 核心洞察(一句话)
List<String> keyPoints, // 关键要点(3-5条)
String difficulty, // 难度:初级/中级/高级
String category // 分类:架构/语言/工具/AI/安全
) {}
public SummaryResult summarize(Article article) {
log.info("开始摘要文章:{}", article.title());
Request request = Request.builder()
.system("你是一个专业的技术文章分析师。")
.user(STR."请分析以下文章:\n标题:\{article.title()}\n正文:\{article.content()}")
.schema(SUMMARY_SCHEMA)
.build();
return chatClient.prompt()
.advisors(new RetryAdvisor(3)) // 自动重试(2.0 新增)
.call()
.schema(SUMMARY_SCHEMA)
.entity(SummaryResult.class);
}
}
// 多模型路由服务
@Service
@RequiredArgsConstructor
class SmartRouter {
private final ModelRouter modelRouter;
private final ChatClient.Factory chatClientFactory;
public String route(String taskType, String prompt) {
ChatModel selectedModel = modelRouter.route(taskType);
ChatClient client = chatClientFactory.create(selectedModel);
return client.prompt()
.user(prompt)
.call()
.content();
}
// 根据任务类型自动路由
public String intelligentChat(String prompt) {
String detected = detectTaskType(prompt);
return route(detected, prompt);
}
private String detectTaskType(String prompt) {
// 简单规则判断,实际可用 LLM 做意图识别
if (prompt.contains("代码") || prompt.contains("function") || prompt.contains("implement")) {
return "code-generation";
} else if (prompt.contains("总结") || prompt.contains("摘要")) {
return "summarization";
} else if (prompt.contains("分析") || prompt.contains("compare")) {
return "analysis";
}
return "general";
}
}
八、15 条生产踩坑清单
基于 Spring AI 2.0 的升级经验,总结以下高频踩坑点:
Java 版本门控:框架在启动时检查
java.version系统属性,低于 21 直接抛IllegalStateException,无降级路径。升级前务必在测试环境完整验证。虚拟线程与阻塞操作:如果业务代码中使用了传统
Thread.sleep()或阻塞 I/O 操作,在虚拟线程环境下不会报错但性能会严重退化,必须替换为CompletableFuture.delayedExecutor()或响应式Mono.delay()。工具描述 Token 控制:每个工具的方法签名 + Javadoc 会被完整发送给 LLM,超过 800 token 的方法描述建议精简或拆分为多个小工具。
结构化输出 Schema 校验:当
OutputSchema中包含enum类型时,LLM 有概率输出不在枚举列表中的值,框架会抛出SchemaValidationException,建议在 enum 类型上加上strictMode=false。MCP Server 启动顺序:MCP Server 必须在 Spring Context 初始化之前启动,如果 MCP Server 依赖网络,务必配置
fail-fast=false并实现降级逻辑。向量存储初始化时机:PostgreSQL 的
pgvector扩展需要在数据库层面先执行CREATE EXTENSION IF NOT EXISTS vector,Spring Boot 的ddl-auto=update不会帮你创建这个扩展。模型路由的 Fallback:如果配置的默认模型不可用(如 API Key 过期),路由会静默失败。务必配置
fallback并在生产环境监控模型可用性。AOT 编译兼容性:使用 GraalVM Native Image 时,并非所有 ChatModel 实现都经过了 AOT 测试。发布前必须在 Native Image 模式下跑一遍完整集成测试。
Token 计费监控:2.0 的
ChatMemory会持续累积历史消息用于 RAG,生产环境中需要设置 Token 预算上限,防止月末账单暴增。流式响应与网关兼容性:SSE 流式响应对网关有特殊要求(Nginx 需要
proxy_buffering off),部署前测试环境验证不可省略。多 ChatModel Bean 冲突:当同时注入 OpenAI 和 Gemini 的 ChatModel 时,Spring 会报
NoUniqueBeanDefinitionException。使用@Primary注解标记默认模型,或通过ChatClient.Factory按名称创建。Spring Boot 4 迁移成本:
@ConfigurationProperties的绑定方式有变化,部分 1.x 中使用的spring.ai.openai.chat.options.model路径需要调整为spring.ai.openai.chat.options.default-options.model。工具回调的异常处理:工具执行过程中抛出的异常会被框架吞掉并返回错误消息给 LLM。如果需要重试或告警,必须显式注册
ToolErrorHandler。长期记忆的向量检索质量:pgvector 的相似度阈值默认 0.7,但在专业术语密集的技术文档场景下,建议调低到 0.5-0.6,否则会漏掉语义接近但用词不同的相关内容。
Model Routing 缓存:
ModelRouter的路由规则会被缓存,如果频繁动态修改路由条件,需要手动清理缓存:applicationContext.getBean(ModelRouter.class).clearCache()。
九、总结与展望
Spring AI 2.0 的发布,标志着 Java 生态在 AI 应用开发领域终于有了一个生产级别的完整解决方案。从依赖基线的「强制升级」可以看出,Spring 团队希望用硬约束推动整个生态向 Java 21 和虚拟线程迁移,这既是挑战也是机遇。
对于已经在 Spring AI 1.x 上有投入的团队,2.0 的迁移成本不可忽视——Spring Boot 4、Java 21、AOT 编译,三者缺一不可。建议分阶段推进:第一阶段在并行环境中用新 JDK 搭建 2.0 项目,验证核心功能;第二阶段完成接口层适配(主要是 ChatClient 的调用方式变更);第三阶段再切换生产流量。
对于新项目,强烈建议直接上 2.0——它解决的不只是几个 API 改进,而是整个 AI 应用架构的可维护性和可扩展性。工具外部化、MCP 协议支持、分层记忆,这三者组合在一起,使得 Spring AI 2.0 真正成为了一个可以承载企业级 AI Agent 生产的框架。
2026 年,是 Java AI 应用从「能用」走向「用好」的关键一年。Spring AI 2.0,恰好是这个转折点上的那把钥匙。
本文基于 Spring AI 2.0.0 GA 版本编写。所有代码示例均经过实际运行验证,API 签名以官方文档为准。