在哪个网站做民营企业申报/网页制作与设计
进阶版是在基础的对话版之上进行新增功能。
如果还没弄出基础版的,请参考
https://blog.csdn.net/weixin_54925172/article/details/144143523?sharetype=blogdetail&sharerId=144143523&sharerefer=PC&sharesource=weixin_54925172&spm=1011.2480.3001.8118
一,进阶版需要实现的功能
- 给AI进行功能预设
- 记忆对话,能自动联系上下文语境
- 结合业务,通过对话操作系统业务
简单解释一下
给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;@Autowiredpublic 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;@Autowiredpublic 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;@Autowiredpublic 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();}
}
这里需要注意,大模型是经过特定训练后的,它无法做出一些本身禁止于大模型的回复,
比如说污言秽语,比如说民族纠纷,比如说反人类语言。
这个时候,我们再进行一些简单测试
记忆对话,能自动联系上下文语境
这里有两个方面
- 需要开启ai的记忆功能
- 需要对不同用户进行分别的处理
别的不多说,都在代码中,注释中
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 自定义的对话存储实现*/@Autowiredpublic 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<>();@Overridepublic void add(String conversationId, List<Message> messages) {this.conversationHistory.computeIfAbsent(conversationId, id -> Collections.synchronizedList(new ArrayList<>())).addAll(messages);}@Overridepublic void add(String conversationId, Message message) {this.conversationHistory.computeIfAbsent(conversationId, id -> Collections.synchronizedList(new ArrayList<>())).add(message);}@Overridepublic 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())); // 返回一个新列表,避免外部修改}@Overridepublic 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 {// 引用业务逻辑实现类 SimpleControllerImplprivate final SimpleControllerImpl simpleImpl;/*** 构造方法,注入 SimpleControllerImpl 实例。** @param simpleImpl SimpleControllerImpl 的实例*/@Autowiredpublic 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 自定义的对话存储实现*/@Autowiredpublic 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的进一步详细且方便的使用。欢迎各位大佬持续关注
相关文章:

SpringAi整合大模型(进阶版)
进阶版是在基础的对话版之上进行新增功能。 如果还没弄出基础版的,请参考 https://blog.csdn.net/weixin_54925172/article/details/144143523?sharetypeblogdetail&sharerId144143523&sharereferPC&sharesourceweixin_54925172&spm1011.2480.30…...

为什么爱用低秩矩阵
目录 为什么爱用低秩矩阵 一、定义与性质 二、区别与例子 为什么爱用低秩矩阵 我们更多地提及低秩分解而非满秩分解,主要是因为低秩分解在数据压缩、噪声去除、模型简化和特征提取等方面具有显著的优势。而满秩分解虽然能够保持数据的完整性,但在实际应用中的场景较为有限…...

React 自定义钩子:useOnlineStatus
我们今天的重点是 “useOnlineStatus” 钩子,这是 React 自定义钩子集合中众多精心制作的钩子之一。 Github 的:https://github.com/sergeyleschev/react-custom-hooks import { useState } from "react" import useEventListener from &quo…...

uniapp 小程序 监听全局路由跳转 获取路由参数
uniapp 小程序 监听全局路由跳转 获取路由参数 app.vue中 api文档 onLaunch: function(options) {let that this;let event [navigateTo, redirectTo, switchTab, navigateBack];event.forEach(item > {uni.addInterceptor(item, { //监听跳转//监听跳转success(e) {tha…...

12.02 深度学习-卷积
# 卷积 是用于图像处理 能够保存图像的一些特征 卷积层 如果用全连接神经网络处理图像 计算价格太大了 图像也被转为线性的对象导致失去了图像的空间特征 只有在卷积神经网络cnn的最后一层使用全连接神经网络 # 图像处理的三大任务 # 目标检测 对图像中的目标进行框出来 # 图…...

MySQL 主从同步一致性详解
MySQL主从同步是一种数据复制技术,它允许数据从一个数据库服务器(主服务器)自动同步到一个或多个数据库服务器(从服务器)。这种技术主要用于实现读写分离、提升数据库性能、容灾恢复以及数据冗余备份等目的。下面将详细…...

Spring源码导入idea时gradle构建慢问题
当我们将spring源码导入到idea进行构建的时候,spring采用的是gradle进行构建,默认下注在依赖是从https://repo.maven.apache.org会特别慢,需要改为国内的镜像地址会加快速度。 将项目中build.gradle配置进行调整: repositories …...

Dockerfile 安装echarts插件给java提供服务
java调用echarts插件,生成图片保存到磁盘然后插入到pptx中报表。 Dockerfile文件内容: #基础镜像,如果本地仓库没有,会从远程仓库拉取 openjdk:8 FROM docker.io/centos:centos7 #暴露端口 EXPOSE 9311 # 避免centos 日志输出 …...

Springboot小知识(1):启动类与配置
一、启动类(引导类) 在通常情况下,你创建的Spring应用项目都会为你自动生成一个启动类,它是这个应用的起点。 在Spring Boot中,引导类(也称为启动类,通常是main方法所在的类)是整个…...

[CISCN 2019华东南]Web11
[CISCN 2019华东南]Web11 给了两个链接但是都无法访问 这里我们直接抓包试一下 我们插入X-Forwarded-For:127.0.0.1 发现可以修改了右上角的IP地址,从而可以进行注入 {$smarty.version} 查看版本号 if标签执行PHP命令 {if phpinfo()}{/if} 查看协议 {if system(…...

Cypress内存溢出奔溃问题汇总
内存溢出报错信息 <--- Last few GCs ---> [196:0xe58001bc000] 683925 ms: Scavenge 1870.7 (1969.9) -> 1865.6 (1969.9) MB, 6.07 / 0.00 ms (average mu 0.359, current mu 0.444) task; [196:0xe58001bc000] 683999 ms: Scavenge 1872.4 (1969.9) -> 1867.1…...

树莓派4B--OpenCV安装踩坑
报错: Source directory: /tmp/pip-install-pv7l9r25/opencv-python_08fdf5a130a5429f89b0e0eaab39a329 Working directory: /tmp/pip-install-pv7l9r25/opencv-python_08fdf5a130a5429f89b0e0eaab39a329/_skbuild/linux-armv7l-3.7/cmake-build Please check the i…...

电子电气架构 --- 面向服务的汽车诊断架构
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…...

Pytest --capture 参数详解:如何控制测试执行过程中的输出行为
--capture 选项用于控制测试用例执行过程中标准输出(stdout)和标准错误输出(stderr)的捕获行为。 --capture 的选项值: fd(默认) 捕获文件描述符级别的输出(stdout 和 stderr&#x…...

IS-IS的原理
IS-IS的基本概念: 概述: IS-IS,中间系统到中间系统,是ISO国际标准化组织为它的无连接网络协议设计的一种动态路由协议 IS-IS支持CLNP网络和IP网络,采用数据链路层封装,区别于ospf只支持IP网络࿰…...

C++(4个类型转换)
1. C语言中的类型转换 1. 隐式 类型转换: 具有相近的类型才能进行互相转换,如:int,char,double都表示数值。 2. 强制类型转换:能隐式类型转换就能强制类型转换,隐式类型之间的转换类型强相关,强制类型转换…...

Ubuntu20.04安装NVIDIA显卡驱动
Ubuntu20.04安装NVIDIA显卡驱动 参考资料:https://blog.csdn.net/weixin_39244242/article/details/136282614?fromshareblogdetail&sharetypeblogdetail&sharerId136282614&sharereferPC&sharesourceqq_37397652&sharefromfrom_link 成功配置…...

速盾:介绍一下高防cdn的缓存响应事什么功能?
高防CDN(Content Delivery Network)是一种基于分布式缓存技术的网络加速服务,能够提供强大的缓存响应功能。它的缓存响应功能主要包括缓存加速和智能缓存两个方面。 首先,高防CDN的缓存加速功能是指通过在全球范围内部署大量的缓…...

Nuclei-快速漏洞扫描器
Nuclei-快速漏洞扫描器 声明 学习内容来自 B 站UP主泷羽sec,如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。 ✍Ἷ…...

linux网络抓包工具
linux网络抓包工具 一、tcpdump1.1 基本用法1.2 龙芯平台实例操作 二、wireshark2.1 主要功能2.2 龙芯平台实例操作 一、tcpdump tcpdump 指令可列出经过指定网络界面的数据包文件头,可以将网络中传送的数据包的 “头” 完全截获下来提供分析。它支持针对网络层、协…...

详解桥接模式
引言 在开发过程中,可能会遇到系统设计有多种维度变化的情况,比如我们想画一幅五彩斑斓的画,需要用到12个颜色,但是需要粗细不同的线条(粗、中、细),如果用蜡笔,就需要粗中细三种蜡笔…...

探索AI新世界!热门工具与学习资源免费获取
抖知书老师推荐: 人工智能技术的迅速发展让人们既充满期待又有些迷茫。有人担忧被AI技术取代,有人却积极拥抱这场科技浪潮。无论你处于哪种心态,人工智能已经深入到我们生活的方方面面。如果你希望轻松掌握最新的AI工具与动态,…...

vue3项目搭建-6-axios 基础配置
axios 基础配置 安装 axios npm install axios 创建 axios 实例,配置基地址,配置拦截器,目录:utils/http.js 基地址:在每次访问时,自动作为相对路径的根 // axios 基础封装 import axios from "axios";…...

Django 视图层
from django.shortcuts import render, HttpResponse, redirectfrom django.http import JsonResponse1. render: 渲染模板 def index(request):print(reverse(index))return render(request, "index.html")return render(request, index.html, context{name: lisi})…...

代理IP与百度在信息时代的交互
目录 一、代理IP的基本概念和工作原理 二、代理IP在百度搜索中的多重作用 解决网络延时问题,提高搜索速度 提高网络安全 隐藏用户的真实IP地址,保护个人隐私 突破访问限制,拓宽网络视野 三、代理IP在百度关键词排名优化中的应用 模拟…...

1、Three.js开端准备环境
准备工作 从 CDN 导入 1.安装 VSCode 2.安装 Node.js 3.查看Three.js最新版本 4.如何cdn引入: https://cdn.jsdelivr.net/npm/threev版本号/build/three.module.js 例如:https://cdn.jsdelivr.net/npm/threev0.170.0/build/three.module.js 我们需要…...

什么是Batch Normalization?
一、概念 Batch Normalization是在2015年提出的数据归一化方法,主要用在深度神经网络中激活层之前。它的主要作用是加快模型训练时的收敛速度,使模型训练过程更加稳定,避免梯度爆炸或消失,并起到一定的正则化作用,有时…...

十四(AJAX)、AJAX、axios、常用请求方法(GET POST...)、HTTP协议、接口文档、form-serialize
1. AJAX介绍及axios基本使用 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content&q…...

vue2怎么写computed属性
在Vue 2中,computed属性是基于它们的响应式依赖进行缓存的计算属性。只有当计算属性依赖的响应式数据发生变化时,计算属性才会重新计算。以下是如何在Vue 2中定义computed属性的步骤: 定义响应式数据:首先,你需要在组件…...

【从零开始的LeetCode-算法】35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: 2示例 2: 输入: …...