文章目录
- [1. 概述](#1. 概述)
- [2. Advisor 变更](#2. Advisor 变更)
-
- [2.1 模块重命名](#2.1 模块重命名)
- [2.2 ToolSearchToolCallingAdvisor 独立为专用模块](#2.2 ToolSearchToolCallingAdvisor 独立为专用模块)
- [2.3 Advisor 优先级默认值调整](#2.3 Advisor 优先级默认值调整)
- [3. Tool Calling 变更](#3. Tool Calling 变更)
-
- [3.1 移除 internalToolExecutionEnabled](#3.1 移除 internalToolExecutionEnabled)
- [3.2 移除 ToolExecutionEligibilityPredicate](#3.2 移除 ToolExecutionEligibilityPredicate)
- [3.3 新增 spring.ai.chat.client.tool-calling.enabled 属性](#3.3 新增 spring.ai.chat.client.tool-calling.enabled 属性)
- [3.4 移除 streamToolCallResponses](#3.4 移除 streamToolCallResponses)
- [4. Options 及配置变更](#4. Options 及配置变更)
-
- [4.1 Options 严格不可变](#4.1 Options 严格不可变)
- [4.2 默认值移至 Options 构造函数](#4.2 默认值移至 Options 构造函数)
- [4.3 配置属性扁平化](#4.3 配置属性扁平化)
- [4.4 N() 重命名为 n()](#4.4 N() 重命名为 n())
- [4.5 ChatClient Options 现在接受 Builder](#4.5 ChatClient Options 现在接受 Builder)
- [4.6 移除默认 Temperature 配置](#4.6 移除默认 Temperature 配置)
- [5. JSON 工具类重构](#5. JSON 工具类重构)
-
- [5.1 新增 JsonHelper](#5.1 新增 JsonHelper)
- [5.2 JsonParser 废弃](#5.2 JsonParser 废弃)
- [5.3 ModelOptionsUtils JSON 方法移除](#5.3 ModelOptionsUtils JSON 方法移除)
- [5.4 McpJsonParser 删除](#5.4 McpJsonParser 删除)
- [6. MCP SDK 变更](#6. MCP SDK 变更)
-
- [6.1 Elicitation API:TypeReference 替换](#6.1 Elicitation API:TypeReference 替换)
- [6.2 构造器必填字段](#6.2 构造器必填字段)
- [6.3 Builder API 废弃](#6.3 Builder API 废弃)
- [6.4 MCP 注解迁移至 Spring AI](#6.4 MCP 注解迁移至 Spring AI)
- [6.5 MCP Spring Transport 模块迁移](#6.5 MCP Spring Transport 模块迁移)
- [6.6 MCP Client Customizer API 统一](#6.6 MCP Client Customizer API 统一)
- [6.7 服务端工具输入校验默认开启](#6.7 服务端工具输入校验默认开启)
- [6.8 `Tool.inputSchema` 返回类型变更](#6.8
Tool.inputSchema返回类型变更) - [6.9 MCP WebMvc Transport Header 小写标准化](#6.9 MCP WebMvc Transport Header 小写标准化)
- [7. Chat Memory 变更](#7. Chat Memory 变更)
-
- [7.1 Conversation ID 现在必填](#7.1 Conversation ID 现在必填)
- [7.2 `getConversationId` 签名变更](#7.2
getConversationId签名变更) - [7.3 PromptChatMemoryAdvisor 删除](#7.3 PromptChatMemoryAdvisor 删除)
- [7.4 JDBC Chat Memory 新增 `sequence_id` 列](#7.4 JDBC Chat Memory 新增
sequence_id列) - [7.5 MongoDB Chat Memory 排序修正](#7.5 MongoDB Chat Memory 排序修正)
- [7.6 Conversation History 从 ToolContext 移除](#7.6 Conversation History 从 ToolContext 移除)
- [8. 模型模块变更](#8. 模型模块变更)
-
- [8.1 Anthropic 模块:切换至官方 Java SDK](#8.1 Anthropic 模块:切换至官方 Java SDK)
- [8.2 Ollama:属性重命名](#8.2 Ollama:属性重命名)
- [8.3 OpenAI:切换至官方 openai-java SDK](#8.3 OpenAI:切换至官方 openai-java SDK)
- [8.4 Minimax、Azure OpenAI、OpenAI SDK、OCI GenAI 模块删除](#8.4 Minimax、Azure OpenAI、OpenAI SDK、OCI GenAI 模块删除)
- [8.5 `buildRequestPrompt` 从公开 API 移除](#8.5
buildRequestPrompt从公开 API 移除) - [8.6 Model 内部方法访问级别变更](#8.6 Model 内部方法访问级别变更)
- [9. 模块及依赖变更](#9. 模块及依赖变更)
-
- [9.1 移除的模块](#9.1 移除的模块)
- [9.2 OpenSearch 依赖升级](#9.2 OpenSearch 依赖升级)
- [9.3 Development-time Services](#9.3 Development-time Services)
- [10. 其他变更](#10. 其他变更)
-
- [10.1 Google GenAI Embedding 包变更](#10.1 Google GenAI Embedding 包变更)
- [10.2 ChatClient 自动注册 ToolCallingAdvisor](#10.2 ChatClient 自动注册 ToolCallingAdvisor)
- [10.3 移除 ToolSpec Consumer API](#10.3 移除 ToolSpec Consumer API)
- [10.4 Spring Bean Tool Resolution 删除](#10.4 Spring Bean Tool Resolution 删除)
- [10.5 BeanOutputConverter JSON Schema 变更](#10.5 BeanOutputConverter JSON Schema 变更)
- [10.6 Observability 属性调整](#10.6 Observability 属性调整)
- [10.7 统一缓存用量指标](#10.7 统一缓存用量指标)
- [10.8 AbstractFilterExpressionConverter 变更](#10.8 AbstractFilterExpressionConverter 变更)
- [10.9 MethodToolCallbackProvider 异常类型变更](#10.9 MethodToolCallbackProvider 异常类型变更)
- [10.10 MCP Sealed 接口移除](#10.10 MCP Sealed 接口移除)
- [10.11 Builder.customizeRequest() 删除](#10.11 Builder.customizeRequest() 删除)
基于官方 Spring AI 2.0.0 Upgrade Notes 翻译整理。
1. 概述
Spring AI 2.0 的底座绑定 Spring Boot 4.0 和 Spring Framework 7.0,全面落地 Jakarta EE 11,与 Boot 3.x 的向后兼容彻底断开。还在 3.x 上的项目需先完成底座迁移,然后才轮到 AI 层。
Java 版本 :最低仍是 Java 17,但 AI 场景推荐 Java 25。AI 应用以密集 I/O 阻塞为主(调用大模型 API、处理流式响应),Java 25 的虚拟线程在此场景下吞吐量提升明显,并发长连接流式响应尤其受益。
2. Advisor 变更
2.1 模块重命名
| 旧名称 | 新名称 |
|---|---|
spring-ai-advisors-vector-store |
spring-ai-vector-store-advisor |
2.2 ToolSearchToolCallingAdvisor 独立为专用模块
| 项目 | 旧值 | 新值 |
|---|---|---|
| Artifact | spring-ai-tool-search-tool |
spring-ai-tool-search-advisor |
| 包名 | org.springframework.ai.tool.toolsearch.advisor |
org.springframework.ai.chat.client.advisor.toolsearch |
同时新增自动配置(spring-ai-autoconfigure-tool-search-advisor)和 Starter(spring-ai-starter-tool-search-advisor)。启用后,ToolSearchToolCallingAdvisor 会替换默认的 ToolCallingAdvisor,每次调用只发送最相关的工具定义给 LLM。
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-tool-search-advisor</artifactId>
</dependency>
properties
spring.ai.chat.client.tool-search-advisor.enabled=true
spring.ai.chat.client.tool-search-advisor.tool-index-type=regex # regex | lucene | vector
2.3 Advisor 优先级默认值调整
Advisor.DEFAULT_CHAT_MEMORY_PRECEDENCE_ORDER 从 HIGHEST_PRECEDENCE + 1000 改为 HIGHEST_PRECEDENCE + 200,将 Memory Advisor 置于 ToolCallingAdvisor(+300)之前。
ToolCallingAdvisor 现在默认在工具调用迭代期间自行管理对话历史,Memory Advisor 只保存最终的用户/助手对话交换,不再写入工具调用消息。如需在循环内使用 Memory(如 InMemoryChatMemoryRepository),需显式设置优先级并禁用内部历史:
java
var toolCallingAdvisor = ToolCallingAdvisor.builder()
.disableInternalConversationHistory()
.build();
var chatMemoryAdvisor = MessageChatMemoryAdvisor.builder(chatMemory)
.advisorOrder(Ordered.HIGHEST_PRECEDENCE + 400)
.build();
3. Tool Calling 变更
3.1 移除 internalToolExecutionEnabled
从 ToolCallingChatOptions 及所有 provider 的 ChatOptions 中移除。对应的配置属性 spring.ai.<provider>.chat.internal-tool-execution-enabled 也一并移除。
迁移 :删除所有 .internalToolExecutionEnabled(...) 调用。
推荐方案:
- 通过 ChatClient + ToolCallingAdvisor(推荐)--- 有工具时自动注册,无需任何标志位。
- 通过 ChatModel 手动控制循环 --- 直接调用
ChatModel,检查chatResponse.hasToolCalls()自行驱动循环。
java
// Before
ChatOptions options = ToolCallingChatOptions.builder()
.toolCallbacks(ToolCallbacks.from(new MyTools()))
.internalToolExecutionEnabled(false) // 删除此行
.build();
// After
ChatOptions options = ToolCallingChatOptions.builder()
.toolCallbacks(ToolCallbacks.from(new MyTools()))
.build();
3.2 移除 ToolExecutionEligibilityPredicate
已被 ToolExecutionEligibilityChecker(Function<ChatResponse, Boolean>)替代,通过 ToolCallingAdvisor.Builder 设置:
java
ToolCallingAdvisor advisor = ToolCallingAdvisor.builder()
.toolExecutionEligibilityChecker(response ->
response != null && response.hasToolCalls()
&& !"stop".equals(response.getResult().getMetadata().getFinishReason()))
.build();
Spring Boot 用户可声明 ToolExecutionEligibilityChecker Bean,自动配置会拾取。
3.3 新增 spring.ai.chat.client.tool-calling.enabled 属性
默认 true,设为 false 可全局禁用工具调用的自动执行(工具定义仍发送给模型,但工具调用结果不会自动执行)。
3.4 移除 streamToolCallResponses
从所有 Advisor Builder 和自动配置属性中移除。原因:当设为 true 时,中间工具调用请求块会被流式传输,但对应的 ToolResponseMessage 不会,导致下游 Memory Advisor 记录的对话历史损坏。该设计缺陷无法在不破坏 ChatClientResponse 的前提下修复。
迁移 :删除所有 .streamToolCallResponses(...) 调用。如需观察工具调用循环的每次迭代,使用手动循环:
java
ToolCallingManager toolCallingManager = ToolCallingManager.builder().build();
ChatOptions chatOptions = ToolCallingChatOptions.builder()
.toolCallbacks(ToolCallbacks.from(new WeatherTools()))
.build();
ChatClientResponse response = chatClient.prompt()
.user("What is the weather in Amsterdam and Paris?")
.options(chatOptions)
.advisors(AdvisorParams.toolCallingAdvisorAutoRegister(false))
.call().chatClientResponse();
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();
}
4. Options 及配置变更
4.1 Options 严格不可变
所有 Options 类(ChatOptions、EmbeddingOptions 等)现在严格不可变。集合字段(toolCallbacks、stopSequences 等)存储为不可修改集合,且使用 nullable 集合替代空集合。
ChatOptions#copy()和*Options#fromOptions(*)已移除- 修改
getter返回的集合将抛出UnsupportedOperationException
迁移 :使用 mutate() 替代 copy() / fromOptions()
java
// Before
OllamaChatOptions options = originalOptions.copy();
options.setFoo("...");
// After
OllamaChatOptions options = originalOptions.mutate().foo("...").build();
4.2 默认值移至 Options 构造函数
默认值从 Model 实现和 *Properties 配置类移至 Options 构造函数。
ChatModel#getDefaultOptions()废弃,改用getOptions()*Properties类中不再重复定义默认值
4.3 配置属性扁平化
所有模型的配置属性不再使用 .options 前缀:
properties
# Before
spring.ai.openai.embedding.options.model=text-embedding-3-small
# After
spring.ai.openai.embedding.model=text-embedding-3-small
java
// Before
String model = properties.getOptions().getModel();
OpenAiEmbeddingOptions options = properties.getOptions().toOptions();
// After
String model = properties.getModel();
OpenAiEmbeddingOptions options = properties.toOptions();
4.4 N() 重命名为 n()
Builder 中的 N() 方法重命名为 n() 以符合 Java 命名规范。
java
// Before
OpenAiChatOptions.builder().N(1).build();
// After
OpenAiChatOptions.builder().n(1).build();
4.5 ChatClient Options 现在接受 Builder
ChatClient 的 .options() / .defaultOptions() 现在接受 ChatOptions.Builder 而非已构建的 ChatOptions 实例。Builder 会在首个 Advisor 调用前与模型默认 Options 合并。
java
// Before
ChatOptions opts = AnthropicChatOptions.builder().maxTokens(100).temperature(0.7).build();
chatClient.prompt("Tell me a joke").options(opts).call().content();
// After
chatClient.prompt("Tell me a joke")
.options(AnthropicChatOptions.builder().maxTokens(100).temperature(0.7))
.call().content();
注意:直接调用
ChatModel.call(Prompt)时仍需传入已构建的ChatOptions实例,ChatModel 层不做合并。
4.6 移除默认 Temperature 配置
Spring AI 不再为 Chat Model 自动配置提供默认 temperature 值(之前为 0.7),改为使用各 AI provider 的原生默认值。
如需保持旧行为,显式配置:
properties
spring.ai.openai.chat.temperature=0.7
spring.ai.anthropic.chat.temperature=0.7
5. JSON 工具类重构
5.1 新增 JsonHelper
新增 JsonHelper 类(位于 spring-ai-commons),作为 JSON 序列化/反序列化的标准入口。可实例化并接受自定义 JsonMapper。
JacksonUtils 新增 getDefaultJsonMapper() 静态方法,返回共享的预配置 JsonMapper 实例。
java
// 默认 --- 使用 JacksonUtils 的共享 JsonMapper
JsonHelper jsonHelper = new JsonHelper();
// 自定义
JsonMapper myMapper = JsonMapper.builder().addModule(new JavaTimeModule()).build();
JsonHelper customHelper = new JsonHelper(myMapper);
5.2 JsonParser 废弃
| Before | After |
|---|---|
JsonParser.getJsonMapper() |
JacksonUtils.getDefaultJsonMapper() |
JsonParser.fromJson(json, MyType.class) |
jsonHelper.fromJson(json, MyType.class) |
JsonParser.toJson(object) |
jsonHelper.toJson(object) |
JsonParser.toTypedObject(value, type) |
jsonHelper.convertToTypedObject(value, type) |
5.3 ModelOptionsUtils JSON 方法移除
| 移除的成员 | 替代 |
|---|---|
ModelOptionsUtils.JSON_MAPPER |
JacksonUtils.getDefaultJsonMapper() |
ModelOptionsUtils.jsonToMap(String) |
jsonHelper.fromJsonToMap(json) |
ModelOptionsUtils.toJsonString(Object) |
jsonHelper.toJson(object) |
ModelOptionsUtils.getJsonSchema(Type) |
JsonSchemaUtils.getJsonSchema(type) |
5.4 McpJsonParser 删除
| Before | After |
|---|---|
McpJsonParser.toMap(object) |
jsonHelper.convertToMap(object) |
McpJsonParser.fromMap(map, MyType.class) |
jsonHelper.convertFromMap(map, MyType.class) |
6. MCP SDK 变更
6.1 Elicitation API:TypeReference 替换
McpAsyncRequestContext 和 McpSyncRequestContext 的 elicit(...) 方法中,Jackson 的 TypeReference 替换为 Spring 的 ParameterizedTypeReference:
java
// Before
import tools.jackson.core.type.TypeReference;
context.elicit(e -> e.message("Please fill in the form"),
new TypeReference<Map<String, Object>>() {});
// After
import org.springframework.core.ParameterizedTypeReference;
context.elicit(e -> e.message("Please fill in the form"),
new ParameterizedTypeReference<Map<String, Object>>() {});
6.2 构造器必填字段
以下构造器现在通过 Assert.notNull() 强制必填参数:
| 类型 | 变更 |
|---|---|
CreateMessageResult |
model 字段现在必填 |
CreateMessageRequest |
maxTokens 字段现在必填 |
java
// Before
CreateMessageResult.builder().content(new TextContent(response)).build();
// After
CreateMessageResult.builder(Role.ASSISTANT, response, modelHint).build();
// Before
CreateMessageRequest.builder().messages(messages).build();
// After
CreateMessageRequest.builder(messages, 500).build();
6.3 Builder API 废弃
以下无参构造器和 builder() 方法废弃,替换为需要必填参数的工厂方法:
| 废弃 | 替代 |
|---|---|
new TextContent(text) |
TextContent.builder(text).build() |
new ReadResourceResult(contents) |
ReadResourceResult.builder(contents).build() |
LoggingMessageNotification.builder() |
LoggingMessageNotification.builder(level, data) |
ElicitRequest.builder() |
ElicitRequest.builder(message, requestedSchema) |
CallToolRequest.builder() |
CallToolRequest.builder(name) |
6.4 MCP 注解迁移至 Spring AI
org.springaicommunity:mcp-annotations 外部库已移除,其类现在属于 Spring AI 自身。所有包名从 org.springaicommunity.mcp.* 迁移到 org.springframework.ai.mcp.*。
| 旧包 | 新包 |
|---|---|
org.springaicommunity.mcp.annotation.* |
org.springframework.ai.mcp.annotation.* |
org.springaicommunity.mcp.method.* |
org.springframework.ai.mcp.annotation.method.* |
org.springaicommunity.mcp.provider.* |
org.springframework.ai.mcp.annotation.provider.* |
可使用 OpenRewrite 自动迁移:
bash
mvn org.openrewrite.maven:rewrite-maven-plugin:6.32.0:run \
-Drewrite.configLocation=https://raw.githubusercontent.com/spring-projects/spring-ai/refs/heads/main/src/rewrite/migrate-to-2-0-0-M3.yaml \
-Drewrite.activeRecipes=org.springframework.ai.migration.M3MigrateMcpAnnotations \
-Dmaven.compiler.failOnError=false
6.5 MCP Spring Transport 模块迁移
mcp-spring-webflux 和 mcp-spring-webmvc 传输模块从 MCP Java SDK 迁移到 Spring AI 项目。
Maven Group ID 变更:
xml
<!-- Before -->
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-spring-webflux</artifactId>
</dependency>
<!-- After -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>mcp-spring-webflux</artifactId>
</dependency>
Java 包重定位:
| 类 | 旧包 | 新包 |
|---|---|---|
WebFluxSseServerTransportProvider |
io.modelcontextprotocol.server.transport |
org.springframework.ai.mcp.server.webflux.transport |
WebMvcSseServerTransportProvider |
io.modelcontextprotocol.server.transport |
org.springframework.ai.mcp.server.webmvc.transport |
WebFluxSseClientTransport |
io.modelcontextprotocol.client.transport |
org.springframework.ai.mcp.client.webflux.transport |
6.6 MCP Client Customizer API 统一
McpAsyncClientCustomizer 和 McpSyncClientCustomizer 合并为单一泛型接口 McpClientCustomizer<B>。
java
// Before
@Bean
public McpSyncClientCustomizer mySyncCustomizer() {
return (name, spec) -> spec.requestTimeout(Duration.ofSeconds(30));
}
// After
@Bean
public McpClientCustomizer<McpClient.SyncSpec> mySyncCustomizer() {
return (name, spec) -> spec.requestTimeout(Duration.ofSeconds(30));
}
6.7 服务端工具输入校验默认开启
MCP Server 现在默认对入参进行 JSON Schema 校验。
如需禁用:
java
McpServer.sync(transportProvider)
.validateToolInputs(false)
.tool(myTool, handler)
.build();
6.8 Tool.inputSchema 返回类型变更
从 JsonSchema record 变为 Map<String, Object>,以支持任意 JSON Schema 方言关键字。
java
// Before
McpSchema.JsonSchema schema = tool.inputSchema();
// After
Map<String, Object> schema = tool.inputSchema();
6.9 MCP WebMvc Transport Header 小写标准化
WebMvcSseServerTransportProvider 等类中传给 securityValidator.validateHeaders(headers) 的 Header 名称现在统一小写。
java
// Before
headers.get("Authorization");
// After
headers.get("authorization");
7. Chat Memory 变更
7.1 Conversation ID 现在必填
内置 Memory Advisor(MessageChatMemoryAdvisor、VectorStoreChatMemoryAdvisor)的 conversation ID 不再可选。每次调用必须通过 advisor context 提供 ChatMemory.CONVERSATION_ID,缺失或为空时抛出 IllegalArgumentException。
ChatMemory.DEFAULT_CONVERSATION_ID常量已删除.conversationId()Builder方法已移除
java
// Before
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory)
.conversationId("my-session").build())
.build();
// After
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();
chatClient.prompt().user("Hello!")
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "my-session"))
.call().content();
7.2 getConversationId 签名变更
BaseChatMemoryAdvisor.getConversationId(Map, String) 替换为 getConversationId(Map)(单参数,缺失时抛异常)。
7.3 PromptChatMemoryAdvisor 删除
使用 MessageChatMemoryAdvisor 替代。API 相同,区别在于不再将记忆作为纯文本注入 system prompt,而是将对话历史直接以 Chat Message 形式包含在 prompt 中。
7.4 JDBC Chat Memory 新增 sequence_id 列
解决了不同数据库 TIMESTAMP 精度不一致导致的排序不确定问题。新增 sequence_id BIGINT 列用于消息排序。
PostgreSQL 迁移:
sql
ALTER TABLE SPRING_AI_CHAT_MEMORY ADD COLUMN sequence_id BIGINT;
WITH ordered AS (
SELECT ctid, ROW_NUMBER() OVER (PARTITION BY conversation_id ORDER BY "timestamp") - 1 AS seq
FROM SPRING_AI_CHAT_MEMORY
)
UPDATE SPRING_AI_CHAT_MEMORY t SET sequence_id = o.seq FROM ordered o WHERE t.ctid = o.ctid;
ALTER TABLE SPRING_AI_CHAT_MEMORY ALTER COLUMN sequence_id SET NOT NULL;
CREATE INDEX SPRING_AI_CHAT_MEMORY_CONVERSATION_ID_SEQUENCE_ID_IDX
ON SPRING_AI_CHAT_MEMORY(conversation_id, sequence_id);
7.5 MongoDB Chat Memory 排序修正
MongoChatMemoryRepository 现在返回按时间正序排列的消息(之前错误地返回了倒序)。需移除之前为纠正此 Bug 而编写的 Collections.reverse() 相关代码。
7.6 Conversation History 从 ToolContext 移除
ToolContext.TOOL_CALL_HISTORY 常量和 getToolCallHistory() 方法已删除。对话历史不再自动填充到 ToolContext。工具应基于参数运行,对话上下文由 Advisor 层管理。如需对话历史管理,使用 ToolCallingAdvisor:
java
ChatClient chatClient = ChatClient.builder()
.defaultAdvisors(ToolCallingAdvisor.builder()
.conversationHistoryEnabled(true) // 默认开启
.build())
.build();
8. 模型模块变更
8.1 Anthropic 模块:切换至官方 Java SDK
spring-ai-anthropic 现在基于 com.anthropic:anthropic-java 构建。
主要影响:
org.springframework.ai.anthropic.api.AnthropicApi及所有嵌套record类型已删除AnthropicChatModel(AnthropicApi, ...)构造器删除,使用BuilderAnthropicChatOptions#maxTokens默认值从500变为4096- 缓存相关类移至
org.springframework.ai.anthropic根包 CitationDocument重命名为AnthropicCitationDocument
java
// Before
AnthropicApi anthropicApi = new AnthropicApi(apiKey);
AnthropicChatModel chatModel = new AnthropicChatModel(anthropicApi, options);
// After
AnthropicChatModel chatModel = AnthropicChatModel.builder()
.apiKey(apiKey).defaultOptions(options).build();
新增 Chat Options:
| Option | 说明 |
|---|---|
| Thinking Display | SUMMARIZED / OMITTED,使用 thinking 预算但不暴露完整推理过程 |
| Service Tier | AUTO / STANDARD_ONLY,Anthropic 优先级容量层级 |
| Web Search | 内置 AnthropicWebSearchTool,让 Claude 在请求期间搜索网页 |
| Inference Geo | us / eu,数据驻留路由 |
8.2 Ollama:属性重命名
properties
# Before
spring.ai.ollama.chat.think-option=true
# After
spring.ai.ollama.chat.think=true
8.3 OpenAI:切换至官方 openai-java SDK
spring-ai-openai 模块底层切换到官方 openai-java SDK。所有 spring.ai.openai.* 属性、Builder 和 Options 保持不变,现有用户无需修改代码。
8.4 Minimax、Azure OpenAI、OpenAI SDK、OCI GenAI 模块删除
| 移除的模块 | 替代方案 |
|---|---|
| Minimax | 使用 Anthropic 支持,配置 https://api.minimax.io/anthropic 作为 base URL |
spring-ai-azure-openai |
使用 spring-ai-openai,去掉类名中的 Azure 前缀 |
spring-ai-openai-sdk |
使用 spring-ai-openai,去掉类名中的 Sdk 后缀 |
spring-ai-oci-genai |
迁移至 github.com/oracle/spring-cloud-oracle |
8.5 buildRequestPrompt 从公开 API 移除
之前被错误暴露为 public,现已恢复为 private/package-private。
8.6 Model 内部方法访问级别变更
所有 Model 类中的 internalCall 和 internalStream 方法改为 private。
java
// Before
ChatResponse response = model.internalCall(prompt, previousChatResponse);
// After
ChatResponse response = model.call(prompt);
9. 模块及依赖变更
9.1 移除的模块
| 模块 | 说明 |
|---|---|
spring-ai-hanadb-store |
从 Spring AI 中移除 |
spring-ai-spring-cloud-bindings |
Cloud Bindings 集成已移除 |
spring-ai-azure-cosmos-db-store |
由 Azure Cosmos DB 团队外部维护 |
spring-ai-model-chat-memory-repository-cosmos-db |
同上 |
9.2 OpenSearch 依赖升级
| 依赖 | 旧版本 | 新版本 |
|---|---|---|
| OpenSearch Java Client | 2.23.0 | 3.6.0 |
| OpenSearch Testcontainers | 2.0.1 | 4.1.0 |
仅在直接使用原生
OpenSearch Client时才需要修改代码,通过VectorStore接口使用则不受影响。
9.3 Development-time Services
MongoDB Atlas 的 Docker Compose 和 Testcontainers 支持现在由 Spring Boot MongoDB 模块原生提供。无需再依赖 org.springframework.ai:spring-ai-spring-boot-testcontainers,使用 org.springframework.boot:spring-boot-testcontainers 即可。
10. 其他变更
10.1 Google GenAI Embedding 包变更
GoogleGenAiEmbeddingConnectionDetails 移至 org.springframework.ai.google.genai.embedding 包。
10.2 ChatClient 自动注册 ToolCallingAdvisor
ChatClient 现在始终在 Advisor 链中自动注册 ToolCallingAdvisor(除非显式禁用)。如已有显式注册的 ToolCallingAdvisor,需删除重复:
java
// Before --- 手动注册
chatClient.prompt("What's the weather?")
.tools(weatherTool)
.advisors(ToolCallingAdvisor.builder().build())
.call().content();
// After --- 自动注册处理
chatClient.prompt("What's the weather?")
.tools(weatherTool)
.call().content();
新增两个 Marker 接口:
ToolAdvisor--- 自定义Advisor实现此接口可防止重复自动注册MemoryAdvisor--- 用于检测下游Memory Advisor并协调ToolCallingAdvisor的内部历史
10.3 移除 ToolSpec Consumer API
ChatClient 的 tools(Consumer<ToolSpec>) / defaultTools(Consumer<ToolSpec>) API 已删除。tools(Object...) 现在直接接受 ToolCallback、ToolCallbackProvider、@Tool 注解的 POJO 等类型。toolContext() 用于单独设置上下文。
java
// Before
chatClient.prompt()
.tools(t -> t.callbacks(myCallback).context("tenantId", "acme"))
.call().content();
// After
chatClient.prompt()
.tools(myCallback)
.toolContext(Map.of("tenantId", "acme"))
.call().content();
10.4 Spring Bean Tool Resolution 删除
SpringBeanToolCallbackResolver 和通过 toolNames() 引用 bean 名称的方式已删除。需显式声明 ToolCallback Bean。
java
// Before
@Bean @Description("Get the weather in location")
Function<WeatherRequest, WeatherResponse> currentWeather() {
return weatherService::getWeather;
}
// After
@Bean
ToolCallback currentWeather() {
return FunctionToolCallback.builder("currentWeather", weatherService::getWeather)
.description("Get the weather in location")
.inputType(WeatherRequest.class)
.build();
}
10.5 BeanOutputConverter JSON Schema 变更
Kotlin可选属性不再出现在required数组@JsonProperty(required = false)注解的属性不再视为 required- 生成的
Schema包含OpenAPI风格的format提示 postProcessSchema(JsonNode)扩展点删除,改用generateSchema()
10.6 Observability 属性调整
| 变更 | 旧值 | 新值 |
|---|---|---|
| Span 名称 | tool_call <name> |
execute_tool <name> |
gen_ai.operation.name |
framework |
execute_tool |
| 新增属性 | --- | spring.ai.tool.type、spring.ai.tool.call.id |
10.7 统一缓存用量指标
Usage 接口新增两个默认方法 getCacheReadInputTokens() 和 getCacheWriteInputTokens()。Anthropic、Bedrock Converse、OpenAI、Google GenAI 均已实现。
10.8 AbstractFilterExpressionConverter 变更
doSingleValue(Object value, StringBuilder context) 从具体方法变为抽象方法。自定义 Vector Store 的 FilterExpressionConverter 必须显式实现。
10.9 MethodToolCallbackProvider 异常类型变更
MethodToolCallbackProvider 在两个场景下抛出 IllegalArgumentException(替代 IllegalStateException):
- 工具对象没有
@Tool注解的方法 - 多个工具对象产生重名的回调
10.10 MCP Sealed 接口移除
JSONRPCMessage、Request、Result、Notification、Content 等接口不再是 sealed 类型。依赖 sealed 层级实现穷举 switch 的代码需添加 default 分支。
10.11 Builder.customizeRequest() 删除
替换为 httpRequestCustomizer()(同步)或 asyncHttpRequestCustomizer()(异步):
java
// Before
HttpClientSseClientTransport.builder(baseUrl)
.customizeRequest(req -> req.header("Authorization", "Bearer token")).build();
// After
HttpClientSseClientTransport.builder(baseUrl)
.httpRequestCustomizer(req -> req.header("Authorization", "Bearer token")).build();