SpringAi整合大模型(进阶版)

进阶版是在基础的对话版之上进行新增功能。

如果还没弄出基础版的,请参考

https://blog.csdn.net/weixin_54925172/article/details/144143523?sharetype=blogdetail&sharerId=144143523&sharerefer=PC&sharesource=weixin_54925172&spm=1011.2480.3001.8118

一,进阶版需要实现的功能

  1. 给AI进行功能预设
  2. 记忆对话,能自动联系上下文语境
  3. 结合业务,通过对话操作系统业务

简单解释一下

给AI进行功能预设

比如当客户发送特定消息时,ai需要做出什么回应

或者

让ai充当淘宝客服之类的角色

记忆对话,能自动联系上下文语境

同一时间多个用户访问时,分别可以对应多个用户,不会混淆上下文语境。

比如用户A说了自己是A,用户B说了自己是B,那么A在问自己是谁时,AI能准确回答出用户是A,而不会混淆说A是B。

结合业务,通过对话操作系统业务

类似于现在的手机助手,叫声“小艺,帮我买杯霸王别姬的奶茶”。小艺就会自动下单购买奶茶。

二,代码编写

首先整合一下上次的样例代码,做一下简单的调整。

简单调整上次的代码

controller

package org.example.springaidemo.controller;

import org.example.springaidemo.impl.SimpleControllerImpl;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
public class SimpleController {


    private final SimpleControllerImpl simpleControllerimpl;

    @Autowired
    public SimpleController(OpenAiChatModel openAiChatModel, SimpleControllerImpl simpleControllerimpl) {
        this.simpleControllerimpl = simpleControllerimpl;
    }


    @GetMapping("/ai/generate")
    public String generate(@RequestParam(value = "message", defaultValue = "讲个笑话") String message) {
        return simpleControllerimpl.generate(message);
    }

    @GetMapping("/ai/generateStream")
    public Flux<String> generateStream(@RequestParam(value = "message", defaultValue = "讲个笑话") String message) {
        return simpleControllerimpl.generateStream(message);
    }

}

impl

package org.example.springaidemo.impl;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

@Service
public class SimpleControllerImpl {

    private final ChatClient client;

    @Autowired
    public SimpleControllerImpl(ChatClient.Builder clientBuilder) {
        this.client = clientBuilder.build();
    }

    public String generate(String msg) {
        return this.client.prompt()
                .user(msg)
                .call()
                .content();
    }

    public Flux<String> generateStream(String msg) {
        return this.client.prompt()
                .user(msg)
                .stream()
                .content();
    }
}

测试

给AI进行功能预设

修改我们的impl类

package org.example.springaidemo.impl;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

@Service
public class SimpleControllerImpl {

    private final ChatClient client;

    @Autowired
    public SimpleControllerImpl(ChatClient.Builder clientBuilder) {
        this.client = clientBuilder.defaultSystem(
                """
        你是一家名叫“Rojer”的淘宝客服。
        当用户语句中包含“退款”时,你需要回复“不好意思,本店不支持7天无理由退款”
        """
        ).build();
    }

    public String generate(String msg) {
        return this.client.prompt()
                .user(msg)
                .call()
                .content();
    }

    public Flux<String> generateStream(String msg) {
        return this.client.prompt()
                .user(msg)
                .stream()
                .content();
    }
}

这里需要注意,大模型是经过特定训练后的,它无法做出一些本身禁止于大模型的回复,

比如说污言秽语,比如说民族纠纷,比如说反人类语言。

这个时候,我们再进行一些简单测试

记忆对话,能自动联系上下文语境

这里有两个方面

  1. 需要开启ai的记忆功能
  2. 需要对不同用户进行分别的处理

别的不多说,都在代码中,注释中

impl

package org.example.springaidemo.impl;

import org.example.springaidemo.config.MychatMemory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

/**
 * SimpleControllerImpl 是一个服务类,用于处理基于 AI 的对话。
 * 它利用 Spring AI Chat 框架,通过会话 ID(token)管理不同用户的上下文和对话。
 */
@Service
public class SimpleControllerImpl {

    // AI 对话客户端实例
    private final ChatClient client;

    // 自定义的对话存储实现,用于保存用户会话上下文
    private final MychatMemory mychatMemory;

    /**
     * 构造方法,初始化 ChatClient 和自定义的对话存储。
     *
     * @param clientBuilder 用于构建 ChatClient 的构建器
     * @param mychatMemory  自定义的对话存储实现
     */
    @Autowired
    public SimpleControllerImpl(ChatClient.Builder clientBuilder, MychatMemory mychatMemory) {
        this.mychatMemory = mychatMemory;
        // 初始化 ChatClient,并设置默认系统提示和对话存储
        this.client = clientBuilder.defaultSystem(
                """
        你是一家名叫“Rojer”的淘宝客服。
        当用户语句中包含“退款”时,你需要回复“不好意思,本店不支持7天无理由退款”
        """
        )
                .defaultAdvisors(new PromptChatMemoryAdvisor(mychatMemory))
                .build();
    }

    /**
     * 生成基于用户消息和会话 token 的 AI 回复。
     *
     * @param msg   用户输入的消息
     * @param token 表示会话唯一标识,用于区分不同用户的上下文
     * @return AI 的回复内容
     */
    public String generate(String msg, String token) {
        return this.client.prompt()
                .user(msg) // 用户的输入
                .advisors(adv -> adv
                        // 设置检索的上下文记录条数
                        .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)
                        // 指定会话唯一标识,用于区分不同的用户对话
                        .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, token))
                .call() // 调用 AI 服务,生成回复
                .content(); // 获取生成的文本内容
    }

    /**
     * 以流式方式生成基于用户消息和会话 token 的 AI 回复。
     * 适用于需要逐步接收回复内容的场景,例如聊天应用中的实时响应。
     *
     * @param msg   用户输入的消息
     * @param token 表示会话唯一标识,用于区分不同用户的上下文
     * @return Flux<String> 流式的回复内容
     */
    public Flux<String> generateStream(String msg, String token) {
        return this.client.prompt()
                .user(msg) // 用户的输入
                .advisors(adv -> adv
                        // 设置检索的上下文记录条数
                        .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)
                        // 指定会话唯一标识,用于区分不同的用户对话
                        .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, token))
                .stream() // 以流式模式调用 AI 服务
                .content(); // 获取生成的文本流内容
    }
}

自定义的chatMemory

package org.example.springaidemo.config;

import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class MychatMemory implements ChatMemory {

    Map<String, List<Message>> conversationHistory = new ConcurrentHashMap<>();

    @Override
    public void add(String conversationId, List<Message> messages) {
        this.conversationHistory.computeIfAbsent(conversationId, id -> Collections.synchronizedList(new ArrayList<>()))
                .addAll(messages);
    }

    @Override
    public void add(String conversationId, Message message) {
        this.conversationHistory.computeIfAbsent(conversationId, id -> Collections.synchronizedList(new ArrayList<>()))
                .add(message);
    }

    @Override
    public List<Message> get(String conversationId, int lastN) {
        List<Message> allMessages = conversationHistory.get(conversationId);
        if (allMessages == null || allMessages.isEmpty()) {
            return List.of(); // 如果没有历史记录,返回空列表
        }

        // 计算获取的起始位置
        int start = Math.max(0, allMessages.size() - lastN);
        return new ArrayList<>(allMessages.subList(start, allMessages.size())); // 返回一个新列表,避免外部修改

    }

    @Override
    public void clear(String conversationId) {
        conversationHistory.remove(conversationId); // 移除该会话的历史记录
    }
}

看看 实际对话是否有分别存储到自定义的chatMemory中

这里可以看出已经按照我的需求将两条不同的会话进行分别处理了。

这里可以根据自己的需要,使用标准的token,或者直接使用sessionID都可以。

结合业务,通过对话操作系统业务

这里需要用到springAI提供的fuction方法

详细都在注释 中

SimpleFunction
package org.example.springaidemo.config;

import org.example.springaidemo.impl.SimpleControllerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;

import java.util.function.Function;

/**
 * SimpleFunction 是一个 Spring 配置类,定义了应用中使用的函数 Bean。
 * 主要用于暴露基于 Lambda 表达式的业务逻辑函数。
 */
@Configuration
public class SimpleFunction {

    // 引用业务逻辑实现类 SimpleControllerImpl
    private final SimpleControllerImpl simpleImpl;

    /**
     * 构造方法,注入 SimpleControllerImpl 实例。
     *
     * @param simpleImpl SimpleControllerImpl 的实例
     */
    @Autowired
    public SimpleFunction(SimpleControllerImpl simpleImpl) {
        this.simpleImpl = simpleImpl;
    }

    /**
     * 内部静态记录类,用于封装输入参数。
     * 在这里,PriceAll 用于传递商品的数量。
     *
     * @param count 商品的数量
     */
    public record PriceAll(int count){}

    /**
     * 定义一个 Function 类型的 Bean,用于计算总价格。
     *
     * @return 一个函数,接收 PriceAll 类型的输入,返回计算结果(总价格)的字符串表示
     */
    @Bean
    @Description("获取总价格")
    public Function<PriceAll, String> getPrice(){
        return priceCount -> {
            // 从输入中获取商品数量,并调用业务逻辑计算总价格
            Double pricedAll = simpleImpl.priceAll(priceCount.count);
            // 返回总价格的字符串表示
            return pricedAll.toString();
        };

    }
}

修改我们的Impl

package org.example.springaidemo.impl;

import org.example.springaidemo.config.MychatMemory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Description;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

/**
 * SimpleControllerImpl 是一个服务类,用于处理基于 AI 的对话。
 * 它利用 Spring AI Chat 框架,通过会话 ID(token)管理不同用户的上下文和对话。
 */
@Service
public class SimpleControllerImpl {

    // AI 对话客户端实例
    private final ChatClient client;

    // 自定义的对话存储实现,用于保存用户会话上下文
    private final MychatMemory mychatMemory;

    /**
     * 构造方法,初始化 ChatClient 和自定义的对话存储。
     *
     * @param clientBuilder 用于构建 ChatClient 的构建器
     * @param mychatMemory  自定义的对话存储实现
     */
    @Autowired
    public SimpleControllerImpl(ChatClient.Builder clientBuilder, MychatMemory mychatMemory) {
        this.mychatMemory = mychatMemory;
        // 初始化 ChatClient,并设置默认系统提示和对话存储
        this.client = clientBuilder.defaultSystem(
                """
        你是一家名叫“Rojer”的淘宝客服。
        当用户语句中包含“退款”时,你需要回复“不好意思,本店不支持7天无理由退款”
        """
        )
                .defaultAdvisors(new PromptChatMemoryAdvisor(mychatMemory))
                .build();
    }

    /**
     * 生成基于用户消息和会话 token 的 AI 回复。
     *
     * @param msg   用户输入的消息
     * @param token 表示会话唯一标识,用于区分不同用户的上下文
     * @return AI 的回复内容
     */
    public String generate(String msg, String token) {
        return this.client.prompt()
                .user(msg) // 用户的输入
                .advisors(adv -> adv
                        // 设置检索的上下文记录条数
                        .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)
                        // 指定会话唯一标识,用于区分不同的用户对话
                        .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, token))
                .call() // 调用 AI 服务,生成回复
                .content(); // 获取生成的文本内容
    }

    /**
     * 以流式方式生成基于用户消息和会话 token 的 AI 回复。
     * 适用于需要逐步接收回复内容的场景,例如聊天应用中的实时响应。
     *
     * @param msg   用户输入的消息
     * @param token 表示会话唯一标识,用于区分不同用户的上下文
     * @return Flux<String> 流式的回复内容
     */
    public Flux<String> generateStream(String msg, String token) {
        return this.client.prompt()
                .user(msg) // 用户的输入
                .advisors(adv -> adv
                        // 设置检索的上下文记录条数
                        .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)
                        // 指定会话唯一标识,用于区分不同的用户对话
                        .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, token))
                .functions("getPrice")// 指定需要调用的功能
                .stream() // 以流式模式调用 AI 服务
                .content(); // 获取生成的文本流内容
    }


    public Double priceAll(int count) {
        double price = 3.25;
        double re = price * count;
        System.out.println("打印这条内容,代表已经执行了priceAll该方法。");
        return re;
    }
}

看看测试结果

以上,后面还会出AI的进一步详细且方便的使用。欢迎各位大佬持续关注

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

redis快速进门

、数据库类型认识 关系型数据库 关系型数据库是一个结构化的数据库&#xff0c;创建在关系模型&#xff08;二维表格模型&#xff09;基础上&#xff0c;一般面向于记录。 SQL 语句&#xff08;标准数据查询语言&#xff09;就是一种基于关系型数据库的语言&#xff0c;用于执行…

爬虫笔记24——纷玩岛自动抢票脚本笔记

纷玩岛自动抢票&#xff0c;协议抢票思路实现 一、获取Authorization凭证二、几个关键的参数三、几个关键的接口获取参数v&#xff0c;这个参数其实可以写死&#xff0c;可忽略通过价位获取演出的参数信息获取观演人信息&#xff0c;账号提前录入即可提交订单接口 先看实现图&a…

Netty的心跳机制怎么实现的?

大家好&#xff0c;我是锋哥。今天分享关于【Netty的心跳机制怎么实现的&#xff1f;】面试题。希望对大家有帮助&#xff1b; Netty的心跳机制怎么实现的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Netty 的心跳机制用于维持客户端和服务器之间的…

RHEL7+Oracle11.2 RAC集群-多路径(multipath+udev)安装步骤

RHEL7Oracle11.2RAC集群-多路径&#xff08;multipathudev&#xff09;安装 配置虚拟存储 使用StarWind Management Console软件&#xff0c;配置存储 dggrid1: 1g*3 Dggrid2: 1g*3 Dgsystem: 5g*1 系统表空间&#xff0c;临时表空间&#xff0c;UNDO&#xff0c;参数文件…

Sybase数据恢复—Sybase数据库无法启动,Sybase Central连接报错的处理案例

Sybase数据库数据恢复环境&#xff1a; Sybase数据库版本&#xff1a;SQL Anywhere 8.0。 Sybase数据库故障&分析&#xff1a; Sybase数据库无法启动。 错误提示&#xff1a; 使用Sybase Central连接报错。 数据库数据恢复工程师经过检测&#xff0c;发现Sybase数据库出现…

数学题转excel;数学题库;数学试卷转excel;大风车excel

一、数学试卷转excel 有些需要刷题的朋友&#xff0c;需要将题库数学题转为excel格式&#xff0c;便于管理 前端时间帮一位朋友实现了数学题转excel&#xff0c;包括选择题、填空题、分析题 示例&#xff1a; 二、问题 数学题是最难以处理的试题&#xff0c;理由如下 1、有…

开源项目:纯Python构建的中后台管理系统

来源&#xff1a;Python大数据分析 费弗里 大家好我是费老师&#xff0c;目前市面上有很多开源的「中后台管理系统」解决方案&#xff0c;复杂如「若依」那种前端基于Vue&#xff0c;后端基于Java的框架&#xff0c;虽然其提供了较为完善的一整套前后端分离权限管理系统解决方…

PS的功能学习

背景差色较大&#xff0c;就魔棒 魔棒的连续就是倒水点的跨越问题 魔棒的容差的选择就有点看经验了&#xff0c;看颜色的统一程度选择 Ctrl D 取消当前所有的选区 至于快速选择工具&#xff0c;和对象选择工具也差不多&#xff0c;只不过控制范围变成了一块一块的&#x…

linux一键部署apache脚本

分享一下自己制作的一键部署apache脚本&#xff1a; 脚本已和当前文章绑定&#xff0c;请移步下载&#xff08;免费&#xff01;免费&#xff01;免费&#xff01;&#xff09; &#xff08;单纯的分享&#xff01;&#xff09; 步骤&#xff1a; 将文件/内容上传到终端中 …

DataWhale—PumpkinBook(TASK07支持向量机)

课程开源地址及相关视频链接&#xff1a;&#xff08;当然这里也希望大家支持一下正版西瓜书和南瓜书图书&#xff0c;支持文睿、秦州等等致力于开源生态建设的大佬✿✿ヽ(▽)ノ✿&#xff09; Datawhale-学用 AI,从此开始 【吃瓜教程】《机器学习公式详解》&#xff08;南瓜…

排序算法之插入排序篇

插入排序 思路&#xff1a; 就是将没有排序的元素逐步地插入到已经排好序的元素后面&#xff0c;保持元素的有序 视频的实现过程如下&#xff1a; 插入排序全过程 代码实现过程如下&#xff1a; public static void Insertion(int[] arr) { for (int i 1; i < arr.length…

3DMAX星空图像生成器插件使用方法详解

3DMAX星空图像生成器插件&#xff0c;一键生成星空或夜空的二维图像。它可用于创建天空盒子或空间场景&#xff0c;或作为2D艺术的天空背景。 【主要特点】 -单击即可创建星空图像或夜空。 -星数、亮度、大小、形状等参数。 -支持任何图像大小&#xff08;方形&#xff09;。…

Flutter 权限申请

这篇文章是基于permission_handler 10.2.0版本写的 前言 在App开发过程中我们经常要用到各种权限&#xff0c;我是用的是permission_handler包来实现权限控制的。 pub地址&#xff1a;https://pub.dev/packages/permission_handler permission_handler 权限列表 变量 Androi…

前端学习笔记之FileReader

概念 FileReader接口允许网页应用程序异步读取用户计算机上存储的文件&#xff08;或原始数据缓冲区&#xff09;的内容&#xff0c;使用File或Blob对象来制定要读取的文件或数据。 File对象可以通过用户使用<input>元素选择文件后返回的FileList对象获得&#xff0c;或…

通过shell脚本分析部署nginx网络服务

要求 1.接收用户部署的服务名称 2.判断服务是否安装 已安装&#xff1b;自定义网站配置路径为/www&#xff1b;并创建共享目录和网页文件&#xff1b;重启服务 没有安装&#xff1b;安装对应的软件包 3.测试 判断服务是否成功运行&#xff1b; 已运行&#xff0c;访问网站…

Java基础——(三)对象和类

1. 面向对象程序设计概述 1.1 OOP OOP&#xff1a;Object Oriented Programming&#xff0c;面向对象编程&#xff1b;OOD&#xff1a;Object Oriented Design&#xff0c;面向对象设计&#xff1b;OOA&#xff1a;Object Oriented Analyse&#xff0c;面向对象分析。 面向对…

vue2日历组件

【效果图】 <template><div style"width: 100%"><!-- <div> --><!-- <div>{{ startDate.getMonth() 1 - startDate.getDate() }}</div><div>{{ endDate.getMonth() 1 - endDate.getDate() }}</div> --&g…

Redis中的分布式锁(步步为营)

分布式锁 概述 分布式锁指的是&#xff0c;所有服务中的所有线程都去获取同一把锁&#xff0c;但只有一个线程可以成功的获得锁&#xff0c;其他没有获得锁的线程必须全部等待&#xff0c;直到持有锁的线程释放锁。 分布式锁是可以跨越多个实例&#xff0c;多个进程的锁 分布…

mmsegmentation自己的数据集

我最大的问题就是没安装官方给定的mask转换格式来转换 这种带白色的不行哦&#xff01; 黑色的可以&#xff0c;其实mask*50就可以看清楚标记的轮廓之类的。 数据集格式转换按照A,B,C代码直接转换&#xff1a;https://github.com/TommyZihao/Label2Everything/tree/main/lab…

yolov8的深度学习环境安装(cuda12.4、ubuntu22.04)

目录 一、先安装基础环境包 1.首先给Ubuntu安装Chrome浏览器&#xff08;搜索引擎换成百度即可&#xff09; 2、ubuntu 22.04中文输入法安装 3、安装 terminator 4、安装WPS for Linux 5、安装其它之前需要先安装anaconda 6、安装配置anaconda 7、安装完成anaconda后创建…