SpringAI实现AI应用-内置顾问

SpringAI实战链接

1.SpringAl实现AI应用-快速搭建-CSDN博客

2.SpringAI实现AI应用-搭建知识库-CSDN博客

3.SpringAI实现AI应用-内置顾问-CSDN博客

4.SpringAI实现AI应用-使用redis持久化聊天记忆-CSDN博客

5.SpringAI实现AI应用-自定义顾问(Advisor)-CSDN博客

概述

通过前两篇帖子,对SpringAI的使用应该有了大致的了解,那么本篇就需要真正去看以下SpringAI里面真正的东西了

首先先看SpringAI官方文档-Advisors

中文版:顾问 API :: Spring AI 参考 - Spring 框架

官方:Advisors API :: Spring AI Reference

通过文档可以知道Spring AI 框架提供了几个内置顾问,以增强 AI 交互。以下是可用顾问的概览:

聊天记忆顾问

        这些顾问在聊天记忆存储中管理对话历史:

        MessageChatMemoryAdvisor

        检索记忆并将其作为消息集合添加到提示中。这种方法保持了对话历史的结构。请注意,并非所有 AI 模型都支持这种方法。

        PromptChatMemoryAdvisor

        检索记忆并将其并入提示的系统文本中。

        VectorStoreChatMemoryAdvisor

        从 VectorStore 中检索记忆并将其添加到提示的系统文本中。这个顾问对于高效搜索和检索大型数据集中的相关信息非常有用。

问题回答顾问

        QuestionAnswerAdvisor

        这个顾问使用向量存储提供问题回答能力,实现了 RAG(检索增强生成)模式。

内容安全顾问

        SafeGuardAdvisor

        一个简单的顾问,旨在防止模型生成有害或不适当的内容。

聊天记忆实例

接下来继续使用之前的代码,逐个验证这些内置顾问的功能和作用

ChatMemory

想要使用聊天记忆顾问之前,先看一下聊天记忆顾问里的源码

MessageChatMemoryAdvisor

PromptChatMemoryAdvisor

VectorStoreChatMemoryAdvisor

从源码中可以看到,两个内置顾问的构造方法中都有ChatMemory,而VectorStoreChatMemoryAdvisor的构造方法入参的是向量库,那就先看一下ChatMemory,它是一个内存管理容器,用于存储和管理多轮对话中的ChatMessage。它不仅允许开发者保存消息,还提供了消息驱逐策略(Eviction Policy)、持久化存储(Persistence)以及特殊消息处理(如SystemMessage和ToolExecutionMessage)等功能。此外,ChatMemory还与high-level组件(如AI服务)集成,便于开发者更方便地管理对话历史。

先看一下ChatMemory里的方法

1.add(String conversationId, Message message):将单个消息添加到指定会话的对话中。
2.add(String conversationId, List<Message> messages):将消息列表添加到指定会话的对话中。
3.get(String conversationId, int lastN):从指定会话的对话中检索最新的N条消息。
4.clear(String conversationId):清除指定会话的对话历史记录。

而ChatMemory的实现类是InMemoryChatMemory这个类再之前两篇帖子的配置类中有实现。

InMemoryChatMemory是Spring AI框架提供的一种ChatMemory实现,它将对话历史记录存储在内存中。这种实现方式具有快速访问和检索消息的优点,适用于快速原型开发和测试场景。由于内存是易失性存储介质,因此InMemoryChatMemory不适用于需要长期保存聊天记录的应用场景。

而其中的方法也为能持久化聊天记录提供了帮助,

修改之前接口代码中的call方法如下(简单实现)

    /*** 根据消息直接输出回答* @param map* @return*/@PostMapping("/ai/call")public String call(@RequestBody Map<String,String> map) {String message = map.get("message");Message message1 = new UserMessage(message);String trim = chatClient.prompt().user(message).call().content().trim();Message message2 = new UserMessage(MessageType.SYSTEM, trim, new ArrayList<>(), Map.of());inMemoryChatMemory.add("123456",List.of(message1,message2));return trim;}

然后再获取聊天记录进行(简单实现)

    /*** 查询聊天记里* @return*/@GetMapping("/ai/chatMemory")public List<Message> chatMemory(){List<Message> messages = inMemoryChatMemory.get("123456", 10);for (Message message : messages) {System.out.println(message.getText());}return messages;}

MessageChatMemoryAdvisor

了解完ChatMemory,那就开始看第一个内置顾问MessageChatMemoryAdvisor,这个也在之前的代码中实现过,当时为了简单实现多轮对话记忆,而且还是加在了方法上

这篇帖子,我们将代码加在配置类上,修改配置类如下,配置类中没有配置会话id和储存大小,是因为统一进行的配置,这种方式将chatClient注册到spring容器的时候,还没有办法知道用户的会话id,所以只能默认,储存大小也使用默认,默认大小为100

    @BeanChatClient chatClient(ChatClient.Builder builder) {return builder// 它定义了聊天机器人在回答问题时应当遵循的风格和角色定位。.defaultSystem("你是一个智能机器人,你的名字叫 Spring AI智能机器人").defaultAdvisors(new MessageChatMemoryAdvisor(inMemoryChatMemory())).build();}

此时所有的接口都实现了记忆对话的功能

测试

由此可见在全局都已经实现了对话记忆

PromptChatMemoryAdvisor

再来看PromptChatMemoryAdvisor,它和MessageChatMemoryAdvisor的类似,也是直接修改配置类,如下

    @BeanChatClient chatClient(ChatClient.Builder builder) {return builder// 它定义了聊天机器人在回答问题时应当遵循的风格和角色定位。.defaultSystem("你是一个智能机器人,你的名字叫 Spring AI智能机器人").defaultAdvisors(
//                        new MessageChatMemoryAdvisor(inMemoryChatMemory())new PromptChatMemoryAdvisor(inMemoryChatMemory())).build();}

VectorStoreChatMemoryAdvisor

VectorStoreChatMemoryAdvisor 是 Spring AI 框架中的一个组件,它结合了向量存储(VectorStore)技术来增强聊天机器人的记忆能力。这个 Advisor 利用向量数据库存储用户与聊天机器人的交互历史,包括用户提出的问题和模型的回答。在生成新的回复时,VectorStoreChatMemoryAdvisor 会检索与当前问题相关的历史记录,并将其作为上下文信息添加到提示中,从而帮助大型语言模型(LLM)生成更连贯和准确的回复。

具体实现需要将聊天记录持久化到向量库,下篇帖子再详细说明聊天记录持久化的问题

区别

看了SpringAI的官方文档,网上也搜了一下这三个内置顾问,都说的太官方了,简单说一下:

MessageChatMemoryAdvisor:将对话历史以消息集合的形式存储和传递。它维护了一个结构化的对话历史记录,通常将用户消息和模型响应封装为消息对象。适用于需要保持对话历史结构的场景,例如需要明确区分用户消息和系统消息。

PromptChatMemoryAdvisor:将对话历史以纯文本的形式合并到系统提示中。它将历史消息转换为一个字符串,并将其附加到系统提示的文本中。适用于需要将历史信息作为上下文传递给模型的场景,尤其是当模型不支持消息集合时。

VectorStoreChatMemoryAdvisor:使用向量存储技术将对话历史存储在向量数据库中。它将对话记录封装为向量形式的文档,并通过向量检索来获取相关的历史信息。适用于需要高效检索和处理大规模数据集的场景。

问题回答实例

QuestionAnswerAdvisor

这个顾问访问的就是上篇帖子实现的向量库,当用户提出问题时,QuestionAnswerAdvisor会首先对知识库进行检索,并将匹配到的相关引用文本添加到用户提问的后面,从而为生成的回答提供更为丰富和准确的上下文。此外,该Advisor还设定了一个默认提示词,旨在确保回答的质量和相关性。如果在知识库中无法找到匹配的文本,系统将可能拒绝回答用户的问题。

实现如下:

    @BeanChatClient chatClient(ChatClient.Builder builder,VectorStore vectorStore) {return builder// 它定义了聊天机器人在回答问题时应当遵循的风格和角色定位。.defaultSystem("你是一个智能机器人,你的名字叫 Spring AI智能机器人").defaultAdvisors(
//                        new MessageChatMemoryAdvisor(inMemoryChatMemory())new PromptChatMemoryAdvisor(inMemoryChatMemory()),QuestionAnswerAdvisor.builder(vectorStore).order(1).build()).build();}

测试

经过测试可以看到,只有问向量库中的内容,才会进行回答

内容安全实例

SafeGuardAdvisor

这个顾问顾名思义就是过滤敏感词汇的,具体实现如下

    @BeanChatClient chatClient(ChatClient.Builder builder,VectorStore vectorStore) {return builder// 它定义了聊天机器人在回答问题时应当遵循的风格和角色定位。.defaultSystem("你是一个智能机器人,你的名字叫 Spring AI智能机器人").defaultAdvisors(
//                        new MessageChatMemoryAdvisor(inMemoryChatMemory())new PromptChatMemoryAdvisor(inMemoryChatMemory()),QuestionAnswerAdvisor.builder(vectorStore).order(1).build(),SafeGuardAdvisor.builder().sensitiveWords(List.of("色情", "暴力")) // 敏感词列表.order(2) // 设置优先级.failureResponse("抱歉,我无法回答这个问题。").build() // 敏感词过滤失败时的响应).build();}

测试

经过测试,安全顾问已经把敏感词进行了过滤

完整代码

AiConfig(配置文件)

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.*;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.List;/*** @Author majinzhong* @Date 2025/4/28 10:34* @Version 1.0*/
@Configuration
public class AiConfig {@BeanChatClient chatClient(ChatClient.Builder builder,VectorStore vectorStore) {return builder// 它定义了聊天机器人在回答问题时应当遵循的风格和角色定位。.defaultSystem("你是一个智能机器人,你的名字叫 Spring AI智能机器人")//这里可以添加多个顾问 order(优先级)越小,越先执行// 注意:顾问添加到链中的顺序至关重要,因为它决定了其执行的顺序。每个顾问都会以某种方式修改提示或上下文,一个顾问所做的更改会传递给链中的下一个顾问。// 在此配置中,将首先执行MessageChatMemoryAdvisor,将对话历史记录添加到提示中。然后,问答顾问将根据用户的问题和添加的对话历史进行搜索,从而可能提供更相关的结果。.defaultAdvisors(//内存存储对话记忆
//                        new MessageChatMemoryAdvisor(inMemoryChatMemory()),new PromptChatMemoryAdvisor(inMemoryChatMemory()),// QuestionAnswerAdvisor 此顾问使用矢量存储提供问答功能,实现RAG(检索增强生成)模式QuestionAnswerAdvisor.builder(vectorStore).order(1).build(),// SafeGuardAdvisor是一个安全防护顾问,它确保生成的内容符合道德和法律标准。SafeGuardAdvisor.builder().sensitiveWords(List.of("色情", "暴力")) // 敏感词列表.order(2) // 设置优先级.failureResponse("抱歉,我无法回答这个问题。").build(), // 敏感词过滤失败时的响应// SimpleLoggerAdvisor是一个记录ChatClient的请求和响应数据的顾问。这对于调试和监控您的AI交互非常有用,建议将其添加到链的末尾。new SimpleLoggerAdvisor()).defaultOptions(ChatOptions.builder().topP(0.7) // 取值越大,生成的随机性越高;取值越低,生成的随机性越低。默认值为0.8.build()).build();}@BeanChatMemory inMemoryChatMemory() {return new InMemoryChatMemory();}
}

AdvisorController(测试接口)

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.web.bind.annotation.*;import java.util.ArrayList;
import java.util.List;
import java.util.Map;import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;/*** @Author majinzhong* @Date 2025/5/6 14:22* @Version 1.0*/
@CrossOrigin
@RestController
public class AdvisorController {// 负责处理OpenAI的bean,所需参数来自properties文件private final ChatClient chatClient;//对话记忆private final InMemoryChatMemory inMemoryChatMemory;public AdvisorController(ChatClient chatClient,InMemoryChatMemory inMemoryChatMemory) {this.chatClient = chatClient;this.inMemoryChatMemory = inMemoryChatMemory;}/*** 普通聊天* @param message* @param sessionId* @return*/@GetMapping("/ai/generateCall")public String generateCall(@RequestParam(value = "message", defaultValue = "讲个笑话") String message, @RequestParam String sessionId) {return chatClient.prompt().user(message).advisors(advisorSpec -> advisorSpec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId).param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)).call().content().trim();}/*** 根据消息直接输出回答* @param map* @return*/@PostMapping("/ai/callAdvisor")public String call(@RequestBody Map<String,String> map) {String message = map.get("message");Message message1 = new UserMessage(message);String trim = chatClient.prompt().user(message).call().content().trim();Message message2 = new UserMessage(MessageType.SYSTEM, trim, new ArrayList<>(), Map.of());inMemoryChatMemory.add("123456",List.of(message1,message2));return trim;}/*** 查询聊天记里* @return*/@GetMapping("/ai/chatMemory")public List<Message> chatMemory(){List<Message> messages = inMemoryChatMemory.get("123456", 10);for (Message message : messages) {System.out.println(message.getText());}return messages;}
}

代码中的这个方法设置了记忆对话的对话id和存储的大小

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

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

相关文章

Nginx核心原理以及案例分析(AI)

一、Nginx核心原理分析 1. ‌事件驱动与非阻塞模型‌ ‌Epoll异步机制‌&#xff1a;基于Linux的epoll模型实现异步非阻塞I/O处理&#xff0c;单线程可高效管理数万并发连接&#xff0c;避免传统select模型的轮询性能瓶颈。‌多进程架构‌&#xff1a;采用Master-Worker模式&…

【Bug经验分享】SourceTree用户设置必须被修复/SSH 主机密钥未缓存(踩坑)

文章目录 配置错误问题原因配置错误问题解决主机密钥缓存问题原因主机密钥缓存问题解决 更多相关内容可查看 配置错误问题原因 电脑太卡&#xff0c;曾多次强制关机&#xff0c;在关机前没有关闭SourceTree&#xff0c;导致配置错误等问题 配置错误问题解决 方式一&#xff…

阿里云服务器-centos部署定时同步数据库数据-dbswitch

前言&#xff1a; 本文章介绍通过dbswitch工具实现2个mysql数据库之间实现自动同步数据。 应用场景&#xff1a;公司要求实现正式环境数据库数据自动冷备 dbswitch依赖环境&#xff1a;git ,maven,jdk 方式一&#xff1a; 不需要在服务器中安装git和maven&#xff0c;直接用…

windows10 环境下通过huggingface_hub下载huggingface社区模型

项目场景&#xff1a; 有一些模型需要在huggingface下载&#xff0c;因为国内限制&#xff0c;一般无法访问huggingface网站进行下载。然而&#xff0c;可以通过国内的镜像下载。网上大部分都是在linux系统下&#xff0c;通过huggingface提供的指令下载。本文针对采用python脚…

C++之异常

目录 前言 一、什么是异常 二、C中的异常 2.1 C语言中的异常处理 2.2 C中的异常处理 2.3 异常的抛出与捕获 2.4 栈展开 2.5 查找匹配的处理代码 2.6 异常重新抛出 2.7 异常安全问题 2.8 异常规范 2.9 标准库的异常 前言 在之前我们已经学习了C中不少知识了&#xff0c;但是其中…

$在R语言中的作用

在 R 语言中&#xff0c;$ 是一个非常重要的操作符&#xff0c;主要用于访问对象的成员或组件。它的用途非常广泛&#xff0c;不仅限于数据框&#xff08;data frame&#xff09;&#xff0c;还可以用于列表&#xff08;list&#xff09;、环境&#xff08;environment&#xf…

设计一个分布式系统:要求全局消息顺序,如何使用Kafka实现?

一、高吞吐低延迟 Kafka 集群设计要点 1. 分区策略优化 // 计算合理分区数公式&#xff08;动态调整&#xff09; int numPartitions max(Tp, Tc) / min(Tp, Tc) // Tp生产者吞吐量 Tc消费者吞吐量建议初始按业务键&#xff08;如订单ID&#xff09;哈希分区单分区吞吐建议…

[dify]官方模板DeepResearch工作流学习笔记

一、功能 根据用户输入的主题进行多轮搜索并生成综合报告 1、流程分析 1.1 初始阶段 Start节点&#xff1a;接收用户输入的"depth"参数&#xff0c;决定搜索的深度/轮数 参数可以不填&#xff0c;不填的时候取默认值3 Create Array节点&#xff1a;根据depth参数…

hadoop中的序列化和反序列化(3)

3. Java的序列化 Java提供了内置的序列化机制&#xff0c;通过java.io.Serializable接口实现。 3.1 如何实现Java序列化 让类实现Serializable接口。 使用ObjectOutputStream进行序列化。 使用ObjectInputStream进行反序列化。 示例代码 序列化 java 复制 import jav…

6、CMake基础:流程控制

流程控制 1. 条件判断1.1 基本表达式1.2 逻辑判断1.3 比较基于数值的比较基于字符串的比较 1.4 文件操作1.5 其他 2. 循环2.1 foreach方法1方法2方法3方法4 2.2 while 在 CMake 的 CMakeLists.txt 中也可以进行流程控制&#xff0c;也就是说可以像写 shell 脚本那样进行条件判断…

【网络编程】二、UDP网络套接字编程详解

文章目录 前言Ⅰ. UDP服务端一、服务器创建流程二、创建套接字 -- socketsocket 属于什么类型的接口❓❓❓socket 是被谁调用的❓❓❓socket 底层做了什么❓❓❓和其函数返回值有没有什么关系❓❓❓ 三、绑定对应端口号、IP地址到套接字 -- bind四、数据的发送和接收 -- sendto…

准确--Notepad++ 实用的插件介绍

Notepad 提供了很多实用的插件&#xff0c;可以极大地提升编程和文本编辑的效率。以下是一些常用且有用的插件介绍&#xff1a; 1. NPP Export 功能&#xff1a;可以将打开的文件导出为 HTML 或 RTF 格式&#xff0c;方便生成漂亮的代码文档。用途&#xff1a;适合需要将代码…

[20250507] AI边缘计算开发板行业调研报告 ​​(2024年最新版)​

[20250507] AI边缘计算开发板行业调研报告 ​​(2024年最新版&#xff09;​ 一、行业背景​​ 随着物联网设备激增与AI模型轻量化&#xff0c;边缘计算成为AI落地核心场景。AI边缘计算开发板&#xff08;Edge AI Board&#xff09;作为硬件载体&#xff0c;需满足​​低延迟…

传输层协议 1.TCP 2.UDP

传输层协议 1.TCP 2.UDP TCP协议 回顾内容 传输层功能&#xff1a;定义应用层协议数据报文的端口号&#xff0c;流量控制对原始数据进行分段处理 传输层所提供服务 传输连接服务数据传输服务&#xff1a;流量控制、差错控制、序列控制 一、传输层的TCP协议 1.面向连接的…

LVGL -meter的应用

1 meter介绍 lv_meter 是 LVGL v8 引入的一种图形控件&#xff0c;用于创建仪表盘样式的用户界面元素&#xff0c;它可以模拟像速度表、电压表、温度表这类模拟表盘。它通过可视化刻度、指针、颜色弧线等来展示数值信息&#xff0c;是一种非常直观的数据展示控件。 1.1 核心特…

GoFly企业版框架升级2.6.6版本说明(框架在2025-05-06发布了)

前端框架升级说明&#xff1a; 1.vue版本升级到^3.5.4 把"vue": "^3.2.40",升级到"vue": "^3.5.4"&#xff0c;新版插件需要时useTemplateRef,所以框架就对齐进行升级。 2.ArcoDesign升级到2.57.0&#xff08;目前最新2025-02-10&a…

阿里联合北大开源数字人项目FantasyTalking,输出内容更加动态化~

简介 FantasyTalking 的核心目标是从单一静态图像、音频&#xff08;以及可选的文本提示&#xff09;生成高保真、连贯一致的说话肖像。研究表明&#xff0c;现有方法在生成可动画化头像时面临多重挑战&#xff0c;包括难以捕捉细微的面部表情、整体身体动作以及动态背景的协调…

基于nnom的多选择器

核心组件 元件类型目的接口STM32F103CB微控制器主处理单元-MPU60506 轴 IMU移动侦测I2C 接口W25Q64 系列闪存信号和配置存储SPI 系列按钮用户输入模式选择和激活GPIO &#xff08;通用输出&#xff09;搭载了LED用户反馈系统状态指示GPIO &#xff08;通用输出&#xff09;RT6…

Redis中6种缓存更新策略

Redis作为一款高性能的内存数据库&#xff0c;已经成为缓存层的首选解决方案。然而&#xff0c;使用缓存时最大的挑战在于保证缓存数据与底层数据源的一致性。缓存更新策略直接影响系统的性能、可靠性和数据一致性&#xff0c;选择合适的策略至关重要。 本文将介绍Redis中6种缓…

项目优先级频繁变动,如何应对?

项目优先级频繁变动是许多公司和团队在工作中常遇到的挑战。 这种情况通常由业务需求变化、市场压力或高层决策调整等因素引起&#xff0c;常常让团队成员感到困惑和不安。首先&#xff0c;制定明确的优先级管理框架是应对项目优先级变动的基础&#xff0c; 通过清晰的优先级排…