当前位置: 首页 > news >正文

SpringAI从入门到熟练

学习SpringAI的记录情况

文章目录


前言

因公司需要故而学习SpringAI文档,故将自己所见所想写成文章,供大佬们参考

主要是为什么这么写呢,为何不抽出来呢,还是希望可以用的时候更加方便一点,如果大家有需求可以自行去优化。

SrpingAI入门

这里我用到的是智普AI,大家可以根据自己喜欢用的AI自由进行切换

 至于API-KEY可自行去智谱AI开放平台可自行去找,这里新用户注册目前是还送2000万TOKEN的

引包

        <!--智普AI--><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-zhipuai-spring-boot-starter</artifactId></dependency>

 配置文件

 至于API-KEY可自行去智谱AI开放平台可自行去找,这里新用户注册目前是还送2000万TOKEN的

配置类

获取API-KEY

@Component
public class ChatConfig {//获取配置文件中的API-KEY@Value("${spring.ai.zhipuai.api-key}")private String apiKey;public String getApiKey() {return apiKey;}
}

 测试用例代码

    //为啥用这个模型呢,因为免费private static final String default_model = "GLM-4-Flash";//temperature 是一个超参数,用于控制生成文本的多样性和随机性。//低温度(例如:0.1 到 0.3):模型会生成更确定、常规和一致的输出。低温度通常会使模型产生更 加保守的回答,重复性较高,生成的内容更加准确、接近训练数据中的常见模式。//高温度(例如:0.7 到 1.0):模型的输出会更加随机、多样、创意性强。高温度会导致生成的内容 更加多样化,可能包括一些不太常见或创新性的回答,但也可能带来不太准确或不太连贯的结果。private static final double default_temperature = 0.7;   @GetMapping("/AIchat")public BaseResponse<String> AIGeneration(@RequestParam(value = "message", defaultValue = "你是谁呢") String message) {// 创建ZhiPuAiChatOptions对象,设置模型和温度ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().withModel(default_model).withTemperature(default_temperature).build();// 创建ZhiPuAiChatModel对象,传入ZhiPuAiApi和optionsChatModel chatModel = new ZhiPuAiChatModel(new                 ZhiPuAiApi(chatConfig.getApiKey()), options);// 创建ChatClient对象,传入chatModelChatClient build = ChatClient.builder(chatModel).build();String substring = "";String content = null;try {// 调用build.prompt()方法,传入用户消息,调用call()方法,获取返回内容content = build.prompt().user(message).call().content();} catch (Exception e) {// 获取异常信息String errorMessage = e.getMessage();// 获取异常信息中冒号后面的内容int i = errorMessage.lastIndexOf(":");String newString = errorMessage.substring(i + 2);// 去掉异常信息中的最后一个字符substring = newString.substring(0, newString.length() - 3);}// 如果异常信息不为空,抛出BusinessException异常if(!substring.isEmpty()){throw new BusinessException(ErrorCode.PARAMS_ERROR,substring);}// 返回成功结果return ResultUtils.success(content);}

 测试AI返回结果

 全参数响应结果

这里是对token的消耗做了一个统计,查看用户的所剩token情况的一个返回结果展示

其实也就只是把String类型的返回结果转成了ChatResponse类型仅此而已

测试用例代码

 @GetMapping("/AIchat")public BaseResponse<ChatResponse> AIGeneration(@RequestParam(value = "message", defaultValue = "你是谁呢") String message) {// 创建ZhiPuAiChatOptions对象,设置模型和温度ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().withModel(default_model).withTemperature(default_temperature).build();// 创建ZhiPuAiChatModel对象,传入ZhiPuAiApi和optionsChatModel chatModel = new ZhiPuAiChatModel(new ZhiPuAiApi(chatConfig.getApiKey()), options);// 创建ChatClient对象,传入chatModelChatClient build = ChatClient.builder(chatModel).build();String substring = "";ChatResponse chatResponse = null;try {chatResponse = build.prompt().user(message).call().chatResponse();} catch (Exception e) {// 获取异常信息String errorMessage = e.getMessage();// 获取异常信息中冒号后面的内容int i = errorMessage.lastIndexOf(":");String newString = errorMessage.substring(i + 2);// 去掉异常信息中的最后一个字符substring = newString.substring(0, newString.length() - 3);}// 如果异常信息不为空,抛出BusinessException异常if(!substring.isEmpty()){throw new BusinessException(ErrorCode.PARAMS_ERROR,substring);}// 返回成功结果return ResultUtils.success(chatResponse);}

返回结果

 前端传递不同的模型测试方法

测试用例代码

    @GetMapping("/chat")public BaseResponse<String> generation(@RequestParam(value = "message", defaultValue = "你是谁呢") String message,@RequestParam(value = "model", defaultValue = "GLM-4-Flash") String model,@RequestParam(value = "temperature", defaultValue = "0.7") double temperature) {// 创建新的 ZhiPuAiChatOptions 实例,根据请求的参数动态设置ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().withModel(model).withTemperature(temperature).build();// 获取 ChatModel 实例,使用新的配置ChatModel chatModel = new ZhiPuAiChatModel(new ZhiPuAiApi(chatConfig.getApiKey()), options);ChatClient build = ChatClient.builder(chatModel).build();String substring = "";// 使用新的 ChatModel 进行对话生成String content = null;try {content = build.prompt().user(message).call().content();} catch (Exception e) {// 获取错误消息String errorMessage = e.getMessage();int i = errorMessage.lastIndexOf(":");String newString = errorMessage.substring(i + 2);substring = newString.substring(0, newString.length() - 3);}if(!substring.isEmpty()){throw new BusinessException(ErrorCode.PARAMS_ERROR,substring);}return ResultUtils.success(content);}

 其实跟上面的代码差不多,只不过是从前端传递过来一个模型,当然这里我并没有对于上传上来的模型做校验,如果感兴趣的话,可自行查看,并解决

 测试结果

 这里可以看到我们的异常返回起到效果了,原谅我是一个穷鬼,不想花钱在测试这个上面

 测试到这里,相信你已经知道了点什么,就是如果你问的问题较长的话,实际使用GET传输是有问题的,因为默认GET请求的长度是有限制的,建议自行换成POST请求,然后再继续往下

流式响应

测试用例代码

@GetMapping(value = "/AIStream",produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> AIStream(@RequestParam(value = "message", defaultValue = "你是谁呢") String message) {// 创建ZhiPuAiChatOptions对象,设置模型和温度ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().withModel(default_model).withTemperature(default_temperature).build();// 创建ZhiPuAiChatModel对象,传入ZhiPuAiApi和optionsChatModel chatModel = new ZhiPuAiChatModel(new ZhiPuAiApi(chatConfig.getApiKey()), options);// 创建ChatClient对象,传入chatModelChatClient chatClient = ChatClient.builder(chatModel).build();Flux<String> content = chatClient.prompt().user(message).stream().content();// 返回成功结果return content;}

响应结果

这里使用的是SSE,SSE是一种服务端向客户端推送的一种技术,需要的可自行去浏览这个技术

 流式响应全参数

测试用例代码

// 使用GetMapping注解,指定请求路径为/AIChatResponseStream,返回类型为TEXT_EVENT_STREAM_VALUE@GetMapping(value = "/AIChatResponseStream",produces = MediaType.TEXT_EVENT_STREAM_VALUE)// 定义一个方法,返回类型为Flux<ChatResponse>,参数为String类型的message,默认值为"你是谁呢"public Flux<ChatResponse> AIChatResponseStream(@RequestParam(value = "message", defaultValue = "你是谁呢") String message) {// 创建ZhiPuAiChatOptions对象,设置模型和温度ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().withModel(default_model).withTemperature(default_temperature).build();// 创建ChatModel对象,传入ZhiPuAiApi和optionsChatModel chatModel = new ZhiPuAiChatModel(new ZhiPuAiApi(chatConfig.getApiKey()), options);// 创建ChatClient对象,传入chatModelChatClient chatClient = ChatClient.builder(chatModel).build();// 调用chatClient的prompt方法,传入message,返回一个Flux<ChatResponse>对象Flux<ChatResponse> chatResponseFlux = chatClient.prompt().user(message).stream().chatResponse();// 返回Flux<ChatResponse>对象return chatResponseFlux;}

响应结果

 至于这里如何查看内容流式响应全参数输出完毕,有一个STOP的停止参数可以使用

位置贴到下面

//全参数流失响应地址接口停止标志--------------当然这里如果你要配合前端可以通过这个STOP来观察结果是否输出完毕,可以通过这个标志来停掉SSE连接
parsedData.results[0].metadata.finishReason === "STOP"

 默认角色回复实现

测试用例代码

// 使用GetMapping注解,指定请求路径为/AIChatDefaultStream,返回类型为文本流@GetMapping(value = "/AIChatDefaultStream",produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> AIChatDefaultStream(// 使用@RequestParam注解,指定请求参数名为message,默认值为"你是谁呢"@RequestParam(value = "message", defaultValue = "你是谁呢") String message) {// 创建ZhiPuAiChatOptions对象,设置模型和温度ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().withModel(default_model).withTemperature(default_temperature).build();// 创建ChatModel对象,使用ZhiPuAiChatModel和ZhiPuAiApiChatModel chatModel = new ZhiPuAiChatModel(new ZhiPuAiApi(chatConfig.getApiKey()), options);// 创建ChatClient对象,设置默认系统ChatClient chatClient = ChatClient.builder(chatModel).defaultSystem("你现在的身份是一个星轨会议系统的客服助手,请以友好、乐于助人且愉快的方式来回复。").build();// 调用chatClient的prompt方法,设置用户消息,并返回内容流Flux<String> content = chatClient.prompt().user(message).stream().content();// 返回内容流return content;}

 响应结果

 这里就可以看到响应结果他已经换成了星轨会议系统的客服助手,如果你希望做某一个角色的内容,你可以通过预训练这个参数,使得这个AI客服助手的回复更加友好。

AI知晓日期

测试用例代码

// 使用GetMapping注解,指定请求路径为/AIChatDefaultStream,返回类型为文本流@GetMapping(value = "/AIChatDefaultStream",produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> AIChatDefaultStream(// 使用@RequestParam注解,指定请求参数名为message,默认值为"你是谁呢"@RequestParam(value = "message", defaultValue = "你是谁呢") String message) {// 创建ZhiPuAiChatOptions对象,设置模型和温度ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().withModel(default_model).withTemperature(default_temperature).build();// 创建ChatModel对象,使用ZhiPuAiChatModel和ZhiPuAiApiChatModel chatModel = new ZhiPuAiChatModel(new ZhiPuAiApi(chatConfig.getApiKey()), options);// 创建ChatClient对象,设置默认系统ChatClient chatClient = ChatClient.builder(chatModel).defaultSystem("你现在的身份是一个星轨会议系统的客服助手,请以友好、乐于助人且愉快的方式来回复。我希望你可以以中文的方式给我回答。今天的日期是 {current_date}.").build();// 调用chatClient的prompt方法,设置用户消息,并返回内容流Flux<String> content = chatClient.prompt().user(message).system(s->s.param("current_date", LocalDate.now().toString())).stream().content();// 返回内容流return content;}

响应结果

 这样的话AI就知道当前的日期

 记忆对话

测试用例代码

创建一个配置类引入ChatMemory

@Configuration
public class ZhiPuChatMemoryConfig {@Bean@Qualifier("customMemory")public ChatMemory chatMemory() {return new InMemoryChatMemory();}}

 引入ChatMemory

// 使用GetMapping注解,指定请求路径为/AIChatDefaultStream,返回类型为文本流@GetMapping(value = "/AIChatDefaultStream",produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> AIChatDefaultStream(// 使用RequestParam注解,指定请求参数名为message,类型为String@RequestParam(value = "message") String message) {// 创建ZhiPuAiChatOptions对象,设置模型和温度ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().withModel(default_model).withTemperature(default_temperature).build();// 创建ChatModel对象,传入ZhiPuAiApi和optionsChatModel chatModel = new ZhiPuAiChatModel(new ZhiPuAiApi(chatConfig.getApiKey()), options);// 创建ChatClient对象,传入chatModel,设置默认系统消息和默认顾问ChatClient chatClient = ChatClient.builder(chatModel).defaultSystem("你现在的身份是一个星轨会议系统的客服助手,请以友好、乐于助人且愉快的方式来回复。我希望你可以以中文的方式给我回答。这里我问你日期的话再回答,否则的话你不要回答,今天的日期是 {current_date}.")//.defaultAdvisors(new PromptChatMemoryAdvisor(chatMemory)).defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)).build();// 调用chatClient的prompt方法,设置用户消息、系统消息参数、顾问参数,返回内容流Flux<String> content = chatClient.prompt().user(message).system(s->s.param("current_date", LocalDate.now().toString())).advisors(a -> a.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)).stream().content();// 返回内容流return content;}

 响应结果

这样的话就会记住你最近的100条对话,当然这里你也可以自行实现ChatMemory,使用Redis去进行获取

 上面两种记忆是不同的,具体详情,请看下表

特性MessageChatMemoryAdvisorPromptChatMemoryAdvisor
记忆管理粒度基于消息(Message)级别的记忆基于提示(Prompt)级别的记忆
记忆的存储方式将每一条消息存储到记忆中生成合适的提示,将历史对话作为提示提供给模型
适用场景适用于需要精细管理每一条消息的场景适用于需要生成合适提示来为模型提供上下文的场景
如何影响对话直接影响聊天记录,确保每一条消息都被记住影响提示构造,确保生成的提示与上下文一致
内存管理的灵活性依赖于每个消息的存储提示的构造和上下文的动态管理

打印日志功能

 测试用例代码

其实也就是再次添加一个Advisors,再控制台打印一下就可以

public class LoggingAdvisors implements RequestResponseAdvisor {@Overridepublic AdvisedRequest adviseRequest(AdvisedRequest request, Map<String, Object> adviseContext) {System.out.println("Request"+request);return request;}@Overridepublic int getOrder() {return 0;}
}
// 使用GetMapping注解,指定请求路径为/AIChatDefaultStream,返回类型为文本流@GetMapping(value = "/AIChatDefaultLoggingStream",produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> AIChatDefaultLoggingStream(// 使用RequestParam注解,指定请求参数名为message,类型为String@RequestParam(value = "message") String message) {// 创建ZhiPuAiChatOptions对象,设置模型和温度ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().withModel(default_model).withTemperature(default_temperature).build();// 创建ChatModel对象,传入ZhiPuAiApi和optionsChatModel chatModel = new ZhiPuAiChatModel(new ZhiPuAiApi(chatConfig.getApiKey()), options);// 创建ChatClient对象,传入chatModel,设置默认系统消息和默认顾问ChatClient chatClient = ChatClient.builder(chatModel).defaultSystem("你现在的身份是一个星轨会议系统的客服助手,请以友好、乐于助人且愉快的方式来回复。我希望你可以以中文的方式给我回答。这里我问你日期的话再回答,否则的话你不要回答,今天的日期是 {current_date}.")//.defaultAdvisors(new PromptChatMemoryAdvisor(chatMemory)).defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory),new LoggingAdvisors()).build();// 调用chatClient的prompt方法,设置用户消息、系统消息参数、顾问参数,返回内容流Flux<String> content = chatClient.prompt().user(message).system(s->s.param("current_date", LocalDate.now().toString())).advisors(a -> a.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)).stream().content();// 返回内容流return content;}

 响应结果

 

 FunctionCall回调

测试用例代码

package com.hhh.springai_test.Client;import com.hhh.springai_test.config.ChatConfig;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;@Component
public class ZhipuChatClient {@Resourceprivate ChatConfig chatConfig;@Autowired@Qualifier("customMemory")  // 明确指定使用你自定义的 ChatMemory 实现private ChatMemory chatMemory;public ChatClient getZhipuChatClient() {ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().withModel("GLM-4-Flash").withTemperature(0.95F).build();// 创建ChatModel对象,传入ZhiPuAiApi和optionsChatModel chatModel = new ZhiPuAiChatModel(new ZhiPuAiApi(chatConfig.getApiKey()), options);// 创建ChatClient对象,传入chatModel,设置默认系统消息和默认顾问ChatClient chatClient = ChatClient.builder(chatModel).defaultSystem("你现在的身份是一个星轨会议系统的客服助手,请以友好、乐于助人且愉快的方式来回复。我希望你可以以中文的方式给我回答。这里我问你日期的话再回答,否则的话你不要回答").defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)).build();return chatClient;}
}
 @GetMapping(value = "/AIChatDefaultLoggingStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> AIChatDefaultLoggingStream(@RequestParam(value = "message") String message) {Flux<String> content = zhipuChatClient.getZhipuChatClient().prompt().user(message).function("report", "举报", new Function<MyController.Request, Flux<String>>() {@Overridepublic Flux<String> apply(MyController.Request request) {System.out.println("举报名字是" + request.name);return Flux.just("星轨");}}).stream().content();return content;}

 测试用例结果

 

 可以看到日志也已经解决了,在这里遇到了整整两天的bug,一直在尝试使用functions,通过传递functionBean来进行解决,但是一直是有问题的,但是一直报错,只能使用这种方式来解决,当然,如果大佬们有好的文章,记得可以推荐我使用一下,谢谢各位大佬们

相关文章:

SpringAI从入门到熟练

学习SpringAI的记录情况 文章目录 前言 因公司需要故而学习SpringAI文档&#xff0c;故将自己所见所想写成文章&#xff0c;供大佬们参考 主要是为什么这么写呢&#xff0c;为何不抽出来呢&#xff0c;还是希望可以用的时候更加方便一点&#xff0c;如果大家有需求可以自行去…...

[算法] [leetcode-20] 有效的括号

20 有效的括号 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合…...

R语言入门笔记:第一节,快速了解R语言——文件与基础操作

关于 R 语言的简单介绍 上一期 R 语言入门笔记里面我简单介绍了 R 语言的安装和使用方法&#xff0c;以及各项避免踩坑的注意事项。我想把这个系列的笔记持续写下去。 这份笔记只是我的 R 语言入门学习笔记&#xff0c;而不是一套 R 语言教程。换句话说&#xff1a;这份笔记不…...

【亚马逊云】基于Amazon EC2实例部署 NextCloud 云网盘并使用 Docker-compose 搭建 ONLYOFFICE 企业在线办公应用软件

文章目录 1. 部署EC2实例2. 安装 Docker 服务3. 安装docker-compose4. 创建Docker-compose文件5. 创建nginx.conf文件6. 运行docker-compose命令开始部署7. 访问ONLYOFFICE插件8. 访问NextCloud云盘9. 下载并启用ONLYOFFICE插件10. 上传文件测试11. 所遇问题12. 参考链接 1. 部…...

java Redisson 实现限流每秒/分钟/小时限制N个

1.引入maven包: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.redisson</groupId><artifactId>red…...

【漫话机器学习系列】029.累积分布函数(Cumulative Distribution Function)

累积分布函数&#xff08;Cumulative Distribution Function, CDF&#xff09; 累积分布函数&#xff08;CDF&#xff09;是概率论和统计学中的一个基本概念&#xff0c;用于描述随机变量取值的累积概率分布情况。它在理论研究和实际应用中广泛使用。 定义 给定随机变量 X&am…...

设计模式之访问者模式:一楼千面 各有玄机

~犬&#x1f4f0;余~ “我欲贱而贵&#xff0c;愚而智&#xff0c;贫而富&#xff0c;可乎&#xff1f; 曰&#xff1a;其唯学乎” 一、访问者模式概述 \quad 江湖中有一个传说&#xff1a;在遥远的东方&#xff0c;有一座神秘的玉楼。每当武林中人来访&#xff0c;楼中的各个房…...

AI 编程的世界:用Cursor编写评分项目

AI 编程的世界&#xff1a;用Cursor编写评分项目 今天是2024年的最后一天&#xff0c;祝大家在新的一年&#xff0c;健康开心快乐&#xff01; 岁末之际&#xff0c;星辰为伴&#xff0c;灯火长明&#xff0c;我终于在 2024 年的最后一天成功上线了 AI 编程项目。回首这一年&am…...

Cesium教程(二十三):Cesium实现下雨场景

文章目录 实现效果代码引入js文件创建容器创建视图定义下雨场景完整代码下载实现效果 代码 在 Cesium 中利用PostProcessStageLibrary实现下雪场景,你可以按照以下步骤进行: 创建一个 PostProcessStage:首先,你需要创建一个PostProcessStage对象,它将用于定义下雪效果的渲…...

SpringCloudAlibaba技术栈-Higress

1、什么是Higress? 云原生网关&#xff0c;干啥的&#xff1f;用通俗易懂的话来说&#xff0c;微服务架构下Higress 就像是一个智能的“交通警察”&#xff0c;它站在你的网络世界里&#xff0c;负责指挥和调度所有进出的“车辆”&#xff08;也就是数据流量&#xff09;。它的…...

uniapp 微信小程序开发使用高德地图、腾讯地图

一、高德地图 1.注册高德地图开放平台账号 &#xff08;1&#xff09;创建应用 这个key 第3步骤&#xff0c;配置到项目中locationGps.js 2.下载高德地图微信小程序插件 &#xff08;1&#xff09;下载地址 高德地图API | 微信小程序插件 &#xff08;2&#xff09;引入项目…...

Springboot:后端接收数组形式参数

1、接收端写法 PermissionAnnotation(permissionName "",isCheckToken true)PostMapping("/batchDeleteByIds")public ReturnBean webPageSelf( NotNull(message "请选择要删除的单据&#xff01;") Long[] ids) {for (Long string : ids) {l…...

Postman[2] 入门——界面介绍

可参考官方 文档 Postman 导航 | Postman 官方帮助文档中文版Postman 拥有各种工具、视图和控件&#xff0c;帮助你管理 API 项目。本指南是对 Postman 主要界面区域的高级概述&#xff1a;https://postman.xiniushu.com/docs/getting-started/navigating-postman 1. Header&a…...

1月第四讲:Java Web学生自习管理系统

一、项目背景与需求分析 随着网络技术的不断发展和学校规模的扩大&#xff0c;学生自习管理系统的需求日益增加。传统的自习管理方式存在效率低下、资源浪费等问题&#xff0c;因此&#xff0c;开发一个智能化的学生自习管理系统显得尤为重要。该系统旨在提高自习室的利用率和…...

【Redis】Redis 典型应用 - 缓存 (cache)

目录 1. 什么是缓存 2. 使用 Redis 作为缓存 3. 缓存的更新策略 3.1 定期生成 3.2 实时生成 4. 缓存的淘汰策略 5. 缓存预热, 缓存穿透, 缓存雪崩 和 缓存击穿 关于缓存预热 (Cache preheating) 关于缓存穿透 (Cache penetration) 关于缓存雪崩 (Cache avalanche) 关…...

HTML——38.Span标签和字符实体

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>span标签和字符实体</title><style type"text/css">h1{text-align: center;}p{text-indent: 2em;}span{color: red;}</style></head><…...

ROS2+OpenCV综合应用--10. AprilTag标签码追踪

1. 简介 apriltag标签码追踪是在apriltag标签码识别的基础上&#xff0c;增加了小车摄像头云台运动的功能&#xff0c;摄像头会保持标签码在视觉中间而运动&#xff0c;根据这一特性&#xff0c;从而实现标签码追踪功能。 2. 启动 2.1 程序启动前的准备 本次apriltag标签码使…...

python Celery 是一个基于分布式消息传递的异步任务队列系统

Celery 是一个基于分布式消息传递的异步任务队列系统&#xff0c;主要用于处理耗时任务、定时任务和周期性任务。它能够将任务分配到多个工作节点&#xff08;Worker&#xff09;上执行&#xff0c;从而提高应用程序的性能和可扩展性。Celery 是 Python 生态中最流行的任务队列…...

嵌入式硬件杂谈(七)IGBT MOS管 三极管应用场景与区别

引言&#xff1a;在现代嵌入式硬件设计中&#xff0c;开关元件作为电路中的重要组成部分&#xff0c;起着至关重要的作用。三种主要的开关元件——IGBT&#xff08;绝缘栅双极型晶体管&#xff09;、MOSFET&#xff08;金属氧化物半导体场效应晶体管&#xff09;和三极管&#…...

麒麟信安云在长沙某银行的应用入选“云建设与应用领航计划(2024)”,打造湖湘金融云化升级优质范本

12月26日&#xff0c;2024云计算产业和标准应用大会在北京成功召开。大会汇集政产学研用各方专家学者&#xff0c;共同探讨云计算产业发展方向和未来机遇&#xff0c;展示云计算标准化工作重要成果。 会上&#xff0c;云建设与应用领航计划&#xff08;2024&#xff09;建云用…...

好用的随机生成图片的网站

官网&#xff1a; Lorem Picsum 获取自定义大小的随机图像 https://picsum.photos/200/300 获取正方形图像 https://picsum.photos/200 获取特定类型的图像 通过添加到 /id/{image} url 的开头来获取特定图像。 https://picsum.photos/id/237/200/300 获取静态随机图像…...

添加 env 配置,解决import路径问题

添加 env 配置&#xff0c;解决import路径问题 { // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息&#xff0c;请访问: https://go.microsoft.com/fwlink/?linkid830387 “version”: “0.2.0”, “configurations”: [ {"name&q…...

Go work stealing 机制

Go语言的Work Stealing&#xff08;工作窃取&#xff09;机制是一种用于调度Goroutines&#xff08;协程&#xff09;的策略&#xff0c;其核心目的是最大化CPU使用率&#xff0c;减少任务调度的开销&#xff0c;并提高并发性能和吞吐量。以下是Go Work Stealing机制的详细解释…...

基础数据结构--二叉树

一、二叉树的定义 二叉树是 n( n > 0 ) 个结点组成的有限集合&#xff0c;这个集合要么是空集&#xff08;当 n 等于 0 时&#xff09;&#xff0c;要么是由一个根结点和两棵互不相交的二叉树组成。其中这两棵互不相交的二叉树被称为根结点的左子树和右子树。 如图所示&am…...

《C++设计模式》策略模式

文章目录 1、引言1.1 什么是策略模式1.2 策略模式的应用场景1.3 本文结构概览 2、策略模式的基本概念2.1 定义与结构2.2 核心角色解析2.2.1 策略接口&#xff08;Strategy&#xff09;2.2.2 具体策略实现&#xff08;ConcreteStrategy&#xff09;2.2.3 上下文&#xff08;Cont…...

JavaScript学习记录6

第一节 算数运算符 1. 概述 JavaScript 共提供10个算术运算符&#xff0c;用来完成基本的算术运算。 加法运算符x y减法运算符 x - y乘法运算符 x * y除法运算符x / y指数运算符x ** y余数运算符x % y自增运算符x 、x自减运算符--x 、x--数值运算符 x负数值运算符-x 减法、…...

如何在没有 iCloud 的情况下将数据从 iPhone 传输到 iPhone

概括 您可能会遇到将数据从 iPhone 转移到 iPhone 的情况&#xff0c;尤其是当您获得新的 iPhone 15/14 时&#xff0c;您会很兴奋并希望将数据转移到它。 使用iCloud最终可以做到这一点&#xff0c;但它的缺点也不容忽视&#xff0c;阻碍了你选择它。例如&#xff0c;您需要…...

Doris安装部署

Doris 概述 Apache Doris由百度大数据部研发&#xff08;之前叫百度 Palo&#xff0c;2018年贡献到 Apache 社区后&#xff0c;更名为 Doris &#xff09;&#xff0c;在百度内部&#xff0c;有超过200个产品线在使用&#xff0c;部署机器超过1000台&#xff0c;单一业务最大可…...

[服务器][教程]Ubuntu24.04 Server开机自动挂载硬盘教程

1. 查看硬盘ID ls -l /dev/disk/by-uuid可以看到对应的UUID所对应的分区 2. 创建挂载文件夹 创建好文件夹即可 3. 修改配置文件 sudo vim /etc/fstab把对应的UUID和创建的挂载目录对应即可 其中# Personal mount points下面的是自己新添加的 &#xff1a;分区定位&#xff…...

io多路复用, select, poll, epoll

系列文章目录 异步I/O操作函数aio_xxx函数 https://blog.csdn.net/surfaceyan/article/details/134710393 文章目录 系列文章目录前言一、5种IO模型二、IO多路复用APIselectpollepoll 三、两种高效的事件处理模式Reactor模式Proactor模式模拟 Proactor 模式基于事件驱动的非阻…...