Java+LangChain實戰入門:深度剖析開發大語言模型應用!

在人工智能飛速發展的今天,大語言模型(如GPT系列)正改變著我們構建應用的方式。但如何將這些先進模型無縫集成到企業級Java應用中?這正是LangChain框架的強項——它簡化了語言模型的調用、鏈式處理和上下文管理,讓開發者專注于業務邏輯。本教程將帶您從零開始,實戰入門Java與LangChain的結合,一步步構建高效、可擴展的大語言模型應用。

在本教程中,我們將詳細探討 LangChain,一個用于開發基于語言模型的應用程序的框架。我們將首先了解語言模型的基礎概念,這些知識將對本教程有所幫助。

盡管 LangChain 主要提供 Python 和 JavaScript/TypeScript 版本,但也可以在 Java 中使用 LangChain。我們會討論 LangChain 作為框架的構建模塊,然后嘗試在 Java 中進行實驗。

2. 背景

在深入探討為什么需要一個用于構建基于語言模型的應用程序的框架之前,我們需要弄清楚語言模型是什么,并了解使用語言模型時可能遇到的一些典型復雜性。

2.1. 大型語言模型

語言模型是自然語言的概率模型,可以生成一系列單詞的概率。大型語言模型(LLM)則是以其規模龐大而著稱,通常包含數十億參數的人工神經網絡。

大型語言模型通常通過在大量未標記數據上進行預訓練,使用自監督學習和弱監督學習技術。之后,通過微調提示詞工程等技術將預訓練模型適配于特定任務:

大型語言模型可以執行多種自然語言處理任務,如語言翻譯、內容摘要等。此外,它們還具備生成內容的能力,因此在回答問題等應用場景中非常有用。

幾乎所有主流云服務提供商都在其服務中引入了大型語言模型。例如,Microsoft Azure 提供了 Llama 2 和 OpenAI GPT-4,Amazon Bedrock 提供了 AI21 Labs、Anthropic、Cohere、Meta 和 Stability AI 的模型。

2.2. 提示詞工程

大型語言模型是一種基礎模型,經過大規模文本數據的訓練后,可以捕捉人類語言的語法和語義。然而,為了讓模型執行特定任務,它們需要進一步調整。

提示詞工程(Prompt engineering)是讓語言模型完成特定任務的最快捷方法之一。它通過結構化文本向模型描述任務目標,使其能夠理解并執行任務:

提示詞幫助大型語言模型執行上下文學習,這種學習是暫時的。通過提示詞工程,我們可以促進大型語言模型的安全使用,并構建新的功能,比如將領域知識和外部工具整合到模型中。

這一領域目前是一個活躍的研究方向,不斷涌現新的技術。然而,諸如 鏈式思維提示 等技術已經變得頗為流行。這種方法的核心是讓大型語言模型在給出最終答案之前,將問題分解為一系列中間步驟。

2.3. 詞向量

如前所述,大型語言模型能夠高效處理自然語言。如果我們將自然語言中的單詞表示為詞向量(Word Embeddings ),模型的性能將顯著提升。詞向量是能夠編碼單詞語義的實值向量

詞向量通常通過算法生成,例如 Word2vec 或 GloVe。

GloVe 是一種無監督學習算法,在語料庫的全局詞共現統計上進行訓練:

在提示詞工程中,我們將提示轉換成詞向量,這使得模型更容易理解和響應提示。此外,它也對增強我們提供給模型的上下文非常有幫助,從而使模型能夠給出更具上下文意義的回答。

例如,我們可以從現有數據集中生成詞向量并將其存儲在向量數據庫中。然后,我們可以使用用戶提供的輸入在向量數據庫中執行語義搜索,并將搜索結果作為附加上下文提供給模型。

3. 使用 LangChain 構建 LLM 技術棧

正如我們已經了解的那樣,創建有效的提示詞是成功利用 LLM 的關鍵元素。這包括使與語言模型的交互具有上下文感知能力,并依賴語言模型進行推理。

為此,我們需要執行多項任務,例如為提示詞創建模板、調用語言模型,以及從多種來源提供用戶特定數據。為了簡化這些任務,我們需要一個像 LangChain 這樣的框架作為 LLM 技術棧的一部分:

該框架還幫助開發需要鏈式調用多個語言模型的應用程序,并能夠回憶起過去與語言模型過去交互的信息。此外,還有更復雜的用例,例如將語言模型用作推理引擎。

最后,我們可以執行日志記錄、監控、流式處理以及其他重要的維護和故障排除任務。LLM 技術棧正在快速發展以應對許多此類問題,而 LangChain 正迅速成為 LLM 技術棧的寶貴組成部分。

4. 面向 Java 的 LangChain

LangChain 于 2022 年作為開源項目推出,憑借社區支持迅速發展壯大。最初是由 Harrison Chase 開發的 Python 項目,后來成為 AI 領域增長最快的初創企業之一。

隨后,JavaScript/TypeScript 版本的 LangChain 于 2023 年初推出,并迅速流行起來,支持多個 JavaScript 環境,如 Node.js、瀏覽器、CloudFlare workers、Vercel/Next.js、Deno 和 Supabase Edge functions。

然而,目前沒有官方的 Java 版本 LangChain 可供 Java 或 Spring 應用使用。不過,社區開發了 Java 版本 LangChain,稱為 LangChain4j ,支持 Java 8 或更高版本,并兼容 Spring Boot 2 和 3。

LangChain 的各種依賴項可以在 Maven Central 上找到。根據我們使用的功能,可能需要在應用程序中添加一個或多個依賴項

<dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j</artifactId> <version>0.23.0</version> </dependency>

5. LangChain 的構建模塊

LangChain 為我們的應用程序提供了多種價值主張,這些功能以模塊化組件的形式提供。模塊化組件不僅提供了有用的抽象,還包含了一系列操作語言模型的實現。接下來,我們將通過 Java 示例來討論其中的一些模塊。

5.1. 模型輸入/輸出(Models I/O)

在使用任何語言模型時,我們需要具備與其交互的能力。LangChain 提供了必要的構建模塊,例如模板化提示的能力,以及動態選擇和管理模型輸入的能力。此外,我們還可以使用輸出解析器從模型輸出中提取信息:

提示模板(Prompt Templates)是用于生成語言模型提示的預定義配方,可以包括指令、少樣本示例和特定上下文:

PromptTemplate promptTemplate = PromptTemplate .from("Tell me a {{adjective}} joke about {{content}}.."); Map<String, Object> variables = new HashMap<>(); variables.put("adjective", "funny"); variables.put("content", "computers"); Prompt prompt = promptTemplate.apply(variables);

5.2. 內存

通常,一個利用大型語言模型(LLM)的應用程序會有一個對話界面。對話的一個重要方面是能夠引用對話中先前的信息。這種存儲過去交互信息的能力稱為內存

LangChain 提供了一些關鍵功能,可以為應用程序添加內存。例如,我們需要能夠從內存中讀取信息以增強用戶輸入,同時還需要將當前運行的輸入和輸出寫入內存:

ChatMemory chatMemory = TokenWindowChatMemory .withMaxTokens(300, new OpenAiTokenizer(GPT_3_5_TURBO)); chatMemory.add(userMessage("你好,我叫 Kumar")); AiMessage answer = model.generate(chatMemory.messages()).content(); System.out.println(answer.text()); // 你好 Kumar!今天我能為您做些什么? chatMemory.add(answer); chatMemory.add(userMessage("我叫什么名字?")); AiMessage answerWithName = model.generate(chatMemory.messages()).content(); System.out.println(answerWithName.text()); // 您的名字是 Kumar。 chatMemory.add(answerWithName);

在這里,我們使用 TokenWindowChatMemory 實現了固定窗口聊天內存,它允許我們讀取和寫入與語言模型交換的聊天消息。

LangChain 還提供更復雜的數據結構和算法,以便從內存中返回選定的消息, 而不是返回所有內容。例如,它支持返回過去幾條消息的摘要,或者僅返回與當前運行相關的消息。

5.3. 檢索(Retrieval)

大型語言模型通常是在大量的文本語料庫上進行訓練的。因此,它們在處理通用任務時表現得非常高效,但在處理特定領域任務時可能效果不佳。為了解決這一問題,我們需要在生成階段檢索相關的外部數據,并將其傳遞給語言模型

這個過程被稱為檢索增強生成(Retrieval Augmented Generation,RAG)。RAG 有助于將模型的生成過程與相關且準確的信息結合,同時也讓我們更深入地了解模型的生成過程。LangChain 提供了構建 RAG 應用程序所需的核心組件:

首先,LangChain 提供了文檔加載器 FileSystemDocumentLoader,用于從存儲位置檢索文檔。然后,LangChain 還提供了轉換器,用于進一步處理文檔,例如將大型文檔分割成更小的塊:

Document document = FileSystemDocumentLoader.loadDocument("simpson's_adventures.txt"); DocumentSplitter splitter = DocumentSplitters.recursive(100, 0, new OpenAiTokenizer(GPT_3_5_TURBO)); List<TextSegment> segments = splitter.split(document);

在這里,我們使用 FileSystemDocumentLoader 從文件系統中加載文檔。然后使用 OpenAiTokenizer 將文檔分割成更小的段落。

為了提高檢索效率,這些文檔通常會被轉換成嵌入(embeddings),并存儲在向量數據庫中。LangChain 支持多種嵌入提供商和方法,并與幾乎所有主流的向量存儲集成:

EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel(); List<Embedding> embeddings = embeddingModel.embedAll(segments).content(); EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>(); embeddingStore.addAll(embeddings, segments);

在這里,我們使用 AllMiniLmL6V2EmbeddingModel 為文檔段落創建嵌入,然后將嵌入存儲在內存中的向量存儲中。

現在,我們的外部數據已經以嵌入的形式存儲在向量存儲中,可以從中進行檢索。LangChain 支持多種檢索算法,例如簡單的語義搜索和更復雜的集成檢索器(ensemble retriever):

String question = "Who is Simpson?"; // 假設該問題的答案包含在我們之前處理的文檔中。 Embedding questionEmbedding = embeddingModel.embed(question).content(); int maxResults = 3; double minScore = 0.7; List<EmbeddingMatch<TextSegment>> relevantEmbeddings = embeddingStore .findRelevant(questionEmbedding, maxResults, minScore);

我們為用戶的問題生成嵌入,然后使用該問題的嵌入從向量存儲中檢索相關的匹配項。現在,我們可以將檢索到的相關內容作為上下文,添加到我們打算發送給模型的提示中。

6. LangChain 的復雜應用

到目前為止,我們已經了解了如何使用單個組件來創建一個基于語言模型的應用程序。LangChain 還提供了構建更復雜應用程序的組件。例如,我們可以使用鏈(Chains)和代理(Agents)來構建更加自適應、功能增強的應用程序。

6.1. 鏈(Chains)

通常,一個應用程序需要按特定順序調用多個組件。在 LangChain 中,這被稱為鏈(Chain)。鏈簡化了開發更復雜應用程序的過程,并使調試、維護和改進更加容易。

鏈還可以組合多個鏈來構建更復雜的應用程序,這些應用程序可能需要與多個語言模型交互。LangChain 提供了創建此類鏈的便捷方式,并內置了許多預構建鏈:

ConversationalRetrievalChain chain = ConversationalRetrievalChain.builder() .chatLanguageModel(chatModel) .retriever(EmbeddingStoreRetriever.from(embeddingStore, embeddingModel)) .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) .promptTemplate(PromptTemplate .from("Answer the following question to the best of your ability: {{question}}\n\nBase your answer on the following information:\n{{information}}")) .build();

在這里,我們使用了預構建的鏈 ConversationalRetrievalChain,它允許我們將聊天模型與檢索器、內存和提示模板結合使用。現在,我們可以簡單地使用該鏈來執行用戶查詢:

String answer = chain.execute("Who is Simpson?");

該鏈提供了默認的內存和提示模板,我們可以根據需要進行覆蓋。創建自定義鏈也非常容易。鏈的能力使我們能夠更輕松地實現復雜應用程序的模塊化實現。

6.2. 代理(Agents)

LangChain 還提供了更強大的結構,例如代理(Agent)。與鏈不同,代理將語言模型用作推理引擎,以確定應該采取哪些操作以及操作的順序。我們還可以為代理提供訪問合適工具的權限,以執行必要的操作。

在 LangChain4j 中,代理作為 AI 服務(AI Services)提供,用于聲明性地定義復雜的 AI 行為。讓我們看看如何通過提供一個計算器工具,為 AI 服務賦能,從而使語言模型能夠執行計算。

首先,我們定義一個包含一些基本計算功能的類,并用自然語言描述每個函數,這樣模型可以理解:

public class AIServiceWithCalculator { static class Calculator { @Tool("Calculates the length of a string") int stringLength(String s) { return s.length(); } @Tool("Calculates the sum of two numbers") int add(int a, int b) { return a + b; } }

接下來,我們定義一個接口,用于構建我們的 AI 服務。這里的接口相對簡單,但也可以描述更復雜的行為:

interface Assistant { String chat(String userMessage); }

然后,我們使用 LangChain4j 提供的構建器工廠,通過定義的接口和工具創建一個 AI 服務:

Assistant assistant = AiServices.builder(Assistant.class) .chatLanguageModel(OpenAiChatModel.withApiKey(<OPENAI_API_KEY>)) .tools(new Calculator()) .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) .build();

完成了!現在,我們可以向語言模型發送包含計算任務的問題:

String question = "What is the sum of the numbers of letters in the words \"language\" and \"model\"?"; String answer = assistant.chat(question); System.out.println(answer); // The sum of the numbers of letters in the words "language" and "model" is 13.

運行這段代碼后,我們會發現語言模型現在能夠執行計算。

需要注意的是,語言模型在執行某些任務時可能會遇到困難,例如需要時間和空間概念的任務或復雜的算術操作。然而,我們可以通過為模型提供必要的工具來解決這些問題。

7. 總結

在本教程中,我們探討了創建基于大型語言模型的應用程序的一些基本元素。此外,我們討論了將 LangChain 作為技術棧的一部分對開發此類應用程序的重要價值。

這使得我們能夠探索 LangChain 的 Java 版本 —— LangChain4j 的一些核心組件 。這些庫未來將快速發展,它們會讓開發由語言模型驅動的應用程序的過程變得更成熟和有趣!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/86515.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/86515.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/86515.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

論文筆記:Large language model augmented narrative driven recommendations

RecSys 2023 代碼&#xff1a;iesl/narrative-driven-rec-mint: Mint: A data augmentation method for narrative driven recommendation. 1 intro 盡管基于歷史交互的數據能夠有效地提供推薦&#xff0c;但用戶在請求推薦時&#xff0c;往往只是對目標物品有一個模糊的概念…

興達易控Modbus TCP轉Profibus DP網關與安科瑞多功能電表的快速通訊

興達易控Modbus TCP轉Profibus DP網關與安科瑞多功能電表的快速通訊 在工業自動化領域&#xff0c;不同設備之間的通信連接至關重要。興達易控Modbus TCP轉Profibus DP網關接APM810/MCE安科瑞多功能電表與300plc通訊&#xff0c;這一過程涉及到多個關鍵技術和環節&#xff0c;…

epoll實現理解

根據前文高性能網絡設計推演中&#xff0c;epoll作為一個“大殺器”為網絡開發提供強大的支持。Linux系統上IO多路復用方案有select、poll、epoll。其中epoll的性能表現最優&#xff0c;且支持的并發量最大。本文大概介紹epoll的底層實現。 一、示例引入 了解epoll開發&#…

協議轉換賦能光伏制造:DeviceNET轉PROFINET網關的通信質檢實踐

協議轉換賦能光伏制造&#xff1a;DeviceNET轉PROFINET網關的通信質檢實踐 某光伏電池片生產線創新性地將網關作為計算節點&#xff0c;通過搭載DeviceNET-PROFINET智能網關-穩聯技術WL-PN-DVNM&#xff0c;在協議轉換層直接運行AI質檢模型。DeviceNET端采集的高清圖像數據經網…

學習永無止境

已掌握以下每個&#xff0c;有屬于自己的一套架構方式&#xff1a; vue.element-ui&#xff1a;后臺管理 vue.uni-app&#xff1a;H5&#xff0c;小程序&#xff0c;Android&#xff0c;IOS php&#xff1a;??RESTful&#xff0c;服務&#xff0c;業務邏輯&#xff08;如電商…

永磁無刷電機旋轉原理

目錄 1. 磁場的基本知識 2. 角速度&#xff0c;線速度&#xff0c;工程轉速 3.力和力矩 4. 慣量&#xff0c;轉動慣量 5. 電機的四種狀態 5.1 空載 5.2 帶載 5.3 滿載 5.4 堵轉 6. 功和功率 1. 磁場的基本知識 無頭無尾&#xff0c;轉了一圈&#xff0c;就叫有旋…

Ubuntu 物理桌面遠程訪問教程(基于 RealVNC / mstsc)

Ubuntu 物理桌面遠程訪問教程&#xff08;基于 RealVNC / mstsc&#xff09; 適用對象&#xff1a;任意安裝了 GNOME GDM 的 Ubuntu 系統 目標&#xff1a;遠程連接系統默認物理桌面 :0&#xff0c;無虛擬桌面、無 Xfce&#xff0c;真實 GNOME 桌面環境 1. 準備條件 Ubuntu 系…

Vue3 工程化實戰

Vue3 工程化實戰 引言&#xff1a;構建工具的演進與選擇 在前端工程化領域&#xff0c;構建工具的選擇直接影響開發效率與項目性能。隨著Vue3的普及&#xff0c;構建工具生態也發生了顯著變化&#xff1a;傳統vue-cli逐漸進入維護模式&#xff0c;而新一代構建工具Vite憑借其…

調用phantomjs(前端)插件生成ECharts圖片

package com.demo.common.utils; //json格式化工具,可以其他工具類 import cn.hutool.json.JSONUtil; import lombok.extern. public class FileUtil { /** * 調用phantomjs(前端)插件生成ECharts圖片 * @param path 根路徑 * @param option ECharts配置J…

React Hooks詳解

React Hooks 常考內容 React Hooks 是 React 16.8 引入的重要特性&#xff0c;用于在函數組件中使用狀態和其他 React 特性。以下是面試中常考的核心內容&#xff1a; 基礎 Hook useState: 用于管理組件內部狀態&#xff0c;返回狀態變量和更新狀態的函數。useEffect: 處理副…

c++17標準std::filesystem常用函數

std::filesystem 是 C17 引入的標準庫&#xff0c;用于處理文件系統操作&#xff0c;提供了跨平臺的文件和目錄操作能力。以下是一些常用的函數和類&#xff1a; 一、路徑操作&#xff08;std::filesystem::path&#xff09; cpp 運行 #include <filesystem> namespa…

非結構化文檔的自動化敏感標識方法技術解析

在數字化時代&#xff0c;企業與組織面臨的數據形態正發生深刻變革。據統計&#xff0c;非結構化數據占企業數據總量的 80% 以上&#xff0c;涵蓋文本、郵件、PDF、日志、社交媒體內容等多種形式。這些數據中往往蘊含著大量敏感信息&#xff0c;如個人身份信息、商業機密、醫療…

c語言中的字符類型

字符類型 char char是一種整數&#xff0c;也是一種特殊的類型&#xff1a;字符。 #include <stdio.h> int main(){char c,d;c 1; //把整數1賦值給變量cd 1; //把字符‘1’賦值給變量dif (c d){printf("相等");}else{printf("不相等\n");…

Cribl stream 管道對時間的改變時區

先說一下時區的重要性&#xff0c;要是cribl 時區是UTC&#xff0c;但是過來數據是GTM8 就是中國時區&#xff0c;那么數據過來&#xff0c;就可能在后端的Splunk 沒有顯示&#xff0c;那么解決這個問題&#xff0c;cribl 管道引入了auto timestamp 的功能&#xff1a; 注意到&…

深度學習:PyTorch卷積神經網絡(1)

本文目錄&#xff1a; 一、CNN概述二、CNN日常應用三、CNN的卷積層&#xff08;一 &#xff09;基本介紹&#xff08;二&#xff09;卷積層計算1.對輸入數據的要求2.卷積核核心參數3.計算過程4.特征圖尺寸計算5.1、多通道卷積計算5.2、多卷積核計算6.PyTorch卷積層API 前言&…

linux網絡編程socket套接字

套接字概念 Socket本身有“插座”的意思&#xff0c;在Linux環境下&#xff0c;用于表示進程間網絡通信的特殊文件類型。本質為內核借助緩沖區形成的偽文件。 既然是文件&#xff0c;那么理所當然的&#xff0c;我們可以使用文件描述符引用套接字。與管道類似的&#xff0c;L…

Python 數據分析與可視化 Day 5 - 數據可視化入門(Matplotlib Seaborn)

&#x1f3af; 今日目標 掌握 Matplotlib 的基本繪圖方法&#xff08;折線圖、柱狀圖、餅圖&#xff09;掌握 Seaborn 的高級繪圖方法&#xff08;分類圖、分布圖、箱線圖&#xff09;熟悉圖像美化&#xff08;標題、標簽、顏色、風格&#xff09;完成一組學生成績數據的可視化…

CephFS “Client Failing to Respond to Cache Pressure“ 告警分析

告警含義 當出現 Client failing to respond to cache pressure 警告時,表明: 元數據服務器 (MDS) 要求客戶端釋放緩存的元數據(如 inode Capabilities)客戶端未能及時響應 釋放請求核心觸發機制 MDS 通過以下周期性流程管理緩存 階段操作觸發條件Cache Trim 周期每隔 mds…

生成式人工智能實戰 | 生成對抗網絡(Generative Adversarial Network, GAN)

生成式人工智能實戰 | 生成對抗網絡 0. 前言1. 生成對抗網絡2. 模型構建2.1 生成器2.2 判別器 3. 模型訓練3.1 數據加載3.2 訓練流程 0. 前言 生成對抗網絡 (Generative Adversarial Networks, GAN) 是一種由兩個相互競爭的神經網絡組成的深度學習模型&#xff0c;它由一個生成…

緩存與加速技術實踐-MongoDB數據庫應用

一.什么是MongoDB MongoDB 是一個文檔型數據庫&#xff0c;數據以類似 JSON 的文檔形式存儲。 MongoDB 的設計理念是為了應對大數據量、高性能和靈活性需求。 MongoDB 使用集合&#xff08;Collections&#xff09;來組織文檔&#xff08;Documents&#xff09;&#xff0…