【Spring AI】 2.0升级指南二

📅 2026/7/21 12:15:41
【Spring AI】 2.0升级指南二
第三章JDBC Chat Memory——sequence_id3.1sequence_id问题背景在 1.x 中JDBC 聊天记忆的消息顺序依赖于timestamp列。但不同数据库的时间戳精度不同MySQL / MariaDB默认精度为秒级同一秒内保存的多条消息顺序不确定PostgreSQL精度较高但在极端情况下仍可能存在竞态条件解决方案新增sequence_id列整数类型通过递增数字精确控制消息顺序在所有数据库上行为一致。3.2 变更一览升级迁移2.0.0 表结构idconversation_idsequence_id✅ 精确排序timestamp保留作为创建时间content1.x 表结构idconversation_idtimestamp⚠️ 精度问题content3.3 PostgreSQL 迁移 SQL-- 1. 添加新列ALTERTABLESPRING_AI_CHAT_MEMORYADDCOLUMNsequence_idBIGINT;-- 2. 按现有顺序回填数据WITHorderedAS(SELECTctid,ROW_NUMBER()OVER(PARTITIONBYconversation_idORDERBYtimestamp)-1ASseqFROMSPRING_AI_CHAT_MEMORY)UPDATESPRING_AI_CHAT_MEMORY tSETsequence_ido.seqFROMordered oWHEREt.ctido.ctid;-- 3. 设置非空约束ALTERTABLESPRING_AI_CHAT_MEMORYALTERCOLUMNsequence_idSETNOTNULL;-- 4. 创建索引CREATEINDEXSPRING_AI_CHAT_MEMORY_CONVERSATION_ID_SEQUENCE_ID_IDXONSPRING_AI_CHAT_MEMORY(conversation_id,sequence_id);提示不同数据库请调整标识符引用方式和行标识表达式如 PostgreSQL 的ctid。如果聊天记忆只作为短期对话缓存也可以直接删表后用新 schema 重建。第四章Options 不可变性与配置扁平化4.1 Options 类严格不可变设计理念不可变对象更安全、更易于推理尤其是在并发场景下。主要变更ChatOptions、EmbeddingOptions等 Options 类中的所有集合字段如toolCallbacks、stopSequences现在存储为不可修改集合移除了copy()和fromOptions()方法修改 Getter 返回的集合会抛出UnsupportedOperationException迁移方式——使用mutate()// 之前OllamaChatOptionsoptionsoriginalOptions.copy();options.setFoo(...);// 之后OllamaChatOptionsoptionsoriginalOptions.mutate().foo(...).build();4.2 默认值移至 Options 构造函数设计变化默认值不再分散在 Model 实现和 Properties 配置类中而是统一在 Options 构造函数中定义。单一数据源更易维护。迁移方式// 之前ChatOptionsoptionschatModel.getDefaultOptions();// 之后ChatOptionsoptionschatModel.getOptions();4.3 配置属性扁平化移除.options层级所有模型Embedding、Image、Audio、Moderation、OCR 等的配置属性不再使用.options前缀。# 之前 spring.ai.openai.embedding.options.modeltext-embedding-3-small # 之后 spring.ai.openai.embedding.modeltext-embedding-3-smallJava 代码中// 之前Stringmodelproperties.getOptions().getModel();OpenAiEmbeddingOptionsoptionsproperties.getOptions().toOptions();// 之后Stringmodelproperties.getModel();OpenAiEmbeddingOptionsoptionsproperties.toOptions();4.4N()重命名为n()// 之前OpenAiChatOptions.builder().N(1).build();// 之后OpenAiChatOptions.builder().n(1).build();第五章JSON 工具类重构5.1 统一为 JsonHelper在 1.x 中JSON 序列化/反序列化功能分散在多个类中JsonParserModelOptionsUtils部分方法McpJsonParser这种分散导致功能重复维护困难配置不一致5.2 新的统一入口JsonHelper// 默认——使用共享的 JsonMapperJsonHelperjsonHelpernewJsonHelper();// 自定义——注入自己的 JsonMapperJsonMappermyMapperJsonMapper.builder().addModule(newJavaTimeModule()).build();JsonHelpercustomHelpernewJsonHelper(myMapper);5.3 迁移速查表旧方法新方法JsonParser.getJsonMapper()JacksonUtils.getDefaultJsonMapper()JsonParser.fromJson(json, MyType.class)jsonHelper.fromJson(json, MyType.class)JsonParser.toJson(object)jsonHelper.toJson(object)ModelOptionsUtils.jsonToMap(json)jsonHelper.fromJsonToMap(json)ModelOptionsUtils.toJsonString(object)jsonHelper.toJson(object)ModelOptionsUtils.JSON_MAPPERJacksonUtils.getDefaultJsonMapper()McpJsonParser.toMap(object)jsonHelper.convertToMap(object)第六章ChatClient 工具调用行为变更6.1 ToolCallingAdvisor 自动注册新行为ChatClient现在始终自动在顾问链中注册一个ToolCallingAdvisor除非显式禁用。是否ChatClient.prompt是否有工具?自动注册 ToolCallingAdvisor跳过执行顾问链调用模型影响如果您的代码中已经显式添加了ToolCallingAdvisor现在会重复注册两次。迁移方式// 之前——显式注册chatClient.prompt(Whats the weather?).tools(weatherTool).advisors(ToolCallingAdvisor.builder().build()).call().content();// 之后——自动注册无需显式添加chatClient.prompt(Whats the weather?).tools(weatherTool).call().content();// 如需完全手动控制禁用自动注册chatClient.prompt(Whats the weather?).tools(weatherTool).advisors(AdvisorParams.toolCallingAdvisorAutoRegister(false),ToolCallingAdvisor.builder().build()).call().content();6.2 新增标记接口ToolAdvisor 和 MemoryAdvisorDefaultChatClient通过这两个标记接口来智能决策标记接口用途ToolAdvisor表示该 Advisor 负责工具调用生命周期。链中存在此接口实现时跳过自动注册MemoryAdvisor表示该 Advisor 管理记忆。存在时ToolCallingAdvisor自动关闭内部历史管理// 自定义 Advisor 如果拥有工具调用生命周期应实现 ToolAdvisorpublicclassMyCustomToolAdvisorimplementsAdvisor,ToolAdvisor{// ...}6.3 ToolSpec API 移除tools(ConsumerToolSpec)API 已移除上下文信息通过独立的toolContext()方法设置// 之前chatClient.prompt().tools(t-t.callbacks(myCallback).context(tenantId,acme)).call().content();// 之后chatClient.prompt().tools(myCallback).toolContext(Map.of(tenantId,acme)).call().content();6.4 Spring Bean 工具解析器移除背景1.x 支持将普通的Function、Supplier、ConsumerBean 通过toolNames()引用框架在运行时解析。这种方式缺乏类型安全且与 Spring 的 Bean 管理方式不够协调。迁移方式——直接声明ToolCallbackBean// 之前——普通的 Function BeanBeanDescription(Get the weather in location)FunctionWeatherRequest,WeatherResponsecurrentWeather(){returnweatherService::getWeather;}// 之后——显式的 ToolCallback BeanBeanToolCallbackcurrentWeather(){returnFunctionToolCallback.builder(currentWeather,weatherService::getWeather).description(Get the weather in location).inputType(WeatherRequest.class).build();}