Spring AI实现一个简单的对话机器人

news/2025/11/30 15:19:47/文章来源:https://www.cnblogs.com/changelzj/p/19289343

在其他地方查看本文:Spring AI实现一个简单的对话机器人 - Liu Zijian's Blog - 一个个人博客网站

 

本文通过Spring AI基于DeepSeek大模型,以Prompt模式,开发一个智能聊天机器人,并进行对话。Spring AI必须基于jdk-21,因此需要先升级自己的JDK版本

基于jdk-21创建spring-boot项目,引入spring-boot依赖3.5.7,spring-ai依赖1.0.3,以及整合DeepSeek的spring-ai-starter-model-deepseek

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.5.7</version>
</parent><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>1.0.3</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-deepseek</artifactId></dependency>
</dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>21</source><target>21</target><encoding>UTF-8</encoding></configuration></plugin></plugins>
</build>

application.yml配置中进行配置,并填写DeepSeek的API_KEY,我是从DeepSeek官方(https://platform.deepseek.com/)购买获得,充值后,可以从https://platform.deepseek.com/api_keys页面获得API_KEY

⚠ 为防止误提交代码到公开仓库,spring文档建议将API_KEY写进本机环境变量,yml中设置为api-key: ${DEEPSEEK_API_KEY}

更多配置项,可见官方文档:https://docs.spring.io/spring-ai/reference/api/chat/deepseek-chat.html

spring:ai:deepseek:base-url: https://api.deepseek.comapi-key: sk-02**********************d8666

1.ChatClient

编写一个配置类,声明一个对话客户端,并且注入配置好的DeepSeek模型,通过defaultSystem()来指定大模型的默认角色和任务背景

package org.example;import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class ModelConfig {@Beanpublic ChatClient chatClient(DeepSeekChatModel model) {return ChatClient.builder(model).defaultSystem("你是聪明的智能助手,名字叫小羊").build();}
}

在controller中调用

package org.example.controller;import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;@RestController
@RequestMapping("ai")
public class ChatController {@Resourceprivate ChatClient chatClient;@GetMapping(value = "chat-stream")public String stream(String msg) {return chatClient.prompt().user(msg).call().content();}}

通过call()是阻塞的调用,在http请求中使用会出现无限等待的情况,如果要实现不断输出的效果,需要web环境下使用stream()流式调用返回Flux,并设置返回格式为text/html;charset=utf-8,否则输出的中文是乱码

package org.example.controller;import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;@RestController
@RequestMapping("ai")
public class ChatController {@Resourceprivate ChatClient chatClient;@GetMapping(value = "chat-stream", produces = "text/html;charset=utf-8")public Flux<String> stream(String msg) {return chatClient.prompt().user(msg).stream().content();}}

通过使用stream()流式调用返回Flux,可以得到以下效果的输出

2.Advisor

Spring AI通过Advisor(https://docs.spring.io/spring-ai/reference/api/advisors.html)接口提供了会话的增强功能,可以利用其开发更加高级的会话功能

Advisor接口主要用到以下实现类:

  • org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor 简单的日志打印功能
  • org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor 可以实现会话记忆
  • org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor 与RAG知识库功能有关

在使用QuestionAnswerAdvisor时,需要额外添加依赖:

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>

可以在创建ChatClient的时候就指定默认的Advisor为SimpleLoggerAdvisor实现输出日志功能

@Bean
public ChatClient chatClient(DeepSeekChatModel model) {return ChatClient.builder(model).defaultAdvisors(new SimpleLoggerAdvisor()).defaultSystem("你是聪明的智能助手,名字叫小羊").build();
}

SimpleLoggerAdvisor日志级别默认为DEBUG,如果要使用SimpleLoggerAdvisor打印日志到控制台,需要修改yml配置文件中的日志级别:

logging:level:org.springframework.ai: debug

大模型不具备记忆能力,要想让大模型记住之前的聊天内容,唯一的办法是把之前的聊天内容和新的提示词一并发送给大模型,此时就需要用到MessageChatMemoryAdvisor

使用MessageChatMemoryAdvisor,需要先定义一个ChatMemory接口的实现,来自定义管理会话数据的逻辑(添加,获取,删除),比如可以自己选择维护会话数据到mysql,redis,或者Map中

org.springframework.ai.chat.memory.ChatMemory

public interface ChatMemory {String DEFAULT_CONVERSATION_ID = "default";String CONVERSATION_ID = "chat_memory_conversation_id";default void add(String conversationId, Message message) {Assert.hasText(conversationId, "conversationId cannot be null or empty");Assert.notNull(message, "message cannot be null");this.add(conversationId, List.of(message));}void add(String conversationId, List<Message> messages);List<Message> get(String conversationId);void clear(String conversationId);
}

Spring AI为我们默认实现了一个实现类InMemoryChatMemoryRepository,可将会话保存到本地内存中用于测试,如果我们没有自定义ChatMemory实现类注入,默认的InMemoryChatMemoryRepository将会注入

此处,为了测试功能,就以默认的InMemoryChatMemoryRepository为例

@Bean
public ChatClient chatClient(DeepSeekChatModel model, ChatMemory chatMemory) {return ChatClient.builder(model).defaultAdvisors(SimpleLoggerAdvisor.builder().build(),MessageChatMemoryAdvisor.builder(chatMemory).build()).defaultSystem("你是聪明的智能助手,名字叫小羊").build();
}

Controller的代码需要用户发起聊天时,调用接口传入会话的ID:chatId,并通过.advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, chatId))传递给chatClient

@GetMapping(value = "chat-stream", produces = "text/html;charset=utf-8")
public Flux<String> stream(String msg, String chatId) {return chatClient.prompt().user(msg).advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, chatId)).stream().content();}

然后测试,先指定会话ID为001,先后两次分别提问“40除以2等于几”和“那除以5呢”,会发现第二次提问没有带上40也得到了正确答案8,再将ID改为002继续问“那乘以3呢”,大模型随即忘记了数字40,失去了记忆,这说明大模型此时通过MessageChatMemoryAdvisor增强,已经有了记忆,并且能够根据不同的会话进行区分!



以“40除以2等于几”和“那除以5呢”这两个问题为例,分析请求日志,其中,messageType=USER的消息代表的是用户的提问,messageType=ASSISTANT代表的是大模型的回复,messageType=SYSTEM代表的则是系统指令,请求日志是这样的:第二个问题并不直接发问,而是将第一个问题的回答的会话历史记录也一并带上在询问第二个问题。这样,自动将整个会话历史回传给大模型从而形成记忆的功能由MessageChatMemoryAdvisor实现了

2025-10-27T20:20:09.211+08:00 DEBUG 19240 --- [oundedElastic-1] o.s.a.c.c.advisor.SimpleLoggerAdvisor    : request: ChatClientRequest[prompt=Prompt{messages=[SystemMessage{textContent='你是聪明的智能助手,名字叫小羊', messageType=SYSTEM, metadata={messageType=SYSTEM}}, UserMessage{content='messageType=40除以2等于几', metadata={messageType=USER}, messageType=USER}], modelOptions=org.springframework.ai.deepseek.DeepSeekChatOptions@34422e1f}, context={chat_memory_conversation_id=111}]
2025-10-27T20:20:12.391+08:00 DEBUG 19240 --- [oundedElastic-2] o.s.a.c.c.advisor.SimpleLoggerAdvisor    : response: {"result" : {"output" : {"messageType" : "ASSISTANT","metadata" : {"finishReason" : "STOP","id" : "f08c10a5-8bb5-4cda-9c1c-43087452f826","role" : "ASSISTANT","messageType" : "ASSISTANT"},"toolCalls" : [ ],"media" : [ ],"text" : "40 除以 2 等于 **20**。  \n如果你有其他问题,随时问我哦! 😊"},"metadata" : {"finishReason" : "STOP","contentFilters" : [ ],"empty" : true}},"metadata" : {"id" : "f08c10a5-8bb5-4cda-9c1c-43087452f826","model" : "deepseek-chat","rateLimit" : {"tokensReset" : 0.0,"tokensLimit" : 0,"requestsReset" : 0.0,"requestsLimit" : 0,"tokensRemaining" : 0,"requestsRemaining" : 0},"usage" : {"promptTokens" : 21,"completionTokens" : 22,"totalTokens" : 43,"nativeUsage" : {"promptTokens" : 21,"totalTokens" : 43,"completionTokens" : 22}},"promptMetadata" : [ ],"empty" : true},"results" : [ {"output" : {"messageType" : "ASSISTANT","metadata" : {"finishReason" : "STOP","id" : "f08c10a5-8bb5-4cda-9c1c-43087452f826","role" : "ASSISTANT","messageType" : "ASSISTANT"},"toolCalls" : [ ],"media" : [ ],"text" : "40 除以 2 等于 **20**。  \n如果你有其他问题,随时问我哦! 😊"},"metadata" : {"finishReason" : "STOP","contentFilters" : [ ],"empty" : true}} ]
}
2025-10-27T20:20:25.739+08:00 DEBUG 19240 --- [oundedElastic-2] o.s.a.c.c.advisor.SimpleLoggerAdvisor    : request: ChatClientRequest[prompt=Prompt{messages=[UserMessage{content='messageType=40除以2等于几', metadata={messageType=USER}, messageType=USER}, AssistantMessage [messageType=ASSISTANT, toolCalls=[], textContent=40 除以 2 等于 **20**。  
如果你有其他问题,随时问我哦! 😊, metadata={finishReason=STOP, id=f08c10a5-8bb5-4cda-9c1c-43087452f826, role=ASSISTANT, messageType=ASSISTANT}], SystemMessage{textContent='你是聪明的智能助手,名字叫小羊', messageType=SYSTEM, metadata={messageType=SYSTEM}}, UserMessage{content='messageType=那除以5呢', metadata={messageType=USER}, messageType=USER}], modelOptions=org.springframework.ai.deepseek.DeepSeekChatOptions@34422e1f}, context={chat_memory_conversation_id=111}]
2025-10-27T20:20:27.328+08:00 DEBUG 19240 --- [oundedElastic-1] o.s.a.c.c.advisor.SimpleLoggerAdvisor    : response: {"result" : {"output" : {"messageType" : "ASSISTANT","metadata" : {"finishReason" : "STOP","id" : "81223274-c38b-4d65-b88c-8811abfc743d","role" : "ASSISTANT","messageType" : "ASSISTANT"},"toolCalls" : [ ],"media" : [ ],"text" : "40 除以 5 等于 **8**。  \n有其他问题的话,继续问我吧! 😃"},"metadata" : {"finishReason" : "STOP","contentFilters" : [ ],"empty" : true}},"metadata" : {"id" : "81223274-c38b-4d65-b88c-8811abfc743d","model" : "deepseek-chat","rateLimit" : {"tokensReset" : 0.0,"tokensLimit" : 0,"requestsReset" : 0.0,"requestsLimit" : 0,"tokensRemaining" : 0,"requestsRemaining" : 0},"usage" : {"promptTokens" : 54,"completionTokens" : 22,"totalTokens" : 76,"nativeUsage" : {"promptTokens" : 54,"totalTokens" : 76,"completionTokens" : 22}},"promptMetadata" : [ ],"empty" : true},"results" : [ {"output" : {"messageType" : "ASSISTANT","metadata" : {"finishReason" : "STOP","id" : "81223274-c38b-4d65-b88c-8811abfc743d","role" : "ASSISTANT","messageType" : "ASSISTANT"},"toolCalls" : [ ],"media" : [ ],"text" : "40 除以 5 等于 **8**。  \n有其他问题的话,继续问我吧! 😃"},"metadata" : {"finishReason" : "STOP","contentFilters" : [ ],"empty" : true}} ]
}

需要注意,当前使用的InMemoryChatMemoryRepository将会话保存在内存,进程结束即销毁,如果正式的项目需要换成其他的实现来真正的持久化,而且会话的ID应该后台生成并和当前登录用户绑定,而不是由前端随便的传进去。

如果需求包括逐条加载和查看审批历史,可以根据ChatMemory的List<Message> get(String conversationId);方法,传入对话的ID即可获得,返回的List<Message>对象可以进一步包装成自己业务需要的对象数据格式。

package org.example.controller;import jakarta.annotation.Resource;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("ai")
public class ChatController {@Resourceprivate ChatMemory chatMemory;@GetMapping(value = "chat-history")public List<Message> history(String chatId) {return chatMemory.get(chatId);}}

如果要获得某个用户的所有会话以及会话历史,只需要发起会话时自己记录会话ID到数据库,到时候在查出返回即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/981946.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

惠算科技 GEO 优化优选惠州本地生活推荐:生成式引擎优化时代的本地商家获客破局指南

在惠州本地生活领域,生成式引擎优化(GEO)正展现出巨大的市场潜力。据相关数据显示,惠州本地生活 GEO 市场规模近年来以每年 30% 的增长率快速扩张。像惠算科技 GEO、一些知名的 AI 搜索优化工具以及具备意图识别功…

Genie 2:大规模基础世界模型的技术突破

本文介绍了Genie 2基础世界模型的技术架构与能力,这是一个能够从单张提示图像生成可交互3D环境的扩散模型。模型支持键盘鼠标控制,具备长时记忆、物理模拟、角色动画等能力,为具身智能体训练提供无限多样的虚拟环境…

薄壁镀锌方管生产厂TOP5权威推荐:服务不错的镀锌方管工厂甄

建筑工程中,薄壁镀锌方管因防腐性强、自重轻、安装便捷等优势,成为轻钢结构、幕墙、物流货架等场景的核心选材。2024年数据显示,国内薄壁镀锌方管市场需求同比增长32%,但41%的工程投诉集中在材质不符规格缺失售后滞…

2025年靠谱的雕塑定制品牌企业推荐,现代雕塑定制设计哪家好

在城市更新与文化建设的浪潮中,一座独具匠心的雕塑不仅是空间的点睛之笔,更是城市精神与品牌文化的具象表达。面对市场上良莠不齐的雕塑定制服务,如何找到兼具艺术创意、工艺实力与交付保障的合作伙伴?以下结合行业…

Xcode26新特性与iOS26适配指南

Xcode 26 作为苹果适配 iOS 26、macOS 15 等新一代系统的开发工具,在开发效率、AI 赋能、跨平台协同及性能优化上有显著升级;iOS 26 则带来了全新系统能力与合规要求,开发者需重点关注适配要点。以下是核心内容整理…

鸿蒙开发中,module.json5配置文件详解

module.json5 是鸿蒙系统中用于定义应用模块的核心配置文件。它包含模块的基本信息、入口能力、支持的设备类型、权限请求等内容,是应用开发和部署的基础。配置文件结构以下是一个典型的 module.json5 配置示例:{&qu…

茶叶商标购买平台指南:2025 哪个平台最好?从标源到过户一文说透

2025 年茶叶商标购买平台首选福象商标宝 AI(微信小程序) !综合标源真实性、交易安全性、过户效率、费用透明度及茶叶行业适配性五大维度测评,其以 9.9/10 的综合评分稳居榜首。依托福象知识产权集团的专业背景,凭…

2025年智能机械设备研发加工厂哪家更值得选?智能机械设备源

在智能制造升级浪潮下,企业对智能机械设备的自主化、高精度、高效率需求日益迫切。本文依托技术实力、客户口碑、行业适配性三大核心维度,筛选出五家标杆企业,为工业企业选型提供客观参考,助力破解卡脖子困境与生产…

2025年十大专业检测仪器公司排行榜,北京时代光南检测技术有

为帮企业高效锁定适配自身需求的检测仪器合作伙伴,避免选型走弯路,我们从产品技术精准度(如检测数据误差率、设备稳定性)、行业场景适配能力(含多领域定制化方案、极端环境耐受性)、全周期服务质量(覆盖设备选型…

2025年十大讲解机器人供应企业排名,讲解机器人哪家好

为帮助企业高效筛选适配自身场景的智能讲解机器人服务商,避开功能虚标、售后脱节、案例不符的选型陷阱,我们从售后服务质量(响应速度、质保政策、退换货保障)、成功案例适配性(垂直行业落地效果、场景覆盖广度)、…

2025年全国无损检测仪器服务商年度排名:北京时代光南检测技

TOP1推荐:北京时代光南检测技术有限公司 评价指数:★★★★★ 口碑评分:99分 行业表现:A++++级 介绍:北京时代光南检测技术有限公司是国内专业无损检测仪器领域的企业,深耕检测设备研发、销售与服务多年,始终以…

Spring AI实现一个智能客服

在其他地方查看本文:https://blog.liuzijian.com/post/spring-ai/2025/10/28/spring-ai-agent/ 1.引言 在大模型与大模型应用一文中曾经提到,大模型在回答一些专业的问题时,可以通过和传统应用的能力相互调用,使得…

字节跳动在GitHub上有哪些开源项目

字节跳动在GitHub上有哪些开源项目字节跳动在GitHub上有哪些开源项目最新推荐文章于 2025-06-21 13:16:04 发布原创 于 2025-04-23 15:44:05 发布 3.8k 阅读24 33 CC 4.0 BY-SA版权 版权声明:本文为博主…

跨端开发框架横评(跨平台前端框架)

跨端开发框架横评(跨平台前端框架)跨端开发框架横评(跨平台前端框架) 网友投稿 1918 2023-01-27 13:00:32 本篇文章给大家谈谈跨端开发框架横评,以及跨平台前端框架对应的知识点,希望对各位有所帮助,不要忘了收…

esbuild的作者

esbuild的作者 漫思

2025年口碑好的宁海食堂承包公司、企业食堂承包公司推荐:靠

本榜单依托宁波本地市场调研与真实企业合作口碑,深度筛选出五家标杆团膳服务企业,为企事业单位食堂托管选型提供客观依据,助力精准匹配适配的后勤服务伙伴。 TOP1 推荐:宁波星徽餐饮管理有限公司 推荐指数:★★★…

凸优化理论(三)

凸优化理论(三)证明:Simplex是Polyhedron的一种等价于:任意一种Simplex都可以用Polyhedron的定义形式表达出来 矩阵正定 \(\bm{A} \succ 0\)对称矩阵、对称半正定矩阵、对称正定矩阵,是不是凸集?定义证明1:\(S_…

高压电力金具厂家哪家好:权威推荐助选可靠加工伙伴

高压电力金具作为电力传输系统的神经枢纽,其质量直接关乎电网安全。2023年数据显示,国内高压金具市场规模超50亿元,年增速12%,但18%的电网故障源于金具失效——沿海地区盐雾腐蚀导致金具断裂,高山环境低温脆化引发…

上色步骤

1.填充固有色 2.给固有色做渐变 3.做二分 4.做暗中暗

2025年高光谱相机哪家好?年度十大高光谱相机厂商排名,专业

为帮助企业与科研机构精准筛选适配场景需求的高光谱相机合作伙伴,避免选型过程中因技术壁垒高、场景适配性不足走弯路,我们从核心技术自主化程度(芯片/算法自研占比、专利数量)、场景落地能力(工业/野外/实验室等…