Red Hat で Quarkus を担当している伊藤ちひろです。
この記事では、PC 上で LLM に接続するアプリケーションの開発の流れを紹介します。 今回は、LLM としてGraniteを使用し、そこへアクセスするアプリケーションは Quarkus を使用して開発します。 このGraniteのモデルはInstructLabでチューニングされたものを使用しています。 Graniteのモデルは Podman Desktop 上に構築しています。
最終的に完成するアプリはこちらです。
質問すると、AIっぽい返答がもらえます。
Podman の AI 拡張機能をインストール
まずは、Podman Desktop に AI の拡張機能をインストールします。
左のメニューのパズルのポースのようなアイコンを押して、Catalog (カタログ) を選択すると、Podman AI Lab
というのが見つかります。
Podman AI Lab
の右側にある下向き矢印(↓)をクリックして、Podman AI Lab
をインストールします。Podman AI Lab
のインストールが終わると、左側のメニューにPodman AI Lab
のアイコンが表示されます。
Graniteをインストール
次に、Graniteをインストールします。
Podman AI Lab
のCatalog
を選択すると、使用可能なモデルの一覧が表示されます。
今回は一番へのinstructlab/granite
を使用します。
右側にある下向き矢印(↓)をクリックしてダウンロードしましょう。
ダウンロードが終わると、instructlab/granite
のアイコンが黄緑になります。
それではinstructlab/granite
を起動しましょう。
右側のロケットのアイコンをクリックすると、モデルのサービスを作成する画面に移動します。
設定できる項目はコンテナのポートのみです。
Create service
ボタンをクリックすると、モデルのサービスが作成されます。
ここまでで、Podman 上に モデルが構築できました。
最後に、実際に、モデルへ問い合わせしてみましょう。 モデルのサービスが作成されると、そのサービスへアクセスする方法が表示されます。 デフォルトではcURLを使ったアクセス方法が表示されています。 cURL のある環境から次のコマンドを実行してください。 レスポンスは JSON 形式のため、最後に jq コマンドを追加すると良いでしょう。
> curl --location 'http://localhost:35000/v1/chat/completions' --header 'Content-Type: application/json' --data '{ "messages": [ { "content": "東京の首都はどこですか?", role": "user" } ] }' | jq
レスポンスは以下のようになります。結果の文は実行のたびに異なります。
{ "id": "chatcmpl-c6572f33-52bc-41bb-a200-27cc7d88f73c", "object": "chat.completion", "created": 1718946977, "model": "/models/granite-7b-lab-Q4_K_M.gguf", "choices": [ { "index": 0, "message": { "content": "東京は日本の首都です。また、世界の最大の都市です。", "role": "assistant" }, "logprobs": null, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 66, "completion_tokens": 34, "total_tokens": 100 } }
Quarkus からモデルへ接続
Podman AI Lab
は、cURLだけでなく、Quarkus からモデルへ接続する方法も提供します。
ドロップダウンリストをJava
とQuarkus Langchain4J
に変更します。
これによって、モデルへ接続する為に必要な設定やコードが出力されます。
ここで変更するファイルは以下の 3 つです。
- pom.xml
- src/main/resources/application.properties
- src/main/java/io/podman/desktop/quarkus/langchain4j/AiService.java
最初の 2 つはすでにあるものに追記します。 最後のファイルは新たに追加します。
これでQuarkus がモデルへ接続する準備はできました。
Quarkus アプリとの統合
最後に、Quarkusアプリからモデルへ接続してみましょう。 今回は、Qute を使用して画面を作成します。
pom.xml に Qute の依存関係を追加します。
pom.xml
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-rest-qute</artifactId> </dependency>
画面を作成します。
src/resources/templates/ai.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Quarkus + Granite</title> </head> <body> <h1>Quarkus + Granite Demo</h1> <form action="/ai/query" method="get"> <div> <label for="question">質問を入力してください</label><br/> <input type="text" style="width: 500px" name="question" id="question" value="{question ?: ''}" required/> <input type="submit" value="送信"/> </div> </form> <p>{answer ?: ''}</p> </body> </html>
最後に、画面とモデルの橋渡しをする部分を作成します。
src/main/java/ai/AiResource.java
package ai; import io.podman.desktop.quarkus.langchain4j.AiService; import io.quarkus.qute.Template; import io.quarkus.qute.TemplateInstance; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; @Path("/ai") public class AiResource { @Inject Template ai; @Inject AiService aiService; @GET @Produces(MediaType.TEXT_HTML) public TemplateInstance index() { return ai.instance(); } @GET @Path("/query") @Produces(MediaType.TEXT_HTML) public TemplateInstance get(@QueryParam("question") String question) { String answer = aiService.request(question); return ai.data("question", question).data("answer", answer); } }
これで完成です。
きちんと動くか試してみましょう。 Quarkus アプリケーションを起動して、https://localhost:8080/ai にアクセスします。 テキストフィールドに、質問を入力して「送信」ボタンを押してみましょう。 返事が下に表示されれば成功です。
10秒以上かかるとタイムアウトします。
タイムアウトの時間を延ばすにはapplication.propertiesにquarkus.langchain4j.openai.timeout=30s
のように追加してください。