spring-ai|Spring‑AI 2.0.0 新特性 + 入门教程

spring-ai|Spring‑AI 2.0.0 新特性 + 入门教程

Spring AI 2.0.0 GA 最低依赖 Spring Boot 4.x、Spring Framework 7、Java21 不再兼容 Spring Boot3 底层切换厂商官方 SDK,大量 API 重构稳定性提升,面向 Agent、RAG 生产环境

一、核心新特性Spring

1. 底层架构重大升级

  • 全链路 JSpecify 空安全注解,大量返回Optional,减少 NPE,Kotlin 友好;Options 配置全部改为不可变 Builder 模式,移除 setter 方法Spring。
  • Jackson3 序列化,新增JsonHelper工具类,自定义 JSON 更方便。
  • 模型厂商剥离到独立仓库:OpenAI、Anthropic 不再内置 http 封装,直接使用官方 Java SDK;OpenAI 兼容接口依然可用Microsoft ...。
  • 部分向量存储移除:SAP HANA、Infinispan 被移除,需要更换其他向量库。

2. Tool‑Calling(工具调用)Agent 能力大幅增强

  • 术语统一:FunctionCallbackToolCallback,``functions()tools(),行业对齐 Agent 术语Spring。
  • ToolSearchToolCallingAdvisor:工具数量多(>30)时,不会一次性把全部工具定义传给大模型,按需检索工具,减少 token 消耗,解决上下文膨胀问题,支持 regex/lucene/vector 三种索引模式Spring。
  • ToolExecutionEligibilityChecker:自定义工具调用循环终止条件,灵活控制 Agent 执行逻辑Spring。

3. 结构化输出增强(Self‑Correcting)

  • .entity()结构化输出新增自校验纠错机制:模型输出 JSON 不符合 Java Record schema,框架自动把错误返回给模型,让模型自我修正,提升结构化返回成功率;同时支持厂商原生结构化输出模式Spring。

4. ChatMemory 对话内存改进

  • PromptChatMemoryAdvisor 必须显式传入 conversationId 会话 ID,不再隐式自动生成,消除会话状态混乱问题,生产环境更可控GitHub。
  • MessageWindowChatMemory支持按对话轮次边界截断,避免工具消息重复注入内存。

5. RAG 与向量存储

  • 只读向量存储接口ReadOnlyVectorStore,纯检索场景不需要写权限。
  • Advisor 模块包名重构:spring‑ai‑advisors‑vector‑storespring‑ai‑vector‑store‑advisorSpring。

6. 可观测性 & 评估 API

  • Micrometer 完整可观测:自动埋点 token 消耗、调用耗时、模型调用链路,对接 Prometheus/Grafana。
  • Evaluation 评估框架:自动化评估 RAG 回答质量,内置相关性评估、事实校验评估器,输出 0‑1 分数,用于自动化测试 RAG 系统效果。

7. API 变更重点(迁移注意)

  • Options 类全部移除 setter,只能用 Builder 构建;
  • OpenAI 属性类重命名OpenAiConnectionPropertiesOpenAiCommonProperties;
  • OpenAiApi自定义 API 层全部删除,替换为官方 SDK Client 对象GitHub

源码

spring-ai-sample: spring ai 和 spring ai alibaba 相关项目学习 demo - Gitee.com

部分源码

依赖

复制代码

<properties> <spring-boot.version>4.0.0</spring-boot.version> <spring-ai.version>2.0.0</spring-ai.version> </properties> <dependencyManagement> <dependencies> <!-- 1. Spring Boot 依赖管理(替代 parent 的作用) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- 2. Spring AI 依赖管理 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>${spring-ai.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

复制代码

package com.kcnf.ai.controller; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.Map; import java.util.UUID; /** * Spring‑AI 2.0.0 演示Controller * 两个ChatClientBean做隔离: * 2. memoryChatClient:装配了MessageChatMemoryAdvisor,需要传入ConversationId实现多轮上下文记忆 * */ @RestController @RequestMapping("/api/ai") public class AiMemoryController { /** * 带记忆Advisor的ChatClient,用于多轮对话,必须传入会话ID */ private final ChatClient memoryChatClient; public AiMemoryController( @Qualifier("memoryChatClient") ChatClient memoryChatClient) { this.memoryChatClient = memoryChatClient; } /** * ④多轮记忆对话(阻塞版) * POST /api/ai/chat/memory * Header:Conversation‑Id,不传自动生成UUID * advisors():给MemoryAdvisor传入会话ID,绑定ChatMemory存储的历史消息 */ @PostMapping("/chat/memory") public Map<String,String> chatWithMemory( @RequestParam(value = "message") String message, @RequestHeader(value = "Conversation-Id",required = false) String conversationId ){ // 没有传入会话ID,生成全新会话 if(conversationId == null || conversationId.isBlank()){ conversationId = UUID.randomUUID().toString(); } String finalConversationId = conversationId; String reply = memoryChatClient.prompt() .user(message) // 给记忆Advisor设置会话ID,读取/写入该会话历史 .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, finalConversationId)) .call() .content(); return Map.of("conversationId",conversationId,"reply",reply); } /** * ⑥SSE流式 + 上下文记忆 * GET /api/ai/chat/memory/stream * Header Conversation‑Id:同一个ID,历史上下文会被读取 */ @GetMapping(value = "/chat/memory/stream",produces = "text/event-stream") public SseEmitter chatMemoryStream( @RequestParam(value = "message") String message, @RequestHeader(value = "Conversation-Id",required = false) String conversationId ){ SseEmitter emitter = new SseEmitter(60_000L); if(conversationId == null || conversationId.isBlank()){ conversationId = UUID.randomUUID().toString(); } String convId = conversationId; memoryChatClient.prompt() .user(message) // 流式请求同样必须指定CONVERSATION_ID .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, convId)) .stream() .content() .subscribe( token -> { try { emitter.send(SseEmitter.event().data(token)); }catch (Exception e){ emitter.completeWithError(e); } }, emitter::completeWithError, ()->{ try { emitter.send(SseEmitter.event().data("\n会话ID:"+convId)); }catch (Exception ignored){} emitter.complete(); } ); return emitter; } }

演示

相关推荐
计算机学姐6 分钟前
基于SpringBoot的高校爱心慈善管理系统
java·vue.js·spring boot·后端·spring·tomcat·mybatis
vx+_bysj686919 分钟前
springboot 旅行小程序97353
spring boot·后端·小程序·旅行小程序
都叫我大帅哥30 分钟前
Apache Tika 4.0 正式发布:RAG 时代文件解析的终极答案
java·spring boot·spring
大梦想家a1 小时前
基于 Spring Boot 的物流运单管理系统后端设计与实现(JWT + MyBatis-Plus + MySQL)
spring boot·mysql·mybatis
步行cgn10 小时前
YAML 的语法规则
spring boot·后端
骇客野人11 小时前
SpringBoot电商系统用户注册、登录、留存及数据埋点设计与落地实施方案
java·spring boot·后端
摇滚侠11 小时前
《SpringBoot 3:入门与应用实战》第 12 章 JDBC 与事务 数据库初始化机制 阅读笔记 36
数据库·spring boot·笔记
霸道流氓气质11 小时前
Spring AI 输出解析器进阶
人工智能·windows·spring
wxwx_bscxy32212 小时前
基于Python新冠疫情可视化分析系统的设计与实现
java·数据库·spring boot·python·微信小程序·sqlite
leonkay15 小时前
C# 锁机制——【2】深入原理
开发语言·后端·spring·c#·个人开发