Spring AI 2.1.0-RC1 and 2.0.2 Available Now
TL;DR · AI 摘要
Title: Spring AI 2.1.0-RC1 and 2.0.2 Available Now URL Source: Markdown Content: On behalf of the Spring AI team and eve...
核心要点
- 主题聚焦:Spring AI 2.1.0-RC1 and 2.0.2 Available Now
- 来源:Spring Blog,建议结合原文判断细节。
- AI 分析暂不可用,本条为保底评分与摘要。
代表 Spring AI 团队及所有贡献者,我很高兴地宣布 Spring AI 2.1.0-RC1 和 2.0.2 已发布,现已通过 Maven Central 提供下载!
2.1.0-RC1 在 2.1.0-M1 的基础上进一步完善,实现了我们在 "What's next" 部分承诺的大部分功能:主要聊天模型现在原生支持消息片段的生产和消费,Spring AI 内置了会话内存功能。此版本新增了工具调用确认功能,并通过查询向量搜索扩展了预计算嵌入支持。
本版本新增功能
跨供应商的消息片段支持
在 M1 版本中,只有 OpenAiResponsesChatModel 能够原生处理 `MessagePart` 内容。本版本新增了以下 ChatModel 实现对消息片段的支持:
- OpenAI(聊天补全)
- Anthropic
- Google GenAI
- Amazon Bedrock Converse
- Ollama
- Mistral AI
- DeepSeek
因此,推理过程、工具调用以及供应商特定的区块在整个对话中保持顺序和不透明的有效载荷(如 Anthropic 的思考签名和 Gemini 的思考签名)。使用现有访问器(getText()、getToolCalls() 等)的代码无需修改即可继续工作。消息构建器的设置方法现在会直接替换片段,因此 UserMessage.builder().text(...) 后再次调用将不再残留旧片段。
关于兼容 OpenAI 的端点有两个相关细节。reasoning_content 会在助手消息中回传,因为某些端点(如 DeepSeek 的思考模式)需要它,而其他端点(如 Groq)会拒绝它。现在可通过 spring.ai.openai.chat.replay-reasoning-content(或 OpenAiChatOptions.replayReasoningContent)配置是否回传,该属性默认保持发送,设置为 false 时关闭。在 Responses API 中,用户消息的片段顺序将被保留,文件 URL 会以 file_url 格式发送。
会话内存
ChatMemory 按对话 ID 存储每场对话的平铺消息列表。对于长期对话和代理系统,这还不够,因此 Spring AI 现在包含了一个 会话内存 功能,该功能移植自社区项目 Spring AI Session。
会话将对话保存为仅追加的事件日志,并从该日志的视图构建提示:
- 结构化事件。 每条消息都是一个
SessionEvent。其他可自定义名称的事件类型可以记录同一日志中发生的其他操作。 - 基于对话轮次的压缩。 类似
TurnCountTrigger的触发器决定何时历史记录过大,策略则决定哪些内容会移出视图。WindowCompactionStrategy保留最近的事件、最近的对话轮次或适应令牌预算,可选的CompactionSummarizer(ChatModelSummarizer)可以总结被丢弃的内容。压缩操作始终在对话轮次边界进行,因此模型永远不会看到没有结果的工具调用。压缩从不修改日志:它只是追加一个定义此后视图的边界。 - 仓库 SPI。
InMemorySessionRepository用于测试,JdbcSessionRepository支持 PostgreSQL、MySQL、MariaDB 和 H2,具备幂等追加和版本校验的压缩功能。您也可以通过spring-ai-test中的契约测试验证自己的存储实现。
要与 ChatClient 一起使用,请添加 spring-ai-starter-model-session-jdbc 启动器,注册会话顾问,并在每次调用时传递会话 ID:
@Bean
ChatClient chatClient(ChatModel chatModel, SessionService sessionService) {
return ChatClient.builder(chatModel)
.defaultAdvisors(SessionAdvisors.builder(sessionService)
.compaction(new TurnCountTrigger(20), WindowCompactionStrategy.builder().lastTurns(10).build())
.build())
.build();
}
String answer = chatClient.prompt()
.user("Hello!")
.advisors(SessionAdvisors.session("session-abc"))
.call()
.content();首次使用时会自动创建尚未存在的会话,且每次调用都必须提供会话 ID:刻意没有默认会话,因为共享会话会静默合并不同用户的对话历史。顾问本身不保存状态,因此任何应用实例都可以运行会话的任意轮次。
ChatMemory、MessageWindowChatMemory、ChatMemoryRepository、MessageChatMemoryAdvisor以及 JDBC、Cassandra、Neo4j、MongoDB 和 Redis 对话记忆仓库现已 弃用,计划在 3.0.0 中移除。每个弃用项都标明了替代方案。对于尚未有会话对应实现的组件(Cassandra、Neo4j、MongoDB、Redis 以及 HSQLDB、Oracle、SQL Server 和 SQLite 方言),计划在 3.0.0 之前提供替代方案。VectorStoreChatMemoryAdvisor保留下来,因为会话目前尚无语义回忆的对应实现。顾问上下文键ChatMemory.CONVERSATION_ID现在被永久归为MemoryAdvisor.CONVERSATION_ID,且值保持一致。
工具调用确认
预订航班、删除文件或发送电子邮件等操作可能需要用户先确认。现在工具可以请求这种确认:
class BookingTools {
@Tool(description = "Book a flight", requiresConfirmation = true)
String bookFlight(String flightNumber) {
return bookingService.book(flightNumber);
}
}循环在等待时不会保存任何状态:暂停是普通响应,恢复是普通请求,因此只要应用程序保持对话,该功能就能在重启后继续运行。需要确认哪些调用由 ToolCallConfirmationPolicy 决定:默认策略读取工具的元数据,forTools(...) 用于命名您不拥有的工具(例如 MCP 工具),而 lambda 可以检查参数,例如仅确认超过特定金额的转账。策略可以通过 or(...) 组合,spring.ai.tools.confirmation.* 属性和 ToolCallConfirmationPolicy Bean 会被自动配置拾取。该功能已通过针对 OpenAI、Gemini、Anthropic、Bedrock 和 Ollama 的集成测试覆盖。请参阅参考文档中的 Tool Call Confirmation。
使用自定义查询嵌入进行搜索
M1 新增了 VectorStore.upsert() 用于写入自行计算的向量。另一半功能现已就绪:VectorStoreRetriever 增加了 similaritySearch(float[], SearchRequest),该方法从您处获取查询向量。请求仍然提供 topK、相似度阈值和过滤条件,存储的嵌入模型不会被使用,且向量为空、包含 NaN 或无穷大、长度错误时会在前期被拒绝。
float[] queryEmbedding = ...; // 在其他地方由嵌入文档的模型计算得出
List<Document> results = vectorStore.similaritySearch(queryEmbedding,
SearchRequest.builder().topK(5).similarityThreshold(0.7).build());pgvector、Qdrant、Redis 和 Elasticsearch 已实现该功能,OpenSearchVectorStore 现在也支持 upsert 和查询嵌入搜索(upsert 需要 manageDocumentIds,因为 OpenSearch 否则会生成 ID 并无法通过 ID 替换)。不支持这些操作的存储现在会直接失败并抛出 UnsupportedOperationException,而不是先调用嵌入模型。
向量大小检查也更加健壮:预期的宽度现在来自配置的 dimensions 或现有索引、表或集合,嵌入模型仅在创建新索引时被咨询。临时无法读取索引的情况不再导致存储永久拒绝有效向量。请参阅参考文档中的 Searching with a Query Embedding。
Qxotic jinfer
感谢 Qxotic AI 团队,Spring AI 现在支持纯 JVM 推理引擎 jinfer。具体形式包括:
- 一个 ChatModel 实现,
- 一个 EmbeddingModel 及相关
DocumentPostProcessor, - 一个 Text to Speech 和语音转文本 Transcription 模型。
音频
- Google GenAI 新增了文本转语音和语音转文本模型。
- 可观测性 现在支持语音和转录(OpenAI、ElevenLabs)以及 Stability AI 图像生成,包含 Micrometer 观测。新增的
spring-ai-autoconfigure-model-audio-observation模块可以记录文本和转录内容,默认情况下该功能是关闭的。 - Qxotic jinfer 为其聊天、嵌入和转录功能新增了参考文档章节。
小幅改进
TokenTextSplitter支持块重叠。该功能需要显式启用:默认重叠值为0,此时块与之前保持一致。PgVectorStore可通过contentFieldName、metadataFieldName和embeddingFieldName指向具有不同列名的现有表。- Azure OpenAI 支持自定义凭证。
OpenAiChatModel填充限流元数据,自定义请求头会传播到单次调用请求和嵌入请求中。BedrockProxyChatModel缓存工具结果,BedrockChatOptions.requestParameters支持嵌套值(详见下方升级说明)。- Anthropic 提示缓存现在也缓存引用文档。
- Anthropic 流式传输块包含思考文本。
升级说明
一些变更可能需要您修改代码。详细信息请参阅升级说明:
BedrockChatOptions.requestParameters(以及对应的 Boot 属性)现在是Map<String, Object>类型。将它赋值给Map<String, String>变量的源代码不再能编译。- 修复了 Neo4j 聊天记忆索引属性。
PgVectorStore不再覆盖文档自身的distance元数据。计算值可通过Document#getScore()获取。ChatMemory及其相关类型已被弃用(详见上方)。
修复内容
- Anthropic:答案作为主要生成内容,流式请求保留在调用方的追踪中,被丢弃的重放块会记录日志。
- OpenAI:在 Responses API 中检测非 PNG 格式的图像 MIME 类型,正确处理分段转录,无
index的嵌入响应回退到列表位置,超出范围的使用计数会返回明确提示。 StructuredOutputValidationAdvisor不再重复工具调用请求。- Google GenAI:正确提取工具调用,保留未设置的工具选项。
- Bedrock:工具调用参数不再是无效 JSON。
- Ollama:处理无消息的响应。
DefaultUsage.fromJson重新支持遗留的generationTokens,容忍无法序列化的本地使用数据,UsageCalculator处理空使用数据。- 向量存储:Cassandra 数值过滤、Qdrant 过滤中的分数数字、
SimpleVectorStore过滤中的日期标准化。 - 文档读取器:
TikaDocumentReader支持重入,PDF 读取器关闭资源流,PDF 文本位置回退到合并排序,JsoupDocumentReader不再丢弃相对链接 URL。
依赖和构建
- Spring Boot 4.2.0-RC1
- MCP Java SDK 2.1.0
- OpenAI Java SDK 4.80.0
- Anthropic Java SDK 2.72.0
- Google GenAI 1.73.0
- AWS SDK and Bedrock runtime 2.55.14
- Tika 4.0.0
- Kotlin 2.4.21
TypeSafe AI jev API 的 Java 客户端和 Spring AI 集成新版本现已发布。
Spring AI A2A 0.4.0 现在使用 A2A Java SDK 的 1.4.0.Final 版本。感谢 @deejay1 和 @thjanssen 的贡献。
Spring AI 2.0.2
除了 2.1.0-RC1 之外,2.0.2 版本也已发布。2.0.2 中的所有修复内容也都包含在 2.1.0-RC1 中。
贡献者
感谢所有为此次发布做出贡献的人:
@56wj, @ashakirin, @Ashfaqbs, @chabinhwang, @chengwudi1, @chensishang, @CodeTrainerMan, @CryoThrust, @dimitarproynov, @dlwldn30, @flex-ilsub, @herder, @ikaitist, @iuliiasobolevska, @JamesBLewis, @jhpark1227, @jianran, @kezhenxu94, @lazer-dev, @Lubaoshuai, @martin-grofcik, @nicolaskrier, @OreOreDa, @pengjonas, @pengmoubuaixuexi, @Rainmemery, @rvullriede, @ryujungkyun, @sedhossein, @seo92js, @sharanrenukeshbharmshetty, @sobychacko, @ss-bhatt, @stack3mpty, @tzolov, @vinayreddykalluri, @wantaekchoi, @xujiantop-crypto, 和 @zxuhan
下一步计划
接下来是 2.1.0 GA 版本。在发布之前,我们将重点关注上述功能的反馈,特别是会话内存和将聊天模型迁移到消息部分的工作。
入门
尝试在现有应用中使用该发布候选版本,或通过 start.spring.io 启动新项目。会话内存和工具调用确认是新推出的 API,我们希望在正式发布前了解这些功能如何契合您的使用场景——如果发现功能异常,请在 GitHub 提交问题;若对后续功能有建议,欢迎在 GitHub 发起讨论。
感谢支持!