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

Spring AI 入门(持续更新)

介绍

Spring AI 是 Spring 项目中一个面向 AI 应用的模块,旨在通过集成开源框架、提供标准化的工具和便捷的开发体验,加速 AI 应用程序的构建和部署。

依赖

<!-- 基于 WebFlux 的响应式 SSE 传输 -->
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-mcp-client-webflux-spring-boot-starter</artifactId>
</dependency>
<!-- mcp -->
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
</dependency>
<!-- spring-ai -->
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<!-- spring-web -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

配置文件

配置大模型的 API Key 模型类型

spring:ai:openai:base-url: ${AI_BASE_URL}api-key: ${AI_API_KEY} # 通过环境变量文件 .env 获取chat:options:model: ${AI_MODEL}temperature: 0.8

我这里使用的是 DeepSeek 的 API,可以去官网查看:https://platform.deepseek.com/

# AI URL
AI_BASE_URL=https://api.deepseek.com
# AI 密钥
AI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxx
# AI 模型
AI_MODEL=deepseek-chat

配置类

概念

首先,简单介绍一些概念

  1. ChatClient

ChatClient 提供了与 AI 模型通信的 Fluent API,它支持同步和反应式(Reactive)编程模型。

ChatClient 类似于应用程序开发中的服务层,它为应用程序直接提供 AI 服务,开发者可以使用 ChatClient Fluent API 快速完成一整套 AI 交互流程的组装

  1. ChatModel

ChatModel 即对话模型,它接收一系列消息(Message)作为输入,与模型 LLM 服务进行交互,并接收返回的聊天消息(ChatMessage)作为输出。目前,它有 3 种类型:

  • ChatModel:文本聊天交互模型,支持纯文本格式作为输入,并将模型的输出以格式化文本形式返回

  • ImageModel:接收用户文本输入,并将模型生成的图片作为输出返回(文生图

  • AudioModel:接收用户文本输入,并将模型合成的语音作为输出返回

    ChatModel 的工作原理是接收 Prompt 或部分对话作为输入,将输入发送给后端大模型,模型根据其训练数据和对自然语言的理解生成对话响应,应用程序可以将响应呈现给用户或用于进一步处理。

问题

一个项目中可能会存在多个大模型的调用实例,例如 ZhiPuAiChatModel(智谱)、OllamaChatModel(Ollama本地模型)、OpenAiChatModel(OpenAi),这些实例都实现了ChatModel 接口,当然,我们可以直接使用这些模型实例来实现需求,但我们通常通过 ChatModel 来构建 ChatClient,因为这更通用

可以通过在 yml 配置文件中设置 spring.ai.chat.client.enabled=false 来禁用 ChatClient bean 的自动配置,然后为每个聊天模型 build 出一个 ChatClient。

spring:ai:chat:client:enabled: false

配置类

package cn.onism.mcp.config;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.InMemoryChatMemory;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** ChatClient 配置** @author wxw* @date 2025-03-25*/
@Configuration
public class ChatClientConfig {@Resourceprivate OpenAiChatModel openAiChatModel;@Resourceprivate ZhiPuAiChatModel zhiPuAiChatModel;@Resourceprivate OllamaChatModel ollamaChatModel;@Resourceprivate ToolCallbackProvider toolCallbackProvider;@Bean("openAiChatClient")public ChatClient openAiChatClient() {return ChatClient.builder(openAiChatModel)// 默认加载所有的工具,避免重复 new.defaultTools(toolCallbackProvider.getToolCallbacks()).defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory())).build();}@Bean("zhiPuAiChatClient")public ChatClient zhiPuAiChatClient() {return ChatClient.builder(zhiPuAiChatModel)// 默认加载所有的工具,避免重复 new.defaultTools(toolCallbackProvider.getToolCallbacks()).defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory())).build();}@Bean("ollamaChatClient")public ChatClient ollamaChatClient() {return ChatClient.builder(ollamaChatModel)// 默认加载所有的工具,避免重复 new.defaultTools(toolCallbackProvider.getToolCallbacks()).defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory())).build();}
}

使用 ChatClient 的时候,@Resource 注解会按 Bean 的名称注入

@Resource
private ChatClient openAiChatClient;@Resource
private ChatClient ollamaChatClient;@Resource
private ChatClient zhiPuAiChatClient;

基础对话

普通响应

使用 call 方法来调用大模型

private ChatClient openAiChatModel;@GetMapping("/chat")
public String chat(){Prompt prompt = new Prompt("你好,请介绍下你自己");String response = openAiChatModel.prompt(prompt).call().content();return response;
}

流式响应

call 方法修改为 stream,最终返回一个 Flux 对象

@GetMapping(value = "/chat/stream", produces = "text/html;charset=UTF-8")
public Flux<String> stream() {Prompt prompt = new Prompt("你好,请介绍下你自己");String response = openAiChatModel.prompt(prompt).stream().content();return response;
}

tips:我们可以通过缓存减少重复请求,提高性能。可以使用 Spring Cache 的 @Cacheable 注解实现:

@Cacheable("getChatResponse")
public String getChatResponse(String message){String response = openAiChatModel.prompt().user(message).call().content();return response;
}

tips: 适用于批量处理场景。可以使用 Spring 的 @Async 注解实现:

@Async
public CompletableFuture<String> getAsyncChatResponse(String message) {return CompletableFuture.supplyAsync(() -> openAiChatModel.prompt().user(message).call().content());
}

3 种组织提示词的方式

Prompt

通过 Prompt 来封装提示词实体,适用于简单场景

Prompt prompt = new Prompt("介绍下你自己");
PromptTemplate

使用提示词模板 PromptTemplate 来复用提示词,即将提示词的大体框架构建好,用户仅输入关键信息完善提示词

其中,{ } 作为占位符,promptTemplate.render 方法来填充

@GetMapping("/chat/formatPrompt")
public String formatPrompt(@RequestParam(value = "money") String money,@RequestParam(value = "number") String number,@RequestParam(value = "brand") String brand
) {PromptTemplate promptTemplate = new PromptTemplate("""根据我目前的经济情况{money},只推荐{number}部{brand}品牌的手机。""");Prompt prompt = new Prompt(promptTemplate.render(Map.of("money",money,"number", number, "brand", brand)));return openAiChatModel.prompt(prompt).call().content();
}
Message

使用 Message ,提前约定好大模型的功能或角色

消息类型:

系统消息(SystemMessage):设定对话的背景、规则或指令,引导 AI 的行为
用户消息(UserMessage):表示用户的输入,即用户向 AI 提出的问题或请求
助手消息(AssistantMessage):表示 AI 的回复,即模型生成的回答
工具响应消息(ToolResponseMessage):当 AI 调用外部工具(如 API)后,返回 工具的执行结果,供 AI 进一步处理
@GetMapping("/chat/messagePrompt")
public String messagePrompt(@RequestParam(value = "book", defaultValue = "《白夜行》") String book) {// 用户输入UserMessage userMessage = new UserMessage(book);log.info("userMessage: {}", userMessage);// 对系统的指令SystemMessage systemMessage = new SystemMessage("你是一个专业的评书人,给出你的评价吧!");log.info("systemMessage: {}", systemMessage);// 组合成完整的提示词,注意,只能是系统指令在前,用户消息在后,否则会报错Prompt prompt = new Prompt(List.of(systemMessage, userMessage));return openAiChatModel.prompt(prompt).call().content();
}
保存 prompt

prompt 不宜嵌入到代码中,可以将作为一个 .txt 文件 其保存到 src/main/resources/prompt 目录下,使用读取文件的工具类就可以读取到 prompt

package cn.onism.mcp.utils;import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;/*** @description: 读取文件内容的工具类* @date: 2025/5/8*/
@Component
public class FileContentReader {public String readFileContent(String filePath) {StringBuilder content = new StringBuilder();try {// 创建 ClassPathResource 对象以获取类路径下的资源ClassPathResource resource = new ClassPathResource(filePath);// 打开文件输入流InputStream inputStream = resource.getInputStream();// 创建 BufferedReader 用于读取文件内容BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));String line;// 逐行读取文件内容while ((line = reader.readLine()) != null) {content.append(line).append("\n");}// 关闭输入流reader.close();} catch (IOException e) {// 若读取文件时出现异常,打印异常信息e.printStackTrace();}return content.toString();}
}
PromptTemplate promptTemplate = new PromptTemplate(fileContentReader.readFileContent("prompt/formatPrompt.txt")
);

解析模型输出(结构化)

模型输出的格式是不固定的,无法直接解析或映射到 Java 对象,因此,Spring AI 通过在提示词中添加格式化指令要求大模型按特定格式返回内容,在拿到大模型输出数据后通过转换器做结构化输出。

实体类 Json 格式

首先我们定义一个实体类 ActorInfo

@Data
@Description("演员信息")
public class ActorInfo {@JsonPropertyDescription("演员姓名")private String name;@JsonPropertyDescription("演员年龄")private Integer age;@JsonPropertyDescription("演员性别")private String gender;@JsonPropertyDescription("演员出生日期")private String birthday;@JsonPropertyDescription("演员国籍")private String nationality;
}

在 call 方法后面调用 entity 方法,把对应实体类的 class 传递进去即能做到结构化输出

@GetMapping("/chat/actor")
public ActorInfo queryActorInfo(@RequestParam(value = "actorName") String actorName) {PromptTemplate promptTemplate = new PromptTemplate("查询{actorName}演员的详细信息");Prompt prompt = new Prompt(promptTemplate.render(Map.of("actorName", actorName)));ActorInfo response = openAiChatModel.prompt(prompt).call().entity(ActorInfo.class);return response;
}

结果符合要求

List 列表格式

在 entity 方法中传入 new ListOutputConverter(new DefaultConversionService())

@GetMapping("/chat/actorMovieList")
public List<String> queryActorMovieList(@RequestParam(value = "actorName") String actorName) {PromptTemplate promptTemplate = new PromptTemplate("查询{actorName}主演的电影");Prompt prompt = new Prompt(promptTemplate.render(Map.of("actorName", actorName)));List<String> response = openAiChatModel.prompt(prompt).call().entity(new ListOutputConverter(new DefaultConversionService()));return response;
}
Map 格式

tips: 目前在 Map 中暂不支持嵌套复杂类型,因此 Map 中不能返回实体类,而只能是 Object。

在 entity 方法中传入 new ParameterizedTypeReference<>() {}

@GetMapping("/chat/actor")
public Map<String, Object> queryActorInfo(@RequestParam(value = "actorName") String actorName) {PromptTemplate promptTemplate = new PromptTemplate("查询{actorName}演员及另外4名相关演员的详细信息");Prompt prompt = new Prompt(promptTemplate.render(Map.of("actorName", actorName)));Map<String, Object> response = openAiChatModel.prompt(prompt).call().entity(new ParameterizedTypeReference<>() {});return response;
}

多模态

deepseek 暂时不支持多模态,因此这里选用 智谱:https://bigmodel.cn/

依赖与配置

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-zhipuai</artifactId><version>1.0.0-M6</version>
</dependency>
spring:ai:zhipuai:api-key: ${ZHIPUAI_API_KEY}chat:options:model: ${ZHIPUAI_MODEL}temperature: 0.8
# api-key
ZHIPUAI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxx
# 所选模型
ZHIPUAI_MODEL=glm-4v-plus-0111
理解图片

在 src/main/resources/images 目录下保存图片

创建一个 ZhiPuAiChatModel,将用户输入和图片封装成一个 UserMessage,然后使用 call 方法传入一个 prompt,最后获得输出

@Resource
private ZhiPuAiChatModel zhiPuAiChatModel;@GetMapping("/chat/pic")
public String pic() {Resource imageResource = new ClassPathResource("images/mcp.png");// 构造用户消息var userMessage = new UserMessage("解释一下你在这幅图中看到了什么?",new Media(MimeTypeUtils.IMAGE_PNG, imageResource));ChatResponse chatResponse = zhiPuAiChatModel.call(new Prompt(userMessage));return chatResponse.getResult().getOutput().getText();
}

文生图

这里需要使用 zhiPuAiImageModel,我们调用它的 call 方法,传入一个 ImagePrompt,ImagePrompt 由**用户图片描述输入 ImageMessage **和 **图片描述信息 OpenAiImageOptions **所构成,

其中,

  • model 要选择适用于图像生成任务的模型,这里我们选择了 cogview-4-250304
  • quality 为图像生成图像的质量,默认为 standard
    • hd : 生成更精细、细节更丰富的图像,整体一致性更高,耗时约20 秒
    • standard :快速生成图像,适合对生成速度有较高要求的场景,耗时约 5-10 秒
@Autowired
ZhiPuAiImageModel ziPuAiImageModel;@Autowired
private FileUtils fileUtils;@GetMapping("/outputImg")
public void outputImg() throws IOException {ImageMessage userMessage = new ImageMessage("一个仙人掌大象");OpenAiImageOptions chatOptions = OpenAiImageOptions.builder().model("cogview-4-250304").quality("hd").N(1).height(1024).width(1024).build();ImagePrompt prompt = new ImagePrompt(userMessage, chatOptions);// 调用ImageResponse imageResponse = ziPuAiImageModel.call(prompt);// 输出的图片Image image = imageResponse.getResult().getOutput();// 保存到本地InputStream in = new URL(image.getUrl()).openStream();fileUtils.saveStreamToFile(in,"src/main/resources/images", "pic"+RandomUtils.insecure().randomInt(0, 100)+".png");
}
@Component
public class FileUtils {public String saveStreamToFile(InputStream inputStream, String filePath, String fileName) throws IOException {// 创建目录(如果不存在)Path dirPath = Paths.get(filePath);if (!Files.exists(dirPath)) {Files.createDirectories(dirPath);}// 构建完整路径Path targetPath = dirPath.resolve(fileName);// 使用 try-with-resources 确保流关闭try (inputStream) {Files.copy(inputStream, targetPath, StandardCopyOption.REPLACE_EXISTING);}return targetPath.toAbsolutePath().toString();}
}

调用本地模型

_**tips: **_若想零成本调用大模型,并且保障隐私,可以阅读本章节

下载安装 Ollama

下载安装 Ollama:https://ollama.com/ [Ollama 是一个开源的大型语言模型服务工具,旨在帮助用户快速在本地运行大模型。通过简单的安装指令,用户可以通过一条命令轻松启动和运行开源的大型语言模型。Ollama 是 LLM 领域的 Docker],安装完成后执行 ollama 得到如下输出则表明安装成功

选择一个模型下载到本地:https://ollama.com/search,我这里选择了 qwen3:8b

引入 ollama 依赖

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
</dependency>

配置

spring:ai:ollama:chat:model: ${OLLAMA_MODEL}base-url: ${OLLAMA_BASE_URL}
# 本地模型
OLLAMA_MODEL=qwen3:8b
# URL
OLLAMA_BASE_URL=http://localhost:11434

实际调用

/*** ollama本地模型测试* @param input* @return*/
@GetMapping("/ollama/chat")
public String ollamaChat(@RequestParam(value = "input") String input) {Prompt prompt = new Prompt(input);return ollamaChatModel.call(prompt).getResult().getOutput().getText();
}

结果

对话记忆

内存记忆(短期)

MessageChatMemoryAdvisor 可以用来提供聊天记忆功能,这需要传递一个基于内存记忆的 ChatMemory

/*** 内存记忆/短期记忆* @param input* @return*/
@GetMapping("/memory/chat")
public String chat(@RequestParam(value = "input") String input) {Prompt prompt = new Prompt(input);// 内存记忆的 ChatMemoryInMemoryChatMemory inMemoryChatMemory = new InMemoryChatMemory();return openAiChatClient.prompt(prompt).advisors(new MessageChatMemoryAdvisor(inMemoryChatMemory)).call().content();
}

测试

隔离

多用户与 AI 对话,每个用户的对话记录是相互隔离的,因此记忆也要隔离。

有 bug,明天看看怎么个事儿

/*** 短期记忆,按用户id隔离* @param input* @param userId* @return*/
@GetMapping("/memory/chat/user")
public String chatByUser(@RequestParam(value = "input") String input, @RequestParam(value = "userId") String userId) {Prompt prompt = new Prompt(input);return openAiChatClient.prompt(prompt).advisors(new MessageChatMemoryAdvisor(inMemoryChatMemory,userId,AbstractChatMemoryAdvisor.DEFAULT_CHAT_MEMORY_RESPONSE_SIZE)).call().content();
}
集成 Redis

TODO

集成 MySQL

TODO

MCP

TODO

RAG

TODO

相关文章:

Spring AI 入门(持续更新)

介绍 Spring AI 是 Spring 项目中一个面向 AI 应用的模块&#xff0c;旨在通过集成开源框架、提供标准化的工具和便捷的开发体验&#xff0c;加速 AI 应用程序的构建和部署。 依赖 <!-- 基于 WebFlux 的响应式 SSE 传输 --> <dependency><groupId>org.spr…...

[ctfshow web入门] web58

信息收集 if(isset($_POST[c])){$c $_POST[c];eval($c); }else{highlight_file(__FILE__); }这麽简单&#xff1f; 解题 好吧&#xff0c;还是我想得太简单了 把system禁用了。不是参数过滤&#xff0c;而是直接禁用&#xff0c;不管是间接还是直接调用system都不行&#x…...

Python量化交易Backtrader技术指标的实现

一、Backtrader技术指标概览 (一)Backtrader内置指标的优势 Backtrader内置的技术指标具有以下优势: 多样性:涵盖了常见的移动平均线、相对强弱指数(RSI)、布林带等多种指标,满足了不同交易者的需求。易用性:通过简单的函数调用即可在策略中添加和使用这些指标,无需…...

蓝桥杯第十六届c组c++题目及个人理解

本篇文章只是部分题目的理解&#xff0c;代码和思路仅供参考&#xff0c;切勿当成正确答案&#xff0c;欢迎各位小伙伴在评论区与博主交流&#xff01; 题目&#xff1a;2025 题目解析 核心提取 要求的数中至少有1个0、2个2、1个5 代码展示 #include<iostream> #incl…...

ARM 芯片上移植 Ubuntu 操作系统详细步骤

一、准备工作 &#xff08;一&#xff09;硬件准备 ARM 开发板&#xff1a;确保 ARM 开发板的型号与 Ubuntu 官方支持的 ARM 架构兼容&#xff0c;常见的 ARM 架构有 ARMv7、ARMv8 等。例如树莓派系列开发板&#xff0c;广泛用于 ARM 系统移植&#xff0c;其采用 ARM 架构。存…...

能耗优化新引擎:EIOT平台助力企业降本增效

安科瑞顾强 数字化转型的背景下&#xff0c;能源管理正加速向智能化、远程化方向演进。安科瑞电气推出的EIOT托管平台及ADW300系列4G无线计量仪表&#xff0c;通过云端技术与无线通信的深度融合&#xff0c;为用户打造了高效、便捷的远程能源监测与管理体系&#xff0c;助力企…...

录播课视觉包装与转化率提升指南

1. 封面设计黄金法则 1.1 程序员审美三要素 极客风配色方案 主色&#xff1a;深空灰(#2D2D2D) 代码蓝(#007BFF) 点缀色&#xff1a;终端绿(#28A745) 警告黄(#FFC107) 信息密度控制 核心标语≤9字&#xff08;如&#xff1a;"3天攻克分布式事务"&#xff09; 技…...

Solidity语言基础:区块链智能合约开发入门指南

一、Solidity概述 Solidity是以太坊生态系统中最重要的智能合约编程语言&#xff0c;由Gavin Wood于2014年提出。作为面向合约的高级语言&#xff0c;它结合了JavaScript、Python和C的语法特点&#xff0c;专为在以太坊虚拟机&#xff08;EVM&#xff09;上运行而设计。 核心…...

QMK开发环境搭建指南:Eclipse和VS Code详解

QMK开发环境搭建指南&#xff1a;Eclipse和VS Code详解 前言 各位键盘DIY爱好者们&#xff0c;今天跟大家分享如何搭建QMK固件开发环境。无论你是想定制自己的客制化键盘固件&#xff0c;还是对开源键盘固件开发感兴趣&#xff0c;这篇教程都能帮你搞定开发环境配置。本文将详…...

Python pandas 向excel追加数据,不覆盖之前的数据

最近突然看了一下pandas向excel追加数据的方法&#xff0c;发现有很多人出了一些馊主意&#xff1b; 比如用concat,append等方法&#xff0c;这种方法的会先将旧数据df_1读取到内存&#xff0c;再把新数据df_2与旧的合并&#xff0c;形成df_new,再覆盖写入&#xff0c;消耗和速…...

spring中RequestContextHolder

1、在 Spring 框架中&#xff0c; RequestAttributes attributes RequestContextHolder.getRequestAttributes(); 是获取当前请求上下文的核心方法。以下是其关键要点及注意事项&#xff1a; ‌一、核心机制‌ ‌作用原理‌ 通过 ThreadLocal 存储当前线程的请求属性对象 …...

Kotlin 遍历

在 Kotlin 中&#xff0c;遍历&#xff08;迭代&#xff09;是操作集合、数组、范围&#xff08;Range&#xff09;等数据结构的常见需求。Kotlin 提供了多种遍历方式&#xff0c;语法简洁且功能强大。以下是不同场景下的遍历方法总结&#xff0c;附代码示例&#xff1a; 一、…...

Ubuntu Linux系统配置账号无密码sudo

在Linux系统中&#xff0c;配置无密码sudo可以通过修改sudoers文件来实现。以下是具体的配置步骤 一、编辑sudoers文件 输入sudo visudo命令来编辑sudo的配置文件。visudo是一个专门用于编辑sudoers文件的命令&#xff0c;它会在保存前检查语法错误&#xff0c;从而防止可能的…...

C# NX二次开发:判断两个体是否干涉和获取系统日志的UFUN函数

大家好&#xff0c;今天要讲关于如何判断两个体是否干涉和获取系统日志的UFUN函数。 &#xff08;1&#xff09;UF_MODL_check_interference&#xff1a;这个函数的定义为根据单个目标体检查每个指定的工具体是否有干扰。 Defined in: uf_modl.h Overview Checks each sp…...

若依项目图片显示问题

图片显示异常问题 路径配置问题&#xff1a;前端图片路径配置错误&#xff0c;最初使用相对路径且未从根目录开始解析&#xff0c;导致浏览器根据当前页面 URL 解析路径出错。例如在用户信息展示页面&#xff0c;若当前页面 URL 为http://localhost:8088/user/profile&#xff…...

线索二叉树

一 概念 线索二叉树&#xff08;Threaded Binary Tree&#xff09;是一种对二叉树的优化结构&#xff0c;主要解决传统二叉树遍历时需要借助栈或递归&#xff08;额外空间开销&#xff09;的问题。通过利用节点中的空指针&#xff08;nullptr&#xff09;存储遍历过程中的前驱…...

Git查看某个commit的改动

在Git中查看特定commit的改动有多种方法&#xff0c;下面是几种常用的命令行方式&#xff1a; 1. 使用 git show 命令 这是最常用的方法&#xff0c;直接显示某个commit的详细信息和改动&#xff1a; git show <commit-hash> 例如&#xff1a; git show abc1234 也可…...

es 里的Filesystem Cache 理解

文章目录 背景问题1&#xff0c;Filesystem Cache 里放的是啥问题2&#xff0c;哪些查询它们会受益于文件系统缓存 问题3 查询分析 背景 对于es 优化来说常常看到会有一条结论给&#xff0c;给 JVM Heap 最多不超过物理内存的 50%&#xff0c;且不要超过 31GB&#xff08;避免…...

2025年3月电子学会等级考试五级题——4、收费站在哪里

文章目录 题目代码公式小结 题目 4、收费站在哪里 在一条高速公路上&#xff0c;如果已知 n 座收费站的位置 x1,x2,… ,xn&#xff08;不妨假设 0x1 ≤ x2 ≤ … ≤ xn&#xff09;&#xff0c;就很容易算出一共有 n(n-1)/2 个距离的值。而比较困难的问题是&#xff0c;在收集…...

深入探索 JavaScript 中的模块对象

引言 在现代 JavaScript 开发中&#xff0c;模块化编程是一项至关重要的技术。它允许开发者将代码拆分成多个独立的模块&#xff0c;每个模块专注于单一功能&#xff0c;从而提高代码的可维护性、可测试性和复用性。而模块对象则是模块化编程中的核心概念之一&#xff0c;它为…...

R1-Searcher:用强化学习解锁大语言模型检索新能力!

R1-Searcher&#xff1a;用强化学习解锁大语言模型检索新能力&#xff01; 大语言模型&#xff08;LLMs&#xff09;发展迅猛&#xff0c;却常因依赖内部知识而在复杂问题上“栽跟头”。今天解读的论文提出R1-Searcher框架&#xff0c;通过强化学习提升LLMs检索能力。它表现超…...

LangChain框架-PromptTemplate 详解

摘要 本文聚焦于 LangChain 框架中PromptTemplate提示词模板模块的深度解析,主要参考langchain_core.prompts源码模块与官方文档。系统梳理 LangChain 对提示词模板的封装逻辑与设计思路,旨在帮助读者构建全面、深入的知识体系,为高效运用LangChain 框架的提示词模板开发应用…...

【Java ee 初阶】文件IO和操作(下)

书接上文 文本操作的方法 String[] list() 返回 File 对象代表的目录下的所有文件名 File[] listFiles() 返回 File 对象代表的目录下的所有文件&#xff0c;以 File 对象表示 此处是针对File对象打印得到的效果&#xff08;调用了File的toString&#xff09; boolean …...

Android7 Input(六)InputChannel

概述: 本文讲述Android Input输入框架中 InputChannel的功能。从前面的讲述&#xff0c;我们知道input系统服务最终将输入事件写入了InputChannel&#xff0c;而input属于system_server进程&#xff0c;App属于另外一个进程&#xff0c;当Input系统服务想要把事件传递给App进行…...

【Java ee初阶】初始网络

一、IP地址 概念 IP地址主要用于标识网络主机、其他网络设备&#xff08;如路由器&#xff09;的网络地址。简单说&#xff0c;IP地址用于定位主机的网络地址。 就像我们发送快递一样&#xff0c;需要知道对方的收货地址&#xff0c;快递员才能将包裹送到目的地。 格式 IP…...

LabVIEW 2019 与 NI VISA 20.0 安装及报错处理

在使用 Windows 11 操作系统的电脑上&#xff0c;同时安装了 LabVIEW 2019 32 位和 64 位版本的软件。此前安装的 NI VISA 2024 Q1 版&#xff0c;该版本与 LabVIEW 2019 32 位和 64 位不兼容&#xff0c;之后重新安装了 NI VISA 20.0。从说明书来看&#xff0c;NI VISA 20.0 …...

http协议理解

文章目录 http协议理解基本概念HTTP版本演变版本编年史版本对比未来趋势 HTTP请求/响应结构请求报文响应报文HTTP方法分类对比方法选择原则必须遵守的约束 常见状态码HTTP头部字段HTTPSHTTPS 核心功能说明HTTPS 如何工作&#xff1f; HTTP特点补充知识点启用HTTP/2Nginx 中配置…...

typecho中的Widget设计文档

组成系统的最基本元素 什么是Widget Widget是组成Typecho的最基本元素&#xff0c;除了已经抽象出来的类库外&#xff0c;其它几乎所有的功能都会通过Widget来完成。在实践中我们发现&#xff0c;在博客这种小型但很灵活的系统中实施一些大型框架的思想是不合适的&#xff0c…...

使用ESPHome烧录固件到ESP32-C3并接入HomeAssistant

文章目录 一、安装ESPHome二、配置ESP32-C3控制灯1.主配置文件esp32c3-luat.yaml2.基础通用配置base.yaml3.密码文件secret.yaml4.围栏灯four_light.yaml5.彩灯rgb_light.yaml6.左右柱灯left_right_light.yaml 三、安装固件四、HomeAssistant配置ESPHome1.直接访问2.配置ESPHom…...

基于STM32、HAL库的CH340N USB转UART收发器 驱动程序设计

一、简介: CH340N是南京沁恒电子生产的一款USB转串口芯片,具有以下特点: 支持USB 2.0全速(12Mbps) 内置时钟,无需外部晶振 支持5V和3.3V电源电压 提供常用的MODEM联络信号 内置上电复位电路 支持Windows/Linux/Mac OSX等多平台驱动 体积小,SOP-8封装 二、硬件接口: CH…...

Spring Boot Controller 如何处理HTTP请求体

Spring Boot (通过Spring MVC) 提供了强大的机制来处理不同 Content-Type​ 的HTTP请求体。这主要依赖于 HttpMessageConverter​ 接口的各种实现&#xff0c;它们能够自动将请求体内容转换成Java方法参数。 一、核心机制&#xff1a;HttpMessageConverter​ Spring MVC会根据…...

【deepseek教学应用】001:deepseek如何撰写教案并自动实现word排版

本文讲述利用deepseek如何撰写教案并自动实现word高效完美排版。 文章目录 一、访问deepseek官网二、输入教案关键词三、格式转换四、word进一步排版 一、访问deepseek官网 官网&#xff1a;https://www.deepseek.com/ 进入主页后&#xff0c;点击【开始对话】&#xff0c;如…...

【Spring Boot 多模块项目】@MapperScan失效、MapperScannerConfigurer 报错终极解决方案

在使用 Spring Boot 构建多模块项目&#xff0c;集成 MyBatis-Plus 时&#xff0c;很多开发者会遇到类似如下启动报错&#xff1a; Error creating bean with name mapperScannerConfigurer ... Caused by: java.lang.IllegalArgumentException: Property basePackage is requ…...

vue 中如何使用region?

vue 中如何使用region&#xff1f; 在 Vue 文件中&#xff0c;你可以使用 //#region 和 //#endregion 注释来创建可折叠的代码区块&#xff08;类似于 C# 的 region&#xff09;。这可以显著提高大型 Vue 组件的可读性。 1. 基本用法 在 <script> 部分使用 <script&…...

Spring Boot 启动原理的核心机制

一、核心启动流程概览 Spring Boot 的启动流程可概括为 ​7 个关键阶段​&#xff1a; 1. 加载启动类 (Main Class) 2. 初始化 SpringApplication 实例 3. 加载配置 & 准备环境 (Environment) 4. 创建 ApplicationContext&#xff08;容器&#xff09; 5. 刷新容器&#…...

【每天学习一点点】使用Python的pathlib模块分割文件路径

使用Python的pathlib模块分割文件路径 pathlib模块&#xff08;Python 3.4&#xff09;提供了面向对象的文件系统路径操作方式&#xff0c;比传统的os.path更加直观和易用。以下是使用pathlib分割文件路径的几种方法&#xff1a; 基本路径分割 from pathlib import Path# 创…...

Qt/C++面试【速通笔记八】—Qt的事件处理机制

在Qt中&#xff0c;事件处理机制是应用程序与用户或系统交互的核心。通过事件处理&#xff0c;Qt能够响应用户的输入、窗口的变化、定时器的触发等各种情况。 1. 事件循环&#xff08;Event Loop&#xff09; 在Qt应用程序中&#xff0c;事件循环是事件处理机制的基础。事件循…...

uniapp自定义步骤条(可二开进行调试)

前言 有一个业务需求是需要一个步骤条&#xff0c;但是发现开源的都不太合适&#xff0c;所以就自己写了一个。 开始 test.vue <template><view class"authenticateRecordDetails_container"><!-- 进度 --><view class"authenticateSte…...

uniapp|实现多终端聊天对话组件、表情选择、消息发送

基于UniApp框架,实现跨平台多终端适配的聊天对话组件开发、表情选择交互设计及消息发送,支持文本与表情混合渲染。 目录 聊天界面静态组件实现消息列表布局消息气泡双向布局辅助元素定位与样式静态数据模拟与扩展性设计表情选择器静态模块浮层实现符号网格排列多端样式适配方…...

1.3.1 Linux音频框架alsa详细介绍

ALSA作为对旧OSS系统的替代方案&#xff0c;始于1998年。当时OSS还闭源商业化&#xff0c;因此社区开始开发开源的ALSA。经过多年的发展&#xff0c;ALSA成为Linux内核中音频架构的标准。 结构和架构 ALSA由以下几个主要部分组成&#xff1a; 内核模块&#xff1a; 这是ALSA的…...

R 语言机器学习:为遥感数据处理开启新视角

技术点目录 基础理论、机器学习与数据准备建模与空间预测实践案例与项目了解更多 ——————————————————————————————————————————— 前言综述 在当今科技快速发展的时代&#xff0c;遥感技术为生态学研究提供了海量的数据资源&#xf…...

深度 |提“智”向新,奔向未来——当前机器人产业观察

机器人踏着“猫步”在T台走秀、进入工厂协助造车&#xff0c;教育、医疗、城市管理等领域都有了机器人的帮助……今天&#xff0c;机器人已得到广泛应用&#xff0c;走进你我的生活。    伴随着技术日新月异&#xff0c;机器人产业加快提“智”向新。特别是今年以来&#xf…...

Web开发-JavaEE应用SpringBoot栈ActuatorSwaggerHeapDump提取自动化

知识点&#xff1a; 1、安全开发-JavaEE-常见依赖-Actuator&Swagger 2、安全开发-JavaEE-安全问题-配置安全&接口测试 一、演示案例-WEB开发-JavaEE-监控依赖-SpringBoot&Actuator&配置安全 SpringBoot Actuator模块提供了生产级别的功能&#xff0c;比如健康…...

AI Agent开发之门:微软官方课程全面解析

AI Agent开发之门&#xff1a;微软官方课程全面解析 引言项目概览10 节核心课程内容详解1. AI 代理简介及应用场景2. 探索 AI Agentic 框架3. 理解 AI Agentic 设计模式4. 工具使用设计模式5. Agentic RAG&#xff08;检索增强生成&#xff09;6. 构建可信赖的 AI Agents7. 规划…...

Unity-Shader详解-其五

关于Unity的Shader部分的基础知识其实已经讲解得差不多了&#xff0c;今天我们来一些实例分享&#xff1a; 溶解 效果如下&#xff1a; 代码如下&#xff1a; Shader "Chapter8/chapter8_1" {Properties{// 定义属性[NoScaleOffset]_Albedo("Albedo", 2…...

从零打造个人博客静态页面与TodoList应用:前端开发实战指南

前言 在当今数字时代&#xff0c;拥有个人博客和高效的任务管理工具已成为开发者展示自我和提升生产力的标配。本文将带你从零开始&#xff0c;通过纯前端技术实现一个兼具个人博客静态页面和TodoList任务管理功能的综合应用。无论你是前端新手还是希望巩固基础的中级开发者&a…...

开发者如何优雅应对HTTPS抓包难题

开发者如何优雅应对HTTPS抓包难题&#xff1a;工具实战 深度解析 调试HTTPS接口这件事&#xff0c;真是程序员永远的痛。特别是在移动端、或者遇到客户端集成了第三方安全SDK的项目时&#xff0c;网络调试的门槛几乎成倍提升。你可能也遇到过&#xff1a;Charles不识别证书、…...

Ubuntu 安装远程桌面连接RDP方式

1. 安装 XFCE4 桌面环境 如果你的 Ubuntu 系统默认使用 GNOME 或其它桌面环境&#xff0c;可以安装轻量级的 XFCE4&#xff1a; sudo apt update sudo apt install xfce4 xfce4-goodies 说明&#xff1a;xfce4-goodies 包含额外的插件和工具&#xff08;如面板插件、终端等&a…...

Ubuntu 22.04 出现 ‘Temporary failure resolving‘ 解决方案

a、使用apt 安装 resolvconf sudo apt-get install resolvconf b、使用 cd /etc/resolvconf/resolv.conf.d/ 进入文件夹&#xff0c;使用 ls 查看目录&#xff0c;会显示 base head tail c、使用 sudo vim base 编辑base文件&#xff0c; 进入时为空&#xff0c;添加 name…...

ubuntu 22.04 换源

参考&#xff1a;清华大学开源软件镜像站 ubuntu | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror...