本文整理自 Spring 官方博客、Spring AI GitHub Releases 及社区报道,信息截至 2026-09-22。
为什么值得关注
很长时间里,"做 AI 应用"几乎等同于"写 Python"。LangChain、LlamaIndex 把生态铺得很开,而 Java 团队手里那些跑了好多年的 Spring Boot 服务、关系型数据库、安全与可观测体系,反而像是被隔在门外。
Spring AI 做的就是把这扇门打开。而过去几个月,这个项目接连完成了两次重要动作:2.0.0 正式 GA,以及随后的第一个维护版本 2.0.1。前者重建了地基,后者补齐了生产环境里那些真正会咬人的细节。
时间线:一年半从 1.0 走到 2.0
- 2025 年 5 月:Spring AI 1.0 GA,第一次给出稳定的、Spring 风格的 AI 应用开发基线——可移植的 Chat、Embedding、Vector Store、结构化输出、工具调用、Chat Memory 抽象,以及一堆 Boot Starter。
- 2025 年 11 月:1.1 GA,继续在模型支持和能力上做加法。
- 2026 年 6 月 12 日:Spring AI 2.0.0 GA。
- 2026 年 8 月 21 日:Spring AI 2.0.1,2.0 线上的首个维护版本。
值得一提的是官方在 GA 公告里的坦率表述:项目在功能、模型支持、用户和贡献上增长得太快,所以他们主动"退后一步",重新定义了范围、质量和一致性的基线。这不是一次版本号升级,而是一次刻意的重构。
2.0.0 GA:重新浇筑的地基
平台基线整体上移
2.0 面向 Spring Boot 4.0 / 4.1 与 Spring Framework 7.0 设计。随之而来的几项改动,对长期维护的项目意义很大:
- Jackson 3:JSON 序列化链路上的改进,并新增
JsonHelper用于提供完全自定义的JsonMapper。 - JSpecify 空安全注解:整个代码库完成标注,既能提前拦截运行期的 NPE,也让 Kotlin API 更符合语言习惯。
- Options 体系重构:明确哪些选项必填、哪些可选;默认值统一收敛到 options 层;options 改为 builder 创建且创建后不可变;builder 提供一致的、免反射的合并能力。顺带还去掉了配置属性里那个多余的
.options层级,修掉了一批相关 bug。
还有一个使用层面的导向被明确下来:ChatClient 是面向用户的常用 API,ChatModel 则退居为更底层的构件。
模型支持从"铺开"转为"收敛"
这是 2.0 里最容易被低估的决策。核心仓库现在聚焦一组明确的开箱即用聊天模型:OpenAI、Anthropic、Amazon Bedrock、Google GenAI、Mistral AI、DeepSeek、Ollama。
同时做减法:
- OpenAI 从 3 种实现(Azure / HTTP / SDK)收敛为 1 种(SDK)
- Anthropic 从 2 种(HTTP / SDK)收敛为 1 种(SDK)
- Google GenAI 从 2 种(GenAI SDK / Vertex)收敛为 1 种(GenAI SDK)
转向厂商官方 SDK 的收益是长期的——模型 API 一有新扩展,框架能更快跟上。而那些不适合进核心的集成,官方选择了另一条路:交给厂商自己维护。Oracle 的 OCI Generative AI、微软的 Azure Cosmos DB 都已成为由厂商协作维护的外部模块——Cosmos DB 那边一次性给出了向量存储、对应自动配置、ChatMemoryRepository 实现和它的自动配置共四个模块。
Agent 能力:把工具调用从"私有循环"里解放出来
这是 2.0 在架构上最实质的变化。
在 1.x 里,每个 ChatModel 内部都藏着一套自己的工具调用循环,埋在实现深处,既没法挂钩、没法包装,也没法替换执行策略。用官方那句很精准的话说:"你可以调用工具,但你无法在工具调用之上构建东西。"
2.0 把这个循环提升为 advisor 链上的一等可组合组件。ChatClient 让每个请求都流经一条有序的 advisor 链,并支持循环——advisor 可以重新进入下游链路。同一套机制同时驱动了工具调用循环、结构化输出重试循环和评估循环。
几个具体落点:
ToolCallingAdvisor:由ChatClient自动注册,实现完整的工具调用往返。各 ChatModel 里那些临时性的工具循环被彻底移除。需要精确控制每一次迭代时,也可以选择退出、手动驱动循环。ToolSearchToolCallingAdvisor:面向"工具有几百个"的场景。不再把全部工具定义塞进每个请求,而是在会话内一次性索引全量工具集,让模型按需检索相关工具——渐进式工具披露。在大规模 MCP 配置下,工具定义本身可能就要吃掉每次请求 10–21K tokens;官方在 OpenAI、Anthropic、Gemini 上的基准测试显示,这一机制把 token 消耗降低了 34%–64%,且没有可测量的准确率损失。它可以用配置直接开启。StructuredOutputValidationAdvisor:即使开了原生结构化输出,模型依然可能吐出不合规的 JSON。这个可自动注册的 advisor 会在校验失败后自我纠正。AugmentedToolCallbackProvider:包装工具对象、在执行前拦截模型给出的工具参数。配合AgentThinking参数类型,每次工具调用都会带上模型填写的innerThought字段——相当于结构化的思维链,应用可以直接记录、展示或据此路由,而不必事后解析。
一个容易被忽略的细节:MessageChatMemoryAdvisor 放在 ToolCallingAdvisor 之前还是之后,决定了完整工具调用记录是否被持久化。想要精简的对话历史,就把 memory 放在工具调用之前;想留审计轨迹,就放在之后。
社区扩展补上两块拼图
- spring-ai-session:内置
ChatMemory的事件溯源替代方案,支持包括工具调用在内的全部消息类型(在任何后端下都能安全地处于工具调用循环内),并在上下文窗口填满时应用可插拔的、按轮次感知的压缩策略——包括由 LLM 驱动的摘要。 - spring-ai-agent-utils:在 2.0 的 agent 地基之上,提供打包成可组合工具与 advisor 的生产级原语,包含 Agent Skills(AgentSkills 规范的可移植 Spring AI 原生实现),以及 file、shell、web-fetch、task、auto-memory 等实用工具。
MCP 从"集成"变成"主线剧情"
Model Context Protocol 正在成为 AI 集成的通用协议。Spring 团队本身就在维护官方 MCP Java SDK,所以 Spring AI 的 MCP 集成能贴着规范源头走。2.0 带来的变化包括:
- 随版本发布 MCP Java SDK 2.0.0,符合最新的 2025-11-25 版 MCP 规范,并把整个 MCP 生态收拢到 Spring AI 名下。
- 注解驱动编程模型:原先在社区孵化的 mcp-annotations 模块正式进入 Spring AI。
@McpTool、@McpResource、@McpPrompt让任意 Spring 服务只需一个方法注解就能暴露为 MCP 服务端能力。统一的McpSyncRequestContext/McpAsyncRequestContext会被自动注入服务端处理方法,为工具和资源提供日志、进度上报、sampling、elicitation 的单一入口。客户端侧同样是一等公民,声明式 handler 覆盖了完整的协议回调模型。 - 传输层:WebMVC 与 WebFlux 传输实现从 MCP Java SDK 移入 Spring AI,发布节奏与框架对齐。Streamable HTTP 成为默认传输,取代已废弃的 SSE(其无状态变体可用于换取远程部署的可伸缩性,代价是放弃 MCP 的双向通信);STDIO 仍可用于本地进程集成。
- 企业特性:直接继承 Spring 的生产栈——面向服务端交互的 Micrometer span 与 OpenTelemetry 兼容指标,以及经由社区项目 mcp-security 提供的 OAuth 2.0 与 API Key 安全。
此外还有一处治理上的调整值得一提:随着编码 agent 提交的 PR 已占绝大多数,官方重写了 CONTRIBUTING.md,同时面向人类与 agent 明确贡献规则与约定,并强调人工评审的必要性。
2.0.1:一个"维护版本"该有的样子
2.0.1 处理了 80 多个 issue 和 PR,并且修复了 7 个 CVE。只看版本号容易低估它。
安全:7 个 CVE,其中几个值得特别留意
| CVE | 问题 |
|---|---|
| CVE-2026-47851 | PDF Document Reader 中对攻击者可控的 PDF 大纲树进行无界递归 |
| CVE-2026-47852 | 可预测的缓存目录位置,允许本地 ONNX 模型替换 |
| CVE-2026-59279 | 通过重复 initialize 请求造成无界持久会话分配 |
| CVE-2026-59294 | ResourceCacheService 中的路径穿越导致任意文件写入 |
| CVE-2026-59308 | 语义缓存因 SHA-256 截断导致的跨租户隔离绕过 |
| CVE-2026-59319 | RedisChatMemoryRepository 中的 RediSearch Tag 注入,导致跨会话数据泄露 |
| CVE-2026-59318 | DefaultToolCallingManager 全局解析器兜底允许通过提示注入派发未声明的工具 |
如果只看一条,那就是 CVE-2026-59318——提示注入竟能派发未被声明的工具,这正是 agent 类应用最典型的攻击面。而 CVE-2026-59308 和 CVE-2026-59319 则提醒我们:AI 应用的多租户隔离是全新的课题,语义缓存和会话内存都可能成为越权读取的通道。
结论很简单:跑在 2.0.0 上的应用应当尽快升到 2.0.1。
新能力
- 工具调用次数上限:agentic loop 停不下来是最昂贵的失败模式。
ToolCallingAdvisor现在支持配置单次请求的最大工具调用次数,达到上限抛出ToolCallLimitExceededException;异常路径会返回单个Generation,让错误处理与正常响应保持同一形状。相关的工具解析兜底策略也可配置——无法解析的工具名,是快速失败还是回退,由你决定。 - OpenAI 音频:
OpenAiAudioSpeechModel支持音频流式输出,并暴露instructions选项以引导音色与表达方式;转写侧的选项与响应也被扩充,覆盖了更多 OpenAI API 面。 - Google GenAI:新增
ToolChoice支持(强制调用、禁用调用,或交给模型判断),并接入统一ImageModel抽象的图片生成能力。 - 文档读取:
PagePdfDocumentReader支持页码范围——几百页的文档终于可以只读取需要的部分;TokenTextSplitter开始校验 builder 参数,而不是在后续抛出令人费解的错误。 - AWS 区域解析:Spring AI 现在遵循 AWS SDK 的默认区域解析规则,也不再在解析区域时打印令人困惑的 WARN。如果你的 Bedrock 依赖环境变量或 profile 配置区域,行为终于和 AWS 栈的其余部分一致了。
可靠性修复的重点
流式响应承担了这次最多的注意力:OpenAiChatModel 按索引合并流式工具调用的增量、正确处理空的 tool_calls 数据块、修掉了流式模式下 token 用量为零的报告;取消流后不再泄漏底层 HTTP 响应(chat 与音频转写都修了);ToolCallingAdvisor 的流式循环不再丢弃 doBeforeStream 的修改;token 用量改为跨工具调用迭代累计,而不再只报最后一轮。
Chat Memory 方面,Redis ChatMemoryRepository 三处加固:时间戳原子预留(并发写入不再撞车)、clear() 真正生效、查询中的元数据值被正确转义。
向量库方面,Milvus 修了三处(过滤表达式的分组优先级、整型元数据被反序列化成 Long 而非 Double、针对自定义元数据字段的过滤),OpenSearch 修复文档反序列化,PgVector 在初始化后校验表结构而不是等到第一次查询才失败,Couchbase 的 builder 断言也修正了。
MCP 方面,注解在 GraalVM native image 下恢复可用,@McpTool 的异常处理与 @Tool 契约对齐,无参数的 stdio 连接可用,HTTP 客户端请求定制器 bean 被正确应用,Streamable HTTP WebClient 传输可以接受省略 event 字段的 SSE 帧;服务端还能用 maxSessions 与 sessionIdleTimeout 限制会话状态。
健壮性方面,一批修复让框架面对不可信输入时更稳重:校验已解析的资源路径、缓存改用临时目录、用完整长度哈希替换截断哈希、处理畸形 PDF 而不是直接把解析器异常抛出去。另外,协议值的大小写转换改用 Locale.ROOT,顺手修掉了那个经典的土耳其语 i 问题。
升级前请注意
从 2.0.0 到 2.0.1 多数应用改个版本号即可,但有几处需要留意:
- 已废弃的 Mistral AI 聊天模型被正式退役,仍按常量引用的需要换成受支持的模型名。
- Redis chat memory 自动配置模块改名,与
spring-ai-autoconfigure-*命名保持一致,构建文件里的 artifact id 要更新。 - OpenAI 工具调用 strict 模式默认值改为
false。生成的工具 schema 通过把可选参数从required中省略来表达"可选",而 strict 模式不接受这一点——于是任何带可选参数的工具都会以 400 报错。现在 strict 模式改为显式启用,与 OpenAI API 的默认行为一致。 Mediabuilder 改用带类型的data重载,接受的数据类型变得明确,不再笼统地接收Object。DeepSeekApi被修订,以与其他 API 客户端的约定保持一致。- Couchbase 向量存储改用 Spring Boot 管理的 Couchbase 客户端,从而参与应用已经声明的集群配置。
如果你还在 1.x:这不是一次"打个补丁"
从 1.1.x 升到 2.0.0 的破坏性变更需要预留时间,升级说明里写得很清楚:
- 应用配置键里的
.options层级被移除; toolNames()与SpringBeanToolCallbackResolver被删除,工具必须注册为ToolCallbackbean 并通过.tools()显式传入;- 各 ChatModel 内部的工具调用循环不复存在;
- 模块被重命名、类被移动,advisor 与工具搜索相关的改动尤其集中。
回报是一套连贯可预期的 API 表面,以及一个真正能"在工具调用之上构建东西"的框架。
小结
把这两次发布放在一起看,方向相当清楚:
2.0.0 解决的是"地基"问题——统一基线、统一选项语义、把工具调用提升为可组合的一等组件、把 MCP 纳入主线、收敛模型支持并用厂商 SDK 换取长期跟进能力。
2.0.1 解决的是"上生产"问题——给 agentic loop 装上明确的调用边界,修掉 7 个 CVE,补齐流式、内存、向量库、MCP 里那些只在真实负载下才暴露的缺陷。
对 Java 团队来说,意义或许比版本号更大:生成式 AI 正在从"另一个用别的语言写的边车"变成"应用栈里再普通不过的一组能力"。你依然用 starter、自动配置、依赖注入、模板、advisor、注解、repository 和可观测性来做这件事——只是现在,模型、向量库、工具和 MCP 也在这套体系里了。