使用Quarkus和LangChain4j,LLM在Java中可以实现哪些功能? 原创
本文试图通过一个有趣的原创项目,利用Quarkus和LangChain4j来揭开LLM在Java中使用的神秘面纱。
自从2022年11月公开发布以来,ChatGPT吸引了大量用户,这种人工智能模型不仅提高了他们的创造力,也激发了技术爱好者对其可能存在的缺点甚至弱点的关注。
ChatGPT以及类似的聊天机器人是被称为大型语言模型(LLM)的一种特殊类型的软件,它极大地改变了自然语言处理(NLP)领域,以提供更新和不太常见的任务,例如问答、文本生成和摘要等。所有这些术语听起来非常复杂,虽然很多文章致力阐明LLM的巨大飞跃,但本文试图了解LLM的工作原理,特别是如何在Java中使用它们,突出LLM引人注目的可能性以及存在的一些潜在问题。
LLM发展历史
自然语言处理(NLP)指的是构建能够识别、理解和生成人类语言文本的机器。对于许多人来说,这听起来像是一种新技术,但实际上它与计算机诞生在同一时期。在信息时代初期,能够自动将一种人类语言翻译成另一种语言是程序员的梦想。
艾伦·图灵在1950年发表的一篇论文中指出,如果一台机器能产生与人类无法区别的响应,那么它就可以被认为是“智能机器”。这种被称为图灵测试的方法,现在被认为是所谓的机器“智能”的一种不完整案例,因为它很容易被现代程序实现,这些程序是为了模仿人类的语言而设计的。
世界上首个NLP程序采用了一种简单的方法,使用一组规则和启发式来模仿会话。1966年,麻省理工学院(MIT)教授Joseph Weizenbaum发布了历史上第一个聊天机器人Eliza。基于通用语言模式匹配,该程序通过提出开放式的问题,并对它不“理解”的句子给出通用的回答,例如“请继续”,创造了一种与人会话的假象。
在接下来的几十年,基于规则的文本解析和模式匹配仍然是最常见的NLP方法。到20世纪90年代,NLP发生了一个重要的范式转变,包括采用统计方法取代基于规则的方法。与试图定义和构建语法的原有模型不同,新模型旨在通过“训练”来“学习”语言模式。现在,大量文档被用来为NLP程序提供数据,以便“教授”它们一个给定的语言模型。因此,人们开始为文本生成、分类或其他自然语言任务“训练”程序,一开始,这个过程是基于输入序列的,模型将这些输入序列分解为令牌,通常是单词或部分单词,然后再转换为训练算法给出的相关数学表示。最后,将这种特殊的表示形式转换回令牌,以生成可读的结果。这种来回的令牌化过程称为“编码-解码”。
NLP研究人员在2014年发现了另一种替代传统方法,即通过编码器-解码器模型逐条传递序列。这一新方法引起了人们的注意,它包括让解码器搜索完整的输入序列,并试图从语言模型的角度找到最相关的的部分。几年后,谷歌公司发表了一篇题为《注意力就是你所需要的一切》的论文。其研究结果表明,基于这种新的注意力原理的模型速度更快,并且可以并行化,它们被称为Transformers。
Transformers标志着LLM的诞生,因为它们使得训练更大数据集的模型成为可能。2018年,OpenAI公司推出了第一个名为生成式预训练Transformers (GPT)的LLM。这个LLM是一个基于Transformers的LLM,它使用大量未标记的数据进行训练,然后根据特定任务进行微调,例如机器翻译、文本分类、情感分析等。而在这一年,谷歌公司推出了另一个LLM ——BERT (基于Transformers的双向编码器表示),它使用了更大的训练数据量,包括数十亿个单词和1亿多个参数。
与以前的NLP程序不同,这些LLM并不针对特定任务。与其相反,它们只是被训练来预测最适合给定模型特定场景的令牌。它们被应用于不同的领域,并正在成为人们日常生活中不可或缺的一部分。例如苹果的Siri、亚马逊的Alexa或Google Home这些会话代理能够倾听用户的询问,将声音转化为文本,然后回答问题。它们的通用目的和多功能性导致了广泛的自然语言任务,包括但不限于:
- 语言建模
- 回答问题
- 编码
- 内容生成
- 逻辑推理
- 等等。
会话LLM
LLM的任务在于他们能够以高度灵活的方式为各种情况生成文本,这使他们能够完美地与人类交谈。聊天机器人是专门为会话使用而设计的LLM。ChatGPT是最著名的LLM,但还有很多其他的LLM,例如:
- 谷歌的Bard
- 微软的Bing AI
- Meta的LLaMa
- Anthropic的Claude
- GitHub的Copilot
- 等等。
会话LLM嵌入到企业级应用程序中,是客户服务、教育、医疗保健、网络内容生成、化学、生物学等许多领域的理想解决方案。聊天机器人和虚拟助理可以通过访问会话LLM功能来提供动力。LLM在传统应用程序中的这种集成要求它们公开一致的API。为了从应用程序中调用这些API,需要提供一个工具包,它能够与人工智能模型交互并促进自定义创建。
LLM工具包
自从ChatGPT问世以来,人工智能领域得以快速发展,在所有这些新工具中,LLM工具包出现了真正的爆炸式增长。其中一些著名的LLM(例如AutoGPT、MetaGPT、AgentGPT等)试图赶上潮流。但毫无疑问,最现代也是讨论最多的是LangChain。LangChain于2022年作为开源库推出,支持Python、JavaScript和TypeScript,最初由Harrison Chase公司开发,在发布之后不久,就成为人工智能领域发展最快的项目之一。
尽管越来越受欢迎,但LangChain有一个主要缺点:缺乏Java支持。因此,为了解决这个缺点,LangChain4j在2023年初出现,作为LangChain Python库的Java实现。在以下的演示中将使用LangChain4J实现企业级Java服务和组件,这些服务和组件由最主流和最有影响力的LLM提供支持的企业级Java服务和组件。
演示项目
为了说明其论述,将使用一个简单的Java程序来执行自然语言任务。为此选择的用例是实现一个能够编写俳句的人工智能服务。《大英百科全书》对于俳句的定义是:俳句是一种不押韵的诗歌形式,由17个音节组成,分别排成5、7和5个音节的三行句子。
正如人们所看到的,这样一个任务的有用性并不真正引人注目,事实上,它不仅仅是一个真正的用例,而是一个展示LangChain4j一些功能的借口,同时使用一个有趣的并且是原创的形式。
因此,这个项目是一个专业的多模块项目,具有以下结构:
- 一个名为llm-java的主要POM
- 一个名为haiku的JAX-RS模块,公开调用LLM模型的REST API
- 一个名为infra的基础设施模块,用于创建所需的Docker容器
主要POM
这个项目是Quarkus项目。因此,物料清单(BOM)的使用如下:
XML
1 <dependencyManagement>
2 <dependencies>
3 <dependency>
4 <groupId>io.quarkus</groupId>
5 <artifactId>quarkus-bom</artifactId>
6 <version>${quarkus.version}</version>
7 <type>pom</type>
8 <scope>import</scope>
9 </dependency>
10 </dependencies>
11 </dependencyManagement>
它使用Quarkus 3.8.3、Java 17和LangChain4j 0.25.0。
JAX-RS模块
这个名为haiku的模块使用Quarkus - restasy -reactive-jackson Quarkus扩展来公开REST AP:
Java
1 @Path("/haiku")
2 public class HaikuResource
3 {
4 private final HaikuService haikuService;
5
6 public HaikuResource(HaikuService haikuService)
7 {
8 this.haikuService = haikuService;
9 }
10
11 @GET
12 public String makeHaiku(@DefaultValue("samurai") @RestQuery String subject)
13 {
14 return haikuService.writeHaiku(subject);
15 }
16 }
这个API定义了一个监听GET HTTP请求的端点,接受俳句主题作为查询参数,该参数包含默认值:“samurai”。该模块还使用Quarkus -container-image-jib Quarkus扩展来创建运行人工智能服务的Docker映像。这个Docker镜像的属性在应用程序中定义。应用属性(application.properties)文件如下所示:
Properties files
1 ...
2 quarkus.container-image.build=true
3 quarkus.container-image.group=quarkus-llm
4 quarkus.container-image.name=haiku
5quarkus.jib.jvm-entrypoint=/opt/jboss/container/java/run/run-java.sh
6 ...
这些属性说明新创建的Docker映像名称为quarkus-llm/haiku,其入口点将是位于容器的/opt/jboss/container/java/run目录下的run-java.sh shell脚本。
这个项目使用Quarkus扩展quarkus-langchain4j-ollama,它提供了与LangChain4j库和Ollama工具的集成。Ollama是一款先进的人工智能精简实用程序,允许用户在本地设置和运行大型LLM,例如OpenAI、Llama2、Mistral等。在这里是本地运行Llama2。这需要在应用程序中再次配置。应用属性(application.properties)采用以下语句:
Properties files
1 quarkus.langchain4j.ollama.chat-model.model-id=llama2:latest
在此需要声明的是,为了服务人工智能请求,此处使用的LLM将是其最后版本的Llama2。现在看看人工智能服务本身:
Java
1 @RegisterAiService
2 public interface HaikuService
3 {
4 @SystemMessage("You are a professional haiku poet")
5 @UserMessage("Write a haiku about {subject}.")
6 String writeHaiku(String subject);
7 }
可以看到的是,这个人工智能服务是一个带有@RegisterAiService注释的接口。Quarkus扩展提供的注释处理器将生成实现该接口的类。为了能够处理请求,任何会话LLM都需要定义场景或范围。
在这个例子中,其范围是一个专门创作俳句的艺术家的范围。这是@SystemMessage注释的作用:设置当前作用域。最后但并非最不重要的是,@UserMessage注释允许定义为人工智能服务提示的特定文本。在这里请求人工智能服务就一个主题撰写俳句,该主题由类型为String的输入参数subject定义。
基础设施模块
在检查人工智能服务的实现之后,还要了解如何设置所需的基础设施。基础设施模块名为infra,是一个maven子项目,使用Docker -compose实用程序启动以下Docker容器:
一个名为ollama的Docker容器正在运行一个标记为nicolasduminil/ollama:llama2的图像。这个图像只是官方的Ollama Docker图像,它已经被增强以包含Llama2 LLM。如上所述,Ollama能够在本地运行多个LLM,为了使这些LLM可用,需要从它们的Docker注册表中提取。这就是在运行Ollama官方Docker容器时通常需要提取所选的LLM的原因。为了避免这种重复操作,扩展这个官方Docker容器,使其已经包含了Llama2 LLM。
一个名为haiku的Docker容器正在运行标记为quarkus-llm/haiku的图像,这正是人工智能服务。
以下是创建上述基础设施所需的相关docker-compose.yaml文件:
YAML
1 version: "3.7"
2 services:
3 ollama:
4 image: nicolasduminil/ollama:llama2
5 hostname: ollama
6 container_name: ollama
7 ports:
8 - "11434:11434"
9 expose:
10 - 11434
11 haiku:
12 image: quarkus-llm/haiku:1.0-SNAPSHOT
13 depends_on:
14 - ollama
15 hostname: haiku
16 container_name: haiku
17 links:
18 - ollama:ollama
19 ports:
20 - "8080:8080"
21 environment:
22 JAVA_DEBUG: "true"
23 JAVA_APP_DIR: /home/jboss
24 JAVA_APP_JAR: quarkus-run.jar
可以看到,ollama服务运行在一个DNS名称为ollama的节点上,并监听TCP端口号11434。因此,人工智能服务需要适当地配置以连接到相同的节点/端口。同样,应用属性(application.properties)文件用于此目的,如下所示:
Properties files
1 quarkus.langchain4j.ollama.base-url=http://ollama:11434
这个声明意味着AI服务将把它的请求发送到URL: http://ollama:11434,其中ollama被DNS服务转换为IP地址,该IP地址被分配给同名的Docker容器。
运行和测试
为了运行和测试这个示例项目,可以按照以下步骤进行:
1.克隆存储库:
Shell
1 $ git clone https://github.com/nicolasduminil/llm-java.git
2.持续交付(cd)到项目:
Shell
1 $ mvn clean install
3.构建项目:
Shell
1 $ mvn clean install
4.检查所有必需的容器是否正在运行:
Shell
1 $ docker ps
2 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3 19006601c908 quarkus-llm/haiku:1.0-SNAPSHOT "/opt/jboss/containe…" 5 seconds ago Up 4 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 8443/tcp haiku
4 602e6bb06aa9 nicolasduminil/ollama:llama2 "/bin/ollama serve" 5 seconds ago Up 4 seconds 0.0.0.0:11434->11434/tcp, :::11434->11434/tcp ollama
5.运行open-api接口来测试服务。启动首选浏览器:http://localhost:8080/q/swaggerui。在显示的标有Haiku API的Swagger会话框中,单击GET按钮并使用Try it函数执行测试。在标题为“主题”(Subject)的文本字段中,键入希望人工智能服务撰写俳句的主题名称,或保留默认名称(即samurai)。测试结果如下图所示:
也可以通过使用curl工具向人工智能服务发送GET请求来测试项目,如下所示:
Shell
1 $ curl http://localhost:8080/haiku?subject=quarkus
2 Quarkus, tiny gem
3 In the cosmic sea of space
4 Glints like a star
结语
在以上的项目演示中,探索了LLM的发展历史,并使用LangChain4J实现了企业级Java服务和组件,这些服务和组件由最具主导地位和影响力的LLM提供支持。
原文标题:The Power of LLMs in Java: Leveraging Quarkus and LangChain4j,作者:Nicolas Duminil
链接:https://dzone.com/articles/leveraging-the-llm-power-in-java。