OpenAI チャット

Spring AI は、ChatGPT を開発した OpenAI のさまざまな AI 言語モデルをサポートしています。ChatGPT は、業界をリードするテキスト生成モデルと埋め込みの作成により、AI 駆動型テキスト生成への関心を高めるのに役立っています。

前提条件

ChatGPT モデルにアクセスするには、OpenAI を使用して API を作成する必要があります。

OpenAI サインアップページ (英語) でアカウントを作成し、API キーページ (英語) でトークンを生成します。

Spring AI プロジェクトは、spring.ai.openai.api-key という名前の構成プロパティを定義します。このプロパティは、openai.com から取得した API Key の値に設定する必要があります。

この構成プロパティは、application.properties ファイルで設定できます。

spring.ai.openai.api-key=<your-openai-api-key>

API キーなどの機密情報を扱う際のセキュリティを強化するために、Spring 式言語 (SpEL) を使用してカスタム環境変数を参照できます。

# In application.yml
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
# In your environment or .env file
export OPENAI_API_KEY=<your-openai-api-key>

この構成をアプリケーションコード内でプログラム的に設定することもできます。

// Retrieve API key from a secure source or environment variable
String apiKey = System.getenv("OPENAI_API_KEY");

リポジトリと BOM の追加

Spring AI アーティファクトは、Maven Central リポジトリと Spring スナップショットリポジトリに公開されています。これらのリポジトリをビルドシステムに追加するには、アーティファクトリポジトリセクションを参照してください。

依存関係の管理を支援するために、Spring AI は BOM (部品表) を提供し、一貫したバージョンの Spring AI がプロジェクト全体で使用されるようにします。Spring AI BOM をビルドシステムに追加するには、"依存関係管理" セクションを参照してください。

自動構成

Spring AI 自動構成、スターターモジュールのアーティファクト名に大きな変更がありました。詳細については、アップグレードノートを参照してください。

Spring AI は、OpenAI チャットクライアント用の Spring Boot 自動構成を提供します。これを有効にするには、プロジェクトの Maven pom.xml または Gradle build.gradle ビルドファイルに次の依存関係を追加します。

  • Maven

  • Gradle

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-model-openai'
}
Spring AI BOM をビルドファイルに追加するには、"依存関係管理" セクションを参照してください。

チャットのプロパティ

再試行プロパティ

プレフィックス spring.ai.retry は、OpenAI チャットモデルの再試行メカニズムを構成できるプロパティプレフィックスとして使用されます。

プロパティ 説明 デフォルト

spring.ai.retry.max-attempts

再試行の最大回数。

10

spring.ai.retry.backoff.initial-interval

指数関数的バックオフポリシーの初期スリープ期間。

2 秒

spring.ai.retry.backoff.multiplier

バックオフ間隔の乗数。

5

spring.ai.retry.backoff.max-interval

最大バックオフ期間。

3 分

spring.ai.retry.on-client-errors

false の場合、NonTransientAiException をスローし、4xx クライアントエラーコードの再試行を試行しません。

false

spring.ai.retry.exclude-on-http-codes

再試行をトリガーすべきではない HTTP ステータスコードのリスト (NonTransientAiException をスローするなど)。

spring.ai.retry.on-http-codes

再試行をトリガーする必要がある HTTP ステータスコードのリスト (例: TransientAiException をスローする)。

接続プロパティ

接頭辞 spring.ai.openai は、OpenAI への接続を可能にするプロパティ接頭辞として使用されます。

プロパティ 説明 デフォルト

spring.ai.openai.base-url

接続先の URL

api.openai.com (英語)

spring.ai.openai.api-key

API キー

-

spring.ai.openai.organization-id

必要に応じて、API リクエストに使用する組織を指定できます。

-

spring.ai.openai.project-id

必要に応じて、API リクエストに使用するプロジェクトを指定できます。

-

複数の組織に属しているユーザー(または従来のユーザー API キーを使用してプロジェクトにアクセスしているユーザー)の場合は、オプションで、API リクエストに使用する組織とプロジェクトを指定できます。これらの API リクエストからの使用量は、指定された組織とプロジェクトの使用量としてカウントされます。

ユーザーエージェントヘッダー

Spring AI は、OpenAI へのすべてのリクエストに User-Agent: spring-ai ヘッダーを自動的に送信します。これにより、OpenAI は分析とサポートを目的として、Spring AI からのリクエストを識別できるようになります。このヘッダーは自動的に送信され、Spring AI ユーザーによる設定は不要です。

OpenAI 互換サービスを構築している API プロバイダーの場合は、サーバー上の受信リクエストから User-Agent HTTP ヘッダーを読み取ることで、Spring AI の使用状況を追跡できます。

プロパティの構成

チャットの自動構成の有効化と無効化は、プレフィックス spring.ai.model.chat を持つ最上位プロパティを介して設定されるようになりました。

有効にするには、spring.ai.model.chat=openai (デフォルトで有効になっています)

無効にするには、spring.ai.model.chat=none (または openai と一致しない値)

この変更は、複数のモデルの構成を可能にするために行われます。

プレフィックス spring.ai.openai.chat は、OpenAI のチャットモデル実装を構成できるプロパティプレフィックスです。

プロパティ 説明 デフォルト

spring.ai.openai.chat.enabled (削除され、無効になりました)

OpenAI チャットモデルを有効にします。

true

spring.ai.model.chat

OpenAI チャットモデルを有効にします。

開く

spring.ai.openai.chat.base-url

チャット固有の URL を提供するための spring.ai.openai.base-url プロパティのオプションのオーバーライド。

-

spring.ai.openai.chat.completions-path

ベース URL に追加するパス。

/v1/chat/completions

spring.ai.openai.chat.api-key

チャット固有の API キーを提供するための spring.ai.openai.api-key のオプションのオーバーライド。

-

spring.ai.openai.chat.organization-id

必要に応じて、API リクエストに使用する組織を指定できます。

-

spring.ai.openai.chat.project-id

必要に応じて、API リクエストに使用するプロジェクトを指定できます。

-

spring.ai.openai.chat.options.model

使用する OpenAI チャットモデルの名前。gpt-4ogpt-4o-minigpt-4-turbogpt-3.5-turbo などのモデルを選択できます。詳細については、モデル (英語) ページを参照してください。

gpt-4o-mini

spring.ai.openai.chat.options.temperature

生成される補完の明らかな創造性を制御するために使用するサンプリング温度。値が高いほど出力はよりランダムになり、値が低いほど結果はより集中的かつ決定論的になります。これら 2 つの設定の相互作用を予測することは難しいため、同じ補完リクエストに対して temperature と top_p を変更することはお勧めしません。

0.8

spring.ai.openai.chat.options.frequencyPenalty

-2.0 から 2.0 までの数値。正の値を指定すると、これまでのテキスト内の既存の頻度に基づいて新しいトークンにペナルティが課され、モデルが同じ行をそのまま繰り返す可能性が低くなります。

0.0f

spring.ai.openai.chat.options.logitBias

指定したトークンが補完に表示される可能性を変更します。

-

spring.ai.openai.chat.options.maxTokens

チャット補完で生成するトークンの最大数。入力トークンと生成トークンの合計長は、モデルのコンテキスト長によって制限されます。非推論モデルに使用する(例: gpt-4o、gpt-3.5-turbo)。推論モデルでは使用できません(例: o1、o3、o4-mini シリーズ)。maxCompletionTokens とは相互排他的 - 両方を設定すると API エラーが発生します。

-

spring.ai.openai.chat.options.maxCompletionTokens

表示可能な出力トークンと推論トークンを含む、完了時に生成できるトークン数の上限。推論モデルに必要(例: o1、o3、o4-mini シリーズ)。非推論モデルでは使用できません(例: gpt-4o、gpt-3.5-turbo)。maxTokens とは相互排他的 - 両方を設定すると API エラーが発生します。

-

spring.ai.openai.chat.options.n

各入力メッセージに対して生成するチャット補完選択肢の数。すべての選択肢で生成されたトークンの数に基づいて課金されることに注意してください。コストを最小限に抑えるには、n を 1 にしておきます。

1

spring.ai.openai.chat.options.store

このチャット補完リクエストの出力をモデルで使用するために保存するかどうか

false

spring.ai.openai.chat.options.metadata

チャット補完ダッシュボードで完了をフィルタリングするために使用される開発者定義のタグと値

空の地図

spring.ai.openai.chat.options.output-modalities

このリクエストに対してモデルに生成させる出力型。ほとんどのモデルはテキストを生成できます。これはデフォルトです。gpt-4o-audio-preview モデルはオーディオの生成にも使用できます。このモデルにテキストとオーディオの両方のレスポンスを生成するようにリクエストするには、textaudio を使用できます。ストリーミングではサポートされていません。

-

spring.ai.openai.chat.options.output-audio

オーディオ生成のためのオーディオパラメーター。output-modalitiesaudio でオーディオ出力がリクエストされた場合に必要です。gpt-4o-audio-preview モデルが必要であり、ストリーミング補完ではサポートされていません。

-

spring.ai.openai.chat.options.presencePenalty

-2.0 から 2.0 までの数値。正の値を指定すると、これまでにテキストに出現したかどうかに基づいて新しいトークンにペナルティが課され、モデルが新しいトピックについて話す可能性が高まります。

-

spring.ai.openai.chat.options.responseFormat.type

GPT-4oGPT-4o miniGPT-4 Turbo および gpt-3.5-turbo-1106 より新しいすべての GPT-3.5 Turbo モデルと互換性があります。JSON_OBJECT 型は JSON モードを有効にし、モデルが生成するメッセージが有効な JSON であることを保証します。JSON_SCHEMA 型は構造化された出力 (英語) を有効にし、モデルが指定された JSON スキーマと一致することを保証します。JSON_SCHEMA 型では、responseFormat.schema プロパティも設定する必要があります。

-

spring.ai.openai.chat.options.responseFormat.name

レスポンスフォーマットのスキーマ名。responseFormat.type=JSON_SCHEMA にのみ適用可能

custom_schema

spring.ai.openai.chat.options.responseFormat.schema

レスポンス形式 JSON スキーマ。responseFormat.type=JSON_SCHEMA にのみ適用可能

-

spring.ai.openai.chat.options.responseFormat.strict

レスポンスフォーマット JSON スキーマ準拠の厳密さ。responseFormat.type=JSON_SCHEMA にのみ適用可能

-

spring.ai.openai.chat.options.seed

この機能はベータ版です。指定した場合、システムは、同じシードとパラメーターを使用した繰り返しリクエストが同じ結果を返すように、決定論的にサンプリングするために最善の努力をします。

-

spring.ai.openai.chat.options.stop

API がさらなるトークンの生成を停止する最大 4 つのシーケンス。

-

spring.ai.openai.chat.options.topP

温度によるサンプリングの代替として、核サンプリングと呼ばれる方法があります。この方法では、モデルは top_p 確率質量を持つトークンの結果を考慮します。つまり、0.1 は、上位 10% の確率質量を構成するトークンのみが考慮されることを意味します。通常は、この方法か temperature のいずれかを変更することを推奨しますが、両方を変更することは推奨しません。

-

spring.ai.openai.chat.options.tools

モデルが呼び出す可能性のあるツールのリスト。現在、ツールとしては関数のみがサポートされています。これを使用して、モデルが JSON 入力を生成する可能性のある関数のリストを提供します。

-

spring.ai.openai.chat.options.toolChoice

モデルによって呼び出される関数 (ある場合) を制御します。none は、モデルが関数を呼び出さずにメッセージを生成することを意味します。auto は、モデルがメッセージを生成するか関数を呼び出すかを選択できることを意味します。{"type: "function", "function": {"name": "my_function"}} で特定の関数を指定すると、モデルはその関数を強制的に呼び出します。関数が存在しない場合は、none がデフォルトです。関数が存在する場合は、auto がデフォルトです。

-

spring.ai.openai.chat.options.user

エンドユーザーを表す一意の識別子。OpenAI が不正使用を監視および検出できます。

-

spring.ai.openai.chat.options.stream-usage

(ストリーミングのみ) リクエスト全体のトークン使用統計を含む追加のチャンクを追加するように設定します。このチャンクの choices フィールドは空の配列であり、他のすべてのチャンクにも使用状況フィールドが含まれますが、値は null になります。

false

spring.ai.openai.chat.options.parallel-tool-calls

ツールの使用中に並列関数呼び出し (英語) を有効にするかどうか。

true

spring.ai.openai.chat.options.prompt-cache-key

OpenAI が類似リクエストのキャッシュヒット率を最適化するために使用するキャッシュキー。レイテンシを改善し、コストを削減します。キャッシュ用に非推奨となりた user フィールドを置き換えます。さらに学習したい方 (英語) に。

-

spring.ai.openai.chat.options.safety-identifier

OpenAI が利用ポリシーに違反するユーザーを検出するために役立つ、固定の識別子です。ハッシュ値(例: ハッシュ化されたユーザー名またはメールアドレス)である必要があります。安全性追跡のために、非推奨となりた user フィールドを置き換えます。さらに学習したい方 (英語) に。

-

spring.ai.openai.chat.options.http-headers

チャット補完リクエストに追加されるオプションの HTTP ヘッダー。api-key をオーバーライドするには、Authorization ヘッダーキーを使用し、キー値の前に Bearer プレフィックスを付ける必要があります。

-

spring.ai.openai.chat.options.tool-names

単一のプロンプトリクエストで関数呼び出しを有効にするツールのリスト(名前で識別されます)。これらの名前のツールは、ToolCallback レジストリに存在している必要があります。

-

spring.ai.openai.chat.options.tool-callbacks

ChatModel に登録するツールコールバック。

-

spring.ai.openai.chat.options.internal-tool-execution-enabled

False の場合、Spring AI はツール呼び出しを内部で処理せず、クライアントにプロキシします。その後、ツール呼び出しを処理し、適切な関数にディスパッチして、結果を返すのはクライアントの責任です。True (デフォルト) の場合、Spring AI は関数呼び出しを内部で処理します。関数呼び出しをサポートするチャットモデルにのみ適用されます。

true

spring.ai.openai.chat.options.service-tier

リクエストを処理するために使用される処理型 (英語) を指定します。

-

spring.ai.openai.chat.options.extra-body

リクエストに含める追加パラメーター。JSON リクエストの最上位レベルにフラット化された任意のキーと値のペアを受け入れます。標準の OpenAI API を超えるパラメーターをサポートする OpenAI 互換サーバー(vLLM、Ollama など)での使用を想定しています。公式の OpenAI API は不明なパラメーターを無視します。詳細は OpenAI 互換サーバーでの追加パラメーターの使用を参照してください。

-

gpt-5gpt-5-minigpt-5-nano などの GPT-5 モデルを使用する場合、temperature パラメーターはサポートされません。これらのモデルは推論に最適化されており、温度は使用しません。温度値を指定するとエラーが発生します。一方、gpt-5-chat などの会話型モデルは temperature パラメーターをサポートしています。

ChatModel および EmbeddingModel 実装の共通の spring.ai.openai.base-url および spring.ai.openai.api-key をオーバーライドできます。spring.ai.openai.chat.base-url および spring.ai.openai.chat.api-key プロパティが設定されている場合は、共通のプロパティよりも優先されます。これは、異なるモデルおよび異なるモデルエンドポイントに異なる OpenAI アカウントを使用する場合に便利です。
spring.ai.openai.chat.options で始まるすべてのプロパティは、リクエスト固有のランタイムオプションを Prompt 呼び出しに追加することによって実行時にオーバーライドできます。

トークン制限パラメーター: モデル固有の使用箇所

OpenAI は、トークン生成制限を制御するための相互に排他的な 2 つのパラメーターを提供します。

パラメーター ユースケース 対応モデル

maxTokens

非推論モデル

gpt-4o、gpt-4o-mini、gpt-4-turbo、gpt-3.5-turbo

maxCompletionTokens

推論モデル

o1、o1-mini、o1-preview、o3、o4-mini シリーズ

これらのパラメーターは相互に排他的です。両方を設定すると、OpenAI から API エラーが発生します。

使用例

非推論モデル(gpt-4o、gpt-3.5-turbo)の場合:

ChatResponse response = chatModel.call(
    new Prompt(
        "Explain quantum computing in simple terms.",
        OpenAiChatOptions.builder()
            .model("gpt-4o")
            .maxTokens(150)  // Use maxTokens for non-reasoning models
        .build()
    ));

推論モデル(o1、o3 シリーズ)の場合:

ChatResponse response = chatModel.call(
    new Prompt(
        "Solve this complex math problem step by step: ...",
        OpenAiChatOptions.builder()
            .model("o1-preview")
            .maxCompletionTokens(1000)  // Use maxCompletionTokens for reasoning models
        .build()
    ));

ビルダーパターン検証 : OpenAI ChatOptions ビルダーは、「最後のセットが勝つ」アプローチを使用して相互排他性を自動的に強制します。

// This will automatically clear maxTokens and use maxCompletionTokens
OpenAiChatOptions options = OpenAiChatOptions.builder()
    .maxTokens(100)           // Set first
    .maxCompletionTokens(200) // This clears maxTokens and logs a warning
    .build();

// Result: maxTokens = null, maxCompletionTokens = 200

ランタイムオプション

OpenAiChatOptions.java [GitHub] (英語) クラスは、使用するモデル、温度、周波数ペナルティなどのモデル構成を提供します。

起動時に、OpenAiChatModel(api, options) コンストラクターまたは spring.ai.openai.chat.options.* プロパティを使用してデフォルトのオプションを構成できます。

実行時に、Prompt 呼び出しに新しいリクエスト固有のオプションを追加することで、デフォルトのオプションをオーバーライドできます。例: 特定のリクエストのデフォルトのモデルと温度をオーバーライドするには、次のようにします。

ChatResponse response = chatModel.call(
    new Prompt(
        "Generate the names of 5 famous pirates.",
        OpenAiChatOptions.builder()
            .model("gpt-4o")
            .temperature(0.4)
        .build()
    ));
モデル固有の OpenAiChatOptions [GitHub] (英語) に加えて、ChatOptions#builder() [GitHub] (英語) で作成されたポータブル ChatOptions [GitHub] (英語) インスタンスを使用することもできます。

関数呼び出し

OpenAiChatModel にカスタム Java 関数を登録し、OpenAI モデルで、登録された関数の 1 つまたは複数を呼び出すための引数を含む JSON オブジェクトをインテリジェントに出力するように選択できます。これは、LLM 機能を外部ツールや API に接続するための強力な手法です。ツール呼び出しの詳細については、こちらを参照してください。

マルチモーダル

マルチモダリティとは、テキスト、イメージ、音声、その他のデータ形式など、さまざまなソースからの情報を同時に理解して処理するモデルの機能を指します。OpenAI は、テキスト、視覚、音声の入力モダリティをサポートしています。

Vision

ビジョンマルチモーダルサポートを提供する OpenAI モデルには、gpt-4gpt-4ogpt-4o-mini が含まれます。詳細については、Vision (英語) ガイドを参照してください。

OpenAI ユーザーメッセージ API (英語) は、メッセージに base64 でエンコードされたイメージのリストまたはイメージ URL を組み込むことができます。Spring AI のメッセージ [GitHub] (英語) インターフェースは、メディア [GitHub] (英語) 型を導入することで、マルチモーダル AI モデルをサポートします。この型には、メッセージ内のメディア添付ファイルに関するデータと詳細が含まれており、Spring の org.springframework.util.MimeType と、生のメディアデータ用の org.springframework.core.io.Resource が使用されます。

以下は、OpenAiChatModelIT.java [GitHub] (英語) から抜粋したコード例であり、gpt-4o モデルを使用してユーザーテキストとイメージを融合する方法を示しています。

var imageResource = new ClassPathResource("/multimodal.test.png");

var userMessage = new UserMessage("Explain what do you see on this picture?",
        new Media(MimeTypeUtils.IMAGE_PNG, this.imageResource));

ChatResponse response = chatModel.call(new Prompt(this.userMessage,
        OpenAiChatOptions.builder().model(OpenAiApi.ChatModel.GPT_4_O.getValue()).build()));
GPT_4_VISION_PREVIEW は、2024 年 6 月 17 日より、このモデルの既存ユーザーのみご利用いただけます。既存ユーザーでない場合は、GPT_4_O または GPT_4_TURBO モデルをご利用ください。詳細はこちら (英語)

または、gpt-4o モデルを使用した同等のイメージ URL:

var userMessage = new UserMessage("Explain what do you see on this picture?",
        new Media(MimeTypeUtils.IMAGE_PNG,
                URI.create("https://docs.spring.io/spring-ai/reference/_images/multimodal.test.png")));

ChatResponse response = chatModel.call(new Prompt(this.userMessage,
        OpenAiChatOptions.builder().model(OpenAiApi.ChatModel.GPT_4_O.getValue()).build()));
複数のイメージを渡すこともできます。

この例では、multimodal.test.png イメージを入力として受け取るモデルを示します。

Multimodal Test Image

「この写真に何が写っているか説明してください」というテキストメッセージとともに、次のようなレスポンスが生成されます。

This is an image of a fruit bowl with a simple design. The bowl is made of metal with curved wire edges that
create an open structure, allowing the fruit to be visible from all angles. Inside the bowl, there are two
yellow bananas resting on top of what appears to be a red apple. The bananas are slightly overripe, as
indicated by the brown spots on their peels. The bowl has a metal ring at the top, likely to serve as a handle
for carrying. The bowl is placed on a flat surface with a neutral-colored background that provides a clear
view of the fruit inside.

音声

入力オーディオマルチモーダルサポートを提供する OpenAI モデルには、gpt-4o-audio-preview が含まれます。詳細については、音声 (英語) ガイドを参照してください。

OpenAI ユーザーメッセージ API (英語) は、メッセージに base64 でエンコードされたオーディオファイルのリストを組み込むことができます。Spring AI のメッセージ [GitHub] (英語) インターフェースは、メディア [GitHub] (英語) 型を導入することで、マルチモーダル AI モデルを容易にします。この型には、メッセージ内のメディア添付ファイルに関するデータと詳細が含まれており、Spring の org.springframework.util.MimeType と、生のメディアデータ用の org.springframework.core.io.Resource が使用されます。現在、OpenAI は、audio/mp3 と audio/wav のメディア型のみをサポートしています。

以下は、OpenAiChatModelIT.java [GitHub] (英語) から抜粋したコード例であり、gpt-4o-audio-preview モデルを使用してユーザーテキストとオーディオファイルを融合することを示しています。

var audioResource = new ClassPathResource("speech1.mp3");

var userMessage = new UserMessage("What is this recording about?",
        List.of(new Media(MimeTypeUtils.parseMimeType("audio/mp3"), audioResource)));

ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
        OpenAiChatOptions.builder().model(OpenAiApi.ChatModel.GPT_4_O_AUDIO_PREVIEW).build()));
複数のオーディオファイルを渡すこともできます。

オーディオ出力

入力オーディオマルチモーダルサポートを提供する OpenAI モデルには、gpt-4o-audio-preview が含まれます。詳細については、音声 (英語) ガイドを参照してください。

OpenAI アシスタントメッセージ API (英語) には、メッセージとともに base64 でエンコードされたオーディオファイルのリストを含めることができます。Spring AI のメッセージ [GitHub] (英語) インターフェースは、メディア [GitHub] (英語) 型を導入することで、マルチモーダル AI モデルを容易にします。この型には、メッセージ内のメディア添付ファイルに関するデータと詳細が含まれており、Spring の org.springframework.util.MimeType と、生のメディアデータ用の org.springframework.core.io.Resource が利用されます。現在、OpenAI は、audio/mp3 と audio/wav のオーディオ型のみをサポートしています。

以下は、gpt-4o-audio-preview モデルを使用して、ユーザーテキストとオーディオバイト配列のレスポンスを示すコード例です。

var userMessage = new UserMessage("Tell me joke about Spring Framework");

ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
        OpenAiChatOptions.builder()
            .model(OpenAiApi.ChatModel.GPT_4_O_AUDIO_PREVIEW)
            .outputModalities(List.of("text", "audio"))
            .outputAudio(new AudioParameters(Voice.ALLOY, AudioResponseFormat.WAV))
            .build()));

String text = response.getResult().getOutput().getContent(); // audio transcript

byte[] waveAudio = response.getResult().getOutput().getMedia().get(0).getDataAsByteArray(); // audio data

オーディオ出力を生成するには、OpenAiChatOptions で audio モダリティを指定する必要があります。AudioParameters クラスは、オーディオ出力の音声とオーディオ形式を提供します。

構造化された出力

OpenAI は、モデルが指定された JSON Schema に厳密に準拠したレスポンスを生成することを保証するカスタム構造化された出力 (英語) API を提供します。既存の Spring AI モデルに依存しない構造化出力コンバーターに加えて、これらの API は強化された制御と精度を提供します。

現在、OpenAI は JSON スキーマ言語形式のサブセット (英語) をサポートしています。

構成

Spring AI を使用すると、OpenAiChatOptions ビルダーを使用してプログラム的に、またはアプリケーションプロパティを通じてレスポンス形式を構成できます。

チャットオプションビルダーの使用

次に示すように、OpenAiChatOptions ビルダーを使用してプログラムでレスポンス形式を設定できます。

String jsonSchema = """
        {
            "type": "object",
            "properties": {
                "steps": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "explanation": { "type": "string" },
                            "output": { "type": "string" }
                        },
                        "required": ["explanation", "output"],
                        "additionalProperties": false
                    }
                },
                "final_answer": { "type": "string" }
            },
            "required": ["steps", "final_answer"],
            "additionalProperties": false
        }
        """;

Prompt prompt = new Prompt("how can I solve 8x + 7 = -23",
        OpenAiChatOptions.builder()
            .model(ChatModel.GPT_4_O_MINI)
            .responseFormat(new ResponseFormat(ResponseFormat.Type.JSON_SCHEMA, this.jsonSchema))
            .build());

ChatResponse response = this.openAiChatModel.call(this.prompt);

BeanOutputConverter ユーティリティとの統合

既存の BeanOutputConverter ユーティリティを活用して、ドメインオブジェクトから JSON スキーマを自動的に生成し、後で構造化されたレスポンスをドメイン固有のインスタンスに変換できます。

  • Java

  • Kotlin

record MathReasoning(
    @JsonProperty(required = true, value = "steps") Steps steps,
    @JsonProperty(required = true, value = "final_answer") String finalAnswer) {

    record Steps(
        @JsonProperty(required = true, value = "items") Items[] items) {

        record Items(
            @JsonProperty(required = true, value = "explanation") String explanation,
            @JsonProperty(required = true, value = "output") String output) {
        }
    }
}

var outputConverter = new BeanOutputConverter<>(MathReasoning.class);

var jsonSchema = this.outputConverter.getJsonSchema();

Prompt prompt = new Prompt("how can I solve 8x + 7 = -23",
        OpenAiChatOptions.builder()
            .model(ChatModel.GPT_4_O_MINI)
            .responseFormat(new ResponseFormat(ResponseFormat.Type.JSON_SCHEMA, this.jsonSchema))
            .build());

ChatResponse response = this.openAiChatModel.call(this.prompt);
String content = this.response.getResult().getOutput().getContent();

MathReasoning mathReasoning = this.outputConverter.convert(this.content);
data class MathReasoning(
	val steps: Steps,
	@get:JsonProperty(value = "final_answer") val finalAnswer: String) {

	data class Steps(val items: Array<Items>) {

		data class Items(
			val explanation: String,
			val output: String)
	}
}

val outputConverter = BeanOutputConverter(MathReasoning::class.java)

val jsonSchema = outputConverter.jsonSchema;

val prompt = Prompt("how can I solve 8x + 7 = -23",
	OpenAiChatOptions.builder()
		.model(ChatModel.GPT_4_O_MINI)
		.responseFormat(ResponseFormat(ResponseFormat.Type.JSON_SCHEMA, jsonSchema))
		.build())

val response = openAiChatModel.call(prompt)
val content = response.getResult().getOutput().getContent()

val mathReasoning = outputConverter.convert(content)
これは JSON スキーマではオプションですが、OpenAI では構造化されたレスポンスが正しく機能するために必須フィールドが義務付けられています (英語) 。Kotlin リフレクションは、型の null 可能性とパラメーターのデフォルト値に基づいて、どのプロパティが必須かそうでないか推測するために使用されるため、ほとんどのユースケースでは @get:JsonProperty(required = true) は必要ありません。@get:JsonProperty(value = "custom_name") は、プロパティ名をカスタマイズできます。この @get: 構文を使用して、関連する getter のアノテーションを必ず生成してください。関連ドキュメント (英語) を参照してください。

アプリケーションプロパティによる設定

あるいは、OpenAI 自動構成を使用する場合は、次のアプリケーションプロパティを通じて必要なレスポンス形式を構成できます。

spring.ai.openai.api-key=YOUR_API_KEY
spring.ai.openai.chat.options.model=gpt-4o-mini

spring.ai.openai.chat.options.response-format.type=JSON_SCHEMA
spring.ai.openai.chat.options.response-format.name=MySchemaName
spring.ai.openai.chat.options.response-format.schema={"type":"object","properties":{"steps":{"type":"array","items":{"type":"object","properties":{"explanation":{"type":"string"},"output":{"type":"string"}},"required":["explanation","output"],"additionalProperties":false}},"final_answer":{"type":"string"}},"required":["steps","final_answer"],"additionalProperties":false}
spring.ai.openai.chat.options.response-format.strict=true

サンプルコントローラー

新しい Spring Boot プロジェクトを作成し、spring-ai-starter-model-openai を pom (または gradle) の依存関係に追加します。

src/main/resources ディレクトリに application.properties ファイルを追加して、OpenAi チャットモデルを有効にして構成します。

spring.ai.openai.api-key=YOUR_API_KEY
spring.ai.openai.chat.options.model=gpt-4o
spring.ai.openai.chat.options.temperature=0.7
api-key を OpenAI の資格情報に置き換えます。

これにより、クラスに挿入できる OpenAiChatModel 実装が作成されます。以下は、テキスト生成にチャットモデルを使用する単純な @RestController クラスの例です。

@RestController
public class ChatController {

    private final OpenAiChatModel chatModel;

    @Autowired
    public ChatController(OpenAiChatModel chatModel) {
        this.chatModel = chatModel;
    }

    @GetMapping("/ai/generate")
    public Map<String,String> generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of("generation", this.chatModel.call(message));
    }

    @GetMapping("/ai/generateStream")
	public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        Prompt prompt = new Prompt(new UserMessage(message));
        return this.chatModel.stream(prompt);
    }
}

手動構成

OpenAiChatModel [GitHub] (英語) は ChatModel と StreamingChatModel を実装し、低レベル OpenAiApi クライアントを使用して OpenAI サービスに接続します。

spring-ai-openai 依存関係をプロジェクトの Maven pom.xml ファイルに追加します。

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai</artifactId>
</dependency>

または、Gradle build.gradle ビルドファイルに保存します。

dependencies {
    implementation 'org.springframework.ai:spring-ai-openai'
}
Spring AI BOM をビルドファイルに追加するには、"依存関係管理" セクションを参照してください。

次に、OpenAiChatModel を作成し、テキスト生成に使用します。

var openAiApi = OpenAiApi.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .build();
var openAiChatOptions = OpenAiChatOptions.builder()
            .model("gpt-3.5-turbo")
            .temperature(0.4)
            .maxTokens(200)
            .build();
var chatModel = new OpenAiChatModel(this.openAiApi, this.openAiChatOptions);

ChatResponse response = this.chatModel.call(
    new Prompt("Generate the names of 5 famous pirates."));

// Or with streaming responses
Flux<ChatResponse> response = this.chatModel.stream(
    new Prompt("Generate the names of 5 famous pirates."));

OpenAiChatOptions はチャットリクエストの設定情報を提供します。OpenAiApi.Builder と OpenAiChatOptions.Builder は、それぞれ API クライアントとチャット設定のための流れるようなオプションビルダーです。

低レベル OpenAiApi クライアント

OpenAiApi [GitHub] (英語) が提供するのは、OpenAI チャット API OpenAI チャット API (英語) 用の軽量 Java クライアントです。

次のクラス図は、OpenAiApi チャットインターフェースと構成要素を示しています。

OpenAiApi Chat API Diagram

以下は、API をプログラムで使用する方法を示す簡単なスニペットです。

OpenAiApi openAiApi = OpenAiApi.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .build();

ChatCompletionMessage chatCompletionMessage =
    new ChatCompletionMessage("Hello world", Role.USER);

// Sync request
ResponseEntity<ChatCompletion> response = this.openAiApi.chatCompletionEntity(
    new ChatCompletionRequest(List.of(this.chatCompletionMessage), "gpt-3.5-turbo", 0.8, false));

// Streaming request
Flux<ChatCompletionChunk> streamResponse = this.openAiApi.chatCompletionStream(
        new ChatCompletionRequest(List.of(this.chatCompletionMessage), "gpt-3.5-turbo", 0.8, true));

詳細については、OpenAiApi.java [GitHub] (英語) の JavaDoc を参照してください。

低レベル API の例

低レベル OpenAiFileApi クライアント

OpenAiFileApi [GitHub] (英語) は、OpenAI ファイル API 用の軽量 Java クライアントを提供し、ファイルのアップロード、一覧表示、取得、削除、ファイル内容へのアクセスなどのファイル管理操作を可能にします。OpenAI ファイル API (英語)

以下は、API をプログラムで使用する方法を示す簡単なスニペットです。

OpenAiFileApi openAiFileApi = OpenAiFileApi.builder()
			.apiKey(new SimpleApiKey(System.getenv("OPENAI_API_KEY")))
			.build();

// Upload a file
byte[] fileBytes = Files.readAllBytes(Paths.get("evals.jsonl"));
OpenAiFileApi.UploadFileRequest uploadRequest = OpenAiFileApi.UploadFileRequest.builder()
			.file(fileBytes)
			.fileName("evals-data.jsonl")
			.purpose(OpenAiFileApi.Purpose.EVALS)
			.build();
ResponseEntity<OpenAiFileApi.FileObject> uploadResponse = openAiFileApi.uploadFile(uploadRequest);

// List files
OpenAiFileApi.ListFileRequest listRequest = OpenAiFileApi.ListFileRequest.builder()
			.purpose(OpenAiFileApi.Purpose.EVALS)
			.build();
ResponseEntity<OpenAiFileApi.FileObjectResponse> listResponse = openAiFileApi.listFiles(listRequest);

// Retrieve file information
ResponseEntity<OpenAiFileApi.FileObject> fileInfo = openAiFileApi.retrieveFile("file-id");

// Delete a file
ResponseEntity<OpenAiFileApi.DeleteFileResponse> deleteResponse = openAiFileApi.deleteFile("file-id");

// Retrieve file content
ResponseEntity<String> fileContent = openAiFileApi.retrieveFileContent("file-id");

低レベルファイル API の例

API キー管理

Spring AI は、ApiKey インターフェースとその実装を通じて柔軟な API キー管理を提供します。デフォルトの実装である SimpleApiKey はほとんどのユースケースに適していますが、より複雑なシナリオ向けにカスタム実装を作成することもできます。

デフォルト構成

デフォルトでは、Spring Boot 自動構成により、spring.ai.openai.api-key プロパティを使用して API キー Bean が作成されます。

spring.ai.openai.api-key=your-api-key-here

カスタム API キー設定

ビルダーパターンを使用して、独自の ApiKey 実装で OpenAiApi のカスタムインスタンスを作成できます。

ApiKey customApiKey = new ApiKey() {
    @Override
    public String getValue() {
        // Custom logic to retrieve API key
        return "your-api-key-here";
    }
};

OpenAiApi openAiApi = OpenAiApi.builder()
    .apiKey(customApiKey)
    .build();

// Create a chat model with the custom OpenAiApi instance
OpenAiChatModel chatModel = OpenAiChatModel.builder()
    .openAiApi(openAiApi)
    .build();
// Build the ChatClient using the custom chat model
ChatClient openAiChatClient = ChatClient.builder(chatModel).build();

これは、次のことが必要な場合に役立ちます。

  • 安全なキーストアから API キーを取得する

  • API キーを動的にローテーションする

  • カスタム API キー選択ロジックを実装する

OpenAI 互換サーバーでの追加パラメーターの使用

vLLM、Ollama などの OpenAI 互換推論サーバーは、多くの場合、OpenAI の標準 API で定義されているもの以外の追加パラメーターをサポートしています。例: これらのサーバーは、top_krepetition_penalty、または公式の OpenAI API が認識しないその他のサンプリング制御などのパラメーターを受け入れる場合があります。

extraBody オプションを使用すると、これらのサーバーに任意のパラメーターを渡すことができます。extraBody で提供されるキーと値のペアはすべて JSON リクエストの最上位レベルに含まれるため、Spring AI の OpenAI クライアントを使用しながら、サーバー固有の機能を活用できます。

extraBody パラメーターは OpenAI 互換サーバーで使用するためのものであり、公式の OpenAI API で使用するためのものではありません。公式の OpenAI API は不明なパラメーターを無視しますが、これらのパラメーターはそこでは役に立ちません。サポートされているパラメーターを確認するには、必ずサーバーのドキュメントを参照してください。

プロパティを使用した構成

Spring Boot プロパティを使用して追加パラメーターを設定できます。spring.ai.openai.chat.options.extra-body 以下の各プロパティは、リクエストの最上位パラメーターになります。

spring.ai.openai.base-url=http://localhost:8000/v1
spring.ai.openai.chat.options.model=meta-llama/Llama-3-8B-Instruct
spring.ai.openai.chat.options.temperature=0.7
spring.ai.openai.chat.options.extra-body.top_k=50
spring.ai.openai.chat.options.extra-body.repetition_penalty=1.1

この構成では、次のような JSON リクエストが生成されます。

{
  "model": "meta-llama/Llama-3-8B-Instruct",
  "temperature": 0.7,
  "top_k": 50,
  "repetition_penalty": 1.1,
  "messages": [...]
}

ビルダーを使用したランタイム構成

オプションビルダーを使用して実行時に追加のパラメーターを指定することもできます。

ChatResponse response = chatModel.call(
    new Prompt(
        "Tell me a creative story",
        OpenAiChatOptions.builder()
            .model("meta-llama/Llama-3-8B-Instruct")
            .temperature(0.7)
            .extraBody(Map.of(
                "top_k", 50,
                "repetition_penalty", 1.1,
                "frequency_penalty", 0.5
            ))
            .build()
    ));

サンプル: vLLM サーバー

Llama モデルで vLLM を実行する場合、vLLM 固有のサンプリングパラメーターを使用することをお勧めします。

spring.ai.openai.base-url=http://localhost:8000/v1
spring.ai.openai.chat.options.model=meta-llama/Llama-3-70B-Instruct
spring.ai.openai.chat.options.extra-body.top_k=40
spring.ai.openai.chat.options.extra-body.top_p=0.95
spring.ai.openai.chat.options.extra-body.repetition_penalty=1.05
spring.ai.openai.chat.options.extra-body.min_p=0.05

サポートされているサンプリングパラメーターの完全なリストについては、vLLM のドキュメント (英語) を参照してください。

サンプル: Ollama サーバー

OpenAI 互換エンドポイントを介して Ollama を使用する場合、Ollama 固有のパラメーターを渡すことができます。

OpenAiChatOptions options = OpenAiChatOptions.builder()
    .model("llama3.2")
    .extraBody(Map.of(
        "num_predict", 100,
        "top_k", 40,
        "repeat_penalty", 1.1
    ))
    .build();

ChatResponse response = chatModel.call(new Prompt("Generate text", options));

使用可能なパラメーターについては、Ollama API ドキュメント [GitHub] (英語) を参照してください。

extraBody パラメーターは任意の Map<String, Object> を受け入れるため、ターゲットサーバーがサポートするあらゆるパラメーターを渡すことができます。Spring AI はこれらのパラメーターを検証せず、サーバーに直接渡します。この設計により、多様な OpenAI 互換実装で最大限の柔軟性が実現されます。

推論モデルからの推論コンテンツ

推論モデルをサポートする一部の OpenAI 互換サーバー(DeepSeek R1、推論パーサーを備えた vLLM など)は、API レスポンスの reasoning_content フィールドを介して、モデルの内部的な思考のチェーンを公開しています。このフィールドには、モデルが最終的な答えに到達するために使用した段階的な推論プロセスが含まれています。

Spring AI は、JSON レスポンスのこのフィールドを AssistantMessage メタデータの reasoningContent キーにマッピングします。

reasoning_content の可用性に関する重要な違い:

  • OpenAI 互換サーバー (DeepSeek、vLLM): チャット補完 API レスポンスで reasoning_content を公開する ✅

  • 公式 OpenAI モデル (GPT-5、o1、o3): Chat Completions API のレスポンスに推論テキストを公開しないでください ❌

公式 OpenAI 推論モデルは、チャット補完 API の使用時に思考連鎖の内容を非表示にします。使用統計情報では reasoning_tokens カウントのみが公開されます。公式 OpenAI モデルから実際の推論テキストにアクセスするには、OpenAI の Responses API(このクライアントでは現在サポートされていない別のエンドポイント)を使用する必要があります。

フォールバック動作 reasoning_content がサーバーによって提供されない場合 (公式の OpenAI チャット補完など)、reasoningContent メタデータフィールドは空の文字列になります。

推論コンテンツへのアクセス

互換性のあるサーバーを使用する場合は、レスポンスメタデータから推論コンテンツにアクセスできます。

ChatModel を直接使用する:

// Configure to use DeepSeek R1 or vLLM with a reasoning model
ChatResponse response = chatModel.call(
    new Prompt("Which number is larger: 9.11 or 9.8?")
);

// Get the assistant message
AssistantMessage message = response.getResult().getOutput();

// Access the reasoning content from metadata
String reasoning = message.getMetadata().get("reasoningContent");
if (reasoning != null && !reasoning.isEmpty()) {
    System.out.println("Model's reasoning process:");
    System.out.println(reasoning);
}

// The final answer is in the regular content
System.out.println("\nFinal answer:");
System.out.println(message.getContent());

ChatClient の使用:

ChatClient chatClient = ChatClient.create(chatModel);

String result = chatClient.prompt()
    .user("Which number is larger: 9.11 or 9.8?")
    .call()
    .chatResponse()
    .getResult()
    .getOutput()
    .getContent();

// To access reasoning content with ChatClient, retrieve the full response
ChatResponse response = chatClient.prompt()
    .user("Which number is larger: 9.11 or 9.8?")
    .call()
    .chatResponse();

AssistantMessage message = response.getResult().getOutput();
String reasoning = message.getMetadata().get("reasoningContent");

ストリーミング推論コンテンツ

ストリーミングレスポンスを使用する場合、推論コンテンツは通常のメッセージコンテンツと同様にチャンク全体に蓄積されます。

Flux<ChatResponse> responseFlux = chatModel.stream(
    new Prompt("Solve this logic puzzle...")
);

StringBuilder reasoning = new StringBuilder();
StringBuilder answer = new StringBuilder();

responseFlux.subscribe(chunk -> {
    AssistantMessage message = chunk.getResult().getOutput();

    // Accumulate reasoning if present
    String reasoningChunk = message.getMetadata().get("reasoningContent");
    if (reasoningChunk != null) {
        reasoning.append(reasoningChunk);
    }

    // Accumulate the final answer
    if (message.getContent() != null) {
        answer.append(message.getContent());
    }
});

サンプル: DeepSeek R1

DeepSeek R1 は、内部の推論プロセスを公開する推論モデルです。

spring.ai.openai.api-key=${DEEPSEEK_API_KEY}
spring.ai.openai.base-url=https://api.deepseek.com
spring.ai.openai.chat.options.model=deepseek-reasoner

DeepSeek R1 にリクエストを送信すると、レスポンスには推論内容 (モデルの思考プロセス) と最終的な回答の両方が含まれます。

推論モデルの詳細については、DeepSeek API ドキュメント (英語) を参照してください。

サンプル: 推論パーサー付き vLLM

vLLM は、推論パーサーが設定されている場合、推論モデルをサポートします。

vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B \
    --enable-reasoning \
    --reasoning-parser deepseek_r1
spring.ai.openai.base-url=http://localhost:8000/v1
spring.ai.openai.chat.options.model=deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B

サポートされている推論モデルとパーサーについては、vLLM 推論出力のドキュメント (英語) を参照してください。

reasoning_content の利用可能性は、使用している推論サーバーによって大きく異なります。OpenAI 互換サーバーの中には、推論対応モデルを使用している場合でも、推論コンテンツを公開しないものもあります。レスポンスで利用可能なフィールドを確認するには、必ずサーバーの API ドキュメントを参照してください。