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; } }

演示

相关推荐
小强库计算机毕业设计4 小时前
SpringBoot+Vue3 学生宿舍管理系统实战
java·spring boot·后端·vue·学生宿舍管理系统
lv__pf6 小时前
spring之整合mybatis【TL spring 12】
mysql·spring·mybatis
AI人工智能+电脑小能手7 小时前
大白话说Java设计模式-17-装饰器模式(源码剖析篇)
java·spring·设计模式·装饰器模式·源码分析·io流
counting money12 小时前
Spring AI Alibaba 从入门到实战:构建企业级 AI 应用
java·人工智能·spring
城管不管13 小时前
MySQL 慢查询完整排查
java·服务器·jvm·数据库·mysql·spring·面试
风流 少年1 天前
Spring AI 2.0:Memory
java·后端·spring
Java成神之路-1 天前
Spring Cloud 微服务契约先行:为什么 Controller 建议要实现 Feign 接口?
spring·spring cloud·微服务
Flittly1 天前
【雕虫大技】Agent 动态 Skill 供应链安全加固(三):输出校验与治理闭环实战
java·spring boot·spring
风流 少年1 天前
Spring AI 2.0:MCP
java·后端·spring