Spring AI 2.0.1 正式发布

Spring AI 2.0.1 已经发布,现已可以从 Maven Central 获取!

2.0.1 是在 2.0.0 GA 版本 基础上推出的第一个维护版本,也是一次分量十足的更新:涉及超过 80 个 issue 与 PR,本次版本还加入了几项自 GA 发布以来社区呼声较高的新能力。(PS: 版本号太保守了)

安全问题修复

  • CVE-2026-47851 —— Spring AI PDF 文档读取器中,攻击者可控的 PDF 大纲树导致无限递归
  • CVE-2026-47852 —— 缓存目录路径可预测,导致本地 ONNX 模型可被替换
  • CVE-2026-59279 —— 重复发送初始化请求会导致持久化会话无限分配
  • CVE-2026-59294 —— ResourceCacheService 中的路径穿越漏洞可导致任意文件写入
  • CVE-2026-59308 —— 语义缓存因 SHA-256 截断而导致跨租户隔离被绕过
  • CVE-2026-59319 —— RedisChatMemoryRepository 存在 RediSearch 标签注入,可导致跨会话数据泄露
  • CVE-2026-59318 —— DefaultToolCallingManager 的全局解析回退机制,可能被提示词注入(prompt injection)利用来调用未声明的工具

升级须知

绝大多数应用只需把版本号提升到 2.0.1 即可完成迁移,但仍有几处改动需要注意。完整细节见升级说明(本次也针对 2.0.1 做了内容补充):

  • 已弃用的 Mistral AI 聊天模型被正式下线(#6772)。如果你的代码中仍以常量方式引用这些模型,请切换到当前受支持的模型名称。
  • Redis 聊天记忆自动配置模块被重命名(#6416),以与 spring-ai-autoconfigure-* 系列模块的命名规范保持一致。请更新构建文件中的 artifact id。
  • OpenAI 工具调用严格模式(strict mode)默认值改为 false(#6755)。此前生成的工具 Schema 会通过省略字段的方式来标记可选参数,而严格模式要求所有字段必须出现在 required 中,导致任何带可选参数的工具都会收到 400 错误。现在严格模式改为默认关闭、需要显式开启,行为上与 OpenAI API 的默认设置保持一致;如果你的 Schema 符合严格模式的要求,可以手动重新启用。
  • Media 构建器改用带类型的 data 重载方法(#6481),使可接受的负载类型更加明确,不再笼统接受 Object
  • DeepSeekApi 进行了重构(#6428),使其与其他 API 客户端的编码规范保持一致。
  • Couchbase 向量存储现在复用 Spring Boot 托管的 Couchbase 客户端(#6583),而不再自行创建客户端,因此会遵循应用中已声明的集群配置。

新特性

工具调用次数限制

一个永不终止的智能体循环(agentic loop)是一种代价高昂的失败模式。ToolCallingAdvisor 现在支持为每次请求配置工具调用次数上限,一旦达到上限就会抛出 ToolCallLimitExceededException。异常处理路径会返回单个 Generation,因此错误处理的结构与正常响应保持一致。与此相关的是,工具解析回退机制现已可配置:你可以自行决定,当工具名无法解析时是直接快速失败,还是走回退逻辑。

OpenAI 音频

OpenAiAudioSpeechModel 现已支持音频流式输出,并新增了 instructions 选项,用于控制语音风格与表达方式。在转写(transcription)方面,配置选项与响应内容都得到了扩充,覆盖了更多 OpenAI API 的能力。

Google GenAI

Google GenAI 新增了 ToolChoice 支持,可以强制指定、禁用工具调用,或者交由模型自主决定;同时通过标准的 ImageModel 抽象层新增了图像生成支持。

文档读取

PagePdfDocumentReader 现在支持指定页码范围,可以只摄取大文档中的某一部分,而不必全部读取。TokenTextSplitter 现在会校验构建器参数,不再是运行到后面才抛出令人费解的错误。

AWS 区域解析

两个由来已久的问题终于得到解决:Spring AI 现在会遵循 AWS SDK 默认的区域解析规则,并且不再在解析区域时打印令人困惑的 WARN 日志。如果你此前依赖环境变量或 Profile 来配置 Bedrock 的区域,现在它的行为将与你 AWS 技术栈中其他组件保持一致。

优化

1. Redis 聊天记忆自动配置模块重命名

  • Artifactspring-ai-autoconfigure-model-chat-memory-redisspring-ai-autoconfigure-model-chat-memory-repository-redis
  • 配置属性前缀spring.ai.chat.memory.redis.*spring.ai.chat.memory.repository.redis.*
  • 平滑过渡:旧模块依然存在,并通过传递依赖指向新模块,因此现有依赖无需改动即可继续工作;旧的配置属性也会自动委托给新属性。不过官方提示,旧模块与旧配置前缀都将在未来版本中移除,建议尽早迁移。

2. 工具调用新增次数上限

DefaultToolCallingManager 现在默认对每个工具设置 40 次调用上限(DEFAULT_MAX_CALLS_PER_TOOL),总体调用次数上限为 150 次DEFAULT_MAX_TOTAL_TOOL_CALLS),此前是没有任何限制的。绝大多数应用不会感知到这一变化,因为默认值比较宽松;如果确实有正当场景需要更高上限,可以通过 ToolCallingManager.builder().maxCallsPerTool(...) / .unlimitedCallsPerTool(),或对应的 spring.ai.tools.limits.* 配置属性进行调整。

3. ToolCallingAdvisor 的 token 用量现在会跨迭代累加

此前只会暴露工具调用循环中最后一次模型调用的 Usage;现在会把整个循环内每一次内部模型调用的 token 用量累加起来。如果测试代码断言了精确的 token 数量,需要注意数值会比之前更高。这一变化不需要修改任何 API 调用方式。

4. OpenAI 工具调用严格模式默认关闭

OpenAiChatModel 不再默认将工具 Schema 标记为 strict(true)。原因是 JsonSchemaGenerator 生成 Schema 时,是通过把可选参数从 required 列表中省略来表示“可选”,而 OpenAI 的严格模式要求的做法不同(需要将可选字段标记为可为空类型并仍然放入 required),这导致此前任何带可选参数的工具在严格模式下都会被 OpenAI 判为不合规而返回 400 错误。

如果需要恢复严格模式,可以显式开启:

1
2
3
OpenAiChatOptions options = OpenAiChatOptions.builder()
.strict(true)
.build();

开启后,可选参数会被自动放宽为可为空类型,并回填进 required 列表,以满足严格模式的 Schema 约定。

5. OpenAI 语音流式输出行为变化

OpenAiAudioSpeechModel.stream(TextToSpeechPrompt) 此前会把整段响应缓冲后作为单个 Flux 元素一次性发出;现在会向 OpenAI 请求 stream_format=audio,真正按数据块(chunk)流式发出。如果你的代码之前用 blockFirst() 之类的方式只消费第一个元素、并假设它就是完整音频,现在只会拿到第一个数据块,需要改为拼接所有数据块。

6. TranscriptionModel 现在继承自 StreamingTranscriptionModel

流式转写现已成为所有转写模型的一等能力。默认实现会返回一个携带 UnsupportedOperationExceptionFlux,因此现有自定义实现无需修改即可继续编译;如果需要真正支持流式转写,需要自行重写 stream(AudioTranscriptionPrompt) 方法。

7. Media.Builder.data(Object) 改为多个带类型的重载方法

data(Object) 已被拆分为 data(byte[])data(String)data(URI)data(URL)data(Resource) 等具体类型的重载。原本以 Object 静态类型调用 .data(...) 的代码将无法编译,需要先将数据窄化为具体类型再调用。

8. 工具解析回退机制默认关闭

此前,当模型返回的工具调用并未附加在当次请求上时,DefaultToolCallingManager 会回退到应用级别的 ToolCallbackResolver(基于应用上下文中所有 ToolCallback Bean)去解析并执行该工具。从 2.0.1 开始,只有显式附加到请求上的工具(通过 .tools(...).defaultTools(...)ToolCallingChatOptions.toolCallbacks(...))才能被执行。

如需恢复旧行为,可设置:

1
spring.ai.tools.resolution.fallback.enabled=true

或在直接构建 ToolCallingManager 时使用:

1
2
3
4
ToolCallingManager toolCallingManager = ToolCallingManager.builder()
.toolCallbackResolver(toolCallbackResolver)
.resolutionFallbackEnabled(true) // 默认值为 false
.build();