初识SpringAl:Chat篇
一、AI应用开发技术架构
1.纯Prompt问答
用户直接向AI应用进行提问,AI应用拿到提示词后进行整理分析后传给大模型,大模型将结果返还给AI应用最后给到用户。类似于我们平时的直接对话
利用大模型推理能力完成应用的核心功能
应用场景:
- 文本摘要分析
- 舆情分析
- 坐席检查
- AI对话

2.Agent+Function Calling
当我们的需求中涉及到业务的实现,比如让AI生成一份旅行计划,并根据计划给我们订酒店。如:千问给我们订外卖
将应用端业务能力与AI大模型推理能力结合,简化复杂业务功能开发
应用场景:
- 旅行指南
- 数据提取
- 数据聚合分析
- 课程顾问

3.RAG Embeddings(知识库拓展)
大模型的知识是通过历史的数据训练来的。如果要大模型生成发布之后的事情,很有可能大模型就不知道,RAG相当于给大模型一本教材,让它根据这本教材进行学习。
离线步骤:
- 文档加载
- 文档切分
- 文档编码
- 写入知识库
在线步骤:
- 获得用户问题
- 检索知识库中相关知识片段
- 将检索结果和用户问题填入Prompt模版
- 用最终获得的Prompti调用LLM
- 由LLM生成回复
应用场景:
- 个人知识库
- AI客服助手

4.Fine-tuning(模型微调)
在大模型实在不如人意的时候,自己调试大模型。一般实现不了
二、java语言中当下最热门的两个框架
当下最热门的两个框架:springAI和langchain4j

他们的异同:

SpringAI是Spring出版的,所以适配了SpringBoot等,要求jdk高一些
LangChain4j是python中LangChain框架出版的,更适用于低版本
因为spring是专门为java开发的框架,所以更新会很快,更适用于新的大模型,并且更能无缝接入springboot项目
三、SpringAI
快速入门
1.引入依赖
▼xml复制代码<!-- Spring AI 版本管理(必须) --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>1.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- Spring AI 核心(所有模型通用) --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-core</artifactId> </dependency> <!-- OpenAI(ChatGPT) --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> </dependency> <!-- 阿里云通义千问 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-qwen-spring-boot-starter</artifactId> </dependency> <!-- 百度文心一言 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-wenxin-spring-boot-starter</artifactId> </dependency> <!-- 字节跳动豆包 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-doubao-spring-boot-starter</artifactId> </dependency> <!-- 讯飞星火 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-spark-spring-boot-starter</artifactId> </dependency>
2.配置化
▼xml复制代码spring: ai: # 通义千问(阿里) qwen: api-key: sk-你的APIKey chat: options: model: qwen-turbo temperature: 0.7 # 豆包(字节) doubao: api-key: sk-你的APIKey chat: options: model: doubao-lite-4k temperature: 0.7 # OpenAI openai: api-key: sk-你的APIKey base-url: https://api.openai.com chat: options: model: gpt-3.5-turbo temperature: 0.7 # 文心一言(百度) wenxin: api-key: 你的APIKey secret-key: 你的SecretKey chat: options: model: ernie-3.5-8k # 讯飞星火 spark: api-key: 你的APIKey api-secret: 你的APISecret app-id: 你的APPID chat: options: model: generalv3
3.配置客户端
配置客户端

▼java复制代码@Configuration public class CommonConfiguration { @Bean public ChatClient chatClient(OllamaChatModel chatModel){ return ChatClient .builder(chatModel) .defaultSystem("你是小查,是我的智能助手,以后你要为我的生活、学习服务,请以小查的省份和语气回答问题") .build(); } }
阻塞式输出

这里springAI已经帮我们整理好了,call()方法用来调用大模型,content()用来将结果解析返回,不用我们自己解析。
流式输出

流式输出只需要把call()方法改为Stream()
会话日志
SpringAI利用AOP原理提供了AI会话时的拦截、增强等功能,也就是Advisor。
▼java复制代码@Configuration public class CommonConfiguration { @Bean public ChatClient chatClient(OllamaChatModel chatModel){ return ChatClient .builder(chatModel) .defaultSystem("你是小查,是我的智能助手,以后你要为我的生活、学习服务,请以小查的省份和语气回答问题") // 配置日志Advisor .defaultAdvisors(new SimpleLoggerAdvisor()) .build(); } }
▼xml复制代码logging: level: org.springframework.ai.chat.client.advisor: debug com.langdang.heimaai: debug
▼xml复制代码2026-05-10T17:21:33.719+08:00 DEBUG 29784 --- [heima-ai] [nio-8080-exec-1] o.s.a.c.c.advisor.SimpleLoggerAdvisor : request: ChatClientRequest[prompt=Prompt{messages=[SystemMessage{textContent='你是小查,是我的智能助手,以后你要为我的生活、学习服务,请以小查的省份和语气回答问题', messageType=SYSTEM, metadata={messageType=SYSTEM}}, UserMessage{content='你是谁', metadata={messageType=USER}, messageType=USER}], modelOptions=org.springframework.ai.ollama.api.OllamaChatOptions@717b7c3b}, context={}] 2026-05-10T17:21:46.626+08:00 DEBUG 29784 --- [heima-ai] [nio-8080-exec-1] o.s.a.c.c.advisor.SimpleLoggerAdvisor : response: { "result" : { "output" : { "messageType" : "ASSISTANT", "metadata" : { "messageType" : "ASSISTANT" }, "toolCalls" : [ ], "media" : [ ], "text" : "您好!我是由中国的深度求索(DeepSeek)公司开发的智能助手。我可以帮助您处理各种问题、提供信息和指导,您可以随时问我任何问题或请求帮助。" }, "metadata" : { "finishReason" : "stop", "contentFilters" : [ ], "empty" : false } }, "results" : [ { "output" : { "messageType" : "ASSISTANT", "metadata" : { "messageType" : "ASSISTANT" }, "toolCalls" : [ ], "media" : [ ], "text" : "您好!我是由中国的深度求索(DeepSeek)公司开发的智能助手。我可以帮助您处理各种问题、提供信息和指导,您可以随时问我任何问题或请求帮助。" }, "metadata" : { "finishReason" : "stop", "contentFilters" : [ ], "empty" : false } } ], "metadata" : { "id" : "", "model" : "deepseek-r1:7b", "rateLimit" : { "requestsRemaining" : 0, "requestsLimit" : 0, "requestsReset" : 0.0, "tokensLimit" : 0, "tokensRemaining" : 0, "tokensReset" : 0.0 }, "usage" : { "promptTokens" : 33, "completionTokens" : 240, "totalTokens" : 273 }, "promptMetadata" : [ ], "empty" : false } } 您好!我是由中国的深度求索(DeepSeek)公司开发的智能助手。我可以帮助您处理各种问题、提供信息和指导,您可以随时问我任何问题或请求帮助。
会话记忆
如果想让AI有对话记忆,其实就是靠存储它自己生成的回答再发给它来实现。

也就是把他自己的回答重新放到messages里


SpringAI已经提供了相应的存储对话id的接口

我们直接使用spring封装好的方法
▼java复制代码@Bean public ChatClient chatClient(OllamaChatModel chatModel, ChatMemory chatMemory) { return ChatClient.builder(chatModel) .defaultSystem("你是小查,是我的智能助手,以后你要为我的生活、学习服务,请以小查的身份和语气回答问题") .defaultAdvisors( new SimpleLoggerAdvisor(), // 直接用 builder(chatMemory) 构建,不额外指定 defaultConversationId MessageChatMemoryAdvisor.builder(chatMemory) .build() ) .build(); } @Bean public ChatMemory chatMemory() { return MessageWindowChatMemory.builder() .maxMessages(20) // 保留最近20轮对话 .build(); }
也就是加上这一段即可让对话有记忆
▼java复制代码// 直接用 builder(chatMemory) 构建,不额外指定defaultConversationId MessageChatMemoryAdvisor.builder(chatMemory) @Bean public ChatMemory chatMemory() { return MessageWindowChatMemory.builder() .maxMessages(20) // 保留最近20轮对话 .build(); }

但是一个正常的的AI软件肯定不是我一个人用,假设现在另一个问,如果2个人呢?他还会保持着原有的记忆。现在也就是记忆是没有边界的,是模糊的。
会话ID
▼java复制代码// 官方文档 https://springdoc.cn/spring-ai/api/chat-memory.html#_%E8%81%8A%E5%A4%A9%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%9A%84_memory @RequestMapping("/chat") public String chatModel(String prompt,String conversationId){ String content = chatClient.prompt() .user(prompt) .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId)) .call() .content(); System.out.println(content); return content; }
增加 .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
其中conversationId就是会话id


可以看到在会话id相同时候是有记忆的
但是如果我更换了会话id呢?

他就懵了
这是因为springai的chatMemory方法是通过存储会话id(conversationId)和会话内容(message)来记录内容
会话记录



可以看到,这里的chatMemoryStore是一个map其中key为String,value是一个List泛型是一个message,
那么message是什么呢?


这里就不卖关子了,点进message后里面是一个接口,接口中MessageType是一个枚举,其中记录了发送人的类型和内容。
利用这一点,我们重写一个messageVO来展示发送人和发送内容

调用chatMemory的get()方法获取一个List,这个list里存储了发送人和发送内容

利用stream留将message转化成我们需要的类型即可获取到会话记录
