Spring AI 2.0 深度解读:从架构重构到生产实践
Tool Calling 重塑、MCP 原生集成、Advisor 链式编排——Java AI 开发的新纪元
一、概览:Spring AI 2.0 是什么
2026 年 6 月 12 日,Spring AI 2.0.0 GA 正式发布。距离 2025 年 12 月 11 日的 M1 恰好半年。这半年里,团队交付了 8 个 milestone + 2 个 RC,最终完成了从底层到上层的彻底重构。
这不是一个小版本升级。基线全面拉升:
- Spring Boot 4.1.0 + Spring Framework 7.0 + Jakarta EE 11
- Java 17 起步,推荐 Java 21(虚拟线程原生支持)
- MCP Java SDK 直接跳到 2.0.0(从 0.x 跨大版本)
- Jackson 3 全面引入(GA 版本中
OpenAiChatModel改回只用 Jackson 2,属于兼容修正)
版本时间线
| 版本 | 发布时间 | 性质 |
|---|---|---|
| 2.0.0 GA | 2026-06-12 | 首个正式版 |
| 2.0.0-RC2 | 2026-06-09 | 预发布,修复 Bedrock 模型选项、Ollama 思考字段丢失等问题 |
| 2.0.0-RC1 | 2026-06-06 | 预发布 |
| 2.0.0-M8 | 2026-05-27 | 最后一个里程碑,引入 ChatResponseMetadata 暴露 Anthropic 限流 |
| 2.0.0-M1 | 2025-12-11 | 2.0 系列首个里程碑 |
| 1.1.x | 持续维护 | 兼容 Spring Boot 3.5 |
GA 与 RC 的关键差异(很多人漏看)
| 类别 | 变化 |
|---|---|
| 新特性 | OpenAiChatModel 改回只用 Jackson 2(RC 阶段误升级) |
| 新特性 | Google GenAI 模型列表更新,新增 GEMINI_3_1_PRO_PREVIEW |
| Bug 修复 | Cassandra / Mongo / JDBC ChatMemory 不再处理 unsupported tool message |
| Bug 修复 | OpenAiChatOptions 补齐 promptCacheKey 字段(OpenAI prompt caching 2.0 需要) |
| 依赖升级 | MCP SDK → 2.0.0 |
| 依赖升级 | Spring Boot → 4.1.0(从 M 系列的 4.0 升上来) |
关键时间节点:Spring Boot 3.5 和 Spring Framework 6.2 已于 2026-06-30 EOL,距 GA 发布仅 18 天。要么升 2.0,要么停在 1.1.x 等下一个 LTS,没有"再等等"的路。
二、核心架构变化:从"单体核心"到"领域驱动模块化"
2.1 模块拆分
spring-ai-core 被拆分为多个独立模块:
spring-ai-commons—— 公共工具和基础设施spring-ai-model—— 模型抽象层spring-ai-client-chat—— ChatClient 及其 Advisor 链spring-ai-vector-store—— 向量存储抽象spring-ai-rag—— RAG 检索增强生成
开发者可以按需引入,大幅减少不必要的依赖。模块间遵循严格的分层依赖原则(DAG),底层模块禁止向上依赖。
2.2 基线升级详情
| 升级项 | 说明 |
|---|---|
| Jackson 3 | JSON 处理引擎全面升级(GA 中 OpenAI 模块回退至 Jackson 2 以保兼容) |
| JSpecify Null 安全注解 | 编译期空指针检测,org.springframework.ai.image.observation 等包标记为 null-marked |
| Options 不可变 | setter 废弃,builder 必须,不可变对象 |
ChatOptions#copy() 移除 |
改用 .mutate() 创建修改后的副本 |
[*]Options#fromOptions() 移除 |
同上,统一使用 .mutate() 模式 |
Options 设计从可变到不可变的转变,是整个 2.0 设计哲学的缩影:显式优于隐式,组合优于继承。
三、Tool Calling 重塑:从"私有实现"到"一等公民"
这是 2.0 最核心的架构变化。 没有之一。
3.1 1.x 的痛点
在 Spring AI 1.x 中,每个 ChatModel 实现包含自己的私有工具执行循环。功能可用,但深埋在模型实现内部:
- 无法观测中间步骤
- 无法与其他行为组合(日志、校验、重试)
- 无法在工具调用前后插入自定义逻辑
- 工具调用的 request/response 对 Advisor 链完全不透明
一句话总结:你能调用工具,但无法在工具调用之上构建任何东西。
┌─────────────────────────┐
│ ChatClient │
│ ┌───────────────────┐ │
│ │ Advisor Chain │ │ ← 看不到工具调用过程
│ └───────┬───────────┘ │
│ ▼ │
│ ┌───────────────────┐ │
│ │ ChatModel │ │
│ │ ┌─────────────┐ │ │
│ │ │ Tool Loop │ │ │ ← 黑盒,私有循环
│ │ │ (不可见) │ │ │
│ │ └─────────────┘ │ │
│ └───────────────────┘ │
└─────────────────────────┘
3.2 2.0 的解决方案:ToolCallingAdvisor
工具循环被提升到 Advisor 链中,成为一等公民、可组合的组件。ChatClient 通过有序 Advisor 链处理每个请求,支持循环——允许 Advisor 重新进入下游链。同一机制驱动工具调用循环、结构化输出重试循环、评估循环。
┌──────────────────────────────────┐
│ ChatClient │
│ ┌────────────────────────────┐ │
│ │ Advisor Chain │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ Memory Advisor │ │ │ ← order: HIGHEST + 200
│ │ ├──────────────────────┤ │ │
│ │ │ ToolCallingAdvisor │ │ │ ← order: HIGHEST + 300(递归)
│ │ │ ↻ 循环执行 │ │ │
│ │ ├──────────────────────┤ │ │
│ │ │ Custom Advisor │ │ │
│ │ ├──────────────────────┤ │ │
│ │ │ LLM Call │ │ │
│ │ └──────────────────────┘ │ │
│ └────────────────────────────┘ │
└──────────────────────────────────┘
ToolCallingAdvisor 是递归 Advisor——反复重新进入下游链,直到停止条件满足(模型输出不包含工具调用)。DefaultChatClient 自动将其加入链中,且同一时刻只允许一个 ToolAdvisor 存在。
3.3 完整的工具调用生命周期
1. 工具注册
通过 @Tool、@McpTool、java.util.function.Function 或 ToolCallback 定义
↓
2. 初始注入
Advisor 提取工具的名称、描述和输入 JSON Schema
注入到初始上下文(与用户问题、system prompt 合并)
↓
3. 迭代循环
将累积的对话历史(用户消息 + AI 工具调用请求 + 工具响应)
与当前上下文合并,发送给 LLM
↓
4. 判断响应
├─ 包含工具调用 → ToolCallingManager 执行工具 → 追加响应 → 回到步骤 3
└─ 不包含工具调用 → 返回最终答案
Blocking(.call())和 Streaming(.stream())模式完全支持。
3.4 代码示例:定义工具
class WeatherTools {
@Tool(description = "Get the current weather for a given city")
public String getWeather(String city) {
return weatherService.fetch(city);
}
@Tool(description = "Book a flight between two cities on a given date")
public BookingConfirmation bookFlight(
String origin,
String destination,
@ToolParam(description = "Date in YYYY-MM-DD format") String date) {
return flightService.book(origin, destination, date);
}
}
Spring AI 自动生成输入参数的 JSON Schema。@ToolParam 添加参数级别的描述和可选/必填提示。标记了 @Nullable 的参数默认视为可选。
3.5 代码示例:使用 ChatClient 调用
String response = ChatClient.create(chatModel)
.prompt("What's the weather in Amsterdam? Book a flight from London if it's sunny.")
.tools(new WeatherTools())
.call()
.content();
简洁到令人发指——背后是完整的工具发现、调用、结果合并、循环决策。
3.6 ToolSearchToolCallingAdvisor:大规模工具场景
问题:工具超过 20-30 个时,每次请求都把所有工具定义塞进 prompt,导致上下文膨胀、精度下降、token 成本翻倍。多 MCP Server 场景下,单次会话可能聚合数百个工具定义。
解决方案:ToolSearchToolCallingAdvisor——渐进式工具发现(Progressive Tool Disclosure)。
工作原理:
- 会话开始时,索引全部工具集
- 每次迭代,只注入一个内置的
toolSearchTool - 模型通过自然语言查询按需检索相关工具
- 只有被发现的工具才会加入后续请求
基准测试显示 34-64% 的 token 节省(覆盖 OpenAI、Anthropic、Gemini)。
配置示例:
spring.ai.chat.client.tool-search-advisor.enabled=true
spring.ai.chat.client.tool-search-advisor.tool-index-type=vector
三种索引策略:
| 策略 | 说明 | 适用场景 |
|---|---|---|
regex |
轻量,无额外依赖,默认 | 工具数量 < 50,简单匹配 |
lucene |
关键词搜索,starter 内置 | 中等规模工具集 |
vector |
基于 Embedding 的语义搜索,需要 VectorStore bean |
大规模工具集,语义相似度检索 |
注意:工具索引按 session 隔离,调用者必须提供 session ID:
chatClient.prompt()
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "user-42-session"))
.user("Help me plan my trip to Amsterdam")
.call()
.content();
该 Advisor 从社区毕业进入核心 Spring AI 2.0,是 ToolCallingAdvisor 的直接替代品。
3.7 Tool Argument Augmentation(工具参数增强)
动态扩展工具的输入 Schema,不修改工具实现。模型看到增强后的 Schema 并填充额外字段,你的代码通过 consumer 接收,原始工具只接收自己的参数。
主要用途:inner thinking——强制模型在执行工具前表达推理过程,提升可追溯性。
public record AgentThinking(
@ToolParam(description = "Your reasoning for calling this tool")
String innerThought) {}
AugmentedToolCallbackProvider<AgentThinking> toolProvider =
AugmentedToolCallbackProvider.<AgentThinking>builder()
.toolObject(new WeatherTools()) // 包装原始工具
.argumentType(AgentThinking.class) // 增强的参数类型
.argumentConsumer(event -> log.info( // 可选 consumer
"Tool: {} | Reasoning: {}",
event.toolDefinition().name(),
event.arguments().innerThought()))
.build();
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultTools(toolProvider)
.build();
模型看到的是"天气工具 + innerThought 字段",执行时只调用原始工具方法,推理过程通过 consumer 被记录或送入长期记忆。
3.8 用户控制的工具执行
自动循环覆盖大多数场景。但有些场景需要你自己掌控每一步迭代:外部审批、中间进度推送(SSE/WebSocket)、条件逻辑、基于旁路信号停止。
退出自动循环的方式:AdvisorParams.toolCallingAdvisorAutoRegister(false)。
ChatClient chatClient = ...;
ToolCallingManager toolCallingManager = ToolCallingManager.builder().build();
ToolCallback[] tools = ToolCallbacks.from(new WeatherTools());
ChatOptions chatOptions = ToolCallingChatOptions.builder().toolCallbacks(tools).build();
String question = "What is the weather in Amsterdam and Paris?";
// 禁用自动 ToolCallingAdvisor
ChatClientResponse response = chatClient.prompt()
.user(question)
.options(chatOptions)
.advisors(AdvisorParams.toolCallingAdvisorAutoRegister(false))
.call()
.chatClientResponse();
Prompt prompt = new Prompt(List.of(new UserMessage(question)), chatOptions);
// 自己驱动循环——每次迭代可观察、可中断
while (response.chatResponse() != null && response.chatResponse().hasToolCalls()) {
ToolExecutionResult result = toolCallingManager.executeToolCalls(prompt, response.chatResponse());
prompt = new Prompt(result.conversationHistory(), chatOptions);
response = chatClient.prompt()
.messages(result.conversationHistory())
.options(chatOptions)
.advisors(AdvisorParams.toolCallingAdvisorAutoRegister(false))
.call()
.chatClientResponse();
}
四、Advisor 链:递归 Advisors 与可组合架构
4.1 Advisor 链核心概念
ChatClient 通过有序 Advisor 链处理请求。Advisor 按 getOrder() 值排序(值越小越先执行),处理 ChatClientRequest 和 ChatClientResponse。
2.0 引入递归 Advisor——可以重新进入下游链,循环执行:
public class MyRecursiveAdvisor implements CallAdvisor {
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
// 初始调用
ChatClientResponse response = chain.nextCall(request);
// 条件不满足则循环
while (!isConditionMet(response)) {
ChatClientRequest modifiedRequest = modifyRequest(request, response);
// 关键:chain.copy(this) 创建子链,避免重复执行上游 Advisor
response = chain.copy(this).nextCall(modifiedRequest);
}
return response;
}
}
chain.copy(this) 是核心设计——创建包含当前 Advisor 之后所有下游 Advisor 的子链,确保每次迭代经过完整的下游链,同时避免上游 Advisor 被重复执行。
同一机制驱动多种循环模式:
- 工具调用循环(
ToolCallingAdvisor) - 结构化输出验证循环(
StructuredOutputValidationAdvisor) - 评估循环
- 自定义重试逻辑
4.2 Advisor 排序的重要性
Advisor 相对于 ToolCallingAdvisor(默认 order: HIGHEST_PRECEDENCE + 300)的位置决定了行为:
| 位置 | Order 值 | 行为 |
|---|---|---|
| 循环外部 | < HIGHEST_PRECEDENCE + 300 |
只看到最终结果 |
| 循环内部 | > HIGHEST_PRECEDENCE + 300 |
看到每次迭代的完整过程 |
这不是抽象的理论——直接决定了 Memory 存什么、日志看什么、监控采集什么。
4.3 Memory 与 Tool Loop 的协作
MessageChatMemoryAdvisor 放置位置决定了记忆存储的内容范围:
外部记忆(默认,order HIGHEST_PRECEDENCE + 200)
- 循环开始前加载一次历史
- 只持久化最终的用户和助手消息
- 工具请求/响应不写入存储
- 兼容所有
ChatMemoryRepository实现
内部记忆(order > ToolCallingAdvisor.DEFAULT_ORDER)
- 每次迭代都被调用
- 持久化完整的工具请求/响应记录
- 后续轮次中 LLM 可以推理之前尝试了什么、调用了哪些工具、返回了什么
- 需要
ToolCallingAdvisor禁用内部对话历史以避免重复写入(自动注册的 Advisor 会自动检测并处理)
支持完整消息集的内置仓库:
InMemoryChatMemoryRepositoryRedisChatMemoryRepositoryNeo4jChatMemoryRepository
对于需要 JDBC 持久化 + 完整工具消息支持 + 事件溯源历史 + 轮次感知压缩 + 多 Agent 分支隔离的场景,使用 Spring-AI-Session 社区项目(计划纳入 Spring AI 2.1)。
4.4 自定义 Advisor 扩展
通过 ToolCallingAdvisor.Builder<?> bean 替换默认实现:
@AutoConfiguration(
beforeName = "org.springframework.ai.model.chat.client.autoconfigure.ChatClientAutoConfiguration")
@ConditionalOnProperty(prefix = "my.advisor", name = "enabled", havingValue = "true")
public class MyToolAdvisorAutoConfiguration {
@Bean
@ConditionalOnMissingBean
ToolCallingAdvisor.Builder<?> toolCallingAdvisorBuilder(
ToolCallingManager toolCallingManager) {
return MyCustomToolCallingAdvisor.builder()
.toolCallingManager(toolCallingManager);
}
}
ToolSearchToolCallingAdvisor 就是用这个机制注册的——它的 auto-configuration 注册一个 ToolSearchToolCallingAdvisor.Builder,类型标注为 ToolCallingAdvisor.Builder<?>,DefaultChatClient 就会自动替换默认的 ToolCallingAdvisor。
4.5 扩展点 Hook 方法
ToolSearchToolCallingAdvisor 不是什么框架魔法——它是 ToolCallingAdvisor 的子类,通过覆写 protected hook 方法在循环的关键节点拦截:
| Hook | 触发时机 |
|---|---|
doInitializeLoop / doInitializeLoopStream |
第一次迭代前,仅执行一次 |
doBeforeCall / doBeforeStream |
每次迭代前 |
doAfterCall / doAfterStream |
每次迭代后 |
doFinalizeLoop / doFinalizeLoopStream |
循环结束后,仅执行一次 |
五、MCP 原生集成:从社区模块到核心功能
5.1 MCP 概述
Model Context Protocol 正在成为 AI 集成的通用协议。Spring AI 2.0 直接搭载 MCP Java SDK 2.0.0,遵循 2025-11-25 规范。mcp-annotations 模块纳入核心。
一个 Spring Boot 应用可以同时充当 MCP Client 和 MCP Server。
5.2 注解驱动的 MCP Server
@Component
public class WeatherTools {
@McpTool(description = "Get the current weather for a given city")
public String getWeather(
@McpToolParam(description = "City name") String city) {
return weatherService.fetch(city);
}
}
MCP Server 自动配置扫描 @McpTool 注解的 bean,自动生成 JSON Schema,注册到 MCP Server——无需额外布线。
添加依赖即可启用:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
5.3 MCP 传输层升级
| 传输方式 | 状态 | 说明 |
|---|---|---|
| Streamable HTTP | ✅ 默认 | 替代 SSE,支持双向通信,单一端点处理请求和流式响应 |
| Streamable HTTP(无状态) | ✅ 可选 | 牺牲双向性换取水平扩展能力 |
| STDIO | ✅ 保留 | 本地进程集成 |
| SSE | ❌ 废弃 | 被 Streamable HTTP 取代 |
传输层实现从 MCP Java SDK 移交给 Spring AI 侧(WebMVC/WebFlux),更好地与 Spring 生态集成。
配置示例:
server.port=3001
spring.ai.mcp.server.protocol=STREAMABLE
5.4 MCP Client 使用
添加 MCP Client starter:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
配置 MCP Server 连接:
spring.ai.mcp.client.stdio.connections.my-server.command=npx
spring.ai.mcp.client.stdio.connections.my-server.args=-y,@modelcontextprotocol/server-everything
Auto-configuration 连接所有配置的 MCP Server,发现其工具,暴露为 SyncMcpToolCallbackProvider bean(异步客户端类型则为 AsyncMcpToolCallbackProvider)。
注意:MCP Provider 不会被自动注册到 ChatClient——因为列出工具会强制对每个连接的 MCP Server 发起网络请求。需要显式注入:
@Autowired SyncMcpToolCallbackProvider mcpTools;
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultTools(mcpTools)
.build();
// 或按调用注入
chatClient.prompt()
.user("Search the web for the latest Spring AI release notes")
.tools(mcpTools)
.call()
.content();
5.5 本地工具与 MCP 工具混合使用
本地 @Tool 和远程 MCP 工具共享同一个 ToolCallback 接口——模型和 ToolCallingAdvisor 不区分两者:
chatClient.prompt()
.tools(new LocalTools(), mcpTools)
.call()
.content();
注意事项:
- 名称冲突仅在 MCP 侧处理。
DefaultMcpToolNamePrefixGenerator为跨 MCP Server 的重名工具添加前缀,但不感知本地@Tool方法。如果本地工具和远程 MCP 工具同名,需要手动重命名或使用McpToolFilter过滤。 - 限制暴露范围。MCP 工具来自外部源,使用
McpToolFilterbean 按 Server 身份、工具名或描述选择哪些工具进入命名空间。
5.6 MCP 企业级特性
MCP 进入核心意味着 Spring 的生产级栈可以直接继承:
- 可观测性:Micrometer Span + OpenTelemetry 兼容指标,Server 交互延迟、错误率、调用量仪表盘
- 安全:OAuth 2.0 和 API Key 认证(通过
spring-ai-community/mcp-security项目) - 生产警告:外部暴露工具的 MCP Server 是事实上的攻击面,授权设计必须在第一天就确定
六、ChatModel 装饰器模式
生产环境中的 ChatModel 不再是"裸模型",而是多层包装:
InstrumentingTraceChatModel(Trace 追踪)
→ RecoveryInstrumentingChatModel(自愈重试)
→ 基础 ChatModel
装饰器模式让追踪、重试、降级等横切关注点与模型实现解耦。
6.1 ChatResponseMetadata
2.0 M8 引入、GA 完整保留——暴露 Anthropic 限流信息:
ChatResponse resp = chatClient.prompt().user("...").call().chatResponse();
RateLimitMeta rateLimit = resp.getMetadata().getRateLimit();
// rateLimit.getTokensRemaining()
// rateLimit.getResetAt()
// rateLimit.getTokensUsed()
之前 Anthropic 返回的限流 header(x-ratelimit-remaining-tokens 等)是被丢弃的——只能等 429 才能感知。现在能实时看到配额水位,支撑:
- 实时监控面板
- 接近限额时主动排队/降级
- 用户面提示"系统繁忙,请稍后再试"而不是直接 500
做多 provider 混用的团队必看。
七、破坏性变更与迁移指南
7.1 必须升级的前提
- Spring Boot 3.x 无法运行 Spring AI 2.0——这是架构限制,不是推荐
- Spring Boot 3.5 和 Spring Framework 6.2 已于 2026-06-30 EOL
- Java 17 最低,推荐 Java 21
- Spring AI 2.0 是 Spring Boot 4.0+ 的依赖模型上构建的,不存在"只升 AI 不升 Boot"的路径
7.2 主要破坏性变更
类名迁移
| 旧名称 | 新名称 | 影响范围 |
|---|---|---|
MessageAggregator |
ChatClientMessageAggregator |
所有流式输出代码 |
ToolCallAdvisor |
ToolCallingAdvisor |
工具调用相关代码 |
FunctionCallback |
ToolCallback |
整体重命名,Function → Tool |
SemanticCache(org.springframework.ai.cache) |
SemanticCache(org.springframework.ai.semantic.cache) |
语义缓存代码 |
Function beans 替换
// Before (1.x) — 裸 Function bean,按名称解析
@Bean @Description("Get the weather")
Function<WeatherRequest, WeatherResponse> currentWeather() {
return weatherService::getWeather;
}
chatClient.prompt().toolNames("currentWeather"); // ❌ 不再存在
// After (2.0) — 显式 ToolCallback bean
@Bean
ToolCallback currentWeather() {
return FunctionToolCallback.builder("currentWeather", weatherService::getWeather)
.description("Get the weather")
.inputType(WeatherRequest.class)
.build();
}
// 注入 bean 并传递给 ChatClient——名称解析已移除
@Autowired ToolCallback currentWeather;
chatClient.prompt()
.user("What's the weather in Copenhagen?")
.tools(currentWeather)
.call()
.content();
SpringBeanToolCallbackResolver 和 toolNames() API 已被移除。工具必须注册为显式的 ToolCallback bean。
internalToolExecutionEnabled 移除
// Before (1.x)
chatClient.prompt()
.options(OpenAiChatOptions.builder()
.internalToolExecutionEnabled(false)
.build())
.call();
// After (2.0) — 使用 Advisor 级别控制
chatClient.prompt()
.advisors(AdvisorParams.toolCallingAdvisorAutoRegister(false))
.call();
internalToolExecutionEnabled 选项和对应配置属性已移除。每个模型内部的工具执行不再存在——ToolCallingAdvisor 是唯一执行路径。
streamToolCallResponses 移除
从 ToolCallingAdvisor.Builder 和 ToolSearchToolCallingAdvisor.Builder 中移除。
原因:功能有缺陷。启用后只传递了 model 的 tool request messages 到下游,但 advisor 自身生成的 tool response messages 留在循环内部。外部 Advisor 只看到一半——有 request 没有 response——比什么都不看还糟。
替代方案:将 Advisor 放在循环内部(order > ToolCallingAdvisor.DEFAULT_ORDER),每次迭代都能看到完整的 request/response 历史。
Options 不可变
// Before (1.x)
ChatOptions copy = options.copy();
// 或
MyOptions modified = MyOptions.fromOptions(options);
// After (2.0)
ChatOptions modified = options.mutate()
.temperature(0.7)
.build();
Vector Store 异常处理
// Before (1.x)
vectorStore.delete(documentIds); // 返回 void,失败时静默
// After (2.0)
try {
vectorStore.delete(documentIds);
} catch (VectorStoreException e) {
log.error("向量删除失败: {}", e.getMessage());
// 处理失败逻辑,考虑 Spring Retry
}
2.0 的 delete() 方法不再静默失败,而是抛出 VectorStoreException,必须显式捕获。
Provider 移除
| 原 Provider | 状态 | 推荐替代 | 迁移复杂度 |
|---|---|---|---|
| IBM Watson | 已移除 | OpenAI / Azure OpenAI | 中 |
| 百度千帆 QianFan | 已移除 | 智谱 ChatGLM / 通义千问 | 高(接口差异大) |
| 月之暗面 MoonShot | 已移除 | OpenAI / Ollama(自部署) | 中(兼容 OpenAI 协议) |
| MiniMax | 已移除 | Anthropic(接口兼容,需回归测试) | 中 |
迁移示例(QianFan → 智谱 ChatGLM):
// Before (1.x QianFan)
@Bean
public ChatClient qianfanChatClient() {
return ChatClient.builder(new QianFanChatModel(apiKey, secretKey))
.build();
}
// After (2.0 智谱)
@Bean
public ChatClient chatglmChatClient() {
return ChatClient.builder(
new OpenAiChatModel(
new OpenAiApi("https://open.bigmodel.cn/api/paas/v4/chat/completions",
apiKey)
)
).build();
}
7.3 推荐迁移路径
Step 1: 升级到 Spring Boot 3.5,处理所有 deprecation
↓
Step 2: 迁移 Jackson 2 → 3(如需要,GA 中 OpenAI 模块仍用 Jackson 2)
↓
Step 3: 升级 Spring Boot 到 4.0 / 4.1
↓
Step 4: 升级 Spring AI 到 2.0.0
↓
Step 5: 处理破坏性变更
- 类名/包路径替换
- Provider 替换
- Function beans → ToolCallback beans
- Vector Store 异常处理
↓
Step 6: 添加 JSpecify 注解,启用 NullAway 编译检查
八、Spring AI 2.0 vs LangChain4j
| 维度 | Spring AI 2.0 | LangChain4j |
|---|---|---|
| 生态定位 | Spring 官方 AI 框架 | Java 社区 AI 框架 |
| 与 Spring Boot 集成 | 原生深度集成,auto-configuration 开箱即用 | 需要额外适配 |
| MCP 支持 | 核心内置,注解驱动 | 需要第三方扩展 |
| Advisor 链 | 原生支持递归 Advisor,可组合 | 无等价机制 |
| 工具调用架构 | ToolCallingAdvisor 一等公民,可观测可拦截 | 内置工具循环,不可扩展 |
| 模块化 | 按需引入独立模块 | 相对粗粒度 |
| 可观测性 | Micrometer + OpenTelemetry 原生 | 需手动集成 |
| 社区生态 | Spring 生态背书,企业级支持 | 社区驱动,灵活性更高 |
| 适用场景 | Spring 技术栈团队、企业级生产环境 | 非 Spring 或混合技术栈 |
选型建议:Spring 技术栈团队选 Spring AI 2.0,这不是一个需要犹豫的决定。 LangChain4j 的价值在于非 Spring 项目或需要更多定制灵活性的场景。
九、生产部署建议
9.1 何时升级
| 场景 | 建议 | 理由 |
|---|---|---|
| ✅ 新项目(Greenfield) | 直接用 Boot 4.1 + AI 2.0 | 零包袱,最新架构 |
| ✅ 工具数量 > 10 的 Agent 系统 | 优先升级 | ToolSearchToolCallingAdvisor 省 34-64% token |
| ✅ 多 provider 混用 | 优先升级 | ChatResponseMetadata 限流监控刚需 |
| ✅ Boot 已在 3.5 的新项目 | 直接走 Boot 4.1 + AI 2.0 | 迁移成本最低 |
| ⚠️ Boot 在 3.3/3.4 的旧项目 | 先升 3.5 处理 deprecation | Boot 4 是一次性大跳 |
| ⚠️ 自定义 ChatMemory 的对话系统 | 评估迁移成本 | Advisor 模块拆分,迁移成本不小 |
| ❌ 重度依赖已移除 Provider | 先评估替代方案 | Watson/QianFan/MoonShot 无直接替代 |
9.2 性能优化建议
虚拟线程
spring.threads.virtual.enabled=true
IO 密集型场景(LLM 调用、工具调用、MCP 通信)吞吐量提升 3-5 倍。Java 21 原生支持。
ToolSearchToolCallingAdvisor
大规模工具场景节省 34-64% token。工具超过 20 个就值得评估。
Advisor 顺序调优
- 合理设置 Advisor 顺序,避免不必要的循环内执行
- Memory Advisor 默认在循环外部——只在需要完整工具历史时才放入内部
- 监控 Advisor 链的执行次数和耗时
HTTP Client 可配置(RC2 引入)
Anthropic 和 OpenAI 的 HTTP 客户端现在可配置——OkHttp / Reactor Netty / JDK 11 HttpClient 按需选择。
9.3 完整迁移 Checklist
升级前准备
- 备份生产数据库和配置文件
- 测试环境建立基线性能数据
- 准备回滚方案(保留旧版本镜像)
- 评估与已移除 Provider 的依赖关系
- 评估团队对 Java 21 和 Spring Boot 4 的熟悉度
代码迁移
- 类名替换:
MessageAggregator→ChatClientMessageAggregator、ToolCallAdvisor→ToolCallingAdvisor - 包路径替换:
SemanticCache路径更新 - Function beans →
ToolCallbackbeans vectorStore.delete()添加异常处理- 替换已移除的 Provider
- 移除
internalToolExecutionEnabled调用 - 移除
streamToolCallResponses调用 - Options
copy()/fromOptions()→mutate() - 添加 JSpecify 注解,启用 NullAway
测试验证
- 单元测试 + 集成测试通过
- 性能测试验证虚拟线程效果
- 压力测试验证并发性能
- 工具调用循环完整验证
- MCP 连接测试
部署验证
- Docker 构建成功
- 健康检查通过
- 监控指标正常
- 生产灰度发布
- P95/P99 响应时间对比
十、国内生态:Spring AI Alibaba 的适配现状
在国内,Spring AI 和 Spring AI Alibaba 几乎是绑定使用的。阿里巴巴在这套体系上投入了大量工程——Graph 工作流引擎、多 Agent 编排框架、MCP Gateway、DashScope 模型适配、Admin 可视化平台,这些都是生产级 Agent 开发的核心基础设施。所以 Spring AI 2.0 GA 了,大家第一个问题一定是:Spring AI Alibaba 跟上了吗?
当前版本状态
| 组件 | 最新稳定版 | 最新预发布 | 对应基线 |
|---|---|---|---|
| Spring AI | 2.0.0 GA(2026-06-12) | — | Boot 4.1.0 + Framework 7.0 |
| Spring AI Alibaba | 1.1.2.2(2026-03-10) | 2.0.0-M1.1(2026-06-25) | Boot 4.0.0 + AI 2.0.0-M1 |
三个核心问题
1. 没有 GA 版本
Spring AI Alibaba 的 2.0 适配目前只有一个 Milestone 预发布版 v2.0.0-M1.1,尚未进入 RC 和 GA 阶段。而 Spring AI 官方已经发布了 2.0.0 GA——中间差了好几个迭代。对于生产环境来说,预发布版不适合直接采用。
2. 基线未对齐
v2.0.0-M1.1 对应的是 Spring AI 2.0.0-M1 + Spring Boot 4.0.0,而非最新的 Spring AI 2.0.0 GA + Spring Boot 4.1.0。即使现在冒险使用预发布版,底层基线也对不齐,后续 Alibaba 团队还需要再跟进 M2~GA 的变更。
3. 核心能力的兼容性未知
Spring AI Alibaba 的 Graph 引擎、多 Agent 编排(Supervisor/Routing/Handoffs)、MCP Gateway、AgentScope 集成等高级特性,在 2.0 的架构下是否有 API 变化、是否需要适配,目前都没有明确的文档说明。
实际影响
对于使用 Spring AI Alibaba 的团队(尤其是依赖 Graph 引擎和 DashScope 集成的项目),升级路径实际上被阻塞了:
你的现状 目标状态
───────── ─────────
Spring Boot 3.5.x ──?──→ Spring Boot 4.1.0
Spring AI 1.1.x ──?──→ Spring AI 2.0.0 GA
Spring AI Alibaba ──?──→ ??? (无 GA 版本)
1.1.2.2
不是"改个版本号"就能解决的问题。整条链路中 Alibaba 这一层没有稳定版来兜底,Graph 引擎、Agent 框架、DashScope 适配都可能受影响。
建议策略
| 场景 | 建议 |
|---|---|
| 生产项目,依赖 Alibaba 生态 | 暂不升级,继续用 1.1.x 系列,关注 Alibaba 的 M2/RC 进展 |
| 新项目,不需要 Graph/Agent 框架 | 可以直接用 Spring AI 2.0 GA + Boot 4.1(不引入 Alibaba) |
| 新项目,需要完整 Agent 能力 | 等 Spring AI Alibaba 2.0 GA 发布后再启动 |
核心原则:Spring AI 官方 GA ≠ 你的项目可以升级。 国内项目要等 Alibaba 生态同步跟进,这个时间差是客观存在的。
十一、总结
Spring AI 2.0 的五大核心变化:
- 从"单体核心"到"领域模块":按需引入,减少依赖,模块间严格分层
- 从"私有工具循环"到"可组合 Advisor":工具调用成为一等公民,可观测、可拦截、可组合。这是整个 2.0 最核心的架构决策
- 从"社区 MCP"到"核心内置":注解驱动的 MCP Server/Client,Streamable HTTP 默认传输,企业级安全与可观测性
- 从"可变配置"到"不可变设计":Options 不可变、JSpecify Null 安全、builder 必须——更安全、更可预测
- 从"能用"到"好用":ToolSearchToolCallingAdvisor 省 token、ChatResponseMetadata 暴露限流、HTTP Client 可配置、虚拟线程原生支持
- 从"官方 GA"到"生态就绪":Spring AI 2.0 GA 已发布,但国内广泛使用的 Spring AI Alibaba 尚在 M1 预发布阶段,升级路径客观存在时间差。技术决策不能只看上游节奏,要等整条链路就绪
给还在观望的团队一句话:Spring Boot 3.5 已经 EOL,Spring AI 1.1.x 没有独立的长期支持承诺。升级到 2.0 不是"要不要做"的问题,是"什么时候做"的问题。但如果你在用 Spring AI Alibaba,这个"什么时候"还得等 Alibaba 生态同步跟进。
参考链接
- Spring AI 2.0 GA Release Notes
- Tool Calling in Spring AI 2.0 - Spring Blog
- Spring AI 2.0 Upgrade Notes
- FunctionCallback → ToolCallback Migration Guide
- MCP Client Boot Starter Reference
- MCP Server Boot Starter Reference
- Smart Tool Selection: 34-64% Token Savings
- Spring AI Recursive Advisors
- Spring AI 2.0.0-RC2 Release Notes
- Spring AI Alibaba Releases
- Spring AI Alibaba 官方文档
更多推荐






所有评论(0)