LangChain4j 框架模仿豆包实现智能对话系统:架构与功能详解

系统整体架构设计

基于 LangChain4j 框架构建的智能对话系统采用 "前后端分离 + 大模型中枢" 的三层架构设计,实现了与豆包类似的智能交互体验。系统架构图如下所示:

┌──────────────────────────────────────────────────────────┐
│                        前端展示层                         │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐      │
│  │ 对话界面 │  │ 输入组件 │  │ 历史记录 │  │ 用户操作 │    │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘      │
├──────────────────────────────────────────────────────────┤
│                      通信与协议层                         │
│  ┌────────────┐  ┌────────────┐  ┌────────────┐          │
│  │  SSSE      │  │  REST API  │  │  消息格式   │          │
│  └────────────┘  └────────────┘  └────────────┘          │
├──────────────────────────────────────────────────────────┤
│                        后端逻辑层                         │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐      │
│  │ 模型调用 │  │ 上下文  │  │ 提示工程 │  │ 检索增强 │     │
│  │ (LLM)   │  │ 管理    │  │  模块   │  │  (RAG)  │       │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘      │
├──────────────────────────────────────────────────────────┤
│                      数据持久层                           │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐      │
│  │ 对话历史 │  │ 向量存储 │  │ 知识库  │  │ 用户信息 │     │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘      │
└──────────────────────────────────────────────────────────┘

图 1:LangChain4j 智能对话系统架构图

该架构的核心优势在于:

  • 前后端解耦:前端采用 Vue3 构建交互界面,后端基于 LangChain4j 处理 AI 逻辑,分工明确
  • 大模型能力封装:通过 LangChain4j 标准化接口,屏蔽不同 LLM 提供商的差异
  • 企业级扩展:支持集群部署、负载均衡和数据持久化,满足高并发场景

前端功能模块详解

1. 对话界面模块

前端界面采用 Vue3 实现,模仿豆包的 UI 设计风格,主要包含三大区域:

顶部导航区,中部对话区以及底部输入区。

<template><!-- 整体容器 --><div class="doubao-layout"><!-- 1. 顶部导航区 --><header class="doubao-header"><div class="header-inner"><!-- 标题与新对话 --><div class="left-group "><el-button type="primary" icon="Plus" size="mini" class="mr-4" @click="handleNewChat">新对话</el-button><h2 class="header-title">{{ chatTitle }}</h2></div><!-- 操作与头像 --><div class="right-group"><el-icon @click="handleShare"><Share /></el-icon><el-icon @click="handleFavorite"><Star /></el-icon><el-avatar size="medium"src="https://img0.baidu.com/it/u=2648433959,1760892301&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500"class="cursor-pointer" @click="handleUserCenter" /></div></div></header><!-- 2. 对话内容区 --><div class="chat-container"><!-- 对话内容区 --><section class="doubao-chat" ref="chatContainer"><div class="chat-inner"><!-- 对话历史列表 --><div v-for="(msg, index) in chatHistory" :key="index" class="message-container"><!-- 用户消息 - 居右对齐 --><div v-if="msg.isUser" class="user-message"><div class="message-bubble"><div style="display: flex;align-items: center;" class="message-content"><p style="text-align: left;margin-right: 7px;" class="message-text">{{ msg.content}}</p><el-avatar size="medium"src="https://img0.baidu.com/it/u=2648433959,1760892301&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500"class="avatar-fixed" @click="handleUserCenter" /></div></div></div><!-- AI消息 - 居左对齐 --><div v-else class="ai-message"><div class="message-bubble"><div style="display: flex;align-items: center;" class="message-content"><el-avatar size="medium" src="/doubao.png" @click="handleUserCenter"class="avatar-fixed" /><p style="text-align: left;margin-left: 7px;" class="message-text">{{ msg.content }}</p></div></div></div></div></div></section></div><!-- 3. 输入对话框 --><footer class="doubao-input"><div class="input-inner"><el-input v-model="prompt" class="input-main" placeholder="请输入内容..." clearable@keyup.enter="sendMessage" /><el-button type="primary" icon="Search" size="mini" class="ml-2" @click="sendMessage"style="margin-left: 10px;">发送</el-button></div></footer></div>
</template>
核心交互逻辑:
  • 自动滚动:通过监听chatHistory变化,使用scrollTop = scrollHeight实现新消息自动定位
  • 对话标题:根据历史记录动态更新标题,使用computed属性实现响应式
  • 用户操作:集成分享(复制链接)、收藏(引导快捷键)、新建对话等功能

2. 状态管理模块

采用组合式 API 管理对话状态,核心代码如下:

import { ref, computed, watch } from 'vue';
import { useRoute } from 'vue-router';
import { ElMessage } from 'element-plus';// 对话状态
const chatHistory = ref([]);
const prompt = ref('');
const isLoading = ref(false);
const currentAIResponse = ref('');// 动态标题
const route = useRoute();
const chatTitle = computed(() => {if (chatHistory.value.length > 1) {const firstUserMsg = chatHistory.value.find(msg => msg.isUser);return firstUserMsg?.content || '新对话';}return '新对话';
});// 自动滚动
const chatContainer = ref(null);
const scrollToBottom = () => {if (chatContainer.value) {chatContainer.value.scrollTop = chatContainer.value.scrollHeight;}
};
watch(chatHistory, () => nextTick(scrollToBottom));

3. 主要功能展示

创建新对话:

对话详情:

后端核心功能实现

后端基于 LangChain4j 框架构建,核心功能模块包括:

配置文件:

server:port: 9000servlet:encoding:charset: UTF-8enabled: trueforce: true# openai相关配置
openai:apiKey: #替换成自己的apiKeymodel: gpt-4o-minibaseUrl: https://api.chatanywhere.tech/v1/temperature: 0.7# 单条对话最多存储多少条对话历史记录maxMessages: 100spring:application:name: llm_appdatasource:druid:url: jdbc:mysql://localhost:3306/llm_app?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=trueusername: # 数据库用户名password: # 数据库密码 不存储到数据库就不需要driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcedata:redis:password: # 你的redis密码 如果设置了database: 1host: localhostport: 6379timeout: 5000

1. 大模型交互模块

通过LLMConfig进行统一配置,统一管理大模型调用,支持多模型切换:

package com.example.config;import com.example.entity.ChatLLM;
import com.example.service.*;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.chat.TokenWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.model.openai.OpenAiTokenCountEstimator;
import dev.langchain4j.service.AiServices;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Author: znly* @Description:* @Date: 2025/7/2 9:08*/
@Configuration
public class LLMConfig {@Autowiredprivate ApplicationContext context;@Resourceprivate RedisChatMemoryStore redisChatMemoryStore;@Autowiredprivate OpenAIProperties openAIProperties;@Beanpublic ChatModel chatModel() {return OpenAiChatModel.builder().modelName(openAIProperties.getModel()).baseUrl(openAIProperties.getBaseUrl()).apiKey(openAIProperties.getApiKey()).temperature(openAIProperties.getTemperature()).build();}/*** 创建一个流式模型** @return*/@Beanpublic StreamingChatModel streamingChatModel() {return OpenAiStreamingChatModel.builder().modelName(openAIProperties.getModel()).baseUrl(openAIProperties.getBaseUrl()).apiKey(openAIProperties.getApiKey()).temperature(openAIProperties.getTemperature()).maxTokens(openAIProperties.getMaxTokens()).build();}@Beanpublic ChatLLMService chatLLMService(StreamingChatModel streamingChatModel) {return AiServices.builder(ChatLLMService.class).streamingChatModel(streamingChatModel).chatMemoryProvider(memoryId -> {return MessageWindowChatMemory.withMaxMessages(10);}).build();}@Bean(name = "chatMessageWindowChatMemory")public ChatMemoryAssistant chatMessageWindowChatMemory(ChatModel chatModel) {return AiServices.builder(ChatMemoryAssistant.class).chatModel(chatModel).chatMemoryProvider(memoryId -> {return MessageWindowChatMemory.withMaxMessages(10);}).build();}@Bean(name = "chatTokenWindowChatMemory")public ChatMemoryAssistant chatTokenWindowChatMemory(ChatModel chatModel) {return AiServices.builder(ChatMemoryAssistant.class).chatModel(chatModel).chatMemoryProvider(memoryId -> {return TokenWindowChatMemory.withMaxTokens(1000, new OpenAiTokenCountEstimator("gpt-4o-mini"));}).build();}@Bean(name = "chatRedisChatMemory")public ChatMemoryAssistant chatRedisChatMemory(ChatModel chatModel) {ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder().id(memoryId).maxMessages(10).chatMemoryStore(redisChatMemoryStore).build();return AiServices.builder(ChatMemoryAssistant.class).chatModel(chatModel).chatMemoryProvider(chatMemoryProvider).build();}@Bean(name = "chatExternal")public ChatLLMServiceSimple chatLLMServiceExternal(ChatModel chatModel) {return AiServices.builder(ChatLLMServiceSimple.class).chatModel(chatModel).tools(new WeatherService()).build();}@Bean(name = "chatLLM")public ChatMemoryAssistant chatLLM(ChatModel chatModel) {ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder().id(memoryId).maxMessages(10).chatMemoryStore(redisChatMemoryStore).build();return AiServices.builder(ChatMemoryAssistant.class).chatModel(chatModel).chatMemoryProvider(chatMemoryProvider).tools(new ExternalService()).build();}@Bean(name = "chatLLMStream")public ChatMemoryAssistant chatLLMStream(StreamingChatModel streamingChatModel) {ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder().id(memoryId).maxMessages(openAIProperties.getMaxMessages()).chatMemoryStore(redisChatMemoryStore).build();return AiServices.builder(ChatMemoryAssistant.class).streamingChatModel(streamingChatModel).chatMemoryProvider(chatMemoryProvider).tools(new ExternalService()).build();}}

2. 上下文管理模块

实现对话历史的存储与检索,支持会话级和用户级上下文:

本系统通过redis实现临时存储,不存储至数据库,可以在配置文件中中对存储上限进行动态修改。

@Bean(name = "chatLLMStream")public ChatMemoryAssistant chatLLMStream(StreamingChatModel streamingChatModel) {ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder().id(memoryId).maxMessages(openAIProperties.getMaxMessages()).chatMemoryStore(redisChatMemoryStore).build();return AiServices.builder(ChatMemoryAssistant.class).streamingChatModel(streamingChatModel).chatMemoryProvider(chatMemoryProvider).tools(new ExternalService()).build();}

3. 提示工程模块

封装提示词模板与解析逻辑,提升大模型输出质量:

例如,可以利用@SystemMessage来定义你的提示词,确保大模型只回复相关领域的知识内容。

package com.example.service;import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import reactor.core.publisher.Flux;/*** @Author: znly* @Description:* @Date: 2025/7/3 10:43*/
public interface ChatMemoryAssistant {/*** 带记忆缓存的对话* @param userId* @param prompt* @return*/
@SystemMessage("你是一位本科和研究生均毕业于北京大学的专业后端开发工程师,拥有十年大厂后端开发工作经验,你的主要编程语言是java和python。" +
"你只能回答你的业务领域内的问题,如果问题涉及到其他领域请回复不知道")String chat(@MemoryId String memoryId, @UserMessage String prompt);Flux<String> chatStream(@MemoryId String memoryId, @UserMessage String prompt);}

4. 函数调用

针对大模型对于相关城市天气,当天时间等需要联网查询,或者是用户自己相关的知识,可以通过@Tool这个注解来实现函数调用。

例如:针对天气和时间问题,会调用以下两个函数来执行,大模型不会直接回答。

package com.example.service;import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import org.springframework.stereotype.Service;import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;/*** @Author: znly* @Description: 外部服务类* @Date: 2025/7/3 22:18*/
@Service
public class ExternalService {@Tool(value = "今天天气怎么样")public String getWeather(@P("城市") String city) {System.out.println("城市:" + city);//调用外部 服务return "今天" + city + "的天气是晴天";}@Tool(value = "今天日期是多少")public String getDate() {System.out.println("今天日期" + LocalDate.now().toString());return LocalDate.now().toString();}@Tool(value = "告诉我现在的北京时间")public String getTime() {// 获取当前时间LocalDateTime now = LocalDateTime.now();// 定义日期时间格式DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");// 格式化时间String formattedDateTime = now.format(formatter);// 输出格式化后的时间System.out.println("当前时间: " + formattedDateTime);return "当前时间是:" + formattedDateTime;}
}

5. 检索增强生成 (RAG) 模块

结合向量检索与大模型生成,提升专业领域回答准确性:

// 文档加载与处理
DocumentLoader loader = new FileSystemDocumentLoader("knowledge-base");
DocumentParser parser = new MarkdownDocumentParser();
TextSplitter splitter = new RecursiveCharacterTextSplitter(RecursiveCharacterTextSplitterConfig.builder().chunkSize(800).chunkOverlap(100).build()
);
List<Document> documents = splitter.split(parser.parse(loader.load()));// 向量存储
EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder().apiKey(API_KEY).build();
EmbeddingStore embeddingStore = PineconeEmbeddingStore.builder().apiKey(PINECONE_KEY).environment("us-west1-gcp").indexName("knowledge-index").build();
embeddingStore.storeDocuments(documents, embeddingModel);// RAG服务
Rag rag = Rag.builder().embeddingModel(embeddingModel).embeddingStore(embeddingStore).documentLoader(loader).textSplitter(splitter).build();// 生成回答
String userQuery = "如何配置LangChain4j的RAG模块?";
List<Document> relevantDocs = rag.relatedDocuments(userQuery, 3);
String response = rag.chain().promptTemplate(PromptTemplate.builder().template("根据以下文档回答用户问题:\n{documents}\n用户问题:{userQuery}\n回答:").build()).languageModel(model).build().invoke(Map.of("documents", relevantDocs, "userQuery", userQuery));

技术亮点与创新点

1. 多模态对话增强

在标准文本对话基础上,扩展支持:

  • 富文本处理:解析 Markdown 格式输出,支持加粗、列表等样式
  • 代码块处理:自动识别代码块并高亮显示,提升技术对话体验
  • 数学公式支持:通过 KaTeX 渲染 LaTeX 公式,满足学术交流需求

2. 智能对话控制

实现多种对话策略:

  • 追问策略:当用户问题不明确时,自动生成追问提示(如 "你能具体说明一下吗?")
  • 多轮上下文:智能截断过长对话历史,保留关键信息(基于令牌数统计)
  • 敏感词过滤:集成内容安全模块,自动识别并处理敏感信息

3. 企业级能力集成

与企业系统深度整合:

  • OA 系统集成:对接企业 OA 系统,自动提取日程、审批等信息
  • CRM 集成:根据客户历史订单生成个性化推荐
  • 知识库对接:连接企业内部知识库,提供专业领域支持

应用场景与典型案例

1. 企业智能客服

某电商平台集成该系统后,实现:

  • 85% 的常见问题自动解答,减少客服人力成本
  • 基于购买历史的个性化推荐,提升转化率 15%
  • 多轮对话上下文保持,客户满意度提升 20%

2. 技术支持助手

为软件开发团队提供:

  • 代码问题解答(基于官方文档和项目代码库)
  • 错误日志分析与解决方案推荐
  • 技术选型建议(如 "Spring Boot 与 Quarkus 如何选择")

3. 学术研究助手

服务科研人员:

  • 文献摘要生成与关键信息提取
  • 实验方案设计建议
  • 论文写作辅助(语法检查、引用建议)

总结与未来规划

基于 LangChain4j 构建的智能对话系统,充分发挥了 Java 的企业级优势和 LangChain4j 的大模型集成能力,在功能完整性、性能表现和可扩展性方面均达到生产级水平。系统不仅实现了豆包的核心对话功能,还通过 RAG 技术、多模态支持和企业级集成,拓展了智能对话的应用边界。

未来规划包括:

  1. 多模态增强:支持语音、图像输入输出,实现更自然的交互
  2. 联邦学习集成:保护企业数据隐私,支持跨机构协作
  3. 边缘计算优化:针对边缘设备进行模型轻量化和推理优化
  4. 低代码平台:提供可视化流程编排工具,降低使用门槛

该系统的成功实践证明,Java 与 LangChain4j 的组合不仅适用于企业级大模型应用开发,还能在用户体验、性能优化和系统集成方面超越传统 Python 方案,为智能对话技术的工业化落地提供了新的技术路径。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于uni-app的书法学习管理小程序的设计与实现

一、设计的目的 书法是中华民族传统文化的瑰宝&#xff0c;更是人类文明的宝贵财富&#xff0c;具有深远的意义和实价值。在当今数字化时代&#xff0c;随着信息技术的飞速发展&#xff0c;传统书法学习模式面临着诸多挑战和需要解决的问题。为推动书法学习的现代化转型&#…

NumPy 函数库在数学建模中的基本使用方法

一、引言 在数学建模的世界里,我们常常需要处理大量的数据和进行复杂的数值计算。Python 中的 NumPy 库就像是一位得力的助手,它为我们提供了强大的多维数组对象和丰富的数学函数,让我们能够高效地完成各种数值计算任务。接下来,我们将深入探讨 NumPy 在数学建模中的基本使…

模块三:现代C++工程实践(4篇)第一篇《C++模块化开发:从Header-only到CMake模块化》

引言&#xff1a;现代C工程化的核心挑战&#xff08;终极扩展版&#xff09; 在云计算与物联网时代&#xff0c;C项目规模呈指数级增长。传统Header-only开发模式暴露出编译效率低下、依赖管理混乱、版本冲突频发等致命问题。本文通过CMake 3.22Conan 2.0工具链的深度集成&…

uniapp启动图被拉伸问题

记录下&#xff1a; 安卓手机有不同的规格&#xff0c;很难所有规格都去适配。如果不适配所有机型&#xff0c;那么就会导致部分机型的启动图被拉伸。 安卓提供了.9.png图片格式&#xff0c;允许标注部分拉伸&#xff0c;这样启动图中间的logo就不会被拉伸。 下面2张图是没有…

stm32的三种开发方式

以下是针对STM32F103RC实现LED闪烁&#xff08;PC13引脚&#xff09;的三种开发方式示例代码&#xff0c;每种方式均保持相同的核心逻辑&#xff1a; 1. 寄存器开发方式&#xff08;直接操作寄存器&#xff09; #include "stm32f10x.h"int main(void) {// 1. 开启G…

SpringBoot问卷调查系统设计与实现

概述 基于SpringBoot开发的问卷调查系统&#xff0c;该系统集成了问卷管理、题目管理等多种功能模块。 主要内容 核心功能模块&#xff1a; ​​个人信息管理​​&#xff1a; 修改密码个人信息修改 ​​问卷管理​​&#xff1a; 问卷新增问卷修改问卷删除 ​​题目管理​…

Linux进程管理:从基础到实战

在 Linux 系统编程中&#xff0c;进程&#xff08;Process&#xff09; 是操作系统进行资源分配和调度的基本单位。理解进程的概念是掌握系统编程、多任务处理、并发编程的基础。 目录 一、什么是进程&#xff1f; 定义&#xff1a; 二、进程的生命周期 示例&#xff1a;查…

工业物联网中的 Modbus:传感器与网关通信实战(二)

四、实战案例解析 4.1 项目背景与目标 某智能工厂致力于提升生产过程的自动化和智能化水平&#xff0c;对生产线上的各种设备进行实时监控和数据分析。在该工厂的一个生产车间中&#xff0c;存在着大量的传感器&#xff0c;用于监测设备的运行状态、环境参数等信息。这些传感…

飞算 JavaAI 智控引擎:全链路开发自动化新图景

免责声明: 此文章的所有内容皆是本人实验测评&#xff0c;并非广告推广&#xff0c;并非抄袭。如有侵权&#xff0c;请联系&#xff0c;谢谢! 文章目录&#x1f4dd;前言一、飞算 Java AI 智能开发助手简介1.1何为飞算 Java AI智能助手&#xff1f;2.2 飞算Java AI 直击开发全场…

MYSQL数据库(九)MVCC-多版本并发控制

目录 一 前景导入 1 当前读 2 快照读 二 MVCC 1 隐藏字段 2 UndoLog 回滚日志 (1 UndoLog日志 (2 UndoLog版本链 3 Read View 面试八股 介绍一下MVCC 一 前景导入 1 当前读 可使当前事务读取的是最新版本的数据&#xff0c;读取时还要保证其他并发事务不能修改当中…

[Pytest] [Part 2]增加 log功能

开始实现需求之前先做个log类&#xff0c;可以给其他模块使用&#xff0c;也方便以后修改log类的功能和属性。 使用的是python中的logging包来进行简单的封装&#xff0c;具体代码如下 import logging import sysclass TefLogger:def __init__(self, logger_nameTEST_FRAMEWOR…

NeighborGeo:基于邻居的IP地理定位(三)

NeighborGeo:基于neighbors的IP地理定位 X. Wang, D. Zhao, X. Liu, Z. Zhang, T. Zhao, NeighborGeo: IP geolocation based on neighbors, Comput. Netw. 257 (2025) 110896, 3. NeighborGeo 本文提出NeighborGeo,利用图结构学习和有监督对比学习来建立可靠的地标-目标关…

python使用fastmcp包编写mcp服务端(mcp_server)和mcp客户端(mcp_client)

安装fastmcp pip install fastmcp编写mcp服务端代码 from fastmcp import FastMCP mcp FastMCP(weather)mcp.tool() def get_weather(city: str):获取对应城市的天气:param city: 目标城市:return: 该城市的天气return f"{city}天气晴朗&#xff0c;温度60度&#xff01…

(1)机器学习小白入门 YOLOv:从概念到实践

(1)机器学习小白入门YOLOv &#xff1a;从概念到实践 (2)机器学习小白入门 YOLOv&#xff1a;从模块优化到工程部署 (3)机器学习小白入门 YOLOv&#xff1a; 解锁图片分类新技能 目标检测一直是一个机器学习的一个重要的应用方向。而 YOLOv&#xff08;You Only Look Once&…

Appium 简介

Appium 是一个开源的移动应用自动化测试框架&#xff0c;用于测试原生应用(native)、混合应用(hybrid)和移动网页应用(mobile web)。它支持 iOS、Android 和 Windows 平台。 https://www.bilibili.com/video/BV1R93szkEhi/? App自动化测试&#xff1a;App测试AppiumUiAutomato…

【C语言刷题】第十一天:加量加餐继续,代码题训练,融会贯通IO模式

&#x1f525;个人主页&#xff1a;艾莉丝努力练剑 ❄专栏传送门&#xff1a;《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题 &#x1f349;学习方向&#xff1a;C/C方向 ⭐️人生格言&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为…

免费版安全性缩水?ToDesk、TeamViewer、向日葵、网易UU远程访问隐私防护测评

一、前言 在这个居家办公、远程技术支持成为常态的时代&#xff0c;我们经常需要把电脑控制权交给远方的同事或技术人员。但你想过没有&#xff0c;那些免费远程控制软件&#xff0c;真的能保护好你的隐私吗&#xff1f; 好用的远程软件通常会收费运营&#xff0c;投入经费去开…

nginx部署发布Vite项目

1 引言 在之前的文章《Ubuntu云服务器上部署发布Vite项目》中笔者使用了Vite提供的预览服务(npm run preview)来在云服务器上发布Web应用。这样做轻量应用是没问题的&#xff0c;不过遇到一些专业的问题就不行了&#xff0c;最好还是使用专业的HTTP服务器。除此之外&#xff0…

Unity文件夹标签 —— FolderTag

GitHub地址 FolderTag 下载之后解压&#xff0c;将FolderTag文件夹拖进Unity项目的Assets文件夹 选中文件夹&#xff0c;填上标签

【0基础开发油猴脚本】某漫画网站图片旋转

有朋友在用某漫画网站在线看漫画&#xff0c;但是那个网站会把漫画图片右旋90度&#xff0c;如图。于是&#xff0c;他就像我发起了求助&#xff0c;问我能不能写个脚本。我说&#xff0c;AI都发展到2025了&#xff0c;前端&#xff08;脚本&#xff09;这种东西还用自己写吗&a…