1. はじめに
最終更新日: 2024 年 2 月 5 日
生成 AI とは
生成 AI(Generative Artificial Intelligence)は、AI を活用してテキスト、画像、音楽、音声、動画などの新しいコンテンツを作成することを指します。
生成 AI は、さまざまなタスクに対応した基盤モデル(大規模 AI モデル)をベースにしており、そのままで要約、質疑応答、分類などをすぐに実行できます。さらに、ほんのわずかなサンプルデータで必要最小限のトレーニングを行うだけで、基盤モデルを対象のユースケースに適応させることができます。
生成 AI の仕組み
生成 AI は、ML(ML)モデルを使用して、人間が作成したコンテンツのデータセットにあるパターンと関係を学習します。そして、学習したパターンを使用して新しいコンテンツを生成します。
生成 AI モデルをトレーニングする最も一般的な方法は、教師あり学習を使用することです。教師あり学習では、人間が作成したコンテンツと対応するラベルのセットがモデルに与えられます。次に、人間が作成したコンテンツと類似した、同じラベルが付けられたコンテンツを生成することを学習します。
生成 AI の一般的な用途は何ですか?
生成 AI は膨大な量のコンテンツを処理し、テキストや画像など人間が親しみやすい形式で分析情報と答えを生み出します。生成 AI は、以下のことに使用できます。
- チャットや検索エクスペリエンスを強化して顧客対応を改善する
- 会話型インターフェースと要約を通じて、膨大な量の非構造化データを探索する
- 提案依頼書(RFP)への回答、マーケティング コンテンツの 5 言語へのローカライズ、お客様との契約の遵守状況の確認など、反復的なタスクを支援する
Google Cloud が提供する生成 AI サービス
Vertex AI を使用して、基盤モデルを操作、カスタマイズし、自社のアプリケーションに埋め込むことができます。ML の専門知識はほとんど必要ありません。Model Garden で基盤モデルにアクセスしたり、Generative AI Studio のシンプルな UI でモデルを調整したり、データ サイエンス ノートブックでモデルを使用したりできます。
Vertex AI Search and Conversation を使用すると、デベロッパーは生成 AI を活用した検索エンジンや chatbot を迅速に構築できます。
また、Duet AI は、Google Cloud 全体と IDE でご利用いただける、AI を活用した新しいパートナーです。もっと多くの業務をスピーディーにこなせるようにサポートします。
この Codelab の焦点
この Codelab では、すべての ML プロダクトとサービスを網羅する Google Cloud Vertex AI でホストされている PaLM 2 大規模言語モデル(LLM)に焦点を当てます。
Java を使用して、LangChain4J LLM フレームワーク オーケストレーターと組み合わせて PaLM API を操作します。質問応答、アイデアの生成、エンティティと構造化されたコンテンツの抽出、要約に LLM を活用するための具体的な例をいくつか紹介します。
LangChain4J フレームワークについて詳しく教えてください。
LangChain4J フレームワークは、大規模言語モデルを Java アプリケーションに統合するためのオープンソース ライブラリです。LLM 自体だけでなく、ベクトル データベース(セマンティック検索用)、ドキュメント ローダとスプリッタ(ドキュメントを分析して学習するため)、出力パーサーなど、さまざまなコンポーネントをオーケストレートします。

学習内容
- PaLM と LangChain4J を使用するように Java プロジェクトを設定する方法
- 非構造化コンテンツから有用な情報を抽出する方法(エンティティまたはキーワードの抽出、JSON での出力)
- ユーザーとの会話を作成する方法
- チャットモデルを使用して独自のドキュメントに関する質問をする方法
必要なもの
- Java プログラミング言語の知識
- Google Cloud プロジェクト
- ブラウザ(Chrome、Firefox など)
2. 設定と要件
セルフペース型の環境設定
- Google Cloud Console にログインして、プロジェクトを新規作成するか、既存のプロジェクトを再利用します。Gmail アカウントも Google Workspace アカウントもまだお持ちでない場合は、アカウントを作成してください。



- プロジェクト名は、このプロジェクトの参加者に表示される名称です。Google API では使用されない文字列です。いつでも更新できます。
- プロジェクト ID は、すべての Google Cloud プロジェクトにおいて一意でなければならず、不変です(設定後は変更できません)。Cloud コンソールでは一意の文字列が自動生成されます。通常は、この内容を意識する必要はありません。ほとんどの Codelab では、プロジェクト ID(通常は
PROJECT_IDと識別されます)を参照する必要があります。生成された ID が好みではない場合は、ランダムに別の ID を生成できます。または、ご自身で試して、利用可能かどうかを確認することもできます。このステップ以降は変更できず、プロジェクトを通して同じ ID になります。 - なお、3 つ目の値として、一部の API が使用するプロジェクト番号があります。これら 3 つの値について詳しくは、こちらのドキュメントをご覧ください。
- 次に、Cloud のリソースや API を使用するために、Cloud コンソールで課金を有効にする必要があります。この Codelab の操作をすべて行って、費用が生じたとしても、少額です。このチュートリアルの終了後に請求が発生しないようにリソースをシャットダウンするには、作成したリソースを削除するか、プロジェクトを削除します。Google Cloud の新規ユーザーは、300 米ドル分の無料トライアル プログラムをご利用いただけます。
Cloud Shell の起動
Google Cloud はノートパソコンからリモートで操作できますが、この Codelab では、Cloud Shell(Cloud 上で動作するコマンドライン環境)を使用します。
Cloud Shell をアクティブにする
- Cloud Console で、[Cloud Shell をアクティブにする]
をクリックします。

Cloud Shell を初めて起動する場合は、その内容を説明する中間画面が表示されます。中間画面が表示された場合は、[続行] をクリックします。

すぐにプロビジョニングが実行され、Cloud Shell に接続されます。

この仮想マシンには、必要な開発ツールがすべて用意されています。仮想マシンは Google Cloud で稼働し、永続的なホーム ディレクトリが 5 GB 用意されているため、ネットワークのパフォーマンスと認証が大幅に向上しています。このコードラボで行う作業のほとんどはブラウザから実行できます。
Cloud Shell に接続すると、認証が完了しており、プロジェクトに各自のプロジェクト ID が設定されていることがわかります。
- 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`
- Cloud Shell で次のコマンドを実行して、gcloud コマンドがプロジェクトを認識していることを確認します。
gcloud config list project
コマンド出力
[core] project = <PROJECT_ID>
上記のようになっていない場合は、次のコマンドで設定できます。
gcloud config set project <PROJECT_ID>
コマンド出力
Updated property [core/project].
3. 開発環境を準備する
この Codelab では、Cloud Shell のターミナルとコードエディタを使用して Java プログラムを開発します。
Vertex AI API を有効にする
- Google Cloud コンソールで、Google Cloud コンソールの上部にプロジェクト名が表示されていることを確認します。表示されていない場合は、[プロジェクトの選択] をクリックして [Project Selector] を開き、目的のプロジェクトを選択します。
- Google Cloud コンソールの [Vertex AI] セクションが表示されていない場合は、次の操作を行います。
- [検索] に「Vertex AI」と入力して Enter キーを押します。
- 検索結果で、[Vertex AI] をクリックします。Vertex AI ダッシュボードが表示されます。
- Vertex AI ダッシュボードで、[すべての推奨 API を有効化] をクリックします。
これにより、複数の API が有効になりますが、この Codelab で最も重要なのは aiplatform.googleapis.com です。これは、次のコマンドを実行して、Cloud Shell ターミナルのコマンドラインで有効にすることもできます。
$ 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
アプリケーション(オプション 2)を Java 言語(オプション 3)を使用して、サブプロジェクトを使用せずに(オプション 1)、ビルドファイルの Groovy 構文を使用して(オプション 1)、新しいビルド機能を使用せずに(オプションなし)、JUnit Jupiter(オプション 4)でテストを生成します。プロジェクト名には palm-workshop を使用し、ソース パッケージには 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 つの依存関係があります。
- 1 つはコア プロジェクトに、
- 専用の Vertex AI モジュール用です。
プログラムのコンパイルと実行に Java 17 を使用するには、plugins {} ブロックの下に次のブロックを追加します。
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
もう 1 つ変更があります。app/build.gradle の application ブロックを更新して、ビルドツールを呼び出すときにコマンドラインで実行するメインクラスをユーザーがオーバーライドできるようにします。
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 ディレクトリ(デフォルトの App.java クラスと同じ場所)に ChatPrompts.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 が提供する高レベルの抽象化で、チャット言語モデル自体など、会話を処理するさまざまなコンポーネントをまとめて構成します。チャットの会話の履歴を処理する他のコンポーネントや、ベクトル データベースから情報を取得するリトリーバーなどの他のツールを接続することもできます。心配は要りません。この Codelab の後半で説明します。
次に、チャットモデルを使用してマルチターンの会話を行い、相互に関連する複数の質問をします。まず LLM について疑問に思い、次に LLM で何ができるのか、どのような例があるのかを尋ねます。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. 個性的な便利な chatbot です。
前のセクションでは、特定のコンテキストを指定せずに、LLM チャットボットに質問を始めました。ただし、このような chatbot を特定のタスクやトピックの専門家になるように特化させることはできます。
その方法は、状況を設定する: LLM にタスク、コンテキストを説明し、実行すべきこと、持つべきペルソナ、回答の形式、特定の動作を求める場合はトーンの例をいくつか提示します。
プロンプトの作成に関するこちらの記事では、このアプローチが次の図でわかりやすく説明されています。

https://medium.com/@eldatero/master-the-perfect-chatgpt-prompt-formula-c776adae8f19
この点を説明するために、prompts.chat ウェブサイトからインスピレーションを得ましょう。このサイトには、カスタム調整されたチャットボットを次のように機能させるための、優れた楽しいアイデアが多数掲載されています。
- 絵文字翻訳ツール - ユーザーのメッセージを絵文字に翻訳する
- プロンプト エンハンサー - より効果的なプロンプトを作成する
- ジャーナル レビューア - 研究論文のレビューを支援する
- パーソナル スタイリスト - 服のスタイルに関する提案を受ける
LLM chatbot をチェス プレーヤーに変える例もあります。これを実装しましょう。
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)します。
- 次に、チャットの会話を保存するチャット メモリストアを作成します。
- 実際のウィンドウ チャット メモリを作成して、最後の移動を保持します。
- チャット メモリに「システム」メッセージを追加します。このメッセージは、チャットモデルが誰であるべきか(チェスの専門家など)を指示します。「システム」メッセージはコンテキストを追加し、「ユーザー」メッセージと「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(Portable Game Notation)ファイルを見たことがあるはずです。ただし、この chatbot は AlphaZero(囲碁、将棋、チェスのトッププレイヤーを打ち負かした AI)には勝てないでしょう。また、会話が脱線し、モデルがゲームの実際の状態を覚えていない可能性もあります。
チャットモデルは非常に強力で、ユーザーとのリッチなインタラクションを作成し、さまざまなコンテキスト タスクを処理できます。次のセクションでは、テキストから構造化データを抽出するという便利なタスクについて説明します。
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
はい。こちらはアンナです。23 歳です。
この AiServices アプローチで特に興味深いのは、厳密に型指定されたオブジェクトを操作することです。チャット LLM を直接操作することはありません。代わりに、抽出された個人情報を表す Person クラスなどの具象クラスを使用し、Person インスタンスを返す extractPerson() メソッドを含む PersonExtractor クラスがあります。LLM の概念は抽象化されており、Java デベロッパーは通常のクラスとオブジェクトを操作するだけです。
7. 検索拡張生成: ドキュメントとのチャット
会話に戻りましょう。今回は、ドキュメントについて質問できます。ドキュメントの抽出物のデータベースから関連情報を取得できる chatbot を構築します。この情報は、モデルがトレーニングから得た情報に基づいて回答を生成するのではなく、回答を「グラウンディング」するために使用されます。このパターンは、RAG(検索拡張生成)と呼ばれます。
検索拡張生成には、大きく分けて次の 2 つのフェーズがあります。
- 取り込みフェーズ - ドキュメントが読み込まれ、小さなチャンクに分割され、それらのベクトル表現(「ベクトル エンベディング」)が、セマンティック検索を実行できる「ベクトル データベース」に保存されます。

- クエリフェーズ - ユーザーはドキュメントについて chatbot に質問できるようになりました。質問もベクトルに変換され、データベース内の他のすべてのベクトルと比較されます。最も類似したベクトルは通常、意味的に関連しており、ベクトル データベースから返されます。次に、LLM に会話のコンテキストと、データベースから返されたベクトルに対応するテキスト スニペットが提供され、これらのスニペットを参照して回答をグラウンディングするように求められます。

書類の準備
この新しいデモでは、Google が開発した 「Transformer」ニューラル ネットワーク アーキテクチャについて質問します。これは、現在の大規模言語モデルのすべてが実装されている方法です。
このアーキテクチャを説明した論文(「Attention is all you need」)は、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")));
通常のチャット言語モデルを作成する代わりに、その前に「エンベディング」モデルのインスタンスを作成します。これは、テキストの一部(単語、文、段落など)のベクトル表現を作成する役割を持つ特定のモデルとエンドポイントです。
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 文字のオーバーラップ(単語や文が断片的に切断されないように、次のチャンクとオーバーラップ)を行います。
ストアの「インジェスター」は、ドキュメント スプリッタ、ベクトルを計算するエンベディング モデル、インメモリ ベクトル データベースをリンクします。その後、ingest() メソッドが取り込みを行います。
これで、第 1 フェーズが終了し、ドキュメントが関連するベクトル エンベディングを含むテキスト チャンクに変換され、ベクトル データベースに保存されました。
質問する
質問の準備をしましょう。通常のチャットモデルを作成して会話を開始できます。
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();
また、ベクトル データベース(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();
この「チェーン」は、次のものを結び付けます。
- 前に構成したチャット言語モデル。
- リトリーバーは、ベクトル エンベディング クエリをデータベース内のベクトルと比較します。
- プロンプト テンプレートは、チャットモデルが提供された情報(つまり、ユーザーの質問のベクトルに類似したベクトル エンベディングを持つドキュメントの関連する抜粋)に基づいて回答する必要があることを明示的に示しています。
これで、質問をする準備が整いました。
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 をさらに活用するには、次の Codelab をご覧ください。