AIサービス
ここまでは、ChatModel、ChatMessage、ChatMemory などの低レベルコンポーネントを扱ってきました。
このレベルで作業すると非常に柔軟で完全な自由度が得られますが、同時に大量のボイラープレートコードを書かざるを得なくなります。
LLM 駆動のアプリケーションでは、通常、単一のコンポーネントだけでなく、複数のコンポーネントが連携して動作する必要があり
(例:プロンプトテンプレート、チャットメモリ、LLM、出力パーサー、RAG コンポーネント:埋め込みモデルとストア)、
さらに複数のやり取りを伴うことが多いため、それらすべてをオーケストレーションするのはさらに煩雑になります。
私たちは、低レベルの実装詳細ではなく、ビジネスロジックに集中してほしいと考えています。 そのため、LangChain4j には現在、それを支援する 2 つの高レベル概念があります:AIサービスとチェーンです。
チェーン(レガシー)
チェーンの概念は、Python 版 LangChain(LCEL 導入前)に由来します。
アイデアは、チャットボットや RAG など、一般的なユースケースごとに Chain を持つことです。
チェーンは複数の低レベルコンポーネントを組み合わせ、それらの間のやり取りをオーケストレーションします。
主な問題は、何かをカスタマイズする必要がある場合に硬直的すぎることです。
LangChain4j では現在、2 つのチェーン(ConversationalChain と ConversationalRetrievalChain)のみが実装されており、
現時点ではこれ以上追加する予定はありません。
AIサービス
私たちは、Java 向けに調整された別のソリューションとして、AIサービスを提案します。 アイデアは、LLM やその他のコンポーネントとのやり取りの複雑さを、シンプルな API の背後に隠すことです。
このアプローチは Spring Data JPA や Retrofit に非常に似ています:望ましい API を持つインターフェースを宣言的に定義すると、 LangChain4j がそのインターフェースを実装するオブジェクト(プロキシ)を提供します。 AIサービスは、アプリケーションのサービス層のコンポーネントと考えることができます。 それは AI サービスを提供します。これが名前の由来です。
AIサービスは最も一般的な操作を処理します:
- LLM 向けの入力のフォーマット
- LLM からの出力の解析
また、より高度な機能もサポートします:
- チャットメモリ
- ツール
- RAG
AIサービスは、やり取りを往復させるステートフルなチャットボットの構築にも、 各 LLM 呼び出しが独立しているプロセスの自動化にも使用できます。
まずは、可能な限りシンプルな AIサービスを見てみまし ょう。その後、より複雑な例を探ります。
最もシンプルな AIサービス
まず、入力として String を受け取り、String を返す単一のメソッド chat を持つインターフェースを定義します。
interface Assistant {
String chat(String userMessage);
}
次に、低レベルコンポーネントを作成します。これらのコンポーネントは AIサービスの裏側で使用されます。
この場合、必要なのは ChatModel だけです:
ChatModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName(GPT_4_O_MINI)
.build();
最後に、AiServices クラスを使って AIサービスのインスタンスを作成できます:
Assistant assistant = AiServices.create(Assistant.class, model);
Quarkus
および Spring Boot アプリケーションでは、
オートコンフィギュレーションが Assistant Bean の作成を処理します。
つまり、AiServices.create(...) を呼び出す必要はなく、必要な場所で Assistant を注入/オートワイヤするだけで済みます。
これで Assistant を使用できます:
String answer = assistant.chat("Hello");
System.out.println(answer); // Hello, how can I help you?
どのように動作するのか?
インターフェースの Class を低レベルコンポーネントとともに AiServices に渡すと、
AiServices はこのインターフェースを実装するプロキシオブジェクトを作 成します。
現在はリフレクションを使用していますが、代替手段も検討しています。
このプロキシオブジェクトが、入力と出力のすべての変換を処理します。
この場合、入力は単一の String ですが、使用している ChatModel は入力として ChatMessage を受け取ります。
そのため、AiService は自動的にそれを UserMessage に変換し、ChatModel を呼び出します。
chat メソッドの出力型が String であるため、ChatModel が AiMessage を返した後、
chat メソッドから返される前に String に変換されます。
Quarkus アプリケーションにおける AIサービス
LangChain4j Quarkus 拡張 は、Quarkus アプリケーションでの AIサービスの利用を大幅に簡素化します。
詳細はこちらをご覧ください。
Spring Boot アプリケーションにおける AIサービス
LangChain4j Spring Boot starter は、Spring Boot アプリケーションでの AIサービスの利用を大幅に簡素化します。
@SystemMessage
では、より複雑な例を見てみましょう。 LLM にスラングで返信させるように強制します 😉
これは通常、SystemMessage に指示を与えることで実現します。
interface Friend {
@SystemMessage("You are a good friend of mine. Answer using slang.")
String chat(String userMessage);
}
Friend friend = AiServices.create(Friend.class, model);
String answer = friend.chat("Hello"); // Hey! What's up?
この例では、使用したいシステムプロンプトテンプレート付きの @SystemMessage アノテーションを追加しました。
これは裏側で SystemMessage に変換され、UserMessage とともに LLM に送信されます。
@SystemMessage はリソースからプロンプトテンプレートを読み込むこともできます:
@SystemMessage(fromResource = "my-prompt-template.txt")