透過 PaLM 和 LangChain4J,以 Java 編寫使用者與文件的生成式 AI 功能

1. 簡介

上次更新時間:2024 年 2 月 5 日

什麼是生成式 AI

生成式 AI 又稱為「生成式人工智慧」,是指使用 AI 技術生成新的文字、圖片、音樂、音訊和影片等內容。

生成式 AI 是由基礎模型 (大型 AI 模型) 驅動,可同時處理多項工作,並立即執行各種任務,包括提供摘要、問與答和分類等。此外,只需最少訓練,基礎模型可用極少的範例資料,就能針對目標用途進行調整。

生成式 AI 的運作方式為何?

生成式 AI 運用機器學習 (機器學習) 模型,瞭解人類建立內容資料集內的模式和關係,然後再運用所學的模式生成新內容。

訓練生成式 AI 模型最常見的方式是使用監督式學習,由模型提供一組人類建立的內容和對應的標籤。讓模型學習生成與人類創作內容相似的內容,並加上相同的標籤。

什麼是常見的生成式 AI 應用程式?

生成式 AI 可以處理大量內容,透過文字、圖片和容易使用的格式,產生相關洞察資訊和答案。生成式 AI 有助於:

  • 透過進階即時通訊和搜尋體驗改善客戶互動
  • 透過對話式介面和摘要功能探索大量非結構化資料
  • 協助處理重複性工作,例如回覆提案請求 (RFP)、將行銷內容翻譯成五種語言,以及確認客戶合約是否遵循規定等

Google Cloud 提供哪些生成式 AI 產品與服務?

有了 Vertex AI,您不必具備機器學習專業知識,就能與基礎模型互動,並將模型嵌入應用程式中。您可以在 Model Garden 中存取基礎模型、透過 Generative AI Studio 的簡易使用者介面調整模型,或是運用數據資料學筆記本中的模型。

Vertex AI Search and Conversation 可讓開發人員以最快的速度,建構採用生成式 AI 的搜尋引擎和聊天機器人。

此外,Duet AI 是採用 AI 技術的協作工具,適用於 Google Cloud 和 IDE,讓您更快完成更多工作。

這個程式碼研究室的重點是什麼?

本程式碼研究室著重於託管於 Google Cloud Vertex AI 的 PaLM 2 大型語言模型 (LLM),涵蓋所有機器學習產品和服務。

您將使用 Java 與 PaLM API 互動,並搭配 LangChain4J LLM 架構自動化調度管理器。我們將逐一說明幾個具體範例,說明如何利用大型語言模型回答問題、構思想法、擷取實體與結構化內容,以及提供摘要。

進一步說明 LangChain4J 架構!

LangChain4J 架構是一個開放原始碼程式庫,可透過自動化調度管理各種元件 (例如 LLM 本身) 與向量資料庫 (用於語意搜尋)、文件載入器和分割器 (用於分析文件及從中學習)、輸出剖析器等,在 Java 應用程式中整合大型語言模型。

c6d7f7c3fd0d2951.png

課程內容

  • 如何設定 Java 專案以使用 PaLM 和 LangChain4J
  • 如何從非結構化內容 (實體或關鍵字擷取、JSON 輸出內容) 中擷取實用資訊
  • 如何與使用者建立對話
  • 如何使用聊天模型在自有說明文件中提問

軟硬體需求

  • Java 程式設計語言知識
  • Google Cloud 專案
  • 瀏覽器,例如 Chrome 或 Firefox

2. 設定和需求

自修環境設定

  1. 登入 Google Cloud 控制台,建立新專案或重複使用現有專案。如果您還沒有 Gmail 或 Google Workspace 帳戶,請先建立帳戶

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

  • 「專案名稱」是這項專案參與者的顯示名稱。這是 Google API 未使用的字元字串。您可以隨時更新付款方式。
  • 所有 Google Cloud 專案的專案 ID 均不得重複,而且設定後即無法變更。Cloud 控制台會自動產生一個不重複的字串。但通常是在乎它何在在大部分的程式碼研究室中,您必須參照專案 ID (通常為 PROJECT_ID)。如果您對產生的 ID 不滿意,可以隨機產生一個 ID。或者,您也可以自行嘗試,看看是否支援。在這個步驟後,這個名稱即無法變更,而且在專案期間內仍會保持有效。
  • 資訊中的第三個值是專案編號,部分 API 會使用這個編號。如要進一步瞭解這三個值,請參閱說明文件
  1. 接下來,您需要在 Cloud 控制台中啟用計費功能,才能使用 Cloud 資源/API。執行本程式碼研究室不會產生任何費用 (如果有的話)。如要關閉資源,以免產生本教學課程結束後產生的費用,您可以刪除自己建立的資源或刪除專案。新使用者符合 $300 美元免費試用計畫的資格。

啟動 Cloud Shell

雖然 Google Cloud 可以從筆記型電腦遠端操作,但在本程式碼研究室中,您將使用 Cloud Shell,這是一種在 Cloud 中執行的指令列環境。

啟用 Cloud Shell

  1. 在 Cloud 控制台中,按一下「啟用 Cloud Shell」圖示 d1264ca30785e435.png

cb81e7c8e34bc8d.png

如果您是第一次啟動 Cloud Shell,系統會顯示中繼畫面,說明這項服務的內容。如果系統顯示中繼畫面,請按一下「繼續」

d95252b003979716.png

佈建並連線至 Cloud Shell 只需幾分鐘的時間。

7833d5e1c5d18f54.png

這個虛擬機器已載入所有必要的開發工具。提供永久的 5 GB 主目錄,而且在 Google Cloud 中運作,大幅提高網路效能和驗證能力。在本程式碼研究室中,您的大部分作業都可透過瀏覽器完成。

連線至 Cloud Shell 後,您應會發現自己通過驗證,且專案已設為您的專案 ID。

  1. 在 Cloud Shell 中執行下列指令,確認您已通過驗證:
gcloud auth list

指令輸出

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. 在 Cloud Shell 中執行下列指令,確認 gcloud 指令知道您的專案:
gcloud config list project

指令輸出

[core]
project = <PROJECT_ID>

如果尚未設定,請使用下列指令進行設定:

gcloud config set project <PROJECT_ID>

指令輸出

Updated property [core/project].

3. 準備開發環境

在本程式碼研究室中,您將使用 Cloud Shell 終端機和程式碼編輯器來開發 Java 程式。

啟用 Vertex AI API

  1. 請前往 Google Cloud 控制台,確認 Google Cloud 控制台頂端會顯示你的專案名稱。如果沒有,請按一下「Select a project」開啟「Project Selector」,然後選取所需的專案。
  2. 如果您尚未位於 Google Cloud 控制台的「Vertex AI」部分,請按照下列步驟操作:
  3. 搜尋中輸入 Vertex AI,然後傳回
  4. 在搜尋結果中按一下「Vertex AI Vertex AI 資訊主頁」。
  5. 在 Vertex AI 資訊主頁中,按一下「Enable All Recommended APIs」

這項操作會啟用多個 API,但本程式碼研究室中最重要的 API 是 aiplatform.googleapis.com。您也可以在 Cloud Shell 終端機中透過指令列啟用這個 API,並執行下列指令:

$ gcloud services enable aiplatform.googleapis.com

使用 Gradle 建立專案結構

如要建構 Java 程式碼範例,請使用 Gradle 建構工具和 Java 第 17 版。如要透過 Gradle 設定專案,請在 Cloud Shell 終端機中建立目錄 (此處為 palm-workshop),然後在該目錄中執行 gradle init 指令:

$ mkdir palm-workshop
$ cd palm-workshop

$ gradle init

Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 2

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Scala
  6: Swift
Enter selection (default: Java) [1..6] 3

Split functionality across multiple subprojects?:
  1: no - only one application project
  2: yes - application and library projects
Enter selection (default: no - only one application project) [1..2] 1

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] 

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4] 4

Project name (default: palm-workshop): 
Source package (default: palm.workshop): 

> Task :init
Get more help with your project: https://docs.gradle.org/7.4/samples/sample_building_java_applications.html

BUILD SUCCESSFUL in 51s
2 actionable tasks: 2 executed

您將使用「Java 語言」(選項 2)、「不使用子專案」(選項 3)、「不使用子專案」(選項 1)、使用「建構檔案的 Groovy 語法」(選項 4)、「不要使用新的建構功能」(選項 4) 建構「application」 (選項 2)、使用 JUnit Jupiter (選項 4) 產生測試;您也可以用 palm-workshop 為原始碼產生測試。

專案結構如下所示:

├── gradle 
│   └── ...
├── gradlew 
├── gradlew.bat 
├── settings.gradle 
└── app
    ├── build.gradle 
    └── src
        ├── main
        │   └── java 
        │       └── palm
        │           └── workshop
        │               └── App.java
        └── test
            └── ...

讓我們更新 app/build.gradle 檔案,新增一些必要的依附元件。您可以移除 guava 依附元件 (如果有的話),並替換為 LangChain4J 專案的依附元件和記錄程式庫,以免遺漏記錄器訊息:

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'

    // Logging library
    implementation 'org.slf4j:slf4j-jdk14:2.0.9'

    // This dependency is used by the application.
    implementation 'dev.langchain4j:langchain4j-vertex-ai:0.24.0'
    implementation 'dev.langchain4j:langchain4j:0.24.0'
}

LangChain4J 有 2 個依附元件:

  • 對核心專案來說
  • 另一個則用於專屬的 Vertex AI 模組

如要使用 Java 17 編譯及執行程式,請在 plugins {} 區塊下方新增下列區塊:

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

需進行一項額外變更:更新 app/build.gradleapplication 區塊,讓使用者能夠在叫用建構工具時覆寫主要類別,以便透過指令列執行:

application {
    mainClass = providers.systemProperty('javaMainClass')
                         .orElse('palm.workshop.App')
}

如要確認建構檔案已準備好執行應用程式,可以執行預設的主要類別,該類別會顯示簡單的 Hello World! 訊息:

$ ./gradlew run -DjavaMainClass=palm.workshop.App

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 3s
2 actionable tasks: 2 executed

您現在已可透過使用 LangChain4J 專案,以 PaLM 大型語言文字模型編寫程式!

以下是 app/build.gradle 建構檔案現在的完整外觀,供您參考:

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
}

java {
    toolchain {
        // Ensure we compile and run on Java 17
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'

    // This dependency is used by the application.
    implementation 'dev.langchain4j:langchain4j-vertex-ai:0.24.0'
    implementation 'dev.langchain4j:langchain4j:0.24.0'
    implementation 'org.slf4j:slf4j-jdk14:2.0.9'
}

application {
    mainClass = providers.systemProperty('javaMainClass').orElse('palm.workshop.App')
}

tasks.named('test') {
    // Use JUnit Platform for unit tests.
    useJUnitPlatform()
}

4. 第一次呼叫 PaLM 的聊天模型

現在已正確設定專案,接著要呼叫 PaLM API。

app/src/main/java/palm/workshop 目錄中建立名為 ChatPrompts.java 的新類別 (以及預設的 App.java 類別),然後輸入下列內容:

package palm.workshop;

import dev.langchain4j.model.vertexai.VertexAiChatModel;
import dev.langchain4j.chain.ConversationalChain;

public class ChatPrompts {
    public static void main(String[] args) {
        VertexAiChatModel model = VertexAiChatModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("chat-bison@001")
            .maxOutputTokens(400)
            .maxRetries(3)
            .build();

        ConversationalChain chain = ConversationalChain.builder()
            .chatLanguageModel(model)
            .build();

        String message = "What are large language models?";
        String answer = chain.execute(message);
        System.out.println(answer);

        System.out.println("---------------------------");

        message = "What can you do with them?";
        answer = chain.execute(message);
        System.out.println(answer);

        System.out.println("---------------------------");

        message = "Can you name some of them?";
        answer = chain.execute(message);
        System.out.println(answer);
    }
}

在第一個範例中,您必須匯入 VertexAiChatModel 類別和 LangChain4J ConversationalChain,以便更輕鬆地處理對話的多轉折切面。

接著,在 main 方法中,您要使用 VertexAiChatModel 的建構工具指定即時通訊語言模型,以便指定:

  • 這個端點
  • 專案
  • 區域
  • 發布商
  • 以及模型名稱 (chat-bison@001)。

語言模型已準備就緒,您就可以開始準備 ConversationalChain。這是由 LangChain4J 提供的高階抽象層,用於設定不同的元件來處理對話 (例如即時通訊語言模型本身),但可能會使用其他元件來處理即時通訊對話的記錄,或是連接擷取器等其他工具,從向量資料庫擷取資訊。但別擔心,我們稍後會在本程式碼研究室中再說明這點。

接著,您會使用聊天模型進行多輪對話,提出幾個有關互動的問題。首先,您會想瞭解 LLM 的用途和相關應用範例。請注意,您不必重複輸入相同字詞,LLM 會知道是指大型語言模型

如要進行多輪對話,只要在鏈結上呼叫 execute() 方法,即可將該方法新增至對話的情境中,聊天模型會產生回覆,並將其新增至即時通訊記錄中。

如要執行這個類別,請在 Cloud Shell 終端機中執行下列指令:

./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts

畫面會顯示類似以下的輸出內容:

$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts
Starting a Gradle Daemon, 2 incompatible and 2 stopped Daemons could not be reused, use --status for details

> Task :app:run
Large language models (LLMs) are artificial neural networks that are trained on massive datasets of text and code. They are designed to understand and generate human language, and they can be used for a variety of tasks, such as machine translation, question answering, and text summarization.
---------------------------
LLMs can be used for a variety of tasks, such as:

* Machine translation: LLMs can be used to translate text from one language to another.
* Question answering: LLMs can be used to answer questions posed in natural language.
* Text summarization: LLMs can be used to summarize text into a shorter, more concise form.
* Code generation: LLMs can be used to generate code, such as Python or Java code.
* Creative writing: LLMs can be used to generate creative text, such as poems, stories, and scripts.

LLMs are still under development, but they have the potential to revolutionize a wide range of industries. For example, LLMs could be used to improve customer service, create more personalized marketing campaigns, and develop new products and services.
---------------------------
Some of the most well-known LLMs include:

* GPT-3: Developed by OpenAI, GPT-3 is a large language model that can generate text, translate languages, write different kinds of creative content, and answer your questions in an informative way.
* LaMDA: Developed by Google, LaMDA is a large language model that can chat with you in an open-ended way, answering your questions, telling stories, and providing different kinds of creative content.
* PaLM 2: Developed by Google, PaLM 2 is a large language model that can perform a wide range of tasks, including machine translation, question answering, and text summarization.
* T5: Developed by Google, T5 is a large language model that can be used for a variety of tasks, including text summarization, question answering, and code generation.

These are just a few examples of the many LLMs that are currently being developed. As LLMs continue to improve, they are likely to play an increasingly important role in our lives.

BUILD SUCCESSFUL in 25s
2 actionable tasks: 2 executed

PaLM 回覆了你的 3 個相關問題!

VertexAIChatModel 建構工具可讓您定義已擁有某些預設值的選用參數,並具有可覆寫的預設值。例如:

  • .temperature(0.2):定義您希望回應的廣告素材 (0 表示廣告素材不足且通常與事實不符,1 則代表生成更多創意)
  • .maxOutputTokens(50):在本範例中,要求產生 400 個符記 (3 個符記大約相當於 4 個字詞),取決於您產生的答案有多長
  • .topK(20):從完成文字可能字數上限最多的字詞中隨機選取一個字詞 (從 1 到 40 個字)
  • .topP(0.95):選取總機率加總等於該浮點數的可能字詞 (介於 0 至 1 之間)
  • .maxRetries(3):如果您的執行時間超過每次要求配額,可以讓模型重試呼叫 3 次,例如

5. 展現個人風格的實用聊天機器人!

在上一節中,您馬上開始向 LLM 聊天機器人提問,但未提供任何特定背景資訊。不過,您可以把這類聊天機器人專門用來處理特定工作或特定主題的專家。

該怎麼做呢?建立階段:介紹 LLM 手邊工作、提供背景資訊,也許會提供一些工作要做的事、適當的人物角色、希望以哪種形式取得回覆,以及希望聊天機器人以特定方式運作時可能的語調。

這篇有關編排提示的文章如下圖所示,具體做法如下:

8a4c67679dcbd085.png

https://medium.com/@eldatero/master-the-perfect-chatgpt-prompt-formula-c776adae8f19

為了說明這點,我們來從 prompts.chat 網站獲得一些靈感,當中列出許多有趣的自訂聊天機器人構想,可讓它們的行為如實呈現:

還有一個例子,是將 LLM 聊天機器人轉換成西洋棋玩家!開始實作吧!

請更新 ChatPrompts 類別,如下所示:

package palm.workshop;

import dev.langchain4j.chain.ConversationalChain;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.vertexai.VertexAiChatModel;
import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;

public class ChatPrompts {
    public static void main(String[] args) {
        VertexAiChatModel model = VertexAiChatModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("chat-bison@001")
            .maxOutputTokens(7)
            .maxRetries(3)
            .build();

        InMemoryChatMemoryStore chatMemoryStore = new InMemoryChatMemoryStore();

        MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder()
            .chatMemoryStore(chatMemoryStore)
            .maxMessages(200)
            .build();

        chatMemory.add(SystemMessage.from("""
            You're an expert chess player with a high ELO ranking.
            Use the PGN chess notation to reply with the best next possible move.
            """
        ));


        ConversationalChain chain = ConversationalChain.builder()
            .chatLanguageModel(model)
            .chatMemory(chatMemory)
            .build();

        String pgn = "";
        String[] whiteMoves = { "Nf3", "c4", "Nc3", "e3", "Dc2", "Cd5"};
        for (int i = 0; i < whiteMoves.length; i++) {
            pgn += " " + (i+1) + ". " + whiteMoves[i];
            System.out.println("Playing " + whiteMoves[i]);
            pgn = chain.execute(pgn);
            System.out.println(pgn);
        }
    }
}

讓我們來逐步解析:

  • 必須匯入一些新的項目,才能處理即時通訊的記憶體。
  • 您將聊天模型例項化,但使用少量符記化的符記會例項化 (這裡 7),因為我們的目標是要進行後續動作,而不是在棋子上全盤散播!
  • 接著,您需要建立即時通訊記憶庫,儲存即時通訊對話。
  • 然後建立實際視窗的即時通訊記憶體,保留上次的移動時間。
  • 在即時通訊回憶集錦中,您新增了「系統」訊息,指示即時通訊模型他們的名稱 (例如專家西洋棋選手)。「系統」訊息加上一些背景資訊,而「user」(使用者)以及「AI」就是實際的討論內容。
  • 您會建立結合記憶和聊天模型的對話鏈。
  • 然後,有一份白色的移動清單,並列出您正在疊代的移動。每次執行鏈結時都會以白色動作執行,聊天模型則以接下來的最佳動作進行回覆。

使用這些移動功能執行這個類別時,您應該會看到以下輸出內容:

$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts
Starting a Gradle Daemon (subsequent builds will be faster)

> Task :app:run
Playing Nf3
1... e5
Playing c4
2... Nc6
Playing Nc3
3... Nf6
Playing e3
4... Bb4
Playing Dc2
5... O-O
Playing Cd5
6... exd5 

喔!PaLM 知道如何打西洋棋嗎?簡而言之,但在訓練期間,這個模型必須看過某些西洋棋評論,甚至是過去遊戲的 PGN (可攜式遊戲標記法) 檔案。這個聊天機器人或許不會因 AlphaZero 而受惠 (也就是擊敗最強 Go、Shogi 和 Chess 球員的 AI),而對話可能會走向越遠,而且模型並未確實記住遊戲的實際狀態。

Chat 模型功能非常強大,可讓使用者與使用者互動,並處理各種內容關聯工作。下一節將介紹實用的工作:從文字擷取結構化資料

6. 從非結構化文字中擷取資訊

在上一節中,您已建立使用者與即時通訊語言模型之間的對話。您也可以使用 LangChain4J 的聊天模型,從非結構化文字中擷取結構化資訊。

假設您想要擷取某個人的簡介或描述,因而擷取其姓名和年齡。您可以使用經過微調的提示,指示大型語言模型產生 JSON 資料結構 (這通常稱為「提示工程」)。

您將更新 ChatPrompts 類別,如下所示:

package palm.workshop;

import dev.langchain4j.model.vertexai.VertexAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.UserMessage;

public class ChatPrompts {

    static class Person {
        String name;
        int age;
    }

    interface PersonExtractor {
        @UserMessage("""
            Extract the name and age of the person described below.
            Return a JSON document with a "name" and an "age" property, \
            following this structure: {"name": "John Doe", "age": 34}
            Return only JSON, without any markdown markup surrounding it.
            Here is the document describing the person:
            ---
            {{it}}
            ---
            JSON: 
            """)
        Person extractPerson(String text);
    }

    public static void main(String[] args) {
        VertexAiChatModel model = VertexAiChatModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("chat-bison@001")
            .maxOutputTokens(300)
            .build();
        
        PersonExtractor extractor = AiServices.create(PersonExtractor.class, model);

        Person person = extractor.extractPerson("""
            Anna is a 23 year old artist based in Brooklyn, New York. She was born and 
            raised in the suburbs of Chicago, where she developed a love for art at a 
            young age. She attended the School of the Art Institute of Chicago, where 
            she studied painting and drawing. After graduating, she moved to New York 
            City to pursue her art career. Anna's work is inspired by her personal 
            experiences and observations of the world around her. She often uses bright 
            colors and bold lines to create vibrant and energetic paintings. Her work 
            has been exhibited in galleries and museums in New York City and Chicago.    
            """
        );

        System.out.println(person.name);
        System.out.println(person.age);
    }
}

以下說明這個檔案的各個步驟:

  • Person 類別定義的類別代表人物的描述詳細資料 (名稱和年齡)。
  • PersonExtractor 介面是透過一個方法建立,若指定非結構化文字字串,會傳回具例項化的 Person 執行個體。
  • extractPerson() 會以 @UserMessage 註解加上註解,以建立提示與提示。這就是模型用來擷取資訊,並以 JSON 文件格式傳回詳細資料的提示,系統會剖析該文件,並將其解封為 Person 執行個體。

現在,我們來看看 main() 方法的內容:

  • 即時通訊模型已執行個體化。
  • 藉由 LangChain4J 的 AiServices 類別建立 PersonExtractor 物件,
  • 接著,只要呼叫 Person person = extractor.extractPerson(...) 即可從非結構化文字中擷取人物詳細資料,然後取得包含名稱和年齡的 Person 例項。

現在,請使用下列指令執行這個類別:

$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts

> Task :app:run
Anna
23

當然可以!我是 Anna,今年 23 歲!

這種 AiServices 方法特別值得注意的是,您必須使用強類型物件進行操作。你未直接與聊天 LLM 互動。而是使用具體類別,例如用來代表已擷取個人資訊的 Person 類別,以及擁有可傳回 Person 例項的 extractPerson() 方法的 PersonExtractor 類別。LLM 的概念已經過簡化,而身為 Java 開發人員,您只需處理一般的類別和物件。

7. 檢索增強生成:與文件進行即時通訊

我們回到對話。屆時,您將可以提出與文件相關的問題。您會建構一個聊天機器人,從文件擷取的資料庫擷取相關資訊,然後模型會將這些資訊用於「基礎」,而非嘗試產生與訓練相關的回覆。這個模式稱為 RAG,或稱為「檢索增強生成」

簡單來說,「檢索增強生成」功能分成兩個階段:

  1. 擷取階段 - 載入文件、分割成較小的區塊,並以向量表示法 (「向量嵌入」) 儲存在可執行語意搜尋的「向量資料庫」中。

6c5bb5cb2e3b8088.png

  1. 查詢階段:使用者現在可以向您的聊天機器人詢問有關說明文件的問題。問題也會轉換為向量,與資料庫中的所有其他向量進行比較。最相似的向量通常在語意上彼此相關,並且由向量資料庫傳回。接著,LLM 會提供對話的脈絡、與資料庫傳回的向量對應的文字片段,並要求 LLM 查看這些程式碼片段,以決定答案。

2c279c506d7606cd.png

準備文件

在本次新的示範中,您將提出有關 "transformer" 類神經網路架構的問題,這是 Google 開創的,這也是 Google 現今所有現代大型語言模型的實作方式。

您可以使用 wget 指令從網際網路下載 PDF,擷取描述這個架構的研究論文 (「只需注意即可」):

wget -O attention-is-all-you-need.pdf \
    https://proceedings.neurips.cc/paper_files/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf

實作對話式擷取鏈

接著,讓我們逐一探索如何建構 2 階段方法,首先是擷取文件,再來到使用者詢問文件相關問題時的查詢時間。

文件擷取

文件擷取階段的第一步是找出我們下載的 PDF 檔案,然後準備 PdfParser 以便讀取:

PdfDocumentParser pdfParser = new PdfDocumentParser();
Document document = pdfParser.parse(
    new FileInputStream(new File("/home/YOUR_USER_NAME/palm-workshop/attention-is-all-you-need.pdf")));

在這個情況下,您要建立 "embedding" 模型的執行個體,而不是建立一般的聊天語言模型。這個模型和端點是用於建立文字片段 (字詞、句子或段落) 的向量表示法。

VertexAiEmbeddingModel embeddingModel = VertexAiEmbeddingModel.builder()
    .endpoint("us-central1-aiplatform.googleapis.com:443")
    .project("YOUR_PROJECT_ID")
    .location("us-central1")
    .publisher("google")
    .modelName("textembedding-gecko@001")
    .maxRetries(3)
    .build();

接下來,你需要在幾堂課程中協作,達成以下目標:

  • 載入並分割 PDF 文件。
  • 為所有這些區塊建立向量嵌入。
InMemoryEmbeddingStore<TextSegment> embeddingStore = 
    new InMemoryEmbeddingStore<>();

EmbeddingStoreIngestor storeIngestor = EmbeddingStoreIngestor.builder()
    .documentSplitter(DocumentSplitters.recursive(500, 100))
    .embeddingModel(embeddingModel)
    .embeddingStore(embeddingStore)
    .build();
storeIngestor.ingest(document);

EmbeddingStoreRetriever retriever = EmbeddingStoreRetriever.from(embeddingStore, embeddingModel);

系統會建立 InMemoryEmbeddingStore 的執行個體,即記憶體內向量資料庫,以儲存向量嵌入。

因為 DocumentSplitters 類別會將文件分為多個部分。我們要將 PDF 檔案的文字分割成 500 個字元的片段,並且與 100 個字元重疊 (若為避免截斷字或句子,以位元和片段進行避免)。

「ingestor」商店連結文件分割器、用來計算向量的嵌入模型,以及記憶體內向量資料庫接著,ingest() 方法會負責擷取。

第一階段結束後,文件已轉換為文字區塊,內含相關向量嵌入項目,並儲存在向量資料庫中。

提出問題

現在就開放提問!您可以建立一般的聊天模型來展開對話:

VertexAiChatModel model = VertexAiChatModel.builder()
    .endpoint("us-central1-aiplatform.googleapis.com:443")
    .project("YOUR_PROJECT_ID")
    .location("us-central1")
    .publisher("google")
    .modelName("chat-bison@001")
    .maxOutputTokens(1000)
    .build();

您也會需要 "retriever" 類別,用來連結向量資料庫 (在 embeddingStore 變數中) 和嵌入模型。其工作為計算使用者查詢的向量嵌入,藉此查詢向量資料庫,進而在資料庫中找出類似的向量:

EmbeddingStoreRetriever retriever = 
    EmbeddingStoreRetriever.from(embeddingStore, embeddingModel);

這時,您可以將 ConversationalRetrievalChain 類別例項化 (這只是擷取增強生成模式的名稱不同):

ConversationalRetrievalChain rag = ConversationalRetrievalChain.builder()
    .chatLanguageModel(model)
    .retriever(retriever)
    .promptTemplate(PromptTemplate.from("""
        Answer to the following query the best as you can: {{question}}
        Base your answer on the information provided below:
        {{information}}
        """
    ))
    .build();

這款「鍊條」結合運用:

  • 您先前設定的即時通訊語言模型。
  • retriever 會將向量嵌入查詢與資料庫中的向量進行比對。
  • 提示範本會明確指出聊天模型應根據所提供的資訊做出回覆,也就是相關文件摘錄,其向量嵌入與使用者問題的向量相似。

現在可以開始提問了!

String result = rag.execute("What neural network architecture can be used for language models?");
System.out.println(result);
System.out.println("------------");

result = rag.execute("What are the different components of a transformer neural network?");
System.out.println(result);
System.out.println("------------");

result = rag.execute("What is attention in large language models?");
System.out.println(result);
System.out.println("------------");

result = rag.execute("What is the name of the process that transforms text into vectors?");
System.out.println(result);

使用下列指令執行程式:

$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts

輸出結果中應會顯示問題的答案:

The Transformer is a neural network architecture that can be used for 
language models. It is based solely on attention mechanisms, dispensing 
with recurrence and convolutions. The Transformer has been shown to 
outperform recurrent neural networks and convolutional neural networks on 
a variety of language modeling tasks.
------------
The Transformer is a neural network architecture that can be used for 
language models. It is based solely on attention mechanisms, dispensing 
with recurrence and convolutions. The Transformer has been shown to 
outperform recurrent neural networks and convolutional neural networks on a 
variety of language modeling tasks. The Transformer consists of an encoder 
and a decoder. The encoder is responsible for encoding the input sequence 
into a fixed-length vector representation. The decoder is responsible for 
decoding the output sequence from the input sequence. The decoder uses the 
attention mechanism to attend to different parts of the input sequence when 
generating the output sequence.
------------
Attention is a mechanism that allows a neural network to focus on specific 
parts of an input sequence. In the context of large language models, 
attention is used to allow the model to focus on specific words or phrases 
in a sentence when generating output. This allows the model to generate 
more relevant and informative output.
------------
The process of transforming text into vectors is called word embedding. 
Word embedding is a technique that represents words as vectors in a 
high-dimensional space. The vectors are typically learned from a large 
corpus of text, and they capture the semantic and syntactic relationships 
between words. Word embedding has been shown to be effective for a variety 
of natural language processing tasks, such as machine translation, question 
answering, and sentiment analysis.

完整解決方案

為方便複製及貼上,以下是 ChatPrompts 類別的完整內容:

package palm.workshop;

import dev.langchain4j.chain.ConversationalRetrievalChain;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.parser.PdfDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment; 
import dev.langchain4j.model.input.PromptTemplate;
import dev.langchain4j.model.vertexai.VertexAiChatModel;
import dev.langchain4j.model.vertexai.VertexAiEmbeddingModel;
import dev.langchain4j.retriever.EmbeddingStoreRetriever;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class ChatPrompts {
    public static void main(String[] args) throws IOException {
        PdfDocumentParser pdfParser = new PdfDocumentParser();
        Document document = pdfParser.parse(new FileInputStream(new File("/ABSOLUTE_PATH/attention-is-all-you-need.pdf")));

        VertexAiEmbeddingModel embeddingModel = VertexAiEmbeddingModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("textembedding-gecko@001")
            .maxRetries(3)
            .build();

        InMemoryEmbeddingStore<TextSegment> embeddingStore = 
            new InMemoryEmbeddingStore<>();

        EmbeddingStoreIngestor storeIngestor = EmbeddingStoreIngestor.builder()
            .documentSplitter(DocumentSplitters.recursive(500, 100))
            .embeddingModel(embeddingModel)
            .embeddingStore(embeddingStore)
            .build();
        storeIngestor.ingest(document);

        EmbeddingStoreRetriever retriever = EmbeddingStoreRetriever.from(embeddingStore, embeddingModel);

        VertexAiChatModel model = VertexAiChatModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("genai-java-demos")
            .location("us-central1")
            .publisher("google")
            .modelName("chat-bison@001")
            .maxOutputTokens(1000)
            .build();

        ConversationalRetrievalChain rag = ConversationalRetrievalChain.builder()
            .chatLanguageModel(model)
            .retriever(retriever)
            .promptTemplate(PromptTemplate.from("""
                Answer to the following query the best as you can: {{question}}
                Base your answer on the information provided below:
                {{information}}
                """
            ))
            .build();

        String result = rag.execute("What neural network architecture can be used for language models?");
        System.out.println(result);
        System.out.println("------------");

        result = rag.execute("What are the different components of a transformer neural network?");
        System.out.println(result);
        System.out.println("------------");

        result = rag.execute("What is attention in large language models?");
        System.out.println(result);
        System.out.println("------------");

        result = rag.execute("What is the name of the process that transforms text into vectors?");
        System.out.println(result);
    }
}

8. 恭喜

恭喜,您已成功使用 LangChain4J 和 PaLM API,在 Java 中建構第一個生成式 AI 即時通訊應用程式!一路走來,您發現大型語言聊天模型的功能強大且能夠處理各種工作,例如提問/回答,即使是您自己的文件、資料擷取,甚至在某種程度上甚至能玩一些西洋棋!

後續步驟

請參閱下列程式碼研究室,進一步在 Java 中使用 PaLM:

其他資訊

參考文件