浪鏈簡介
一、簡介
在本教程中,我們將研究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.及時工程
法學碩士是在大量文字資料上訓練的基礎模型。因此,它們可以捕捉人類語言固有的語法和語義。然而,它們必須適應我們希望它們執行的特定任務。
即時工程是適應法學碩士最快的方法之一。這是一個建構可由法學碩士解釋和理解的文本的過程。在這裡,我們使用自然語言文本來描述我們期望法學碩士執行的任務:
我們創建的提示可以幫助法學碩士進行情境學習,這是暫時的。我們可以使用即時工程來促進法學碩士的安全使用,並建立新的功能,例如透過領域知識和外部工具來增強法學碩士。
這是一個活躍的研究領域,新技術不斷湧現。然而,像**思維鏈提示這樣的技術已經相當流行了**。這裡的想法是讓法學碩士在給出最終答案之前通過一系列中間步驟來解決問題。
2.3.詞嵌入
正如我們所見,法學碩士能夠處理大量自然語言文本。如果我們將自然語言中的單字表示為單字嵌入,法學碩士的表現會大大提高。這是一個能夠編碼單字意義的實值向量。
通常,詞嵌入是使用Tomáš Mikolov 的 Word2vec或史丹佛大學的 GloVe等演算法產生的。 GloVe 是一種無監督學習演算法,根據語料庫中聚合的全局詞與詞共現統計數據進行訓練:
在提示工程中,我們將提示轉換為其詞嵌入,使模型能夠更好地理解並回應提示。此外,它對於增強我們為模型提供的上下文也非常有幫助,使他們能夠提供更多上下文答案。
例如,我們可以從現有資料集生成詞嵌入並將其儲存在向量資料庫中。此外,我們可以使用使用者提供的輸入對該向量資料庫執行語義搜尋。然後我們可以使用搜尋結果作為模型的附加上下文。
3. LLM技術棧與LangChain
正如我們已經看到的,創建有效的提示是在任何應用程式中成功利用法學碩士力量的關鍵要素。這包括使與語言模型的互動具有上下文感知,並能夠依賴語言模型進行推理。
為此,我們需要執行多項任務,例如建立提示範本、呼叫語言模型以及將來自多個來源的使用者特定資料提供給語言模型。為了讓這些任務更簡單,我們需要一個像 LangChain 這樣的框架作為我們的 LLM 技術堆疊的一部分:
該框架還有助於開發需要連結多個語言模型並能夠回憶過去與語言模型互動的資訊的應用程式。然後,還有更複雜的用例,涉及使用語言模型作為推理引擎。
最後,我們可以執行日誌記錄、監控、串流以及其他維護和故障排除的基本任務。 LLM 技術堆疊正在迅速發展,以解決其中許多問題。然而,LangChain 正迅速成為 LLM 技術堆疊的重要組成部分。
4.浪鏈Java版
LangChain作為一個開源專案於 2022 年推出,並很快透過社群支持獲得了發展勢頭。它最初是由 Harrison Chase 用 Python 開發的,很快就成為人工智慧領域發展最快的新創公司之一。
2023 年初,繼 Python 版本之後,LangChain 又推出了 JavaScript/TypeScript 版本。它很快就變得非常流行,並開始支援多種JavaScript 環境,如Node.js、Web 瀏覽器、CloudFlare Workers、Vercel/Next.js 、Deno 和Supabase邊緣函數。
不幸的是, LangChain 沒有官方的 Java 版本可用於 Java/Spring 應用程式。然而, LangChain for Java 有一個社群版本,稱為LangChain4j 。它適用於 Java 8 或更高版本,並支援 Spring Boot 2 和 3。
LangChain的各種依賴項都可以在 Maven Central 中找到。我們可能需要在應用程式中新增一個或多個依賴項,具體取決於我們使用的功能:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>0.23.0</version>
</dependency>
例如,在本教程的以下部分中,我們還需要支援與 OpenAI 模型整合、提供對嵌入的支援以及像 all-MiniLM-L6-v2 這樣的句子轉換器模型的依賴項。
與 LangChain 的設計目標相似,LangChain4j提供了一個簡單且連貫的抽象層及其眾多的實現。它已經支援多種語言模型提供者(例如 OpenAI)和嵌入商店提供者(例如 Pinecone)。
然而,由於LangChain和LangChain4j都在快速發展,因此Python或JS/TS版本中可能支援一些Java版本中尚未支援的功能。儘管如此,基本概念、一般結構和詞彙基本上相同。
5. 浪鏈的建構模組
LangChain 為我們的應用程式提供了多種作為模組組件的價值主張。模組化元件提供了有用的抽像以及用於處理語言模型的一組實作。讓我們透過 Java 範例來討論其中一些模組。
5.1.型號 I/O
使用任何語言模型時,我們都需要能夠與其互動。 LangChain 提供了必要的建置模組,例如模板化提示以及動態選擇和管理模型輸入的能力。此外,我們可以使用輸出解析器從模型輸出中提取資訊:
提示範本是用於產生語言模型提示的預定義配方,可能包括說明、少量範例和特定上下文:
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);
在這裡,我們建立一個能夠接受多個變數的提示範本。變數是我們從使用者輸入中接收並提供給提示範本的內容。
LangChain支援與兩種類型的模型整合:語言模型和聊天模型。聊天模型也由語言模型支持,但提供聊天功能:
ChatLanguageModel model = OpenAiChatModel.builder()
.apiKey(<OPENAI_API_KEY>)
.modelName(GPT_3_5_TURBO)
.temperature(0.3)
.build();
String response = model.generate(prompt.text());
在這裡,我們使用特定的 OpenAI 模型和關聯的 API 金鑰來建立一個聊天模型。我們可以透過免費註冊從OpenAI取得 API 金鑰。參數溫度用於控制模型輸出的隨機性。
最後,語言模型的輸出可能不夠結構化,無法呈現。 LangChain 提供了輸出解析器,幫助我們建立語言模型響應——例如,從輸出中提取資訊作為 Java 中的 POJO。
5.2.記憶
通常,利用法學碩士的應用程式具有對話介面。任何對話的一個重要方面是能夠參考對話中先前介紹的資訊。儲存有關過去互動的資訊的能力稱為記憶:
LangChain 提供了為應用程式添加記憶體的關鍵推動因素。例如,我們需要能夠從記憶體中讀取資料來增強用戶輸入。然後,我們需要能夠將當前運行的輸入和輸出寫入記憶體:
ChatMemory chatMemory = TokenWindowChatMemory
.withMaxTokens(300, new OpenAiTokenizer(GPT_3_5_TURBO));
chatMemory.add(userMessage("Hello, my name is Kumar"));
AiMessage answer = model.generate(chatMemory.messages()).content();
System.out.println(answer.text()); // Hello Kumar! How can I assist you today?
chatMemory.add(answer);
chatMemory.add(userMessage("What is my name?"));
AiMessage answerWithName = model.generate(chatMemory.messages()).content();
System.out.println(answer.text()); // Your name is Kumar.
chatMemory.add(answerWithName);
在這裡,我們使用TokenWindowChatMemory
實作了一個固定視窗聊天內存,它允許我們讀取和寫入與語言模型交換的聊天訊息。
LangChain也提供了更複雜的資料結構和演算法,從記憶體中傳回選定的訊息,而不是傳回所有內容。例如,它支援傳回過去幾條訊息的摘要,或僅傳回與目前運行相關的訊息。
5.3.恢復
大型語言模型通常是在大量的文字語料庫上進行訓練。因此,它們在一般任務中非常有效,但在特定領域的任務中可能不太有用。為此,我們需要檢索相關的外部資料並將其在生成步驟中傳遞給語言模型。
此過程稱為檢索增強生成 (RAG) 。它有助於將模型建立在相關且準確的資訊之上,並讓我們深入了解模型的生成過程。 LangChain提供了創建RAG應用程式所需的構建塊:
首先,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
將該文件分割成更小的區塊。
為了使檢索更加高效,通常將文件轉換為其嵌入並儲存在向量資料庫中。 LangChain支援多種嵌入提供者和方法,並與幾乎所有流行的向量商店整合:
EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
List<Embedding> embeddings = embeddingModel.embedAll(segments).content();
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
embeddingStore.addAll(embeddings, segments);
在這裡,我們使用AllMiniLmL6V2EmbeddingModel
來建立文件段的嵌入。然後,我們將嵌入儲存在記憶體向量儲存中。
現在我們已經將外部資料作為嵌入存儲在向量存儲中,我們準備從中檢索。 LangChain支援多種檢索演算法,例如簡單的語義搜尋和複雜的檢索演算法,例如整合檢索器:
String question = "Who is Simpson?";
//The assumption here is that the answer to this question is contained in the document we processed earlier.
Embedding questionEmbedding = embeddingModel.embed(question).content();
int maxResults = 3;
double minScore = 0.7;
List<EmbeddingMatch<TextSegment>> relevantEmbeddings = embeddingStore
.findRelevant(questionEmbedding, maxResults, minScore);
我們建立使用者問題的嵌入,然後使用問題嵌入從向量儲存中檢索相關匹配項。現在,我們可以將檢索到的相關匹配作為上下文發送,方法是將它們添加到我們打算發送到模型的提示中。
6. 浪鏈的複雜應用
到目前為止,我們已經了解如何使用各個元件來建立具有語言模型的應用程式。 LangChain還提供元件來建立更複雜的應用程式。例如,我們可以使用鍊和代理來建立具有增強功能的更具適應性的應用程式。
6.1.鏈條
通常,應用程式需要按特定順序呼叫多個元件。這就是LangChain中所說的鏈。它簡化了更複雜應用程式的開發,並使其更易於調試、維護和改進。
這對於組合多個鏈以形成可能需要具有多個語言模型的介面的更複雜的應用程式也很有用。 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();
在這裡,我們使用預先建立的鏈ConversationalRetreivalChain
,它允許我們將聊天模型與檢索器以及記憶體和提示模板一起使用。現在,我們可以簡單地使用鏈來執行使用者查詢:
String answer = chain.execute("Who is Simpson?");
該鏈帶有我們可以覆蓋的預設記憶體和提示模板。創建我們的定制鏈也很容易。創建鏈的能力使得更容易實現複雜應用程式的模組化實作。
6.2.代理商
LangChain也提供了更強大的結構,例如代理商。與鏈不同,代理程式使用語言模型作為推理引擎來決定要採取哪些操作以及按什麼順序。我們也可以為代理提供正確的工具來執行必要的操作。
在 LangChain4j 中,代理程式可作為 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.prtintln(answer); // The sum of the numbers of letters in the words "language" and "model" is 13.
當我們運行此程式碼時,我們將觀察到語言模型現在能夠執行計算。
值得注意的是,語言模型很難執行一些需要它們具有時間和空間概念或執行複雜算術過程的任務。然而,我們總是可以用必要的工具來補充模型來解決這個問題。
七、結論
在本教程中,我們了解了創建由大型語言模型支援的應用程式的一些基本元素。此外,我們還討論了將 LangChain 這樣的框架作為開發此類應用程式的技術堆疊的一部分的價值。
這使我們能夠探索 LangChain4j(LangChain 的 Java 版本)的一些核心元素。這些庫將在未來迅速發展。但是,他們已經使由語言模型驅動的應用程式的開發過程變得成熟且有趣!
不要忘記在 GitHub 上查看本文的完整原始碼。