Ohhnews

分类导航

$ cd ..
Spring Blog原文

Spring AI 2.1.0-RC1 与 2.0.2 现已发布

#spring ai#人工智能#版本发布#会话记忆#工具调用

代表 Spring AI 团队以及所有贡献者,我很高兴地宣布 Spring AI 2.1.0-RC1 和 2.0.2 已发布,现在可从 Maven Central 获取!

发布说明 | 升级说明 | 参考文档

2.1.0-RC1 基于 2.1.0-M1 构建,并兑现了其“下一步”部分承诺的大部分内容:主流聊天模型现在可以原生生成和消费消息部件,会话记忆也进入了 Spring AI 本身。它还新增了工具调用确认,并通过按查询向量搜索扩展了预计算嵌入支持。

本次版本新增内容

跨提供方的消息部件

在 M1 中,只有 OpenAiResponsesChatModel 能原生处理 MessagePart 内容。在此版本中,以下 ChatModel 实现也能生成和消费消息部件:

  • OpenAI(Chat Completions)
  • Anthropic
  • Google GenAI
  • Amazon Bedrock Converse
  • Ollama
  • Mistral AI
  • DeepSeek

因此,推理、工具调用和特定于提供方的块能够在整个对话中保持顺序和不透明载荷,例如 Anthropic 的 thinking signatures 与 Gemini 的 thought signatures。使用现有访问器(getText()、getToolCalls() 等)的代码仍可正常工作。消息构建器的 setter 现在会就地替换部件,因此 UserMessage.builder().text(...) 之后再调用另一个 setter 不会再留下过期部件。

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 保留最近的事件、最近的轮次,或适配 token 预算;可选的 CompactionSummarizer(ChatModelSummarizer)可对被丢弃的内容进行摘要。压缩始终在轮次边界处切分,因此模型绝不会看到没有结果的工具调用。压缩绝不重写日志:它追加一个边界,从此定义视图。
  • 仓储 SPI。 InMemorySessionRepository 用于测试;JdbcSessionRepository 支持 PostgreSQL、MySQL、MariaDB 和 H2,具备幂等追加和版本校验压缩。你自己的存储可依据 spring-ai-test 中的契约测试进行验证。

要在 ChatClient 中使用它,请添加 spring-ai-starter-model-session-jdbc 启动器,注册会话顾问,并在每次调用时传入会话 ID:

$ java
@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,值相同。

工具调用确认

预订航班、删除文件或发送电子邮件等操作,用户可能希望先获得批准。现在工具可以请求这种确认:

$ java
class BookingTools {

    @Tool(description = "Book a flight", requiresConfirmation = true)
    String bookFlight(String flightNumber) {
        return bookingService.book(flightNumber);
    }
}

当模型调用此类工具时,工具调用循环会在执行该回复中的任何调用之前暂停,并将该回复返回给应用,列出等待决策的调用。应用会为每次调用收集一个 ToolCallDecision(允许,或附带消息拒绝),使用 ToolCallingManager.executeToolCalls(prompt, reply, decisions) 执行该回复中的调用,并将结果作为下一次请求发送。被拒绝的调用不会执行,而是把你的消息作为模型的回答。

循环在等待期间不保存状态:暂停是一次普通响应,恢复是一次普通请求,因此只要应用保留对话,这就能在重启后继续。哪些调用需要确认由 ToolCallConfirmationPolicy 决定:默认策略读取工具的元数据,forTools(...) 用于指定你不拥有的工具(例如 MCP 工具),lambda 可以检查参数,例如只确认超过给定金额的转账。策略可通过 or(...) 组合,自动配置会识别 spring.ai.tools.confirmation.* 属性和 ToolCallConfirmationPolicy bean。该功能已通过与 OpenAI、Gemini、Anthropic、Bedrock 和 Ollama 的集成测试覆盖。请参阅参考文档中的工具调用确认。

使用自己的查询嵌入进行搜索

M1 新增了 VectorStore.upsert(),用于写入你自己计算的向量。另一半现在也已就位:VectorStoreRetriever 新增 similaritySearch(float[], SearchRequest),由你提供查询向量。请求仍提供 topK、相似度阈值和过滤器,存储的嵌入模型绝不会被使用;空向量、包含 NaN 或无穷大、或长度错误的向量会在一开始就被拒绝。

$ java
float[] queryEmbedding = ...; // computed elsewhere, by the model that embedded your documents
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,或来自现有索引、表或集合;只有创建新索引时才会查询嵌入模型。读取索引的临时失败不再会导致存储永久拒绝有效向量。请参阅参考文档中的使用查询嵌入进行搜索。

Qxotic jinfer

感谢 Qxotic AI 团队,Spring AI 现在支持纯 JVM 推理引擎 jinfer。具体包括:

音频

  • 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,容忍无法序列化的原生 usage,并且 UsageCalculator 可处理 null usage。
  • 向量存储:修复 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 和 Bedrock 运行时 2.55.14
  • Tika 4.0.0
  • Kotlin 2.4.21

来自 Spring AI 社区

适用于 TypeSafe AI jev API 的新版 Java 客户端和 Spring AI 集成现已可用。

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,我们希望在 GA 之前了解它们如何契合你的用例——如果发现问题,请提交 issue;如果想告诉我们你希望接下来看到什么,请发起讨论。

祝好!

资源

项目页面 | GitHub | 问题 | 参考文档