跳到主要内容

watsonx.ai

この統合は IBM watsonx.ai Java SDK の上に構築されています。以下で説明する各モデルは、その SDK のサービスのいずれかをラップしています。LangChain4j に固有ではない動作(トークンキャッシュ、リトライ、HTTP クライアントのチューニングなど)の詳細が必要な場合は、SDK ドキュメントを参照してください。

Maven 依存関係​

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-watsonx</artifactId>
<version>1.23.0-beta33</version>
</dependency>

認証​

Watsonx.ai は Authenticator インターフェースによる認証をサポートしています。

これにより、デプロイメントに応じて異なる認証メカニズムを使用できます。

  • IBMCloudAuthenticator – API キーを使用して IBM Cloud で認証します。これが最もシンプルな方法で、apiKey(...) ビルダーメソッドを提供した場合に使用されます。
  • CP4DAuthenticator – Cloud Pak for Data デプロイメントで認証します。
  • カスタム認証器 – Authenticator インターフェースの任意の実装を使用できます。

WatsonxChatModel、WatsonxStreamingChatModel、およびその他のサービスビルダーは、.apiKey(...) によるショートカット、または .authenticator(...) による完全な Authenticator インスタンスのいずれかを受け付けます。

トークンのキャッシュと更新は透過的に処理されます。トークンは最初のリクエストで取得されてキャッシュされ、有効期限が切れる前に更新されるため、そのライフサイクルを管理する必要はありません。同じ Authenticator インスタンスを複数のモデルに渡すと、それらが 1 つのキャッシュされたトークンを共有できます。認証器とそのパラメータの完全な一覧については、SDK 認証ガイドを参照してください。

例​

import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxChatModel;
import com.ibm.watsonx.ai.core.auth.cp4d.CP4DAuthenticator;
import com.ibm.watsonx.ai.core.auth.cp4d.AuthMode;
import com.ibm.watsonx.ai.CloudRegion;

WatsonxChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key") // Simple IBM Cloud authentication
.projectId("your-project-id")
.modelName("ibm/granite-4-h-small")
.build();

WatsonxChatModel.builder()
.baseUrl("https://my-instance-url")
.authenticator( // For Cloud Pak for Data deployments
CP4DAuthenticator.builder()
.baseUrl("https://my-instance-url")
.username("username")
.apiKey("api-key")
.authMode(AuthMode.LEGACY)
.build()
)
.projectId("my-project-id")
.modelName("ibm/granite-4-h-small")
.build();

カスタム HttpClient と SSL 設定​

カスタム HttpClient の使用​

すべてのサービスと認証器は、ビルダーパターンを通じてカスタム HttpClient インスタンスをサポートします。これは、カスタム TLS/SSL 設定、プロキシ設定、またはその他の HTTP クライアントプロパティを構成する必要がある Cloud Pak for Data 環境で特に有用です。

HttpClient httpClient = HttpClient.newBuilder()
.sslContext(createCustomSSLContext())
.executor(ExecutorProvider.ioExecutor())
.build();

EmbeddingModel embeddingModel = WatsonxEmbeddingModel.builder()
.baseUrl("https://my-instance-url")
.modelName("ibm/granite-embedding-278m-multilingual")
.projectId("project-id")
.httpClient(httpClient) // Custom HttpClient
.authenticator(
CP4DAuthenticator.builder()
.baseUrl("https://my-instance-url")
.username("username")
.apiKey("api-key")
.httpClient(httpClient) // Custom HttpClient
.build()
)
.build();

注意: Cloud Pak for Data でカスタム HttpClient を使用する場合、すべてのリクエストで一貫した HTTP 動作を確保するため、サービスビルダーと認証器ビルダーの両方に設定してください。

🔗 SDK の HTTP クライアントガイド(プライベートトラストストアから SSLContext を構築する方法を含む)。

SSL 検証の無効化​

SSL 証明書の検証を無効にするだけでよい場合は、カスタム HttpClient を提供する代わりに verifySsl(false) オプションを使用できます:

EmbeddingModel embeddingModel = WatsonxEmbeddingModel.builder()
.baseUrl("https://my-instance-url")
.modelName("ibm/granite-embedding-278m-multilingual")
.projectId("project-id")
.verifySsl(false) // Disable SSL verification
.authenticator(
CP4DAuthenticator.builder()
.baseUrl("https://my-instance-url")
.username("username")
.apiKey("api-key")
.verifySsl(false) // Disable SSL verification
.build()
)
.build();

IBM Cloud API キーの作成方法​

https://cloud.ibm.com/iam/apikeys で Create + をクリックして API キーを作成できます。

Project ID の確認方法​

  1. https://dataplatform.cloud.ibm.com/projects/?context=wx にアクセスする
  2. プロジェクトを開く
  3. Manage タブに移動する
  4. Details セクションから Project ID をコピーする

WatsonxChatModel​

WatsonxChatModel クラスを使用すると、LangChain4j 内に完全にカプセル化された ChatModel インターフェースのインスタンスを作成できます。 インスタンスを作成するには、必須パラメータを指定する必要があります。

  • baseUrl(...) – IBM Cloud のエンドポイント URL(String、URI、または CloudRegion)
  • apiKey(...) – IBM Cloud IAM API キー
  • projectId(...) – IBM Cloud プロジェクト ID(または spaceId(...) を使用)
  • modelName(...) – 推論に使用するファウンデーションモデルの ID

.apiKey(...) で認証するか、.authenticator(...) で完全な Authenticator インスタンスを使用して認証できます。

オンデマンドでデプロイしたモデルを呼び出すには、代わりに WatsonxDeploymentChatModel を使用してください。

例​

import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxChatModel;
import com.ibm.watsonx.ai.CloudRegion;

ChatModel chatModel = WatsonxChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.projectId("your-project-id")
.modelName("ibm/granite-4-h-small")
.temperature(0.7)
.maxOutputTokens(0)
.build();

String answer = chatModel.chat("Hello from watsonx.ai");
System.out.println(answer);

🔗 利用可能なモデルを表示

WatsonxStreamingChatModel​

WatsonxStreamingChatModel は、LangChain4j 内で IBM watsonx.ai のストリーミングサポートを提供します。トークンが生成されるにつれて処理したい場合に有用で、チャット UI や長いテキスト生成などのリアルタイムアプリケーションに最適です。

ストリーミングは、非ストリーミングの WatsonxChatModel と同じ設定構造とパラメータを使用します。主な違いは、レスポンスがハンドラーインターフェースを通じて増分的に配信されることです。

オンデマンドでデプロイしたモデルを呼び出すには、代わりに WatsonxDeploymentStreamingChatModel を使用してください。

例​

import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.chat.StreamingChatResponseHandler;
import dev.langchain4j.model.chat.ChatResponse;
import dev.langchain4j.model.watsonx.WatsonxStreamingChatModel;
import com.ibm.watsonx.ai.CloudRegion;

StreamingChatModel model = WatsonxStreamingChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.projectId("your-project-id")
.modelName("ibm/granite-4-h-small")
.maxOutputTokens(0)
.build();

model.chat("What is the capital of Italy?", new StreamingChatResponseHandler() {

@Override
public void onPartialResponse(String partialResponse) {
System.out.println("Partial: " + partialResponse);
}

@Override
public void onCompleteResponse(ChatResponse completeResponse) {
System.out.println("Complete: " + completeResponse);
}

@Override
public void onError(Throwable error) {
error.printStackTrace();
}
});

🔗 利用可能なモデルを表示

デプロイ済みモデル(オンデマンドデプロイ)(Deployed models (on-demand deployment))​

IBM watsonx.ai では、組織が専有して使用できる専用ハードウェア上に、ファウンデーションモデルをオンデマンドでデプロイできます。これらのデプロイ済みモデルは deploymentId で指定され、ファウンデーションモデルのカタログとは別の watsonx.ai エンドポイントで提供されるため、LangChain4j はそれらを専用のクラスのペア、WatsonxDeploymentChatModel と WatsonxDeploymentStreamingChatModel として公開しています。

インスタンスを作成するには、次を指定する必要があります:

  • baseUrl(...) – IBM Cloud のエンドポイント URL(String、URI、または CloudRegion)
  • apiKey(...) – IBM Cloud IAM API キー
  • deploymentId(...) – オンデマンドでデプロイしたモデルのデプロイ ID

デプロイはすでにプロジェクトまたはスペース内の特定のモデルを対象としているため、これらのビルダーには modelName(...) も projectId(...)/spaceId(...) もありません。その他すべての生成パラメータ(temperature、maxOutputTokens、thinking、ツール、responseFormat、…)は、WatsonxChatModel とまったく同じように機能します。

注意: deploymentId は、モデルの構築時に固定される接続レベルの設定です。デプロイのエンドポイントを選択するため、WatsonxChatRequestParameters を通じてリクエストごとに上書きすることはできません。

WatsonxDeploymentChatModel​

import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxDeploymentChatModel;
import com.ibm.watsonx.ai.CloudRegion;

ChatModel chatModel = WatsonxDeploymentChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.deploymentId("your-deployment-id")
.temperature(0.7)
.maxOutputTokens(0)
.build();

String answer = chatModel.chat("Hello from watsonx.ai");
System.out.println(answer);

WatsonxDeploymentStreamingChatModel​

import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.chat.StreamingChatResponseHandler;
import dev.langchain4j.model.chat.ChatResponse;
import dev.langchain4j.model.watsonx.WatsonxDeploymentStreamingChatModel;
import com.ibm.watsonx.ai.CloudRegion;

StreamingChatModel model = WatsonxDeploymentStreamingChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.deploymentId("your-deployment-id")
.maxOutputTokens(0)
.build();

model.chat("What is the capital of Italy?", new StreamingChatResponseHandler() {

@Override
public void onPartialResponse(String partialResponse) {
System.out.println("Partial: " + partialResponse);
}

@Override
public void onCompleteResponse(ChatResponse completeResponse) {
System.out.println("Complete: " + completeResponse);
}

@Override
public void onError(Throwable error) {
error.printStackTrace();
}
});

🔗 オンデマンドデプロイモデルの詳細

モデルゲートウェイ(Model Gateway)​

IBM watsonx.ai の Model Gateway は、OpenAI 互換のチャットエンドポイントを公開しており、単一の watsonx.ai のエントリーポイントの背後で、複数のプロバイダー(たとえば OpenAI、Anthropic、または登録したサードパーティのプロバイダー)がホストするモデルにリクエストをルーティングできます。LangChain4j は WatsonxGatewayChatModel と WatsonxGatewayStreamingChatModel を通じてこれと統合します。

注意: ゲートウェイは使用前に管理者が設定する必要があります。渡す各 modelName は、ゲートウェイにすでに登録されている ID でなければなりません。

WatsonxGatewayChatModel​

インスタンスを作成するには、次を指定します:

  • baseUrl(...) – IBM Cloud のエンドポイント URL(String、URI、または CloudRegion)
  • apiKey(...) – IBM Cloud IAM API キー(または .authenticator(...) による完全な Authenticator)
  • modelName(...) – ゲートウェイに登録されている OpenAI 形式のモデル ID
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxGatewayChatModel;
import com.ibm.watsonx.ai.CloudRegion;

ChatModel chatModel = WatsonxGatewayChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.modelName("gpt-4o")
.temperature(0.7)
.build();

String answer = chatModel.chat("Hello from the watsonx.ai Model Gateway");
System.out.println(answer);

WatsonxGatewayStreamingChatModel​

WatsonxGatewayStreamingChatModel は、ゲートウェイのストリーミングサポートを提供します。WatsonxGatewayChatModel と同じ設定を使用し、 レスポンスはハンドラーを通じて段階的に配信されます。

import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.chat.StreamingChatResponseHandler;
import dev.langchain4j.model.chat.ChatResponse;
import dev.langchain4j.model.watsonx.WatsonxGatewayStreamingChatModel;
import com.ibm.watsonx.ai.CloudRegion;

StreamingChatModel model = WatsonxGatewayStreamingChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.modelName("gpt-4o")
.build();

model.chat("What is the capital of Italy?", new StreamingChatResponseHandler() {

@Override
public void onPartialResponse(String partialResponse) {
System.out.println("Partial: " + partialResponse);
}

@Override
public void onCompleteResponse(ChatResponse completeResponse) {
System.out.println("Complete: " + completeResponse);
}

@Override
public void onError(Throwable error) {
error.printStackTrace();
}
});

ゲートウェイ専用パラメータ(Gateway-only parameters)​

各 watsonx.ai チャットサービスには独自の ChatRequestParameters 実装があり、そのサービスが受け付けるパラメータだけを公開します:

クラス使用先
WatsonxChatRequestParametersWatsonxChatModel, WatsonxStreamingChatModel, WatsonxDeploymentChatModel, WatsonxDeploymentStreamingChatModel
WatsonxGatewayChatRequestParametersWatsonxGatewayChatModel, WatsonxGatewayStreamingChatModel

この 2 つのクラスは、ChatRequestParameters の独立した実装です。それぞれがサービスがサポートする内容だけを宣言しているため、互いのパラメータについては何も知りません。一方のサービスのパラメータをもう一方に渡すと(ビルダーの defaultRequestParameters(...) 経由でも、単一の ChatRequest のパラメータ経由でも)、DefaultChatRequestParameters がカバーする内容(modelName、temperature、topP、maxOutputTokens、…)のみが反映され、それらが持つ watsonx.ai 固有のパラメータはすべて無視されます。呼び出すモデルに対応するクラスを使用してください。

共通のチャットパラメータに加えて、WatsonxGatewayChatRequestParameters はゲートウェイ固有のパラメータを公開します:

パラメータ説明
serviceTier(...)サービスティア。AUTO、DEFAULT、FLEX、PRIORITY のいずれか。
reasoningEffort(...)推論モデルの推論の労力。LOW、MEDIUM、HIGH のいずれか。
router(...) / cache(...)ルーターの設定(プロンプトの Cache を含む)。
modalities(...)出力モダリティ(例:["text"])。
store(...)プロバイダーがリクエスト/レスポンスを永続化するかどうか。
parallelToolCalls(...)並列ツール呼び出しを有効/無効にします。
user(...)プロバイダーに転送されるエンドユーザー識別子。
metadata(...)プロバイダーに転送される自由形式のメタデータマップ。
logitBias(...), logprobs(...), topLogprobs(...), seed(...)OpenAI 互換のサンプリング制御。
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.request.ChatRequest;
import dev.langchain4j.model.watsonx.WatsonxGatewayChatRequestParameters;
import com.ibm.watsonx.ai.gateway.chat.ModelGatewayParameters.ReasoningEffort;
import com.ibm.watsonx.ai.gateway.chat.ModelGatewayParameters.ServiceTier;

ChatRequest request = ChatRequest.builder()
.messages(UserMessage.from("Solve this step by step."))
.parameters(
WatsonxGatewayChatRequestParameters.builder()
.serviceTier(ServiceTier.FLEX)
.reasoningEffort(ReasoningEffort.HIGH)
.build()
).build();

String answer = chatModel.chat(request).aiMessage().text();

レスポンスメタデータ(Response metadata)​

すべての watsonx.ai チャットレスポンスは WatsonxChatResponseMetadata を持ちます。そのうち 3 つのフィールドは Model Gateway によってのみ設定され、その他のサービスでは null のままです:

import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.watsonx.WatsonxChatResponseMetadata;

ChatResponse response = chatModel.chat(request);
var metadata = (WatsonxChatResponseMetadata) response.metadata();

metadata.serviceTier(); // service tier that served the request (gateway only)
metadata.systemFingerprint(); // provider system fingerprint (gateway only)
metadata.cached(); // whether the response was served from cache (gateway only)

インラインモデレーション(Inline moderation)​

WatsonxChatModel と WatsonxStreamingChatModel は、モデレーションサービスへの追加の呼び出しなしに、回答の生成中にチャットリクエストの入力と出力をスクリーニングできます。スクリーニングは moderations(...) ビルダーメソッドで有効にします。

import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxChatModel;
import com.ibm.watsonx.ai.CloudRegion;
import com.ibm.watsonx.ai.chat.ChatModeration;

ChatModel chatModel = WatsonxChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.projectId("your-project-id")
.modelName("ibm/granite-4-h-small")
.moderations(
ChatModeration.builder()
.pii(pii -> pii.input(true).output(true))
.hap(hap -> hap.output(0.8f))
.graniteGuardian(guardian -> guardian.input(0.85f))
.build()
)
.build();

3 つの検出器が利用できます。pii と hap は、入力、出力、またはその両方で有効にできますが、graniteGuardian は入力のみをスクリーニングします。

検出器目的有効化の方法
pii電話番号、メールアドレス、クレジットカードなどの個人データを検出します。.pii(pii -> pii.input(true).output(true))
hap信頼度のしきい値を超えるヘイトや不適切な表現を検出します。.hap(hap -> hap.input(0.8f).output(0.9f))
graniteGuardian有害なコンテンツの汎用分類器。.graniteGuardian(guardian -> guardian.input(0.85f))

inputRanges(...) は、入力のスクリーニングを指定した範囲に絞り込みます。開始位置は含まれ、終了位置は含まれません。

import com.ibm.watsonx.ai.chat.ChatModeration.InputRanges;

ChatModeration.builder()
.pii(pii -> pii.input(true))
.inputRanges(List.of(InputRanges.of(0, 50), InputRanges.of(100, 150)))
.build();

マッチ結果の読み取り(Reading the matches)​

マッチ結果は、レスポンスの WatsonxChatResponseMetadata で報告されます。

import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.watsonx.WatsonxChatResponseMetadata;

ChatResponse response = chatModel.chat(request);
var metadata = (WatsonxChatResponseMetadata) response.metadata();

metadata.moderations(); // matches keyed by detector name, "pii", "hap" or "granite_guardian"
metadata.detections(); // Granite Guardian detections keyed by position, "input" or "output"

モデレーションが無効の場合や、どの検出器にもマッチしなかった場合、両方のマップは null になります。各マッチは、入力と出力のどちらに由来するか、検出器が割り当てたスコア、認識されたエンティティの種類、テキスト内の問題のある単語の位置を示します。WatsonxStreamingChatModel では、各チャンクのマッチが統合され、onCompleteResponse(...) に渡されるレスポンスのメタデータで報告されます。

フィールド型説明
score()floatマッチの信頼度。
input()booleanマッチが入力に由来する場合は true、出力に由来する場合は false。
position()Positionテキスト内のマッチの開始(含む)と終了(含まない)のオフセット。
entity()String認識されたエンティティの種類(例:PhoneNumber)。
word()Stringマッチしたテキスト。

サービスは出力のマッチを報告するだけで、回答を書き換えることはないため、テキストの秘匿化は呼び出し側に委ねられ、呼び出し側は各マッチのオフセットを利用できます。各検出器は mask(true) も受け付けます。これは検出されたエンティティの値を削除するようサービスに要求しますが、チャットサービスの回答は変更されずに返ってきます。

import com.ibm.watsonx.ai.chat.TextChatResponse.ModerationResult;

static String mask(String text, ModerationResult result) {
var position = result.position();
return text.substring(0, position.start())
+ "*".repeat(position.end() - position.start())
+ text.substring(position.end());
}

検出器によってブロックされた入力(Input blocked by a detector)​

検出器にマッチした入力は、生成をブロックします。LangChain4j はこれを ContentFilteredException として報告し、その原因は SDK が発生させた ModerationException であるため、ブロックを引き起こした各検出器のマッチ結果には引き続きアクセスできます。

import com.ibm.watsonx.ai.chat.exception.ModerationException;
import dev.langchain4j.exception.ContentFilteredException;

try {
chatModel.chat(request);
} catch (ContentFilteredException e) {
var cause = (ModerationException) e.getCause();
System.out.println(cause.moderations());
}

WatsonxStreamingChatModel では、同じ例外が onError(...) に渡されます。

単一リクエストのモデレーション(Moderation of a single request)​

WatsonxChatRequestParameters は同じ設定を持ち、ビルダーで設定されたものより優先されます。

import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.request.ChatRequest;
import dev.langchain4j.model.watsonx.WatsonxChatRequestParameters;

ChatRequest request = ChatRequest.builder()
.messages(UserMessage.from("Contact me at john@example.com."))
.parameters(
WatsonxChatRequestParameters.builder()
.moderations(ChatModeration.builder().pii(pii -> pii.output(true)).build())
.build()
).build();

注意: インラインモデレーションは、ファウンデーションモデルでのみ利用できます。WatsonxDeploymentChatModel と WatsonxDeploymentStreamingChatModel は UnsupportedFeatureException でこれを拒否し、Model Gateway はこれをサポートしていません。チャットフローの外でテキストをスクリーニングするには、WatsonxModerationModel を使用してください。

🔗 SDK コンテンツモデレーション(各検出器のオプションの完全な一覧)。

ツール統合​

すべての watsonx.ai チャットモデル(WatsonxChatModel、WatsonxStreamingChatModel、WatsonxDeploymentChatModel、WatsonxDeploymentStreamingChatModel、WatsonxGatewayChatModel、WatsonxGatewayStreamingChatModel)は LangChain4j Tools をサポートしており、モデルが @Tool アノテーション付きの Java メソッドを呼び出せるようにします。

以下は同期モデル(WatsonxChatModel)を使用した例ですが、ストリーミングバリアントやデプロイ/ゲートウェイのバリアントにも同じ方法が適用されます。

static class Tools {

@Tool
LocalDate currentDate() {
return LocalDate.now();
}

@Tool
LocalTime currentTime() {
return LocalTime.now();
}
}

interface AiService {
String chat(String userMessage);
}

ChatModel chatModel = WatsonxChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.projectId("your-project-id")
.modelName("mistralai/mistral-small-3-1-24b-instruct-2503")
.maxOutputTokens(0)
.build();

AiService aiService = AiServices.builder(AiService.class)
.chatModel(chatModel)
.tools(new Tools())
.build();

String answer = aiService.chat("What is the date today?");
System.out.println(answer);

注意: 選択したモデルがツール使用をサポートしていることを確認してください。


構造化出力(Structured Outputs)​

すべての watsonx.ai チャットモデルは、レスポンスを JSON スキーマに制約できます。LangChain4j の一般的なドキュメントはこちらにあり、このセクションでは watsonx.ai 固有の動作を説明します。

strictJsonSchema(...) ビルダーメソッドは、スキーマをサービスに送信する方法を制御し、デフォルトは true です。strict モードでは、モデルはスキーマに従う必要があり、すべてのプロパティが required としてマークされ、additionalProperties が false に設定され、必須リストから除外されたプロパティは nullable になります。

import static dev.langchain4j.model.chat.Capability.RESPONSE_FORMAT_JSON_SCHEMA;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxChatModel;
import com.ibm.watsonx.ai.CloudRegion;

ChatModel chatModel = WatsonxChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.projectId("your-project-id")
.modelName("ibm/granite-4-h-small")
.supportedCapabilities(RESPONSE_FORMAT_JSON_SCHEMA)
.strictJsonSchema(true) // default value
.build();

strictJsonSchema(false) を使用すると、スキーマを制約ではなくヒントとして送信します。モデルは引き続きスキーマに準拠したレスポンスを生成しようとしますが、レスポンスがスキーマから外れてもリクエストは失敗せず、必須リストは宣言されたとおりに送信され、additionalProperties は省略されます。オプションのフィールドをオプションのままにしておく必要がある場合は、このモードを使用します。

supportedCapabilities(RESPONSE_FORMAT_JSON_SCHEMA) が必要なのは、AI Services を通じてモデルを使用する場合のみです。この場合、JSON スキーマは AI Service メソッドの戻り値の型から生成されます。

JSON スキーマのルート要素は、JsonObjectSchema または JsonRawSchema でなければなりません。他のルート要素の場合、リクエストは IllegalArgumentException で失敗します。

Thinking / Reasoning 出力の有効化​

一部の基盤モデルは、レスポンスの一部として内部のreasoning(thinking とも呼ばれる)ステップを含めることができます。
モデルによっては、この reasoning は最終レスポンスと同じテキストに埋め込まれている場合もあれば、watsonx.ai から専用フィールドで別途返される場合もあります。

この動作を正しく有効化しキャプチャするには、モデルの出力形式に従って thinking(...) ビルダーメソッドを設定する必要があります。
これにより、LangChain4j がモデル出力から reasoning とレスポンス内容を自動的に抽出できます。

主な設定モードは 2 つあります:

  • ExtractionTags → 同じテキストブロックで reasoning とレスポンスを返すモデル向け(例: ibm/granite-3-3-8b-instruct)。
  • ThinkingEffort → 既に reasoning とレスポンスを自動的に分離するモデル向け(例: openai/gpt-oss-120b)。

thinking(...) ビルダーメソッドは、WatsonxChatModel、WatsonxStreamingChatModel、WatsonxDeploymentChatModel、WatsonxDeploymentStreamingChatModel で利用できます。Model Gateway はこれを受け付けないため、ゲートウェイのモデルでは代わりに reasoningEffort(...) を使用してください。

reasoning とレスポンスを一緒に返すモデル​

モデルが同じテキスト文字列で reasoning とレスポンスを出力する場合は ExtractionTags を使用します。
タグは、reasoning と最終レスポンスを分離するために使用される XML 風のマーカーを定義します。

タグの例:

  • 推論タグ: <think> - モデルの内部推論を含みます。
  • レスポンスタグ: <response> - ユーザー向けの回答を含みます。

動作​

  • 両方のタグが指定されている場合、それらを直接使用して reasoning とレスポンスのセグメントを抽出します。
  • reasoning タグのみが指定されている場合、そのタグの外側にあるすべてがレスポンスと見なされます。

ibm/granite-3-3-8b-instruct の例​

ChatModel chatModel = WatsonxChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.projectId("your-project-id")
.modelName("ibm/granite-3-3-8b-instruct")
.maxOutputTokens(0)
.thinking(ExtractionTags.of("think", "response"))
.build();

ChatResponse chatResponse = chatModel.chat(
UserMessage.userMessage("Why is the sky blue?")
);

AiMessage aiMessage = chatResponse.aiMessage();

System.out.println(aiMessage.thinking());
System.out.println(aiMessage.text());

reasoning とレスポンスを別々に返すモデル​

既に reasoning とレスポンスを別フィールドとして返すモデルでは、生成中にモデルが適用する reasoning の量を制御するために ThinkingEffort を使用します。 あるいは、ブールフラグを使用して有効にします。

openai/gpt-oss-120b の例​

ChatModel chatModel = WatsonxChatModel.builder()
.baseUrl(CloudRegion.DALLAS)
.apiKey("your-api-key")
.projectId("your-project-id")
.modelName("openai/gpt-oss-120b")
.thinking(ThinkingEffort.HIGH)
.build();

または

ChatModel chatModel = WatsonxChatModel.builder()
.baseUrl(CloudRegion.DALLAS)
.apiKey("your-api-key")
.projectId("your-project-id")
.modelName("openai/gpt-oss-120b")
.thinking(true)
.build();

ストリーミングの例​

StreamingChatModel model = WatsonxStreamingChatModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.projectId("your-project-id")
.modelName("ibm/granite-3-3-8b-instruct")
.thinking(ExtractionTags.of("think", "response"))
.build();

List<ChatMessage> messages = List.of(
UserMessage.userMessage("Why is the sky blue?")
);

ChatRequest chatRequest = ChatRequest.builder()
.messages(messages)
.build();

model.chat(chatRequest, new StreamingChatResponseHandler() {

@Override
public void onPartialResponse(String partialResponse) {
...
}

@Override
public void onPartialThinking(PartialThinking partialThinking) {
...
}
});

注意事項:

  • 選択したモデルが reasoning 出力をサポートしていることを確認してください。
  • reasoning とレスポンスを単一のテキスト文字列に埋め込むモデルには ExtractionTags を使用します。
  • 既に reasoning とレスポンスを自動的に分離するモデルには ThinkingEffort または thinking(true) を使用します。

WatsonxModelCatalog​

WatsonxModelCatalog は、IBM watsonx.ai 上で利用可能なすべての基盤モデルをプログラムで発見・一覧表示する方法を提供します。 LangChain4j の ModelCatalog インターフェースを実装しており、各モデルに関する詳細情報を取得できます。

例​

import dev.langchain4j.model.catalog.ModelCatalog;
import dev.langchain4j.model.catalog.ModelDescription;
import dev.langchain4j.model.watsonx.WatsonxModelCatalog;
import com.ibm.watsonx.ai.CloudRegion;

ModelCatalog modelCatalog = WatsonxModelCatalog.builder()
.baseUrl(CloudRegion.FRANKFURT)
.build();

var models = modelCatalog.listModels();

🔗 SDK ファウンデーションモデルサービス

WatsonxGatewayModelCatalog​

WatsonxGatewayModelCatalog は、WatsonxModelCatalog の Model Gateway 版です。watsonx.ai がホストするファウンデーションモデルを一覧表示する代わりに、ゲートウェイに設定されているモデルを、そこに登録されたすべてのプロバイダーにわたって集約して一覧表示します。LangChain4j の ModelCatalog インターフェースも実装しています。

返される各 ModelDescription の name() は、WatsonxGatewayChatModel.modelName(...) と WatsonxGatewayStreamingChatModel.modelName(...) に渡す識別子です。ゲートウェイ管理者がモデルのエイリアスを定義している場合はそのエイリアス、そうでない場合はプロバイダー側のモデル ID です。

例​

import dev.langchain4j.model.catalog.ModelCatalog;
import dev.langchain4j.model.catalog.ModelDescription;
import dev.langchain4j.model.watsonx.WatsonxGatewayModelCatalog;
import com.ibm.watsonx.ai.CloudRegion;

ModelCatalog modelCatalog = WatsonxGatewayModelCatalog.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.build();

for (ModelDescription model : modelCatalog.listModels()) {
System.out.println(model.name() + " (" + model.owner() + ")");
}
// → gpt-4o (openai)
// → claude-3-5-sonnet (anthropic)

ゲートウェイモデルのマッピング(How the gateway models are mapped)​

ModelDescriptionゲートウェイのフィールド備考
name()alias、エイリアスがない場合は idゲートウェイのチャットモデルで使用する ID
displayName()name() と同じゲートウェイには別のラベルがありません
description()descriptionユーザー定義。管理者が設定しない限り null
owner()owned_byプロバイダー(例:openai)
createdAt()createdモデルのリリース時ではなく、ゲートウェイ設定の Unix タイムスタンプ
type()-ゲートウェイはモデルの機能を公開しないため、常に ModelType.CHAT
maxInputTokens()metadata.context_window管理者がメタデータを設定していない場合は null
maxOutputTokens()-常に null。ゲートウェイはこれを返しません

WatsonxTokenCountEstimator​

WatsonxTokenCountEstimator は、watsonx.ai のトークン化エンドポイントを呼び出すことで LangChain4j の TokenCountEstimator インターフェースを実装しており、 カウントはローカルの近似値ではなく、モデル自身のトークナイザーから得られます。 そのため、modelName(...) は必須です。

例​

import dev.langchain4j.model.TokenCountEstimator;
import dev.langchain4j.model.watsonx.WatsonxTokenCountEstimator;
import com.ibm.watsonx.ai.CloudRegion;

TokenCountEstimator tokenCountEstimator = WatsonxTokenCountEstimator.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.projectId("your-project-id")
.modelName("ibm/granite-4-h-small")
.build();

int tokenCount = tokenCountEstimator.estimateTokenCountInText("Hello from watsonx.ai");

注意: すべての見積もりはリモート呼び出しです。estimateTokenCountInMessage(...) は、AiMessage の thinking テキストと ツール実行リクエストもカウントします。画像、音声、PDF、動画のコンテンツはサポートされていません。

🔗 SDK トークン化サービス

WatsonxModerationModel​

WatsonxModerationModel は、IBM watsonx.ai を使用した LangChain4j の ModerationModel インターフェース実装を提供します。
検出器(detectors) を通じて、テキスト内の機密、安全でない、またはポリシー違反のコンテンツを自動的に検出・フラグ付けできます。

1 つ以上の検出器を使用して、次のようなさまざまな種類のコンテンツを識別できます:

  • Pii – 個人識別情報を検出(例: メール、電話番号)
  • Hap – ヘイト、虐待、または冒涜を検出
  • GraniteGuardian – リスクのあるまたは有害な言語を検出

例​

ModerationModel model = WatsonxModerationModel.builder()
.baseUrl(CloudRegion.FRANKFURT)
.apiKey("your-api-key")
.projectId("your-project-id")
.detectors(Hap.ofDefaults(), GraniteGuardian.ofDefaults())
.build();

Response<Moderation> response = model.moderate("...");

メタデータ​

各モデレーションレスポンスには、検出に関する追加コンテキストを提供する metadata マップが含まれます。

キー説明
detection検出器によって割り当てられた検出ラベルまたはカテゴリ
detection_typeフラグをトリガーした検出器のタイプ
start検出されたセグメントの開始文字インデックス
end検出されたセグメントの終了文字インデックス
score検出の信頼度スコア

これらのメタデータ値は Response.metadata() 経由で利用できます。

Map<String, Object> metadata = response.metadata();
System.out.println("Detection type: " + metadata.get("detection_type"));
System.out.println("Score: " + metadata.get("score"));

🔗 SDK 検出サービス(すべての 検出器とそのオプションの完全な一覧)。

環境変数による設定​

基盤となる SDK の内部 HTTP 動作は、コードを変更することなく、環境変数でカスタマイズできます。 これらの設定はオプションであり、変数が明示的に定義されていない場合は適切なデフォルト値が使用されます。

リトライ設定​

HTTP リクエストは、一時的な障害や認証トークンの期限切れの場合に自動的にリトライされます。
リトライ動作は次の環境変数でカスタマイズできます。

環境変数説明デフォルト
WATSONX_RETRY_TOKEN_EXPIRED_MAX_RETRIES認証トークンが期限切れになった場合の最大リトライ回数(HTTP 401 / 403)1
WATSONX_RETRY_STATUS_CODES_MAX_RETRIES一時的な HTTP ステータスコードの最大リトライ回数(429、503、504、520)10
WATSONX_RETRY_STATUS_CODES_BACKOFF_ENABLED一時的なリトライに対する指数バックオフを有効化true
WATSONX_RETRY_STATUS_CODES_INITIAL_INTERVAL_MS初期リトライ間隔(ミリ秒、指数バックオフの基準として使用)20

HTTP IO エグゼキュータ設定​

ストリーミングレスポンスと HTTP レスポンス処理は、内部 IO エグゼキュータによって処理されます。
デフォルトでは、Java 21 以降では仮想スレッドが、Java 17〜20 ではキャッシュされたスレッドプールが使用されます。

この動作は次の環境変数でカスタマイズできます。

環境変数説明デフォルト
WATSONX_IO_EXECUTOR_THREADSIO エグゼキューターを、このスレッド数の固定サイズのプールに制限します未設定

🔗 SDK 環境変数の完全なリファレンス

エラー処理(Error Handling)​

SDK が発生させる watsonx.ai のエラーは、標準的な LangChain4j の例外に変換されるため、他のプロバイダーと同じ方法で処理できます。 マッピングは、watsonx.ai が返すエラーコードに基づいて行われます:

watsonx.ai のエラーコードLangChain4j の例外
authentication_token_expired, authorization_rejectedAuthenticationException
invalid_input_argument, invalid_request_entity, json_type_error, json_validation_errorInvalidRequestException
model_not_supportedModelNotFoundException
token_quota_reachedRateLimitException
その他のエラーコードLangChain4jException

レスポンスにエラーボディがない場合は、代わりに HTTP ステータスコードから例外が選択されます。timeout(...) を超えたリクエストは TimeoutException として報告されます。回答を拒否したモデルや、インラインモデレーションによってブロックされた入力は、ContentFilteredException として報告されます。

try {
String answer = chatModel.chat("Hello from watsonx.ai");
} catch (RateLimitException e) {
// token quota reached
} catch (InvalidRequestException e) {
// a request parameter was rejected by watsonx.ai
}

🔗 SDK の例外階層(基盤となる WatsonxException とその statusCode()、errorCode()、traceId() は、getCause() を通じて利用できます)。

Quarkus​

詳細はこちらを参照してください。

例​