智能聊天机器人-基于Spring AI实现

项目背景

随着⼈⼯智能技术的快速发展和⼤模型开源趋势的兴起,智能聊天机器⼈在客服、知识问答、⽣活助⼿ 等领域得到了⼴泛应⽤,我们接下来模仿这些应用实现一个智能的聊天机器人

核心功能

1.对话

  • 支持用户和机器人之间的对话
  • 实时响应用户的输入,进行回答

2.多轮对话

  • 能够理解和处理多轮对话,保持上下文的连续性
  • 支持基于上下文的智能应答

3.历史记录

  • 自动保存用户和机器人之间的对话历史
  • 支持用户查看历史的对话内容

页面设计

我们通过ollama搭建本地的大模型

首先添加本项目所需要的依赖

<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></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-ollama-spring-boot-starter</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>1.0.0-M6</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

配置.yml文件

spring:application:name: spring-ai-chatRobotai:
#    ollamaollama:base-url: http://127.0.0.1:11434chat:model: deepseek-r1:1.5b
logging:pattern:console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"file: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"level:org.springframework.ai.chat.client.advisor: debug  # 只针对 Spring AI 的 advisor

写出启动类

@SpringBootApplication
public class SpringChatRobotApplication {public static void main(String[] args) {SpringApplication.run(SpringChatRobotApplication.class,args);}
}

对话功能

定义请求的内容

@Beanpublic ChatClient chatClient(OllamaChatModel ollamaChatModel, ChatMemory chatMemory){return ChatClient.builder(ollamaChatModel).defaultSystem("你的名字是小瑞,你是一个智能聊天机器人").defaultAdvisors(new SimpleLoggerAdvisor(), new MessageChatMemoryAdvisor(chatMemory)).build();}
  @RequestMapping(value = "/stream",produces = "text/html;charset=utf-8")public Flux<String> stream(@RequestParam String prompt,String chatId){if (prompt == null || prompt.trim().isEmpty()) {return Flux.just(" message 参数不能为空!");}memoryChatHistoryRepository.save(prompt, chatId);return chatClient.prompt().user(prompt).advisors(spec -> spec.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)).stream().content();}
}

对话记忆(ChatMemory)

⼤型语⾔模型是⽆状态的,也就是它们不会保留有关以前交互的信息.当开发⼈员希望在多个交 互中维护上下⽂或状态时,这可能是⼀个限制.为了解决这个问题,SpringAI提供了对话内存功能,定义 了ChatMemory接⼝,允许开发⼈员在与⼤型语⾔模型的多次交互中存储和检索信息.

定义ChatMemory将其注入到ChatClient中

@Beanpublic ChatMemory chatMemory(){return new InMemoryChatMemory();}

向模型发送请求时,传递ChatId

历史对话

我们需要定义一个实体类表示历史对话

@Data
public class ChatInfo {private String title;private String chatId;public ChatInfo(String title, String chatId) {this.title = title==null?"无标题" : title.length()>15?title.substring(0,15):title;this.chatId = chatId;}
}

实现存储,查询全文,删除三个方法

用LinkedHashMap是因为历史记录是有序的,

private Map<String,String> chatInfos=new LinkedHashMap<>();

模仿ChatMemory中的方法,实现存储,查询全文,删除三个方法

public interface ChatHistoryRepository {void save(String prompt,String chatId);List<ChatInfo> getChats();void clearByChatId(String chatId);
}
@Repository
public class MemoryChatHistoryRepository implements ChatHistoryRepository{//    用LinkedHashMap<>是因为是有序的private Map<String,String> chatInfos=new LinkedHashMap<>();@Overridepublic void save(String title, String chatId) {chatInfos.put(chatId, title);}@Overridepublic List<ChatInfo> getChats() {return chatInfos.entrySet().stream().map(entry->new ChatInfo(entry.getKey(), entry.getValue())).collect(Collectors.toList());}@Overridepublic void clearByChatId(String chatId) {chatInfos.remove(chatId);}
}

注入实现的方法对象

    @Autowiredprivate MemoryChatHistoryRepository memoryChatHistoryRepository;

存储会话

获得会话列表

定义接口

//    获得会话列表
@RequestMapping("/getChatIds")public List<ChatInfo> getChatIds(){return memoryChatHistoryRepository.getChats();}

获取会话记录

定义接口

根据会话的Id,获得记录

//  活得会话记录
@RequestMapping("/getChatHistory")public List<MessageVo> getChatHistory(String chatId){List<Message> messages = chatMemory.get(chatId, 20);return messages.stream().map(MessageVo::new).collect(Collectors.toList());}

为了让前端处理起来更加的简单,我们用VO统一成固定的格式

@Data
public class MessageVo {private String role;private String content;public MessageVo(Message message){switch (message.getMessageType()){case USER -> {this.role = "user"; break;}case ASSISTANT -> {this.role = "assistant"; break;}case SYSTEM -> {this.role = "system"; break;}case TOOL -> {this.role = "tool"; break;}}this.content = message.getText();}}

删除会话记录

定义接口

//    删除会话记录
@RequestMapping("/deleteChat")public boolean clearChat(String chatId){try {memoryChatHistoryRepository.clearByChatId(chatId);chatMemory.clear(chatId);}catch (Exception e){return false;}return true;}

将Ollama切换到DeepSeek

添加依赖和修改.yml文件

        <dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-openai-spring-boot-starter</artifactId></dependency>
    openai:api-key: sk-493d502eee42490f92d3015479aa8f47base-url: https://api.deepseek.comchat:options:model: deepseek-chattemperature: 0.7

定义ChatClient

    @Beanpublic ChatClient chatClient(OpenAiChatModel openAiChatModel, ChatMemory chatMemory){return ChatClient.builder(openAiChatModel).defaultSystem("你的名字小瑞,是一个智能机器人").defaultAdvisors(new SimpleLoggerAdvisor(), new MessageChatMemoryAdvisor(chatMemory)).build();}

希望能对大家有所帮助!!!!!

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

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

相关文章

广东省省考备考(第九十天8.30)——判断推理(强化训练)

判断推理&#xff1a;类比推理&#xff08;训练1&#xff09; 错题解析 第一步&#xff1a;判断题干词语间逻辑关系。 绫、罗、绸、缎表示的是四种不同的丝织物&#xff0c;四者为并列关系&#xff0c;且分别都与丝织物构成包容关系中的种属关系。 第二步&#xff1a;判断选项词…

DFS 回溯 【各种题型+对应LeetCode习题练习】

目录 什么是深度优先搜索&#xff08;DFS&#xff09; DFS题型分类 DFS和回溯的关系 排列与组合 LeetCode 46 全排列 LeetCode 47 全排列 II LeetCode 39 组合总和 LeetCode 40 组合总和 II 子集 LeetCode 78 子集 LeetCode 90 子集 II 分割问题 LeetCode 131 分割…

大模型备案、算法备案补贴政策汇总【广东地区】

广州海珠 《广州市海珠区建设人工智能大模型应用示范区实施细则的通知》规定&#xff0c;自 2024 年 6 月 18 日起至 2027 年 3 月 20 日&#xff0c;大规模企业首次完成国家级生成式人工智能&#xff08;大语言模型&#xff09;上线备案的&#xff0c;可获得最高 100 万元一次…

鸿蒙服务端开发资料汇总

文章目录鸿蒙服务端开发资料汇总一、核心概念1.1 分布式架构1.2 微内核设计1.3 元服务架构二、技术栈2.1 开发语言2.2 开发框架与工具2.3 核心技术能力三、官方文档与资源3.1 官方文档3.2 示例代码与开源资源四、应用案例4.1 政务领域4.2 金融领域4.3 交通出行4.4 企业办公五、…

基于51单片机霍尔测速仪表测转速调速系统设计

1 系统功能介绍 本设计为 基于51单片机霍尔测速仪表测转速调速系统。系统以STC89C52单片机为核心&#xff0c;结合霍尔传感器、LCD1602显示模块、电位器调速电路与电机驱动模块&#xff0c;实现了对旋转装置的转速检测、数据显示以及实时调节电机转速的功能。 系统主要功能包括…

前端-初识Vue实例

一.准备容器 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head>…

基于FPGA的简易医疗呼叫器实现,包含testbench

目录 1.课题概述 2.系统测试效果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 医院护理呼叫系统是病人请求值班医生或护士进行紧急处理或咨询的工具&#xff0c;可将病人的请求快速传送给值班医生或护士。其基本功能就是通过一种简便的途径使护理对象与医…

Maya绑定基础:创建骨骼和蒙皮、蒙皮权重控制的两种方法

目录 1 创建骨骼和蒙皮 2 蒙皮权重控制 方法一 3 蒙皮权重控制 方法二 1 创建骨骼和蒙皮 新建一个圆柱体 把圆柱体拉长一点&#xff0c;调到前视图 骨架--创建关节 同时选中骨骼和模型&#xff0c;菜单栏--蒙皮--绑定蒙皮 对关节进行旋转 详细的步骤参考这个链接&#xf…

【Settings】OTA 升级时更新 Settings 数据库

一、问题描述 基于 Android 14平台&#xff0c;随着后续的 UI 更新需要将某个控制项的 Settings 值更新&#xff0c;需要更新 SettingsProvider 的值。二、问题分析 1. 定义一个 Settings 常量 frameworks/base/core/java/android/provider/Settings.java /*** Whether to use …

开发electron时候Chromium 报 Not allowed to load local resource → 空白页。

报错含义 主进程&#xff08;main.js&#xff09;里 win.loadFile()/win.loadURL() 指向了 file:///…/app.asar/build/index.html&#xff0c; 但打包后真正的文件位于 app.asar 内部&#xff0c;路径拼错&#xff0c;于是 Chromium 报 Not allowed to load local resource →…

Ethan独立开发新品速递 | 2025-08-30

每日精选Product Hunt上最值得关注的独立产品&#xff0c;发现全球创新灵感&#xff0c;助力你的产品成长。 下面从今天的 Product Hunt 热榜中筛选出对独立开发者&#xff08;尤其是注重开发工具、AI 工具、SaaS 与创业工具&#xff09;的10个最有参考价值的项目。筛选标准侧重…

【C++ 】string类操作全解析

1. 为什么学习 string 类&#xff1f; 1.1 C 语言中的字符串 C 语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C 标准库中提供了一些 str 系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合 OOP &…

DAY15-新世纪DL(DeepLearning/深度学习)战士:破(超参数调试、Batch正则化和程序框架)3

本文参考文章0.0 目录-深度学习第一课《神经网络与深度学习》-Stanford吴恩达教授-CSDN博客 1.调试处理 神经网络的改变会涉及到许多不同的超参数设置&#xff0c;现在&#xff0c;对于超参数而言&#xff0c;如何找到一套比较好的设定&#xff1f; 训练深度最难的事之一是你…

Android 14 PMS源码分析

源码参考&#xff1a;Search (aospxref.com) 一、简介 PackageManagerService&#xff08;简称 PMS&#xff09;&#xff0c;是 Android 系统核心服务之一&#xff0c;处理包管理相关的工作&#xff0c;常见的比如安装、卸载应用等。本章针对SyetemServer、PMS构造方法重点模…

内省排序:相对最迅速的通用排序算法

&#x1f50d; 内省排序&#xff1a;相对最迅速的通用排序算法 &#x1f680; 前言&#xff1a;排序算法的演进之路 排序算法是计算机科学的核心基础之一&#xff0c;其性能直接影响着数据库系统、科学计算、图形渲染等领域的效率。随着硬件架构的发展&#xff0c;排序算法经历…

Linux驱动开发重要操作汇总

本文主要记录imx6ull的linux驱动开发过程中常用的一些操作。 uboot编译 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- distclean make ARCHarm CROSS_COMPILEarm-linux-gnueabihf mx6ull_14x14_evk_emmc_defconfig make V1 ARCHarm CROSS_COMPILEarm-linux-gnueabihf- …

【Java后端】MySQL 常见 SQL 语句优化指南

在 MySQL 中&#xff0c;SQL 优化是性能调优的核心环节&#xff0c;尤其是在数据量大、并发高的情况下。这里整理一份 MySQL 常见 SQL 语句优化指南&#xff0c;从查询写法、索引使用到执行计划分析&#xff0c;涵盖实用技巧&#xff1a;1. 查询语句层面的优化 ✅ 避免 SELECT …

Golang 面试题「高级」

以下是 100 道 Golang 高级面试题及答案&#xff0c;聚焦语言底层实现、并发深度优化、性能调优、源码级理解等核心方向&#xff0c;适合资深开发者或架构师级别的面试场景&#xff1a; 一、GPM 调度模型与并发深度 问题&#xff1a;Goroutine 的栈空间初始大小是多少&#xff…

WebGIS视角:体感温度实证,哪座“火炉”火力全开?

目录 前言 一、火炉城市空间分布及特点 1、空间分布 2、气候特点 二、数据来源及技术实现 1、数据来源介绍 2、技术路线简介 三、WebGIS系统实现 1、后端设计与实现 2、前端程序实现 四、成果展示 1、整体展示 2、蒸烤模式城市 3、舒适城市 五、总结 前言 “火炉…

《数据结构入门:顺序表的结构设计与核心操作(C 语言版)》

目录 一. 线性表 二. 顺序表的概念与结构 2.1 核心概念 2.2 两种常见结构 静态顺序表 动态顺序表 2.3 核心区别对比 四. 顺序表的实现 4.1 顺序表的定义 4.2 顺序表初始化 4.3 动态顺序表容量检查与扩容 4.4 动态顺序表插入数据 4.4.1 头插 4.4.2 尾插 4.4.3 指…