使用Quarkus和LangChain4j,LLM在Java中可以實(shí)現(xiàn)哪些功能? 原創(chuàng)
本文試圖通過一個(gè)有趣的原創(chuàng)項(xiàng)目,利用Quarkus和LangChain4j來揭開LLM在Java中使用的神秘面紗。
自從2022年11月公開發(fā)布以來,ChatGPT吸引了大量用戶,這種人工智能模型不僅提高了他們的創(chuàng)造力,也激發(fā)了技術(shù)愛好者對(duì)其可能存在的缺點(diǎn)甚至弱點(diǎn)的關(guān)注。
ChatGPT以及類似的聊天機(jī)器人是被稱為大型語言模型(LLM)的一種特殊類型的軟件,它極大地改變了自然語言處理(NLP)領(lǐng)域,以提供更新和不太常見的任務(wù),例如問答、文本生成和摘要等。所有這些術(shù)語聽起來非常復(fù)雜,雖然很多文章致力闡明LLM的巨大飛躍,但本文試圖了解LLM的工作原理,特別是如何在Java中使用它們,突出LLM引人注目的可能性以及存在的一些潛在問題。
LLM發(fā)展歷史
自然語言處理(NLP)指的是構(gòu)建能夠識(shí)別、理解和生成人類語言文本的機(jī)器。對(duì)于許多人來說,這聽起來像是一種新技術(shù),但實(shí)際上它與計(jì)算機(jī)誕生在同一時(shí)期。在信息時(shí)代初期,能夠自動(dòng)將一種人類語言翻譯成另一種語言是程序員的夢(mèng)想。
艾倫·圖靈在1950年發(fā)表的一篇論文中指出,如果一臺(tái)機(jī)器能產(chǎn)生與人類無法區(qū)別的響應(yīng),那么它就可以被認(rèn)為是“智能機(jī)器”。這種被稱為圖靈測(cè)試的方法,現(xiàn)在被認(rèn)為是所謂的機(jī)器“智能”的一種不完整案例,因?yàn)樗苋菀妆滑F(xiàn)代程序?qū)崿F(xiàn),這些程序是為了模仿人類的語言而設(shè)計(jì)的。
世界上首個(gè)NLP程序采用了一種簡單的方法,使用一組規(guī)則和啟發(fā)式來模仿會(huì)話。1966年,麻省理工學(xué)院(MIT)教授Joseph Weizenbaum發(fā)布了歷史上第一個(gè)聊天機(jī)器人Eliza。基于通用語言模式匹配,該程序通過提出開放式的問題,并對(duì)它不“理解”的句子給出通用的回答,例如“請(qǐng)繼續(xù)”,創(chuàng)造了一種與人會(huì)話的假象。
在接下來的幾十年,基于規(guī)則的文本解析和模式匹配仍然是最常見的NLP方法。到20世紀(jì)90年代,NLP發(fā)生了一個(gè)重要的范式轉(zhuǎn)變,包括采用統(tǒng)計(jì)方法取代基于規(guī)則的方法。與試圖定義和構(gòu)建語法的原有模型不同,新模型旨在通過“訓(xùn)練”來“學(xué)習(xí)”語言模式?,F(xiàn)在,大量文檔被用來為NLP程序提供數(shù)據(jù),以便“教授”它們一個(gè)給定的語言模型。因此,人們開始為文本生成、分類或其他自然語言任務(wù)“訓(xùn)練”程序,一開始,這個(gè)過程是基于輸入序列的,模型將這些輸入序列分解為令牌,通常是單詞或部分單詞,然后再轉(zhuǎn)換為訓(xùn)練算法給出的相關(guān)數(shù)學(xué)表示。最后,將這種特殊的表示形式轉(zhuǎn)換回令牌,以生成可讀的結(jié)果。這種來回的令牌化過程稱為“編碼-解碼”。
NLP研究人員在2014年發(fā)現(xiàn)了另一種替代傳統(tǒng)方法,即通過編碼器-解碼器模型逐條傳遞序列。這一新方法引起了人們的注意,它包括讓解碼器搜索完整的輸入序列,并試圖從語言模型的角度找到最相關(guān)的的部分。幾年后,谷歌公司發(fā)表了一篇題為《注意力就是你所需要的一切》的論文。其研究結(jié)果表明,基于這種新的注意力原理的模型速度更快,并且可以并行化,它們被稱為Transformers。
Transformers標(biāo)志著LLM的誕生,因?yàn)樗鼈兪沟糜?xùn)練更大數(shù)據(jù)集的模型成為可能。2018年,OpenAI公司推出了第一個(gè)名為生成式預(yù)訓(xùn)練Transformers (GPT)的LLM。這個(gè)LLM是一個(gè)基于Transformers的LLM,它使用大量未標(biāo)記的數(shù)據(jù)進(jìn)行訓(xùn)練,然后根據(jù)特定任務(wù)進(jìn)行微調(diào),例如機(jī)器翻譯、文本分類、情感分析等。而在這一年,谷歌公司推出了另一個(gè)LLM ——BERT (基于Transformers的雙向編碼器表示),它使用了更大的訓(xùn)練數(shù)據(jù)量,包括數(shù)十億個(gè)單詞和1億多個(gè)參數(shù)。
與以前的NLP程序不同,這些LLM并不針對(duì)特定任務(wù)。與其相反,它們只是被訓(xùn)練來預(yù)測(cè)最適合給定模型特定場(chǎng)景的令牌。它們被應(yīng)用于不同的領(lǐng)域,并正在成為人們?nèi)粘I钪胁豢苫蛉钡囊徊糠?。例如蘋果的Siri、亞馬遜的Alexa或Google Home這些會(huì)話代理能夠傾聽用戶的詢問,將聲音轉(zhuǎn)化為文本,然后回答問題。它們的通用目的和多功能性導(dǎo)致了廣泛的自然語言任務(wù),包括但不限于:
- 語言建模
- 回答問題
- 編碼
- 內(nèi)容生成
- 邏輯推理
- 等等。
會(huì)話LLM
LLM的任務(wù)在于他們能夠以高度靈活的方式為各種情況生成文本,這使他們能夠完美地與人類交談。聊天機(jī)器人是專門為會(huì)話使用而設(shè)計(jì)的LLM。ChatGPT是最著名的LLM,但還有很多其他的LLM,例如:
- 谷歌的Bard
- 微軟的Bing AI
- Meta的LLaMa
- Anthropic的Claude
- GitHub的Copilot
- 等等。
會(huì)話LLM嵌入到企業(yè)級(jí)應(yīng)用程序中,是客戶服務(wù)、教育、醫(yī)療保健、網(wǎng)絡(luò)內(nèi)容生成、化學(xué)、生物學(xué)等許多領(lǐng)域的理想解決方案。聊天機(jī)器人和虛擬助理可以通過訪問會(huì)話LLM功能來提供動(dòng)力。LLM在傳統(tǒng)應(yīng)用程序中的這種集成要求它們公開一致的API。為了從應(yīng)用程序中調(diào)用這些API,需要提供一個(gè)工具包,它能夠與人工智能模型交互并促進(jìn)自定義創(chuàng)建。
LLM工具包
自從ChatGPT問世以來,人工智能領(lǐng)域得以快速發(fā)展,在所有這些新工具中,LLM工具包出現(xiàn)了真正的爆炸式增長。其中一些著名的LLM(例如AutoGPT、MetaGPT、AgentGPT等)試圖趕上潮流。但毫無疑問,最現(xiàn)代也是討論最多的是LangChain。LangChain于2022年作為開源庫推出,支持Python、JavaScript和TypeScript,最初由Harrison Chase公司開發(fā),在發(fā)布之后不久,就成為人工智能領(lǐng)域發(fā)展最快的項(xiàng)目之一。
盡管越來越受歡迎,但LangChain有一個(gè)主要缺點(diǎn):缺乏Java支持。因此,為了解決這個(gè)缺點(diǎn),LangChain4j在2023年初出現(xiàn),作為LangChain Python庫的Java實(shí)現(xiàn)。在以下的演示中將使用LangChain4J實(shí)現(xiàn)企業(yè)級(jí)Java服務(wù)和組件,這些服務(wù)和組件由最主流和最有影響力的LLM提供支持的企業(yè)級(jí)Java服務(wù)和組件。
演示項(xiàng)目
為了說明其論述,將使用一個(gè)簡單的Java程序來執(zhí)行自然語言任務(wù)。為此選擇的用例是實(shí)現(xiàn)一個(gè)能夠編寫俳句的人工智能服務(wù)?!洞笥倏迫珪穼?duì)于俳句的定義是:俳句是一種不押韻的詩歌形式,由17個(gè)音節(jié)組成,分別排成5、7和5個(gè)音節(jié)的三行句子。
正如人們所看到的,這樣一個(gè)任務(wù)的有用性并不真正引人注目,事實(shí)上,它不僅僅是一個(gè)真正的用例,而是一個(gè)展示LangChain4j一些功能的借口,同時(shí)使用一個(gè)有趣的并且是原創(chuàng)的形式。
因此,這個(gè)項(xiàng)目是一個(gè)專業(yè)的多模塊項(xiàng)目,具有以下結(jié)構(gòu):
- 一個(gè)名為llm-java的主要POM
- 一個(gè)名為haiku的JAX-RS模塊,公開調(diào)用LLM模型的REST API
- 一個(gè)名為infra的基礎(chǔ)設(shè)施模塊,用于創(chuàng)建所需的Docker容器
主要POM
這個(gè)項(xiàng)目是Quarkus項(xiàng)目。因此,物料清單(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模塊
這個(gè)名為haiku的模塊使用Quarkus - restasy -reactive-jackson Quarkus擴(kuò)展來公開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 }
這個(gè)API定義了一個(gè)監(jiān)聽GET HTTP請(qǐng)求的端點(diǎn),接受俳句主題作為查詢參數(shù),該參數(shù)包含默認(rèn)值:“samurai”。該模塊還使用Quarkus -container-image-jib Quarkus擴(kuò)展來創(chuàng)建運(yùn)行人工智能服務(wù)的Docker映像。這個(gè)Docker鏡像的屬性在應(yīng)用程序中定義。應(yīng)用屬性(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 ...
這些屬性說明新創(chuàng)建的Docker映像名稱為quarkus-llm/haiku,其入口點(diǎn)將是位于容器的/opt/jboss/container/java/run目錄下的run-java.sh shell腳本。
這個(gè)項(xiàng)目使用Quarkus擴(kuò)展quarkus-langchain4j-ollama,它提供了與LangChain4j庫和Ollama工具的集成。Ollama是一款先進(jìn)的人工智能精簡實(shí)用程序,允許用戶在本地設(shè)置和運(yùn)行大型LLM,例如OpenAI、Llama2、Mistral等。在這里是本地運(yùn)行Llama2。這需要在應(yīng)用程序中再次配置。應(yīng)用屬性(application.properties)采用以下語句:
Properties files
1 quarkus.langchain4j.ollama.chat-model.model-id=llama2:latest
在此需要聲明的是,為了服務(wù)人工智能請(qǐng)求,此處使用的LLM將是其最后版本的Llama2?,F(xiàn)在看看人工智能服務(wù)本身:
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 }
可以看到的是,這個(gè)人工智能服務(wù)是一個(gè)帶有@RegisterAiService注釋的接口。Quarkus擴(kuò)展提供的注釋處理器將生成實(shí)現(xiàn)該接口的類。為了能夠處理請(qǐng)求,任何會(huì)話LLM都需要定義場(chǎng)景或范圍。
在這個(gè)例子中,其范圍是一個(gè)專門創(chuàng)作俳句的藝術(shù)家的范圍。這是@SystemMessage注釋的作用:設(shè)置當(dāng)前作用域。最后但并非最不重要的是,@UserMessage注釋允許定義為人工智能服務(wù)提示的特定文本。在這里請(qǐng)求人工智能服務(wù)就一個(gè)主題撰寫俳句,該主題由類型為String的輸入?yún)?shù)subject定義。
基礎(chǔ)設(shè)施模塊
在檢查人工智能服務(wù)的實(shí)現(xiàn)之后,還要了解如何設(shè)置所需的基礎(chǔ)設(shè)施?;A(chǔ)設(shè)施模塊名為infra,是一個(gè)maven子項(xiàng)目,使用Docker -compose實(shí)用程序啟動(dòng)以下Docker容器:
一個(gè)名為ollama的Docker容器正在運(yùn)行一個(gè)標(biāo)記為nicolasduminil/ollama:llama2的圖像。這個(gè)圖像只是官方的Ollama Docker圖像,它已經(jīng)被增強(qiáng)以包含Llama2 LLM。如上所述,Ollama能夠在本地運(yùn)行多個(gè)LLM,為了使這些LLM可用,需要從它們的Docker注冊(cè)表中提取。這就是在運(yùn)行Ollama官方Docker容器時(shí)通常需要提取所選的LLM的原因。為了避免這種重復(fù)操作,擴(kuò)展這個(gè)官方Docker容器,使其已經(jīng)包含了Llama2 LLM。
一個(gè)名為haiku的Docker容器正在運(yùn)行標(biāo)記為quarkus-llm/haiku的圖像,這正是人工智能服務(wù)。
以下是創(chuàng)建上述基礎(chǔ)設(shè)施所需的相關(guān)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服務(wù)運(yùn)行在一個(gè)DNS名稱為ollama的節(jié)點(diǎn)上,并監(jiān)聽TCP端口號(hào)11434。因此,人工智能服務(wù)需要適當(dāng)?shù)嘏渲靡赃B接到相同的節(jié)點(diǎn)/端口。同樣,應(yīng)用屬性(application.properties)文件用于此目的,如下所示:
Properties files
1 quarkus.langchain4j.ollama.base-url=http://ollama:11434
這個(gè)聲明意味著AI服務(wù)將把它的請(qǐng)求發(fā)送到URL: http://ollama:11434,其中ollama被DNS服務(wù)轉(zhuǎn)換為IP地址,該IP地址被分配給同名的Docker容器。
運(yùn)行和測(cè)試
為了運(yùn)行和測(cè)試這個(gè)示例項(xiàng)目,可以按照以下步驟進(jìn)行:
1.克隆存儲(chǔ)庫:
Shell
1 $ git clone https://github.com/nicolasduminil/llm-java.git
2.持續(xù)交付(cd)到項(xiàng)目:
Shell
1 $ mvn clean install
3.構(gòu)建項(xiàng)目:
Shell
1 $ mvn clean install
4.檢查所有必需的容器是否正在運(yùn)行:
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.運(yùn)行open-api接口來測(cè)試服務(wù)。啟動(dòng)首選瀏覽器:http://localhost:8080/q/swaggerui。在顯示的標(biāo)有Haiku API的Swagger會(huì)話框中,單擊GET按鈕并使用Try it函數(shù)執(zhí)行測(cè)試。在標(biāo)題為“主題”(Subject)的文本字段中,鍵入希望人工智能服務(wù)撰寫俳句的主題名稱,或保留默認(rèn)名稱(即samurai)。測(cè)試結(jié)果如下圖所示:
也可以通過使用curl工具向人工智能服務(wù)發(fā)送GET請(qǐng)求來測(cè)試項(xiàng)目,如下所示:
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
結(jié)語
在以上的項(xiàng)目演示中,探索了LLM的發(fā)展歷史,并使用LangChain4J實(shí)現(xiàn)了企業(yè)級(jí)Java服務(wù)和組件,這些服務(wù)和組件由最具主導(dǎo)地位和影響力的LLM提供支持。
原文標(biāo)題:The Power of LLMs in Java: Leveraging Quarkus and LangChain4j,作者:Nicolas Duminil
鏈接:https://dzone.com/articles/leveraging-the-llm-power-in-java。
