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

AI应用开发实战分享

一、前言

30年前的Intel+Windows互相绑定,让世界被计算机技术重构了一次,有了程序员这个工种。十几年前iPhone、Android前后脚发布,智能手机和移动App互相绑定,引爆了一个长达十几年的移动互联网大跃进时代。而随着人工智能大模型能力越来越强,特别是DeepSeek等模型显著降低AI应用门槛,推动办公、创意、软件开发等领域涌现出大量革新性应用。与30年前计算机革命、移动互联网浪潮类似,AI已非短暂趋势,而是未来技术核心方向。

当我们进入AI Agent时代之后,作为一个开发程序员,如果能在未来不被淘汰,就需要主动拥抱大模型技术,深化AI工具使用,才能借助大模型走的更远。本篇文章将从学习笔记的角度,介绍一些AI应用的知识点、学习资料和简单应用案例。

二、AI应用开发的两大实现方式

我们用一个例子来看看AI应用开发的两种方式。

需求描述

假如现在有一个 名叫“易速鲜花”在线鲜花销售平台,这个平台有自己专属的运营指南、员工手册、鲜花资料等数据。新员工在入职培训时,需要为其介绍这些信息。

因此我们将开发一个基于各种内部知识手册的AI智能助手,该助手够理解员工的问题,并基于最新的内部数据,给出精准的答案。

方式1:使用编程框架开发实现(以LangChain为例)

LangChain是由Harrison Chase推出的开源框架,旨在解决大语言模型(LLM)在实际应用中的工程化难题。它通过标准化的接口和模块化设计,将LLM与外部数据、计算资源及业务逻辑连接,形成可落地的智能应用。这个框架的定位类似于数据库领域的JDBC,成为AI应用开发的"中间件"。

实现步骤

  • 第一步:通过 LangChain 中的 文档加载器、文本拆分器、嵌入模型、向量存储、索引 模块,构建检索增强生成(RAG)能力,让AI可基于特定的内部知识给出专业回答
  • 第二步:通过LangChain的 模型 模块,实现一个最基本的聊天对话助手
  • 第三步:通过 LangChain 中的 记忆、提示模板 模块,让这个聊天机器人能够记住用户之前所说的话

代码

# 导入所需的库
import os
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Qdrant
from langchain.memory import ConversationSummaryMemory
from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationalRetrievalChain
from langchain.document_loaders import PyPDFLoader
from langchain.document_loaders import Docx2txtLoader
from langchain.document_loaders import TextLoader# 设置OpenAI API密钥
os.environ["OPENAI_API_KEY"] = '自己的key'  # AI助手
class ChatbotWithRetrieval:def __init__(self, dir):# 加载Documents# 文档的存放目录,目录中是提供给ai的私有、内部的pdf、word、txt数据base_dir = dir documents = []for file in os.listdir(base_dir): # 构建完整的文件路径file_path = os.path.join(base_dir, file)if file.endswith('.pdf'):loader = PyPDFLoader(file_path)documents.extend(loader.load())elif file.endswith('.docx') or file.endswith('.doc'):loader = Docx2txtLoader(file_path)documents.extend(loader.load())elif file.endswith('.txt'):loader = TextLoader(file_path)documents.extend(loader.load())# 文本的分割# 将Documents切分成一个个200字符左右文档块,以便后续进行嵌入和向量存储text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=0)all_splits = text_splitter.split_documents(documents)# 向量数据库# 将这些分割后的文本转换成嵌入的形式,并将其存储在一个向量数据库中。# 这里使用了 OpenAIEmbeddings 来生成嵌入,然后使用 Qdrant 这个向量数据库来存储嵌入self.vectorstore = Qdrant.from_documents(documents=all_splits, # 以分块的文档embedding=OpenAIEmbeddings(), # 用OpenAI的Embedding Model做嵌入location=":memory:",  # in-memory 存储collection_name="my_documents",) # 指定collection_name# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!# 通过上面的文档加载、文本分割、文档向量化以及检索功能,就构建好了检索增强生成(RAG)能力。# 当用户输入一个问题时,程序首先在向量数据库中查找与问题最相关的文本块。# 这是通过将用户问题转化为向量,并在数据库中查找最接近的文本块向量来实现的。# 后面程序才能使用 LLM(大模型),以找到的这些相关的文本块为资料,进一步寻找答案,并生成回答。# 初始化LLM模型self.llm = ChatOpenAI()# 初始化Memory# ChatbotWithMemory 类的初始化函数中,定义了一个对话缓冲区记忆,它会跟踪对话历史。# 在 LLMChain 被创建时,就整合了 LLM、提示和记忆,形成完整的对话链。self.memory = ConversationSummaryMemory(llm=self.llm, memory_key="chat_history", return_messages=True)# 设置Retrieval Chain# ConversationalRetrievalChain组件,内部实现了Prompt的自动化传递流程,最中会组成这样的prompt传递给模型# final_prompt = f"""# System: 基于以下知识回答问题:# {检索到的文档}# # Chat History: {记忆中的对话摘要}# # Human: {当前用户输入}# """retriever = self.vectorstore.as_retriever()self.qa = ConversationalRetrievalChain.from_llm(self.llm, retriever=retriever, memory=self.memory)# 交互对话的函数def chat_loop(self):print("Chatbot 已启动! 输入'exit'来退出程序。")while True:user_input = input("你: ")if user_input.lower() == 'exit':print("再见!")break# 调用 Retrieval Chain  response = self.qa(user_input)print(f"Chatbot: {response['answer']}")if __name__ == "__main__":# AI助手folder = "OneFlower"bot = ChatbotWithRetrieval(folder)bot.chat_loop()
 

效果

总结

在上面的 5 个步骤中,我们使用到了很多 LangChain 技术,包括提示工程、模型、链、代理、RAG、数据库检索等,而除此之外LangChain还有下面其他功能强大的核心模块。

另外除了LangChain框架,还有其他的比如java的LangChain 4j、spring ai。各个框架的api可能有差异,但解决的问题基本都是相同的。

LangChain核心模块和解决的问题:

提示模板

提示模板负责将用户输入格式化为可以传递给语言模型的格式。

  • 如何:使用少量示例
  • 如何:在聊天模型中使用少量示例
  • 如何:部分格式化提示模板
  • 如何:组合提示

示例选择器

示例选择器负责选择正确的少量示例以传递给提示。

  • 如何:使用示例选择器
  • 如何:按长度选择示例
  • 如何:按语义相似性选择示例
  • 如何:按语义n-gram重叠选择示例
  • 如何:按最大边际相关性选择示例

聊天模型

聊天模型是较新的语言模型形式,接收消息并输出消息。

  • 如何:进行函数/工具调用
  • 如何:让模型返回结构化输出
  • 如何:缓存模型响应
  • 如何:获取日志概率
  • 如何:创建自定义聊天模型类
  • 如何:流式返回响应

LLMs

LangChain所称的LLM是较旧的语言模型形式,接收字符串输入并输出字符串。

  • 如何:缓存模型响应
  • 如何:创建自定义LLM类
  • 如何:流式返回响应
  • 如何:跟踪令牌使用情况
  • 如何:使用本地LLMs

输出解析器

输出解析器负责将LLM的输出解析为更结构化的格式。

  • 如何:使用输出解析器将LLM响应解析为结构化格式
  • 如何:解析JSON输出
  • 如何:解析XML输出
  • 如何:解析YAML输出

文档加载器

文档加载器负责从各种来源加载文档。

  • 如何:加载CSV数据
  • 如何:从目录加载数据
  • 如何:加载HTML数据
  • 如何:加载JSON数据
  • 如何:加载Markdown数据
  • 如何:加载Microsoft Office数据

文本拆分器

文本拆分器将文档拆分为可用于检索的块。

  • 如何:递归拆分文本
  • 如何:按HTML标题拆分
  • 如何:按HTML部分拆分
  • 如何:按字符拆分
  • 如何:拆分代码
  • 如何:按Markdown标题拆分

嵌入模型

嵌入模型将一段文本转换为数值表示。

  • 如何:嵌入文本数据
  • 如何:缓存嵌入结果

向量存储

向量存储是可以有效存储和检索嵌入的数据库。

  • 如何:使用向量存储检索数据

检索器

检索器负责接收查询并返回相关文档。

  • 如何:使用向量存储检索数据
  • 如何:生成多个查询以检索数据
  • 如何:使用上下文压缩来压缩检索到的数据
  • 如何:编写自定义检索器类

索引

索引是使向量存储与基础数据源保持同步的过程。

  • 如何:重新索引数据以使向量存储与基础数据源保持同步

工具

LangChain工具包含工具的描述(传递给语言模型)以及要调用的函数的实现。

  • 如何:创建自定义工具
  • 如何:使用内置工具和内置工具
  • 如何:使用聊天模型调用工具
  • 如何:向LLMs和聊天模型添加临时工具调用功能

代理

注意:有关代理的深入操作指南,请查看LangGraph文档。

  • 如何:使用传统LangChain代理(AgentExecutor)
  • 如何:从传统LangChain代理迁移到LangGraph

回调

回调允许你在LLM应用程序的各个阶段进行挂钩。

  • 如何:在运行时传递回调
  • 如何:将回调附加到模块
  • 如何:在模块构造函数中传递回调
  • 如何:创建自定义回调处理程序

自定义

所有LangChain组件都可以轻松扩展以支持你自己的版本。

  • 如何:创建自定义聊天模型类
  • 如何:创建自定义LLM类
  • 如何:编写自定义检索器类
  • 如何:编写自定义文档加载器
  • 如何:编写自定义输出解析器类

学习资料

  • LangChain:
    • Introduction | 🦜️🔗 LangChain
    • LangChain中文网:500页中文文档教程,助力大模型LLM应用开发从入门到精通
  • LangChain 4j:
    • LangChain4j | LangChain4j
  • Spring Ai:
    • Spring AI 简介 - spring 中文网
    • Spring AI

方式2:通过LLM应用开发平台搭建(以字节的coze为例)

扣子是新一代 AI 应用开发平台。无论你是否有编程基础,都可以借助扣子提供的可视化设计与编排工具,通过零代码或低代码的方式,快速搭建出基于大模型的各类 AI 项目,并将 AI 应用发布到各个社交平台、通讯软件,也可以通过 API 或 SDK 将 AI 应用集成到你的业务系统中。

(网址:扣子)

实现步骤详情

(可以和方法1的步骤对照,实际上就是把咱们方法1的代码逻辑,封装成了可配置的平台)

  • 第一步:在扣子搭建知识库,构建检索增强生成(RAG)能力,让AI可基于特定的内部知识给出专业回答

新建

上传

配置规则(用默认的就好)

根据规则切割成文本块

完成向量处理

  • 第二步:在扣子创建一个智能体,实现一个最基本的聊天对话助手

创建

关联之前创建的本地知识库: 知识 >文本配置区,单击+添加已经创建的知识库

配置prompt

(之前方法2的代码中,ConversationalRetrievalChain组件内部实现了Prompt的自动化传递流程,所以那个不需要显式的配置)

选择底层的模型,即可完成助手的搭建

(智能体自动实现了短期记忆,也不需要手动配置,长期记忆可以在技能里配)

最后,扣子还可以发布到其他其他平台,或通过调用api来使用

效果

总结

通过AI应用搭建平台,我们可以非常简单的搭建各种ai应用,感兴趣可以看看字节各种类型应用的最佳实践。

而除了字节的扣子,现在还有很多其他的同样优秀的产品,后面我将介绍一款开源的LLM应用开发平台 Dify ,并展示如何 本地化部署模型、搭建本地AI开发平台、构建本地知识库、接入Springboot项目。

学习资料

  • 扣子:
    • 扣子
  • Dify
    • 产品简介 - Dify Docs
  • 其他
    • 国内Agent平台深度测评:扣子、Dify、FastGPT...:全网最全国内Agent平台深度测评:扣子、Dify、FastGPT,谁是你的Agent开发首选? - ExplorerMan - 博客园
    • Dify与Coze平台深度对比分析:Dify与Coze平台深度对比分析 - 53AI-AI知识库|大模型知识库|大模型训练|智能体开发

三、搭建本地化AI助手并引入项目实践(附代码)

该实践采用DeepSeek开源模型与Dify平台,结合SpringBoot实现业务集成,具体细节如下:

模型:模型选择开源的 DeepSeek R1 7b,用ollama来部署

平台:上面展示过的扣子是闭源的,因此这里我们使用的是开源的Dify

服务调用:这里是在springboot项目中用webClient框架,调用搭建好的应用的api,最后基于SSE协议流式返回数据给前端

安装部署

这一步我们需要完成模型和平台的下载、部署、配置。安装细节可以参考以下文章:

  • 安装部署实操指南:DeepSeek + Dify :零成本搭建企业级本地私有化知识库保姆级教程最近,DeepSeek大火,想必大家都有所耳 - 掘金
  • 多平台部署模型文档汇总:接入 Hugging Face 上的开源模型 - Dify Docs
  • Dify安装部署文档:部署社区版 - Dify Docs

搭建应用

创建知识库

创建所需要的ai应用

对应用进行配置:

  • 选择我们本地部署的模型;
  • 连接我们搭建的知识库;
  • 填好prompt;

配置完成后点击发布,即可通过下面的api进行访问

连接项目

这里我们只展示最简单的与ai对话的功能所需要做的操作。简单流程图如下:

后端代码

Dify的服务接口有两种响应模式:

  • streaming 流式模式(推荐)。基于 SSE(Server-Sent Events)实现类似打字机输出方式的流式返回。
  • blocking 阻塞模式,等待执行完毕后返回结果。(请求若流程较长可能会被中断)。 由于 Cloudflare 限制,请求会在 100 秒超时无返回后中断。 注:Agent模式下不允许blocking。

下面代码包含如何在springboot项目中流式接收数据。


controller:import com.pitayafruit.resp.BlockResponse;
import com.pitayafruit.resp.StreamResponse;
import com.pitayafruit.service.DifyService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;@RestController
@RequestMapping("/api/test")
@RequiredArgsConstructor
public class TestController {//下面的testKey是你所搭建的应用的唯一值。位置在 访问api——右上角api密钥@Value("${dify.key.test}")private String testKey;private final DifyService difyService;@GetMapping("/block")public String test1() {String query = "鲁迅和周树人什么关系?";BlockResponse blockResponse = difyService.blockingMessage(query, 0L, testKey);return blockResponse.getAnswer();}@GetMapping("/stream")public Flux<StreamResponse> test2() {String query = "鲁迅和周树人什么关系?";return difyService.streamingMessage(query, 0L, testKey);}
}service:import com.alibaba.fastjson2.JSON;
import com.pitayafruit.req.DifyRequestBody;
import com.pitayafruit.resp.BlockResponse;
import com.pitayafruit.resp.StreamResponse;
import java.util.HashMap;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;@Service
@RequiredArgsConstructor
public class DifyService {@Value("${dify.url}")private String url;private final RestTemplate restTemplate;private final WebClient webClient;/*** 流式调用dify.** @param query  查询文本* @param userId 用户id* @param apiKey apiKey 通过 apiKey 获取权限并区分不同的 dify 应用* @return Flux 响应流*/public Flux<StreamResponse> streamingMessage(String query, Long userId, String apiKey) {//1.设置请求体DifyRequestBody body = new DifyRequestBody();body.setInputs(new HashMap<>());body.setQuery(query);body.setResponseMode("streaming");body.setConversationId("");body.setUser(userId.toString());//2.使用webclient发送post请求return webClient.post().uri(url).headers(httpHeaders -> {httpHeaders.setContentType(MediaType.APPLICATION_JSON);httpHeaders.setBearerAuth(apiKey);}).bodyValue(JSON.toJSONString(body)).retrieve().bodyToFlux(StreamResponse.class);}/*** 阻塞式调用dify.** @param query 查询文本* @param userId 用户id* @param apiKey apiKey 通过 apiKey 获取权限并区分不同的 dify 应用* @return BlockResponse*/public BlockResponse blockingMessage(String query, Long userId, String apiKey) {//1.设置请求体DifyRequestBody body = new DifyRequestBody();body.setInputs(new HashMap<>());body.setQuery(query);body.setResponseMode("blocking");body.setConversationId("");body.setUser(userId.toString());//2.设置请求头HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);headers.setAccept(List.of(MediaType.APPLICATION_JSON));headers.setBearerAuth(apiKey);//3.封装请求体和请求头String jsonString = JSON.toJSONString(body);HttpEntity<String> entity = new HttpEntity<>(jsonString, headers);//4.发送post请求,阻塞式ResponseEntity<BlockResponse> stringResponseEntity =restTemplate.postForEntity(url, entity, BlockResponse.class);//5.返回响应体return stringResponseEntity.getBody();}
}DifyRequestBodyDto:import com.alibaba.fastjson2.annotation.JSONField;
import java.io.Serializable;
import java.util.Map;
import lombok.Data;/*** Dify请求体.*/
@Data
public class DifyRequestBody implements Serializable {/*** 用户输入/提问内容.*/private String query;/*** 允许传入 App 定义的各变量值.*/private Map<String, String> inputs;/*** 响应模式,streaming 流式,blocking 阻塞.*/@JSONField(name = "response_mode")private String responseMode;/*** 用户标识.*/private String user;/*** 会话id.*/@JSONField(name = "conversation_id")private String conversationId;
}BlockResponseDto:import java.io.Serializable;
import java.util.Map;
import lombok.Data;/*** Dify阻塞式调用响应.*/
@Data
public class BlockResponse implements Serializable {/*** 不同模式下的事件类型.*/private String event;/*** 消息唯一 ID.*/private String messageId;/*** 任务ID.*/private String taskId;/*** agent_thought id.*/private String id;/*** 会话 ID.*/private String conversationId;/*** App 模式,固定为 chat.*/private String mode;/*** 完整回复内容.*/private String answer;/*** 元数据.*/private Map<String, Map<String, String>> metadata;/*** 创建时间戳.*/private Long createdAt;}StreamResponseDto:import java.io.Serializable;
import lombok.Data;/*** Dify流式调用响应.*/
@Data
public class StreamResponse implements Serializable {/*** 不同模式下的事件类型.*/private String event;/*** agent_thought id.*/private String id;/*** 任务ID.*/private String taskId;/*** 消息唯一ID.*/private String messageId;/*** LLM 返回文本块内容.*/private String answer;/*** 创建时间戳.*/private Long createdAt;/*** 会话 ID.*/private String conversationId;
}

效果

调用我们发起提问的接口,可以看到数据不停的流式响应

相关文章:

AI应用开发实战分享

一、前言 30年前的IntelWindows互相绑定&#xff0c;让世界被计算机技术重构了一次&#xff0c;有了程序员这个工种。十几年前iPhone、Android前后脚发布&#xff0c;智能手机和移动App互相绑定&#xff0c;引爆了一个长达十几年的移动互联网大跃进时代。而随着人工智能大模型…...

浅聊find_package命令的搜索模式(Search Modes)

背景 find_package应该算是我们使用最多的cmake命令了。但是它是如何找到上游库的.cmake文件的&#xff1f; 根据官方文档&#xff0c;整理下find_package涉及到的搜索模式。 搜索模式 find_package涉及到的搜索模式有两种&#xff1a;模块模式(Module mode)和配置模式(Conf…...

FPGA图像处理(二)-----彩色图像灰度化

由于fpga实现除法相对复杂&#xff0c;故将除法变为乘法再移位。因此每种方法对图像输入数据均分3步进行&#xff0c;极其有效信号打三拍处理。 timescale 1ns / 1ps // // Description: 彩色图像灰度化 // module image_rgb2gray(input wire clk ,input wir…...

Ultralytics中的YOLODataset和BaseDataset

YOLODataset 和 BaseDataset 是 Ultralytics YOLO 框架中用于加载和处理数据集的两个关键类。 YOLODataset类&#xff08;ultralytics/data/dataset.py&#xff09;继承于 BaseDataset类&#xff08;ultralytics/data/base.py&#xff09; BaseDataset() BaseDataset 是一个…...

Mac 使用 Charles代理生成https服务

在Mac电脑上使用Charles软件通过代理生成HTTPS服务&#xff0c;让手机访问电脑的开发地址&#xff0c;可按以下步骤操作&#xff1a; 一、Charles软件设置 安装与启动Charles&#xff1a;从Charles官网下载并安装Charles软件&#xff0c;之后启动它。开启代理服务 点击菜单栏…...

【PostgreSQL】数据库主从库备份与高可用部署

文章目录 一、架构设计原理二、部署清单示例2.1 StatefulSet配置片段2.2 Service配置三、配置详解3.1 主节点postgresql.conf3.2 从节点配置四、初始化流程4.1 创建复制用户4.2 配置pg_hba.conf五、故障转移示例5.1 自动切换脚本5.2 手动提升从节点六、监控与维护6.1 关键监控指…...

ERP进销存系统源码,SaaS模式多租户ERP管理系统,SpringBoot、Vue、UniAPP技术框架

SaaS ERP管理系统源码&#xff0c;覆盖了整个生产企业所有部门的管理&#xff1a;采购、销售、仓库、生产、财务、质量、OA&#xff1a; ERP源码技术架构&#xff1a;SpringBootVueElementUIUniAPP ERP系统功能清单&#xff1a; 流程处理中心&#xff1a;待审批任务、已审批任…...

Decode rpc invocation failed: null -> DecodeableRpcInvocation

DecodeableRpcInvocation 异常情况解决方法 错误警告官方FAQ 异常情况 记录一下Dubbo调用异常 java.util.concurrent.ExecutionException: org.apache.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer. start time: 2025-05-07 22:09:5…...

VAE和Stable Diffusion的关系

文章目录 ✅ 简单回顾&#xff1a;什么是 VAE&#xff1f;&#x1f504; Stable Diffusion 和 VAE 的关系&#xff1a;&#x1f3af; 编码器&#xff1a;&#x1f4a5; 解码器&#xff1a; &#x1f914; 那 Stable Diffusion 本身是 VAE 吗&#xff1f;&#x1f9e0; 简要对比…...

stable Diffusion模型结构

详细描述一下stable Diffusion的推理过程 其实很简单 prompt先经过textencoder tokenizer&#xff0c;embedding 随机生成噪声图片 通过vae encode压缩成潜空间大小 unet with cross attn 去噪 并融合文本信息 # 上面两个信息如何混合 cross-attention sd模型中各种不同的采样器…...

Milvus(16):索引解释

索引是建立在数据之上的附加结构。其内部结构取决于所使用的近似近邻搜索算法。索引可以加快搜索速度&#xff0c;但在搜索过程中会产生额外的预处理时间、空间和 RAM。此外&#xff0c;使用索引通常会降低召回率&#xff08;虽然影响可以忽略不计&#xff0c;但仍然很重要&…...

数字化转型-4A架构之应用架构

系列文章 数字化转型-4A架构&#xff08;业务架构、应用架构、数据架构、技术架构&#xff09;数字化转型-4A架构之业务架构 前言 应用架构AA&#xff08;Application Architecture&#xff09;是规划支撑业务的核心系统与功能模块&#xff0c;实现端到端协同。 一、什么是应…...

中间件-RocketMQ

RocketMQ 基本架构消息模型消费者消费消息模式顺序消息机制延迟消息批量消息事务消息消息重试最佳实践 基本架构 nameServer: 维护broker列表信息&#xff0c;客户端连接时只需要连接nameServer。可配置成集群。 broker&#xff1a;broker分为master和slave&#xff0c;master负…...

AI开发playwright tool提示词

[TASK] 生成一个isModuleElementObject function&#xff0c;若element的qa-test class在对象moduleObj {"qa-test-mycourses-course": "qa-test-mycourses-course-title", "qa-test-discussion-module": "qa-test-discussion-description&…...

《Origin画百图》之带显著性标记的多因子分组柱状图

带显著性标记的多因子分组柱状图 需要数据&#xff1a; 组1&#xff08;大类&#xff09; 组2&#xff08;小类&#xff09; Y数据 Y误差 选中Y数据和Y误差两列数据&#xff0c; 点击绘图--分组图--多因子分组柱状图 数据列就是上一步选择的Y和Y误差&#xff0c; 点击子组…...

邮件发送频率如何设置?尊重文化差异是关键!

一、不同文化背景&#xff0c;邮件频率大不同 1.工作习惯不一样 一些西方国家&#xff0c;美国和欧洲工作时间和个人时间分得很清楚。工作日的上午 9 点到下午 5 点&#xff0c;这期间发邮件&#xff0c;收件人大概率会看也会回。但是在深夜或者周末发邮件容易让收件人觉得你…...

Python 识别图片上标点位置

Python识别图片上标点位置 要识别图片上的标点位置&#xff0c;可以使用Python中的OpenCV库。以下是几种常见的方法&#xff1a; 方法一&#xff1a;使用颜色阈值识别 import cv2 import numpy as np# 读取图片 image cv2.imread(image.jpg)# 转换为HSV颜色空间 hsv cv2.c…...

JDK Version Manager (JVMS)

以下是使用 JDK Version Manager (JVMS) 工具在Windows系统中安装JDK的详细步骤及注意事项&#xff0c;结合多篇搜索结果整理而成&#xff1a; --- 一、安装前准备 1. 下载JVMS - 访问 [GitHub Releases页面](https://github.com/ystyle/jvms/releases) 或镜像地址&#x…...

办公学习 效率提升 超级PDF处理软件 转换批量 本地处理

各位办公小能手们&#xff01;我跟你们说啊&#xff0c;有个软件叫超级PDF&#xff0c;那可真是PDF文件处理界的全能选手&#xff0c;专门解决咱们办公、学习时文档管理的各种难题。接下来我给大家好好唠唠它的厉害之处。 先说说它的核心功能。第一是格式转换&#xff0c;这软件…...

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

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

C++函数栈帧详解

函数栈帧的创建和销毁 在不同的编译器下&#xff0c;函数调用过程中栈帧的创建是略有差异的&#xff0c;具体取决于编译器的实现&#xff01; 且需要注意的是&#xff0c;越高级的编译器越不容易观察到函数栈帧的内部的实现&#xff1b; 关于函数栈帧的维护这里我们要重点介…...

Wireshark抓账号密码

训练内容&#xff1a; 1. 安装Ethereal或者Wireshark&#xff0c;熟悉网络嗅探器的使用方法&#xff1b; 2. 实现浏览器与IIS服务器的ssl安全访问&#xff1b; 3. 利用网络嗅探器截获浏览器访问IIS服务器之间数据包&#xff0c;包括有ssl安全连接&#xff08;https方式&am…...

【hot100】bug指南记录1

之前学了一阵C&#xff0c;还是更熟悉C的语法呀&#xff0c;转Java还有点不适应........ 这个系列纯纯记录自己刷题犯的愚蠢的错误......hhhh&#xff0c;我是人&#xff0c;one 愚蠢的码人...... 巩固巩固基础好吗&#xff1f;&#xff01;编程菜鸟.......hhh&#xff0c;又…...

物联网从HomeAssistant开始

文章目录 一、在树梅派5上安装home-assistant二、接入米家1.对比下趋势2.手动安装插件3.配置方式 三、接入公牛1.手动安装插件2.配置方式 一、在树梅派5上安装home-assistant https://www.home-assistant.io/installation/ https://github.com/home-assistant/operating-syste…...

2025年渗透测试面试题总结-网络安全、Web安全、渗透测试笔试总结(一)(附回答)(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 网络安全、Web安全、渗透测试笔试总结(一) 1.什么是 WebShell? 2.什么是网络钓鱼&#xff1f; 3.你获取网络…...

C++ set和map系列(关联式容器)的介绍及使用

欢迎来到干货小仓库 "一个好汉三个帮&#xff0c;程序员同样如此" 1.关联式容器 STL中的容器分为两类&#xff0c;序列式容器和关联式容器。 序列式容器&#xff1a;例如STL库中的vector、list和deque、forward_list(C11)等&#xff0c;这些容器统称为序列式容器&…...

C#与Halcon联合编程

一、加载图片 导入并初始化 using HalconDotNet; ho_Image new HObject();需要在引用中导入 halcondotnet.dll 关联句柄 打开新窗口 //创建一个句柄变量 绑定winform 窗口 HTuple winfowFater this.pictureBox1.Handle; //打开新的窗口 HOperatorSet.SetWindowAttr(&qu…...

5.0.4 VisualStateManager(视觉状态管理器)使用说明

在 WPF 中,VisualStateManager(视觉状态管理器)是用于管理控件在不同状态下的外观变化的核心组件。它通过定义视觉状态(如按钮的默认、悬停、按下状态)和状态过渡动画,使控件在不同交互场景下动态切换样式,而无需重写整个控件模板。以下是其核心用法和示例: 1. 基本概…...

onenet连接微信小程序(mqtt协议)

一、关于mqtt协议 mqtt协议常用于物联网&#xff0c;是一种轻量级的消息推送协议。 其中有三个角色&#xff0c;Publisher设备&#xff08;客户端&#xff09;发布主题到服务器&#xff0c;其他的设备通过订阅主题&#xff0c;获取该主题下的消息&#xff0c;Publisher可以发…...

IT需求规格说明书,IT软件系统需求设计文档(DOC)

1 范围 1.1 系统概述 1.2 文档概述 1.3 术语及缩略语 2 引用文档 3 需求 3.1 要求的状态和方式 3.2 系统能力需求 3.3 系统外部接口需求 3.3.1 管理接口 3.3.2 业务接口 3.4 系统内部接口需求 3.5 系统内部数据需求 3.6 适应性需求 3.7 安全性需求 3.8 保密性需…...

探索 DevExpress:构建卓越应用的得力助手

探索 DevExpress&#xff1a;构建卓越应用的得力助手 在当今竞争激烈的软件开发领域&#xff0c;打造高效、美观且功能强大的应用程序是每个开发者的追求。而 DevExpress 作为一款备受瞩目的开发工具&#xff0c;为开发者们提供了实现这一目标的有力支持。在本专栏博客中&…...

康养休闲旅游住宿服务实训室:构建产教融合新标杆

随着健康中国战略的深入实施与银发经济市场的持续扩张&#xff0c;康养休闲旅游作为融合健康管理、文化体验与休闲度假的复合型产业&#xff0c;正迎来前所未有的发展机遇。北京凯禾瑞华科技有限公司依托其在智慧康养领域的技术积淀与产业洞察&#xff0c;创新推出“康养休闲旅…...

Python 程序设计教程:构建您的第一个计算器类

Python 程序设计教程:构建您的第一个计算器类 1. 引言:为什么要学习类? 面向对象编程 (Object-Oriented Programming, OOP) 是一种强大的编程范式,它通过将数据和操作数据的函数(方法)捆绑在一起来组织和结构化代码 1。类 (Class) 是 OOP 的核心概念,不仅在 Python 中…...

深入浅出理解常见的分布式ID解决方案

分布式ID在构建大规模分布式系统时扮演着至关重要的角色&#xff0c;主要用于确保在分布式环境中数据的唯一性和一致性。以下是分布式ID的几个主要作用&#xff1a; 确保唯一性&#xff1a;在分布式系统中&#xff0c;可能有成千上万个实例同时请求ID。分布式ID生成系统能保证即…...

mac 使用 Docker 安装向量数据库Milvus独立版的保姆级别教程

Milvus 特点&#xff1a;开源的云原生向量数据库&#xff0c;支持多种索引类型和GPU加速&#xff0c;能够在亿级向量规模下实现低延迟高吞吐。具有灵活的部署选项和强大的社区支持。 适用场景&#xff1a;适合处理超大规模数据和高性能需求的应用&#xff0c;如图像搜索、推荐…...

Ubuntu日志文件清空的三种方式

清空Ubuntu日志文件可以通过三种方式&#xff1a; 使用命令行清空日志文件&#xff1a;可以使用以下命令清空特定日志文件&#xff0c;例如清空syslog文件&#xff1a; sudo truncate -s 0 /var/log/syslog使用编辑器清空日志文件&#xff1a;可以使用文本编辑器如Nano或Vi来…...

文章记单词 | 第68篇(六级)

一&#xff0c;单词释义 differentiate&#xff1a;英 [ˌdɪfəˈrenʃieɪt] 美 [ˌdɪfəˈrenʃieɪt] &#xff0c;动词&#xff0c;意为 “区分&#xff1b;辨别&#xff1b;使有差别&#xff1b;使不同&#xff1b;表明… 间的差别&#xff1b;构成… 间差别的原因”。…...

Postman最佳平替, API测试工具Bruno实用教程(一):基础篇

序言 在前文【github星标超3万!Postman最强平替Bruno你用了吗?】中,我们介绍了目前目前Github上广受关注的新锐接口测试工具Bruno,给厌倦了Postman必须在线使用限制的同学提供了一个很好的替代选择。 Bruno的核心优势,官网重点给出了如下几点: 承诺开源和可扩展,并且专…...

LabVIEW 与 NI 硬件(PXI, CompactRIO, DAQ, RF, Vision)的深度研究与未来发展趋势-分析报告

LabVIEW 与 NI 硬件&#xff08;PXI, CompactRIO, DAQ, RF, Vision&#xff09;的深度研究与未来发展趋势 引言 本报告旨在对 National Instruments (NI) 的 LabVIEW 软件平台及其核心硬件产品线&#xff0c;包括 PXI、CompactRIO、DAQ、RF 和 Vision 系列&#xff0c;进行深…...

上海雏鸟科技再赴越南,助力10518架无人机刷新吉尼斯记录

近日&#xff0c;上海雏鸟科技携手深圳大漠大、河南豆丁智能在越南胡志明市&#xff0c;使用10518架无人机刷新了“最多无人机同时起飞”的世界吉尼斯记录。本次无人机灯光秀表演以越南南部解放50周年为背景突出了越南历史与民族文化的主题&#xff0c;是一场融合了技术与艺术的…...

在云环境中部署Redis服务与自建Redis服务有啥不同?

云服务 Redis概述 常见的云服务Redis提供商有&#xff08;阿里云 Redis、华为云 Redis、AWS ElastiCache for Redis等&#xff09;。这些云提供商负责底层基础设施的部署、配置、维护、操作系统的管理、补丁升级、硬件故障处理等大部分繁琐的运维工作。我们只需要通过控制台或…...

C++类对象的隐式类型转换和编译器返回值优化

文章目录 前言1. 隐式类型转换1.1 单参数的隐式类型转换1.2 多参数的隐式类型转换1.3 explicit关键字 2. 编译器的优化2.1 普通构造优化2.2 函数传参优化2.3 函数返回优化 前言 在类与对象的学习过程中&#xff0c;一定会对隐式类型转换这个词不陌生。对于内置类型而言&#x…...

西门子 PLC 串口转网口模块

在工业自动化领域&#xff0c;高效稳定的通信是保障生产顺畅运行的关键。三格电子西门子 PLC 串口转网口模块&#xff0c;型号涵盖 SG-S7-200-ETH、SG-S7-200-ETH (2P)、SG-S7-300-ETH、SG-S7-300-ETH (2P) 网口扩展与协议支持&#xff1a;该系列模块专为西门子 S7-200/300 PL…...

MATLAB制作直方图

一、什么是直方图&#xff1f; 直方图&#xff08;Histogram&#xff09;是一种用于显示数据分布的图形工具。它通过将数据分成若干个区间&#xff0c;统计每个区间内数据的数量或频率&#xff0c;从而形成类似柱状图的形式。它能帮助我们直观了解数据的集中程度、分布形状、离…...

Linux NVIDIA 显卡驱动安装指南(适用于 RHEL/CentOS)

&#x1f4cc; 一、禁用 Nouveau 开源驱动 NVIDIA 闭源驱动与开源的 nouveau 驱动冲突&#xff0c;需先禁用&#xff1a; if [ ! -f /etc/modprobe.d/blacklist-nouveau.conf ]; thenecho -e "blacklist nouveau\noptions nouveau modeset0" | sudo tee /etc/modpr…...

微机控制电液伺服拉扭疲劳试验系统

微机控制电液伺服拉扭疲劳试验系统&#xff0c;主要用于测定金属材料及其构件在正弦波、三角波、方波、梯形波、斜波、程序块波谱状态下进行&#xff1a; 拉压扭复合疲劳&#xff1b; 单纯的扭转疲劳试验&#xff1b; 拉压扭复合疲劳作用下材料的断裂韧性试验&#xff1b; 拉压…...

ElementUI 表格el-table自适应高度设置

el-table表格占满页面剩余的全部高度空间 首先&#xff0c;el-table父节点要使用flex布局和超出隐藏&#xff08;overflow: hidden&#xff09;&#xff0c;设置样式如下&#xff1a; .list{flex: 1;display: flex;flex-direction: column;overflow: hidden; }其次&#xff0…...

深入探索Linux命名管道(FIFO):原理、实践与高级技巧

引言&#xff1a;跨越进程的“文件桥梁” 在Linux的进程间通信&#xff08;IPC&#xff09;机制中&#xff0c;命名管道&#xff08;Named Pipe&#xff0c;FIFO&#xff09; 是一个看似简单却功能强大的工具。它不仅保留了匿名管道的流式数据传输特性&#xff0c;还通过文件系…...

光伏政策“430”“531”安科瑞光储充为新能源提供解决方案有哪些?

简婷 安科瑞电气股份有限公司 上海嘉定 201801 一、政策节点“430”与“531”的含义 2025年分布式光伏行业的两大核心节点——“4月30日”&#xff08;430&#xff09;和“5月31日”&#xff08;531&#xff09;&#xff0c;分别对应《分布式光伏发电开发建设管理办法》实施…...

VScode一直处于循环“正在重新激活终端“问题的解决方法

方法一&#xff1a; 键盘使用 “ctrlshiftp” 调出快捷命令&#xff0c;也可以按F1&#xff0c;并输入“>Python: Clear Cache and Reload Window ”&#xff0c;回车。清除 VSCode 先前的缓存内容&#xff0c;如下图所示。 方法二&#xff1a; 键盘使用 ” ctrl ,"…...