1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IBM Quarkus LangChain4j入門:AI ServiceからLLMを呼び出す

1
Last updated at Posted at 2026-08-05

はじめに

生成AIの分野では Python が先行している印象がありますが、Javaエコシステムにおいても AI アプリケーション開発を支援するライブラリーやフレームワークが充実してきています。
特に Quarkus には、LLMとの連携を容易にする Quarkus LangChain4j が用意されており、Javaらしい開発スタイルを維持したまま生成AI機能をアプリケーションへ組み込むことができます。

QuarkusのAI関連機能には、LangChain4j、AI Service、Tool Calling、RAG、MCPなど、さまざまな機能や用語があります。
今回は、これらの中でも基本となる AI ServicePromptChat Model の役割を整理します。
また、オープンソースのQuarkusをベースにしたIBM Enterprise Build of Quarkusを使用し、REST APIからLLMを呼び出すところまでを確認します。
なお、本番運用向けには、IBMによるサポートと長期ライフサイクルが提供される製品版も用意されています。

この記事は、Quarkus や生成 AI 関連技術について学習した内容を、自分自身の理解を整理する目的も兼ねてまとめたものです。

今回は以下の機能は扱わず、後続の記事で取り上げる予定です。

  • Tool Calling
  • Chat Memory
  • RAG
  • MCP Server
  • MCP Client
  • Agentic Workflow

なお、Native Image については過去の記事で紹介しています。興味のある方は、こちらもご参照ください。
https://qiita.com/autonomura/items/6af3527658aaf3987abb
https://qiita.com/autonomura/items/79be8a124a39d1b176fe

今回作成するもの

AI Ticket Triage

問い合わせ内容をLLMで分析する「AI Ticket Triage」を作成します。
ユーザーが問い合わせ内容を入力すると、LLMが次の情報を返します。

フィールド 内容
summary 問い合わせの要約
category カテゴリー
priority 優先度
recommendedAction 推奨する初動対応
assignedTeam 担当チーム

例えば、以下のリクエストを送信すると、

POST /tickets/analyze
Content-Type: text/plain

パスワードを忘れてログインできません。

LLM が問い合わせ内容を分析し、業務で扱いやすい構造化データとして返します。

{
  "summary": "パスワードを忘れたためログインできない。",  "category": "APPLICATION",4  "priority": "LOW", "recommendedAction": "パスワードの再設定手順を案内する。", "assignedTeam": "APPLICATION"
}

処理の流れは次のとおりです。

ユーザー
  ↓ HTTP リクエスト
REST Resource (TicketResource)
  ↓ Java メソッド呼び出し
AI Service (TicketAnalyzer)
  ↓ Prompt を組み立てる
Chat Model
  ↓ API リクエスト
LLM Provider (OpenAI)

ソースコードはこちらで公開しています。

LangChain4jとMCPの全体像

LangChain4jとは

LangChain4jは、JavaアプリケーションからLLMを利用するためのライブラリーです。主に次の機能を提供します。

  • Chat Model
  • AI Service
  • Prompt Template
  • Chat Memory
  • Tool Calling
  • RAG
  • Embedding Model
  • Embedding Store

Quarkus LangChain4jは、LangChain4jをQuarkusへ統合するExtensionです。QuarkusのCDIや設定管理などを利用しながら、JavaインターフェースとアノテーションによってAI Serviceを宣言的に定義できます。

MCPとは

MCP(Model Context Protocol)は、AIアプリケーションと検索やファイル操作、業務APIなどの外部機能を共通の方法で接続するためのプロトコルです。

AIアプリケーション
  ↓ MCP Client
MCP Server
  ↓
外部機能

Quarkus LangChain4j の主要要素

AI Service

AI Service は、LLM を利用する処理を Java インターフェースとして定義する仕組みです。

例えば、夕食を提案する AI Service は次のように表現できます。

public interface FoodExpert {
    List<String> recommendMeals(String mood);
}

通常の Java インターフェースに見えますが、Quarkus LangChain4j が実行時に実装を提供し、次の処理を行います。

  1. メソッド引数を Prompt へ埋め込む
  2. Chat Model を呼び出す
  3. LLM から回答を取得する
  4. 回答を Java の戻り値へ変換する

AI Service は、LLM とのやり取りを Java のサービス層として扱うための窓口です。
Chat Memory(会話履歴の保持)、Tool Calling(Javaメソッドなどの外部機能の呼び出し)、RAG(外部データを検索して回答に利用する仕組み)なども組み合わせられます。

Prompt

Prompt は、LLM へ渡す指示です。
Quarkus LangChain4j では、主に次のアノテーションと変数記法を使用して Prompt を定義します。

記述 用途
@SystemMessage AI の役割や全体的なルールを指定する
@UserMessage ユーザーの要求を指定する
{{変数名}} Java メソッドの引数を Prompt へ埋め込む
@SystemMessage("""
    あなたは夕食のメニューを提案するアシスタントです。
    簡潔で実用的な提案をしてください。
    """)
@UserMessage("""
    気分に合った夕食のメニューを3つ提案してください。
    現在の気分は「{{mood}}」です。
    各メニューは料理名のみを返してください。
    """)
List<String> recommendMeals(String mood);

Chat Model

Chat Model は、実際の LLM Provider へリクエストを送信し、回答を受け取るコンポーネントです。

今回はOpenAI用のquarkus-langchain4j-openai Extensionを使用します。
依存関係とapplication.propertiesを設定すると、OpenAIへ接続するChat ModelがQuarkusによって構成されます。

役割の違い

名称 役割
AI Service アプリケーションとしてどのような AI 機能を提供するか
Prompt LLM へ何を指示するか
Chat Model どのモデルへ接続するか

検証環境

項目 バージョン
OS macOS 26.5.2
Java OpenJDK 25.0.1 (GraalVM CE)
Maven 3.9.10
Quarkus IBM Enterprise Build of Quarkus 3.33.2
Quarkus LangChain4j 1.7.6.redhat-00001
LLM Provider OpenAI
実行モード JVM

プロジェクトの作成

IBM Enterprise Build of Quarkusの Application Configurator にて、以下の依存関係を選択してプロジェクトを生成します。

  • quarkus-rest-jackson
  • quarkus-langchain4j-openai

生成された pom.xml の主要な依存関係は次のとおりです。

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest-jackson</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkiverse.langchain4j</groupId>
    <artifactId>quarkus-langchain4j-openai</artifactId>
</dependency>

API キーの設定

今回は OpenAI を使用します。
OpenAI Quickstart に従い API キーを取得し、環境変数に設定します。

export OPENAI_API_KEY="your_api_key_here"

Chat Model の設定

application.properties に以下を追記します。

quarkus.langchain4j.openai.api-key=${OPENAI_API_KEY}

quarkus.langchain4j.log-requests=true
quarkus.langchain4j.log-responses=true

${OPENAI_API_KEY} は先ほど設定した環境変数を参照します。
log-requestslog-responses は開発中のデバッグに便利なため有効化しています。

AI Service の実装

今回のアプリに登場するクラスは 3 つです。

クラス 役割
TicketAnalyzer AI Service インターフェース
TicketAnalysis LLM の回答を受け取る Java Record
TicketResource REST エンドポイント

TicketAnalysis — 出力データ定義

package dev.autonomura.ticket;

public record TicketAnalysis(
        String summary,
        String category,
        String priority,
        String recommendedAction,
        String assignedTeam) {
}

Java Recordで出力形式を定義します。
Quarkus LangChain4jは、LLMの回答をこのRecordへ変換します。

TicketAnalyzer — AI Service

package dev.autonomura.ticket;

import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import io.quarkiverse.langchain4j.RegisterAiService;

@RegisterAiService
public interface TicketAnalyzer {

    @SystemMessage("""
            あなたはIT運用チームのサポート担当者です。

            問い合わせ内容を分析し、以下の項目を返してください。

            - 問い合わせの要約
            - カテゴリー
            - 優先度
            - 推奨される初動対応
            - 担当チーム

            優先度は以下から選択してください。
            LOW, MEDIUM, HIGH, CRITICAL

            カテゴリーは以下から選択してください。
            APPLICATION, DATABASE, NETWORK, SECURITY, INFRASTRUCTURE, OTHER

            問い合わせに記載されていない事実は推測しないでください。
            回答は簡潔かつ実務的にしてください。
            """)
    @UserMessage("""
            以下の問い合わせ内容を分析してください。

            問い合わせ:
            {{ticket}}
            """)
    TicketAnalysis analyze(String ticket);
}

各アノテーションの役割は次のとおりです。

@RegisterAiService
TicketAnalyzer を Quarkus の AI Service として登録します。
開発者が実装クラスを作成しなくても、Quarkus LangChain4j が実装を自動生成します。

@SystemMessage
LLM の役割と、回答全体に適用するルールを定義します。
今回は優先度(LOW / MEDIUM / HIGH / CRITICAL)とカテゴリー(APPLICATION / DATABASE / ...)の選択肢を明示することで、出力を安定させています。

@UserMessage
ユーザーからの依頼を Prompt として定義します。

{{ticket}}
メソッド引数の ticket を Prompt へ埋め込みます。

TicketAnalysis(戻り値)
LLM の回答を単純な文字列ではなく、Java Record として受け取ります。
Quarkus LangChain4j が JSON 解析と型変換を自動的に行います。

TicketResource — REST API

package dev.autonomura.ticket;

import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/tickets")
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.APPLICATION_JSON)
public class TicketResource {

    @Inject
    TicketAnalyzer ticketAnalyzer;

    @POST
    @Path("/analyze")
    public TicketAnalysis analyze(String ticket) {
        return ticketAnalyzer.analyze(ticket);
    }
}

TicketResource には、LLM への接続処理や Prompt を直接記述しません。
AI 関連処理を TicketAnalyzer に分離することで、REST 層と AI サービス層の役割が明確になります。

処理の流れを改めて整理すると次のとおりです。

  1. クライアントが POST /tickets/analyze を呼び出す
  2. TicketResource がリクエストボディの文字列を受け取る
  3. CDI で注入された TicketAnalyzer を呼び出す
  4. AI Service が Prompt を組み立てる
  5. Chat Model が LLM Provider へリクエストする
  6. AI Service が回答を TicketAnalysis へ変換する
  7. REST API が JSON として返す

アプリケーションの起動

mvn quarkus:dev

正常に起動したら、別のターミナルから呼び出します。

curl -s -X POST \
  -H "Content-Type: text/plain" \
  --data-binary "Webアプリケーションにログインできません。今朝から複数の利用者で同じ問題が発生しており、画面には「Database connection timeout」と表示されています。" \
  http://localhost:8080/tickets/analyze | jq .

応答例(LLM の回答のため、実行ごとに表現が変わる場合があります):

{
  "summary": "複数の利用者がWebアプリケーションにログインできず、Database connection timeoutのエラーメッセージが表示されている。",
  "category": "DATABASE",
  "priority": "HIGH",
  "recommendedAction": "データベース接続の状態を確認し、必要に応じて再起動または障害調査を行う。",
  "assignedTeam": "DATABASE"
}

実装の振り返り

TicketResource
  ↓ ticket(問い合わせ文字列)を渡す
TicketAnalyzer
  ↓ Prompt を生成する
Chat Model
  ↓ API を呼び出す
LLM Provider
  ↓ 回答を返す
TicketAnalysis(Java Record)

各クラスの役割

クラス 役割
TicketResource HTTP リクエストの受付とレスポンスの返却
TicketAnalyzer AI 機能と Prompt の定義
TicketAnalysis LLM 出力を受け取るデータモデル
Chat Model LLM Provider との通信
Quarkus LangChain4j AI Service の生成、Prompt の処理、出力の変換

Tool CallingとMCPへの発展

今回のアプリでは、AI ServiceからChat Modelを通じてLLMを呼び出しました。
Tool CallingやMCPは使用していません。

Tool Callingを利用すると、LLMの判断に応じてJavaメソッドなどの外部機能を呼び出せます。
また、MCPを利用すると、別のアプリケーションが提供するToolやデータソースへ共通の方法で接続できます。

まとめ

今回は、Quarkus LangChain4jを使用し、Javaインターフェースとして定義したAI ServiceからLLMを呼び出しました。

  • @RegisterAiServiceを使用すると、LLMとの通信処理を直接実装せず、通常のJavaサービスに近い形でAI機能を定義できる
  • @SystemMessage@UserMessageを使用すると、AIの役割とユーザーからの要求を分けて管理できる
  • Java Recordを戻り値に指定すると、LLMの回答を構造化されたJavaオブジェクトとして受け取れる

今回の実装では、LLMによる問い合わせ内容の分析と構造化までを確認しました。
外部のJavaメソッドや業務システムとの連携は行っていません。

次回はTool Callingを追加し、LLMがユーザーの要求に応じてJavaメソッドを選択・実行する仕組みを確認します。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?