Java AI - Spring AI基础入门:常见组件、常规对话、流式对话、基于Redis的会话记忆【含源码】

张开发
2026/5/24 10:52:24 15 分钟阅读
Java AI - Spring AI基础入门:常见组件、常规对话、流式对话、基于Redis的会话记忆【含源码】
Spring AI参考网址https://spring.p2hp.com/index.htmlhttps://spring.io/projects/spring-ai介绍Spring AI 是一款 AI 工程领域的应用程序框架,核心是将 Spring 生态的可移植性、模块化等设计原则延伸至 AI 领域,推广以 POJO 作为 AI 应用的构建块。它提供了开发 AI 大模型应用所需的基础抽象模型及多种实现方式,支持开发者以少量代码改动完成组件替换,同时具备友好的 API,最终目的是简化 AI 大模型应用的开发流程。Spring AI 的主要功能对主流 AI 大模型供应商提供了支持,比如:OpenAI、DeepSeek、Microsoft、Ollama、Amazon、Google HuggingFace 等。支持 AI 大模型类型包括:聊天、文本到图像、文本到声音等。支持主流的 Embedding Models(嵌入模型)和向量数据库,比如:Azure Vector Search、Chroma、Milvus、Neo4j、Redis、PineCone、PostgreSQL/PGVector 等。把 AI 大模型输出映射到简单的 Java 对象(POJOs)上。支持了函数调用 (Function Calling) 功能。为数据工程提供 ETL(数据抽取、转换和加载)框架。支持 Spring Boot 自动配置和快速启动,便于运行 AI 模型和管理向量库。Chat API注底层厂商的请求格式、认证方式、响应解析等细节。简单说:Spring AI Chat API 是开发者与 LLM 之间的 “翻译官” 和 “统一接口”,让你写一次代码,就能适配多个大模型。核心定位与解决的问题在 Spring AI 出现前,对接不同大模型需要处理:不同厂商的请求参数(如 OpenAI 的 messages vs Anthropic 的 prompt);认证方式差异(API Key、OAuth 等);响应格式解析(不同结构的 JSON 结果);流式 / 非流式调用的实现差异;对话上下文管理(多轮对话的历史消息维护)。Spring AI Chat API 统一了这些差异,提供:标准化的 “请求 - 响应” 模型;内置的对话上下文管理;一致的流式 / 非流式调用接口;可插拔的大模型适配(通过 ChatClient 实现);与 Spring 生态(如 Spring Boot、依赖注入)无缝集成。核心概念ChatClient:作为各主流大模型的标准化客户端抽象,核心职责是封装与底层模型的通信逻辑,包括请求的构建与发送、响应的接收与解析,是开发者与大模型交互的统一入口。Prompt:对话请求的顶层封装载体,内部聚合了两类核心要素:一是构成对话内容的Message集合,二是影响模型生成行为的配置选项(Option)。Message:对话交互的基础数据单元,不仅承载着待传递给大模型的具体内容,还包含角色标识(如用户、系统、助手)、附加属性等元信息,同时通过明确的类型划分(如用户消息、系统提示、工具反馈消息)适配不同交互场景。Option:模型生成过程的参数配置项,用于精细化控制输出效果。例如temperature参数(取值范围通常为 0-1),其值越低,模型输出越聚焦事实、严谨一致;值越高,则输出越具随机性与创造性。ChatResponse:大模型响应结果的统一封装对象,内部聚合了生成结果、响应元数据(如调用耗时、Token 统计)等核心信息,其中核心数据为Generation。Generation:封装了大模型生成的具体业务内容,是ChatResponse中最核心的有效数据载体,直接对应开发者所需的模型输出结果。三个层次前面我们知道SpringAI支持大模型的多种能力,聊天只是其中一种,因此就有一个代表最顶层的抽象层,与大模型有关的各种能力,都在此有个定义,然后是代表各种能力的抽象层,如聊天、图片、嵌入式处理等,最后是每一种能力在各类具体大模型上的实现,如下图所示到现在为止咱们还没有看一行代码一个API,但是从理论上对Chat API的定位、关系已经基本了解了官方示意图最下面橙色这层,中间是client,这里有两种,ModelClient代表了常规的请求响应,StreamingModelClient代表了流式响应(数据并非一次性传输,而是建立链接后源源不断的输出)client的左侧是request,里面包含了option,至于prompt,那是Chat的概念,所以不会出现在橙色这一层client右侧是response,同样只有抽象的ResponseMeta和ResultMetaData,generation是Chat的概念,不会在橙色这一层出现再往上看,绿色的就是功能抽象层了,ChatClient继承了ModelClient,Prompt继承了ModelRequest,代表Chat领域的请求,同理CharResponse继承了ModelResponse有了理论基础,一张官方图就让我们看清了Chat API的大概,现在还缺点东西,就是具体的实现层,毕竟有很多种大模型能,最终编码时还是要用到实现层的类,有没有什么方式将实现层完美的展现出来?实现层和功能抽象层的关系这张图是 Spring AI 中 ChatClient 相关组件的类层级与接口继承关系图,核心呈现了 “通用 API 抽象 → 专用接口 → 厂商具体实现” 的设计架构,清晰展示了 Spring AI 如何通过标准化接口统一不同大模型的对话调用能力,以下是详细拆解:一、核心架构层级(从上到下:抽象→实现)图中组件按 “通用抽象 → 专用扩展 → 厂商适配” 分为 3 个核心层级,每层职责明确:1. 最顶层:通用模型 API 抽象(基础接口)定义了所有 AI 模型交互的通用规范,不局限于 “对话” 场景,是 Spring AI 统一接口设计的根基:ModelClient:核心定位:通用模型 API 顶层接口,支持所有模型类型(文本、图像、音频等)的同步调用。核心方法:call(TReq) : TResp(接收泛型请求 TReq,返回泛型响应 TResp),实现 “输入 - 输出” 的标准化映射。StreamingModelClient:核心定位:通用流式模型 API 接口,继承自通用模型 API 的设计思路,专注于 “流式响应” 场景。核心方法:streamingCall(TReq) : Flux(返回响应式编程的 Flux 流,支持逐段接收模型输出,如 ChatGPT 打字效果)。2. 中间层:对话专用 API 接口(功能扩展)基于顶层通用 API,针对 “对话交互” 场景做专项抽象,屏蔽非对话模型的无关能力,聚焦聊天场景需求:ChatClient:核心定位:通用对话完成 API 接口,继承自 ModelClient 的设计思想(图中 “IS A” 表示继承关系),专门用于非流式对话调用。核心方法:call(Prompt) : ChatResponse(输入为 Spring AI 标准化的 Prompt 对象,输出为对话专用的 ChatResponse,适配多轮对话、角色消息等场景)。StreamingChatClient:核心定位:流式对话 API 接口,继承自 StreamingModelClient 的设计思路,专门用于流式对话调用。核心方法:call(Prompt) : Flux(输入为 Prompt,输出为 ChatResponse 的 Flux 流,支持实时接收对话响应)。3. 最底层:厂商具体实现类(落地适配)针对不同大模型厂商的对话模型,提供 ChatClient 或 StreamingChatClient 的具体实现,是开发者实际使用的 “厂商专属客户端”,无需关注底层调用细节:图中包含 11 个主流厂商 / 平台的实现类,覆盖云厂商、开源模型、本地部署模型等场景:OpenAI 生态:OpenAiChatClient(OpenAI 原生模型,如 GPT-3.5/4)、AzureOpenAiChatClient(Azure 托管的 OpenAI 模型)。Google 生态:VertexAiPaLm2ChatClient(Google Vertex AI 上的 PaLM 2 模型)、VertexAiGeminiChatClient(Google Vertex AI 上的 Gemini 模型)。AWS Bedrock 生态:BedrockAnthropicChatClient(Bedrock 上的 Anthropic Claude 模型)、BedrockTitanChatClient(Bedrock 上的 Titan 模型)、BedrockLlama2ChatClient(Bedrock 上的 Llama 2 模型)、BedrockCohereChatClient(Bedrock 上的 Cohere 模型)。开源 / 本地模型:MistralAiChatClient(Mistral 开源模型)、HuggingfaceChatClient(Hugging Face 开源模型,如 BERT、GPT-2)、OllamaChatClient(Ollama 本地部署模型,如 Llama 2、Mistral 本地版)。二、核心设计思想与价值这张图直观体现了 Spring AI 的核心设计理念:接口抽象解耦:通过 ModelClient/ChatClient 等顶层接口定义标准,厂商实现类专注于 “适配自身 API”,开发者依赖接口编程,无需修改代码即可切换模型。流式与非流式分离:将 “同步单次响应”(ChatClient)与 “流式增量响应”(StreamingChatClient)拆分为两个接口,适配不同业务场景(如简单问答用非流式,实时聊天用流式)。覆盖全场景模型:实现类涵盖云厂商(OpenAI、Azure、Google、AWS)、开源社区(Hugging Face、Mistral)、本地部署(Ollama),满足不同用户的模型选择需求。核心类和接口ChatClient大模型聊天功能的客户端接口,在进程中,其实现就是各大模型对应的客户端类主要是call方法,这就是最常规的聊天功能,调用call发送请求,返回值就是大模型的响应StreamingChatClient这也是客户端类,用于调用大模型的功能,与ChatClient不同的是,ChatClient是请求响应,返回对象ChatResponse就是大模型返回的全部内容,而StreamingChatClient返回的是Flux,这是流式返回,可以讲大模型的响应进行流式输出,如果您使用过各种大模型聊天工具,会发现响应的内容并非一次性展现,而是一段一段的内容,持续不断的展现出来,这就是流式响应的效果注意注解FunctionalInterface,表明这是个函数式接口Prompt前面看过了ChatClient和StreamingChatClient,会发现入参都是Prompt,可见这就是和大模型一次聊天的入参下面是Prompt的源码,去掉了构造函数、toString这些之后就会发现,最重要的是Message和ChatOption,所以Prompt只是个打包,真正要提交到大模型的其实是Message和ChatOption如果您对OpenAI有所了解,就知道prompt(提示词)并非只有用户输入的聊天内容那么简单,而是system、user 、assistant等多种类型 ,所以这里的Prompt并非只是一个外壳那么简单,它与不同类型的message、不同的辅助类等一起提供了完善的提示词功能,这个会有单独的文章来说明和实战,本篇只要记得它的最终形态就是打好的包用于提交给大模型如果只是最基本的聊天,下面这个构造方法来创建对象就行了publicPrompt(Stringcontents){this(newUserMessage(contents));}MessageMessage很好理解:在聊天过程中,聊天内容对应的对象,请求和响应用的都是Message,不过由于消息类型的多样性,Message被设计成了接口,根据不同类型都有对应的实现Message自身非常简单,能保证使用方取到消息内容、类型即可另外要注意的是消息类型,一共四种publicenumMessageType{USER("user"),ASSISTANT("assistant"),SYSTEM("system"),FUNCTION("function");}ChatOptionsChatOptions代表可以传递给大模型的控制参数,具体有哪些参数和大模型自身开放的特性有关,举个例子,下面是OpenAI开放的参数presencePenalty : 影响模型在生成文本时重复词语或概念的倾向frequencyPenalty:影响模型在生成文本时对已出现过词语的偏好程度按照上面的解释,既然各种大模型都有自己的参数,那么设计ChatOptions能干啥?应该能放一些通用的控制参数吧,打开代码一看果然如此,共有三个通用参数。/** * The ChatOptions represent the common options, portable across different chat models. */publicinterfaceChatOptionsextendsModelOptions{// 大模型生成的内容应该更严谨还是更有创造性FloatgetTemperature();// 返回概率超过P的所有内容FloatgetTopP();// 返回概率最高的前K个内容IntegergetTopK();}ChatOptions只是接口,对应的实现是ChatOptionsImpl,源码没啥好看的,就是temperature、topP、topK的get和set而已,为了实例化ChatOptionsImpl,还有配套工具ChatOptionsBuilder,用法如下ChatOptionsportablePromptOptions=ChatOptionsBuilder.builder().withTemperature(0.9f).withTopK(100).withTopP(0.6f).build();ChatResponse看完请求该看响应了,既然Generation才是真正的响应内容,那么ChatResponse也就是个壳,里面包了Generation,打开源码一看,只有Generation和ChatResponseMetadata,这个ChatResponseMetadata可以理解为元信息,主要返回了大模型的API的使用情况说明,以及限速的详细信息publicclassChatResponseimplementsModelResponseGeneration{privatefinalChatResponseMetadatachatResponseMetadata;privatefinalListGenerationgenerations;@OverridepublicChatResponseMetadatagetMetadata(){...}@OverridepublicListGenerationgetResults(){...}// other methods omitted}GenerationGeneration中有响应的具体信息,由ChatGenerationMetadata和AssistantMessage组成publicclassGenerationimplementsModelResultAssistantMessage{privateAssistantMessageassistantMessage;privateChatGenerationMetadatachatGenerationMetadata;@OverridepublicAssistantMessagegetOutput(){...}@OverridepublicChatGenerationMetadatagetMetadata(){...}// other methods omitted}ChatGenerationMetadata代表返回内容的元信息,包含了结束原因、生成内容的过滤规则AssistantMessage更容易理解了:类型是ASSISTANT的消息,这个assistant就是助理角色,assistant消息就是大模型返回的聊天响应,源码如下publicclassAssistantMessageextendsAbstractMessage{publicAssistantMessage(Stringcontent){super(MessageType.ASSISTANT,content);}publicAssistantMessage(Stringcontent,MapString,Objectproperties){super(MessageType.ASSISTANT,content,properties);}@OverridepublicStringtoString(){return"AssistantMessage{"+"content='"+getContent()+'\''+", properties="+properties+", messageType="+messageType+'}';}}示例代码同步对话后端代码依赖propertiesjava.version17/java.versionproject.build.sourceEncodingUTF-8/project.build.sourceEncodingproject.reporting.outputEncodingUTF-8/project.reporting.outputEncodingspring-boot.version3.3.4/spring-boot.versionspring-ai.version1.0.0-M6/spring-ai.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-openai-spring-boot-starter/artifactIdversion${spring-ai.version}/version/dependencydependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-core/artifactIdversion${spring-ai.version}/version/dependencydependencygroupIdcom.alibaba.fastjson2/groupIdartifactIdfastjson2/artifactIdversion2.0.55/version/dependency/dependenciesdependencyManagementdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-dependencies/artifactIdversion${spring-boot.version}/versiontypepom/typescopeimport/scope/dependencydependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-bom/artifactIdversion${spring-ai.version}/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagementapplication.yml主配置文件spring:ai:openai:base-url:https://dashscope.aliyuncs.com/compatible-mode# 基础 URLapi-key:sk-a4ea34ca69f********91167245b1# 百炼大模型API 密钥chat:options:model:qwen-plus# 模型名称temperature:0.1# 温度,控制生成文本的随机性,默认值为 0.1, 范围为 [0.0, 1.0], 较高的温度会使生成的文本更加随机,而较低的温度会使生成的文本更加确定max-tokens:2000# 最大令牌数,控制生成文本的长度,默认值为 2000, 范围为 [100, 4000]main:allow-bean-definition-overriding:truedatasource:driver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://localhost:3306/mall_116?useUnicode=truecharacterEncoding=utf8serverTimezone=UTCusername:rootpassword:root1234server:port:8080logging:level:org.springframework.ai:DEBUGcom.woniuxy.spring.ai.base:DEBUG温度 (Temperature)是控制生成文本随机性与创造性的核心参数,数值越高输出越灵活多样,越低则越确定、保守。1.核心作用本质是调节模型采样概率:低温时,模型优先选择概率最高的词;高温时,会放大低概率词的选中概率。直接影响输出风格:是 “按规矩作答” 还是 “自由发挥” 的关键开关。2.数值范围与效果低温(0–0.3):输出高度确定、精准,重复率可能较高。适合场景:事实问答、代码生成、专业文档撰写等需要准确的场景。中温(0.4–0.7):平衡准确性与创造性,输出自然流畅。适合场景:日常对话、文案创作、邮件撰写等多数通用场景。高温(0.8–1.0):输出随机性强,充满创意但可能偏离主题、逻辑跳跃。适合场景:诗歌创作、脑洞故事、营销创意发散等需要突破常规的场景。3.关键注意点数值并非越高越好,过高可能导致输出无意义、逻辑混乱。不同模型的 Temperature 基准略有差异,但核心逻辑一致。聊天配置类importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.ai.chat.model.ChatModel;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassChatConfig{@BeanpublicChatClientchatClient(ChatModelchatModel){returnChatClient.builder(chatModel).build();}}同步聊天服务接口publicinterfaceChatService{publicStringchat(Stringmessage);}服务实现类importcom.woniuxy.spring.ai.base.memory.RedisChatMemory;importcom.woniuxy.spring.ai.base.service.ChatRecordService;importcom.woniuxy.spring.ai.base.service.ChatService;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.stereotype.Service;@Slf4j@Service@RequiredArgsConstructorpublicclassChatServiceImplimplementsChatService{privatefinalChatClientchatClient;privatefinalRedisChatMemoryredisChatMemory;privatefinalChatRecordServicechatRecordService;/** * 同步对话 */@OverridepublicStringchat(Stringmessage){log.info("发送消息到阿里百炼: {}",message);Stringresponse=chatClient.prompt(message).call().content();log.info("收到阿里百炼响应: {}",response);returnresponse;}}控制层接口importcom.woniuxy.woniuspringai.service.ChatService;importlombok.RequiredArgsConstructor;importorg.springframework.http.MediaType;importorg.springframework.web.bind.annotation.*;importreactor.core.publisher.Flux;importjava.util.Map;@RestController@RequestMapping("/api/ai")@RequiredArgsConstructorpublicclassChatController{privatefinalChatServicechatService;/** * 同步对话 */@PostMapping("/chat")publicMapString,Stringchat(@RequestBodyMapString,Stringrequest){Stringmessage=request.get("message");Stringresponse=chatService.chat(message);returnMap.of("response",response);}}跨域配置importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.cors.CorsConfiguration;importorg.springframework.web.cors.UrlBasedCorsConfigu

更多文章