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

LangChain4j之HelloWorld

什么是LangChain4j

它是Java版本的LangChain,随着大模型的不断发展,如何在程序中更好的利用大模型的能力来提高编程效率是一种趋势,LangChain是这么自己介绍自己的:

LangChain gives developers a framework to construct LLM‑powered apps easily.

意思是:LangChain提供了一个开发框架,使得开发者可以很容易的用来构建具有LLM能力的应用程序。

LLM就是Large Language Model,也就是常说的大语言模型,简称大模型。

个人认为:大模型时代,如何将大模型能力和传统应用相结合,使得传统应用更加智能,是人工智能时代的趋势。以前一个应用要获得智能,需要企业自己投入资源训练模型,而现在只需要接入大模型即可,这种便利性将使得大模型会应用得更为广泛,而如何将大模型能力和Java编程语言相结合,这就是LangChain4j所做的。

注意,大模型的能力远远不止聊天的能力,而LangChain4j就在帮助我们更好的利用大模型的能力,从而帮我们打造出更加智能的应用。

初识LangChain4j

接下来,让我们与LangChain4j初识一下,新建一个Maven工程,然后添加以下依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.timi</groupId><artifactId>langchain4j-demo</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><langchain4j.version>0.27.1</langchain4j.version></properties><dependencies><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j</artifactId><version>${langchain4j.version}</version></dependency><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-open-ai</artifactId><version>${langchain4j.version}</version></dependency><dependency><groupId>org.tinylog</groupId><artifactId>tinylog-impl</artifactId><version>2.6.2</version></dependency><dependency><groupId>org.tinylog</groupId><artifactId>slf4j-tinylog</artifactId><version>2.6.2</version></dependency></dependencies></project>

引入了langchain4j的核心依赖、langchain4j集成OpenAi各个模型的依赖、轻量级实现了slf4j接口的tinylog日志依赖。

和OpenAi的第一次对话

package com.timi;import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;public class _01_HelloWorld {public static void main(String[] args) {ChatLanguageModel model = OpenAiChatModel.withApiKey("demo");String answer = model.generate("你好,你是谁?");System.out.println(answer);}
}

运行代码结果为:

你好,我是一个人工智能助手。我可以回答你的问题和提供帮助。有什么可以帮到你的吗?

这样,我们使用LangChain4j第一次成功的和OpenAi的GPT模型进行了对话,正常来说,调用OpenAi的API接口需要在OpenAi的官网去申请ApiKey才能调用成功,而我这里传入的ApiKey为"demo"却也能调通,这是因为:

public OpenAiChatModel(String baseUrl, String apiKey, String organizationId, String modelName, Double temperature, Double topP, List<String> stop, Integer maxTokens, Double presencePenalty, Double frequencyPenalty, Map<String, Integer> logitBias, String responseFormat, Integer seed, String user, Duration timeout, Integer maxRetries, Proxy proxy, Boolean logRequests, Boolean logResponses, Tokenizer tokenizer) {baseUrl = (String)Utils.getOrDefault(baseUrl, "https://api.openai.com/v1");if ("demo".equals(apiKey)) {baseUrl = "http://langchain4j.dev/demo/openai/v1";}//其他代码
}

在底层在构造OpenAiChatModel时,会判断传入的ApiKey是否等于"demo",如果等于会将OpenAi的原始API地址"https://api.openai.com/v1"改为"http://langchain4j.dev/demo/openai/v1",这个地址是langchain4j专门为我们准备的一个体验地址,实际上这个地址相当于是"https://api.openai.com/v1"的代理,我们请求代理时,代理会去调用真正的OpenAi接口,只不过代理会将自己的ApiKey传过去,从而拿到结果返回给我们。

所以,真正开发时,需要大家设置自己的apiKey或baseUrl,可以这么设置:

ChatLanguageModel model = OpenAiChatModel.builder().baseUrl("http://langchain4j.dev/demo/openai/v1").apiKey("demo").build();

多轮对话

前面的例子中,我们通过ChatLanguageModel的generate()方法向大模型提出问题:

String answer = model.generate("你好,你是谁?");

那如果我继续向大模型说:

model.generate("请重复")

那么大模型还记得它之前的回答吗?我们先看看效果,代码如下:

package com.timi;import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;public class _01_HelloWorld {public static void main(String[] args) {ChatLanguageModel model = OpenAiChatModel.builder().baseUrl("http://langchain4j.dev/demo/openai/v1").apiKey("demo").build();System.out.println(model.generate("你好,你是谁?"));System.out.println("----");System.out.println(model.generate("请重复"));}
}

运行结果如下:

你好,我是一个聊天机器人,可以回答你的问题和进行对话。有什么可以帮助你的吗?
----
请重复

大模型重复了我第二次跟它说的,而不是重复它的第一次回答,这是因为,目前的代码中,每次调用generate()都是一次新的会话,我再举一个例子:

package com.timi;import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;public class _01_HelloWorld {public static void main(String[] args) {ChatLanguageModel model = OpenAiChatModel.builder().baseUrl("http://langchain4j.dev/demo/openai/v1").apiKey("demo").build();System.out.println(model.generate("你好,我是Timi"));System.out.println("----");System.out.println(model.generate("我叫什么"));}
}

运行结果为:

你好Timi,有什么可以帮助你的吗?
----
抱歉,我不知道您的名字。您可以告诉我您的名字吗?我可以记住它并以后称呼您。

一样的情况,因为第二次调用generate()方法是一次单独的会话,那么如何做到使得两次或多次generate()在同一个会话中呢?在LangChain4j中有一个ChatMemory组件,它就是专门用来实现会话功能的,但是它需要结合LangChain4j中的AiService来使用,我们后面再介绍,现在我们先使用笨办法来解决多轮对话的问题。

在ChatLanguageModel中有多个generate()重载方法:

default String generate(String userMessage) {return generate(UserMessage.from(userMessage)).content().text();
}default Response<AiMessage> generate(ChatMessage... messages) {return generate(asList(messages));
}Response<AiMessage> generate(List<ChatMessage> messages);

我们前面使用的就是第一个generate()方法,而第二个和第三个generate()方法都是接收一个ChatMessage集合,并且返回一个AiMessage,那么ChatMessage和AiMessage分别都表示什么意思呢?

ChatMessage是一个接口,表示聊天消息,它有以下四种实现:

  1. UserMessage:表示用户发送给大模型的消息
  2. AiMessage:表示大模型响应给用户的消息
  3. SystemMessage:也是用户发送给大模型的消息,和UserMessage不同在于,SystemMessage一般是应用程序帮用户设置的,举个例子,假如有一个作家应用,那么“请你扮演一名作家,请帮我写一篇关于春天的作文”,其中“请你扮演一名作家”就是SystemMessage,“请帮我写一篇关于春天的作文”就是UserMessage
  4. ToolExecutionResultMessage:也是用户发送给大模型的,表示工具的执行结果,关于LangChain4j的工具机制,会在后续介绍,目前可以忽略

我们先重点关注UserMessage和AiMessage,它们就相当于请求和响应,所以如果我们想要实现多轮对话,可以这么实现:

package com.timi;import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.output.Response;public class _01_HelloWorld {public static void main(String[] args) {ChatLanguageModel model = OpenAiChatModel.builder().baseUrl("http://langchain4j.dev/demo/openai/v1").apiKey("demo").build();UserMessage userMessage1 = UserMessage.userMessage("你好,我是Timi");Response<AiMessage> response1 = model.generate(userMessage1);AiMessage aiMessage1 = response1.content(); // 大模型的第一次响应System.out.println(aiMessage1.text());System.out.println("----");// 下面一行代码是重点Response<AiMessage> response2 = model.generate(userMessage1, aiMessage1, UserMessage.userMessage("我叫什么"));AiMessage aiMessage2 = response2.content(); // 大模型的第二次响应System.out.println(aiMessage2.text());}
}

代码执行结果为:

你好,Timi。有什么可以帮助你的吗?
----
您的名字是Timi。有什么其他问题我可以帮忙解答吗?

其中重点代码为:

Response<AiMessage> response2 = model.generate(userMessage1, aiMessage1, UserMessage.userMessage("我叫什么"));

同样是问"我叫什么",但是这里我把第一次的问题和答案,也就是我和大模型的历史对话传给了大模型,只有这样,大模型才能结合历史对话知道"我叫什么"。事实上,我们在使用ChatGPT时也是一样的原理,因为ChatGPT需要结合历史对话才更能理解你最新一句话的真正意思。

打字机流式响应

在前面的例子中,当我们通过ChatLanguageModel的generate()方法向大模型提问时,ChatLanguageModel一次性给了整段响应结果,而不是一个字一个字打字机式的回答,不过我们可以使用OpenAiStreamingChatModel来实现打字机效果,代码如下:

package com.timi;import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.StreamingResponseHandler;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;import java.util.concurrent.TimeUnit;public class _01_HelloWorld {public static void main(String[] args) {StreamingChatLanguageModel model = OpenAiStreamingChatModel.builder().baseUrl("http://langchain4j.dev/demo/openai/v1").apiKey("demo").build();model.generate("你好,你是谁?", new StreamingResponseHandler<AiMessage>() {@Overridepublic void onNext(String token) {System.out.println(token);try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}}@Overridepublic void onError(Throwable error) {System.out.println(error);}});}
}

这样就能实现打字机效果了。

整合SpringBoot

先引入SpringBoot:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.1</version>
</parent>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-open-ai-spring-boot-starter</artifactId><version>0.27.1</version>
</dependency>

然后定义SpringBoot启动类:

package com.timi;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}
}

然后定义HelloController:

package com.timi;import dev.langchain4j.model.chat.ChatLanguageModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HelloController {@Autowiredprivate ChatLanguageModel chatLanguageModel;@GetMapping("/hello")public String hello(){return chatLanguageModel.generate("你好啊");}
}

配置api-key:

langchain4j.open-ai.chat-model.api-key=demo

启动SpringBoot并访问:image.png

ModerationModel

package com.timi;import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.moderation.Moderation;
import dev.langchain4j.model.moderation.ModerationModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiModerationModel;
import dev.langchain4j.model.output.Response;public class _01_HelloWorld {public static void main(String[] args) {ModerationModel moderationModel = OpenAiModerationModel.withApiKey("demo");Response<Moderation> response = moderationModel.moderate("我要谢谢你");System.out.println(response.content().flaggedText());}
}

ModerationModel能够校验输入中是否存在敏感内容。

ImageModel

package com.timi;import dev.langchain4j.data.image.Image;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.image.ImageModel;
import dev.langchain4j.model.moderation.Moderation;
import dev.langchain4j.model.moderation.ModerationModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiImageModel;
import dev.langchain4j.model.openai.OpenAiModerationModel;
import dev.langchain4j.model.output.Response;public class _01_HelloWorld {public static void main(String[] args) {ImageModel imageModel = OpenAiImageModel.builder().baseUrl("http://localhost:3000/v1").apiKey("sk-peszVtFXoLnWK45bB15370Df6f344cAa9a088eF50f9c7302").build();Response<Image> response = imageModel.generate("一辆车");System.out.println(response.content().url());}
}

ImageModel可以根据提示词来生成图片,默认提供的“demo”key不能用来生成图片,需要大家自己购买apiKey,可以先不买,先学习后面内容。

本节总结

本节我们介绍了LangChain4j的基本使用,以及多轮对话、流式响应的实现,其中我们提到了LangChain4j中的工具机制、AiService机制、ChatMemory机制,接下来我们先学习一下AiService机制。

相关文章:

LangChain4j之HelloWorld

什么是LangChain4j 它是Java版本的LangChain&#xff0c;随着大模型的不断发展&#xff0c;如何在程序中更好的利用大模型的能力来提高编程效率是一种趋势&#xff0c;LangChain是这么自己介绍自己的&#xff1a; LangChain gives developers a framework to construct LLM‑p…...

MySQL 基础概念

MySQL逻辑架构 MySQL 服务器逻辑架构图 最上层的服务并不是MySQL所独有的&#xff0c;大多数基于网络的客户端/服务器的工具或者服务都有类似的架构&#xff0c;比如连接管理、授权认证、安全等等。 大多数MySQL的核心服务都在第二层&#xff0c;包括查询解析、分析、优化、…...

RabbitMQ 学习笔记

RabbitMQ学习笔记 一些概念 Broker &#xff1a;RabbitMQ服务。 virtual host&#xff1a; 其实就是分组。 Connection&#xff1a;连接&#xff0c;生产者消费者与Broker之间的TCP连接。 Channel&#xff1a;网络信道&#xff0c;轻量级的Connection&#xff0c;使用Chann…...

【区分vue2和vue3下的element UI MessageBox 弹框组件,分别详细介绍属性,事件,方法如何使用,并举例】

在 Vue 2 中&#xff0c;Element UI 提供了 MessageBox 弹框组件&#xff0c;用于显示消息提示、确认消息和获取用户输入等。而在 Vue 3 的 Element Plus 中&#xff0c;虽然组件和 API 可能有所变化&#xff0c;但基本概念和用法是相似的。下面我将分别介绍 Vue 2 的 Element …...

避而不见!BigDecimal的四大坑

BigDecimal概述 定义&#xff1a;Java中的类&#xff0c;用于表示任意精度的十进制数。适用场景&#xff1a;需要高精度计算的场合&#xff0c;如金融、货币、税收等。 一、浮点精度的坑 问题&#xff1a;使用BigDecimal的equals和compareTo方法比较数值时&#xff0c;存在精…...

IDEA 安装与激活详细教程最新(附最新激活码)2099年亲测有效!

我们先从 IDEA 官网下载 IDEA 2024.1 版本的安装包&#xff0c;下载链接如下&#xff1a; https://www.jetbrains.com/idea/download/ 点击下载(下载Ultimate版)&#xff0c;静心等待其下载完毕即可。 激活方式&#xff1a; 正版专属激活码领取...

LeetCode 100334. 包含所有 1 的最小矩形面积 I

更多题解尽在 https://sugar.matrixlab.dev/algorithm 每日更新。 组队打卡&#xff0c;更多解法等你一起来参与哦&#xff01; LeetCode 100334. 包含所有 1 的最小矩形面积 I&#xff0c;难度中等。 遍历 解题思路&#xff1a;去掉矩形上下左右全为 0 的行和列 class Solu…...

pdf只要前几页,pdf怎么只要前几页

在现代办公和学习环境中&#xff0c;PDF文件已成为我们日常处理信息的重要工具。然而&#xff0c;有时我们并不需要整个PDF文件的内容&#xff0c;而只是其中的几页。那么&#xff0c;如何高效地提取PDF文件中的特定页面呢&#xff1f;本文将为您介绍几种实用的方法。 打开 “ …...

JAVA JVM 是怎么判定对象已经“死去”?

Java虚拟机&#xff08;JVM&#xff09;使用垃圾收集&#xff08;Garbage Collection&#xff0c;GC&#xff09;机制来自动管理内存&#xff0c;其中包括识别和回收不再使用的对象。JVM判定对象已经“死去”&#xff08;即不再被任何引用所指向&#xff09;的过程主要基于以下…...

springboot加载注入bean的方式

在SpringBoot的大环境下&#xff0c;基本上很少使用之前的xml配置Bean&#xff0c;主要是因为这种方式不好维护而且也不够方便。 springboto注入bean主要采用下图几种方式&#xff0c;分为本地服务工程注解声明的bean和外部依赖包中的bean。 一、 springboot装配本地服务工程…...

PostgreSQL 数据库设计与管理(四)

1. 数据库设计原则 1.1 规范化 规范化是组织数据库结构的一种方法&#xff0c;旨在减少数据冗余并提高数据完整性。常用的规范化范式包括&#xff1a; 第一范式&#xff08;1NF&#xff09;&#xff1a; 确保每列都是原子的&#xff0c;不可再分。第二范式&#xff08;2NF&a…...

Studying-代码随想录训练营day21| 669.修建二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树、二叉树总结

第21天&#xff0c;二叉树最后一篇&#xff0c;冲&#x1f4aa; 目录 669.修建二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树 二叉树总结 669.修建二叉搜索树 文档讲解&#xff1a;代码随想录修建二叉搜索树 视频讲解&#xff1a;手撕修建二叉…...

GraphQL:简介

GraphQL 图片来源&#xff1a; 我们将探索GraphQL 的基础知识&#xff0c;并学习如何使用Apollo将其与 React 和 React Native 等前端框架连接起来。这将帮助您了解如何使用 GraphQL、React、React Native 和 Apollo 构建现代、高效的应用程序。 什么是 GraphQL&#xff1f;…...

AI大模型安全挑战和安全要求解读

引言 随着人工智能技术的飞速发展&#xff0c;大模型技术以其卓越的性能和广泛的应用前景&#xff0c;正在重塑人工智能领域的新格局。然而&#xff0c;任何技术都有两面性&#xff0c;大模型在带来前所未有便利的同时&#xff0c;也引发了深刻的安全和伦理挑战。 大模型&…...

前端面试题-token的存放位置

哈喽小伙伴们大家好,本系列是一个专门针对前端开发岗的面试题系列,每周将会不定期分享一些面试题,希望对大家有所帮助. 面试官:token 一般在客户端存在哪儿 求职者:Token一般在客户端存在以下几个地方&#xff1a; (1)Cookie&#xff1a;Token可以存储在客户端的Cookie中。服…...

深入探讨计算机网络中的各种报文

在计算机网络中&#xff0c;报文&#xff08;Packet&#xff09;是数据传输的基本单位。不同的协议使用不同类型的报文来实现数据传输的各种功能。本文将详细探讨计算机网络中常见的几种报文类型&#xff0c;并通过举例说明其具体应用。 一、TCP/IP协议栈中的报文 TCP/IP协议…...

Debezium系列之:Mysql和SQLServer数据库字段类型覆盖测试

Debezium系列之:Mysql和SQLServer数据库字段类型覆盖测试 一、需求背景二、类型对比三、完整流程三、Mysql数据库全字段类型覆盖测试四、SQLServer数据库字段类型覆盖测试一、需求背景 Debezium版本升级迭代,要做字段类型测试,确保版本间字段类型的差异下游能够自动适应,或…...

Mathtype7在Word2016中闪退(安装过6)

安装教程&#xff1a;https://blog.csdn.net/Little_pudding10/article/details/135465291 Mathtype7在Word2016中闪退是因为安装过Mathtype6&#xff0c;MathPage.wll和MathType Comm***.dotm)&#xff0c;不会随着Mathtype的删除自动删除&#xff0c;而新版的Mathtype中的文件…...

SQL面试题练习 —— 合并用户浏览行为

目录 1 题目2 建表语句3 题解 1 题目 有一份用户访问记录表&#xff0c;记录用户id和访问时间&#xff0c;如果用户访问时间间隔小于60s则认为时一次浏览&#xff0c;请合并用户的浏览行为。 样例数据 ------------------------ | user_id | access_time | ---------------…...

【Docker】docker 替换宿主与容器的映射端口和文件路径

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 docker 替换宿主与容器的映射端口和文件夹 1. 正文 1.1 关闭docker 服务 systemctl stop docker1.2 找到容器的配置文件 cd /var/lib/docker/contain…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?

Pod IP 的本质与特性 Pod IP 的定位 纯端点地址&#xff1a;Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址&#xff08;如 10.244.1.2&#xff09;无特殊名称&#xff1a;在 Kubernetes 中&#xff0c;它通常被称为 “Pod IP” 或 “容器 IP”生命周期&#xff1a;与 Pod …...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...

自然语言处理——文本分类

文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益&#xff08;IG&#xff09; 分类器设计贝叶斯理论&#xff1a;线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别&#xff0c; 有单标签多类别文本分类和多…...

Vue3中的computer和watch

computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)

引言 在嵌入式系统中&#xff0c;用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例&#xff0c;介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单&#xff0c;执行相应操作&#xff0c;并提供平滑的滚动动画效果。 本文设计了一个…...

41道Django高频题整理(附答案背诵版)

解释一下 Django 和 Tornado 的关系&#xff1f; Django和Tornado都是Python的web框架&#xff0c;但它们的设计哲学和应用场景有所不同。 Django是一个高级的Python Web框架&#xff0c;鼓励快速开发和干净、实用的设计。它遵循MVC设计&#xff0c;并强调代码复用。Django有…...