Anthropic チャット

Spring AI は、公式の Anthropic Java SDK [GitHub] (英語) を通じて Anthropic の Claude モデルをサポートし、Anthropic の API を通じて Claude へのアクセスを提供します。

前提条件

Anthropic Console (英語) でアカウントを作成し、API キーページ (英語) で API キーを生成してください。

リポジトリと BOM の追加

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

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

自動構成

Spring Boot の自動構成は、spring-ai-starter-model-anthropic スターターを介して利用可能です。

  • Maven

  • Gradle

プロジェクトの Maven pom.xml ファイルに追加してください。

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-anthropic</artifactId>
</dependency>

または、Gradle build.gradle ビルドファイルに次の内容を追加します。

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

プロパティの構成

spring.ai.anthropic.* のプロパティを使用して、Anthropic の接続とチャットオプションを設定します。

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

spring.ai.anthropic.api-key

Anthropic API キー

-

spring.ai.anthropic.base-url

API ベース URL

api.anthropic.com (英語)

spring.ai.anthropic.timeout

Anthropic クライアントのリクエストがタイムアウトしました

60s

spring.ai.anthropic.max-retries

失敗したリクエストに対する最大再試行回数

2

spring.ai.anthropic.custom-headers.*

すべての Anthropic クライアントリクエストに追加するカスタム HTTP ヘッダー

-

spring.ai.anthropic.chat.model

モデル名

claude-haiku-4-5

spring.ai.anthropic.chat.max-tokens

最大トークン数

4096

spring.ai.anthropic.chat.temperature

サンプリング温度

-

spring.ai.anthropic.chat.top-p

トップ p サンプリング

-

spring.ai.anthropic.chat.top-k

トップ k サンプリング

-

spring.ai.anthropic.chat.cache-options.strategy

使用するキャッシュ戦略

NONE

spring.ai.anthropic.chat.cache-options.multi-block-system-caching

システムメッセージごとに個別のブロックを使用する

false

spring.ai.anthropic.chat.http-headers

個々の API 呼び出しに渡すリクエストごとの HTTP ヘッダー。

-

spring.ai.anthropic.chat.inference-geo

リクエストが処理される地理的領域 (us または eu)

-

spring.ai.anthropic.chat.web-search-tool.max-uses

リクエストあたりの Web 検索の最大回数

-

spring.ai.anthropic.chat.web-search-tool.allowed-domains

検索結果を絞り込むドメインをカンマ区切りで指定します

-

spring.ai.anthropic.chat.web-search-tool.blocked-domains

検索結果から除外するドメインをカンマ区切りで指定します

-

spring.ai.anthropic.chat.web-search-tool.user-location.city

検索結果をローカライズする都市

-

spring.ai.anthropic.chat.web-search-tool.user-location.country

ISO 3166-1 アルファ 2 国コード

-

spring.ai.anthropic.chat.web-search-tool.user-location.region

領域または状態

-

spring.ai.anthropic.chat.web-search-tool.user-location.timezone

IANA タイムゾーン識別子

-

spring.ai.anthropic.chat.service-tier

容量ルーティング: auto (利用可能な場合は優先を使用)または standard_only (常に標準)。Service Tiers (英語) を参照してください。

-

手動構成

AnthropicChatModel [GitHub] (英語) は ChatModel インターフェースを実装し、公式の Anthropic Java SDK を使用して Claude に接続します。

  • Maven

  • Gradle

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

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

または、Gradle build.gradle ビルドファイルに次の内容を追加します。

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

認証

API キーは、プログラムまたは環境変数を使用して設定してください。

var chatOptions = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-20250514")
    .maxTokens(1024)
    .apiKey(System.getenv("ANTHROPIC_API_KEY"))
    .build();

var chatModel = AnthropicChatModel.builder()
    .options(chatOptions)
    .build();

または、環境変数を設定して、SDK に自動検出させることもできます。

export ANTHROPIC_API_KEY=<your-api-key>
// API key will be detected from ANTHROPIC_API_KEY environment variable
var chatModel = AnthropicChatModel.builder()
    .options(AnthropicChatOptions.builder()
        .model("claude-sonnet-4-20250514")
        .maxTokens(1024)
        .build())
    .build();

基本的な使い方

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

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

ランタイムオプション

AnthropicChatOptions.java [GitHub] (英語) クラスは、使用するモデル、温度、最大トークン数などのモデル構成を提供します。

起動時に、AnthropicChatModel.builder().defaultOptions(options).build() コンストラクターを使用してデフォルトオプションを設定します。

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

ChatResponse response = chatModel.call(
    new Prompt(
        "Generate the names of 5 famous pirates.",
        AnthropicChatOptions.builder()
            .model("claude-sonnet-4-20250514")
            .temperature(0.4)
        .build()
    ));

チャットオプション

オプション 説明 デフォルト

model

使用する Claude モデルの名前。モデルには、claude-sonnet-4-20250514claude-opus-4-20250514claude-3-5-sonnet-20241022claude-3-5-haiku-20241022 などが含まれます。Claude モデル (英語) を参照してください。

claude-sonnet-4-20250514

maxTokens

レスポンスで生成するトークンの最大数。

4096

temperature

レスポンスのランダム性を制御します。値が大きいほど出力はランダムになり、値が小さいほど決定論的になります。範囲: 0.0-1.0

1.0

topP

核サンプリングパラメーター。モデルは、top_p 確率質量を持つトークンを考慮します。Supported on Claude Opus 4.6 and earlier models only. Deprecated by Anthropic for models released after Claude Opus 4.6 (e.g. claude-opus-4-7); values < 0.99 are rejected with HTTP 400, and values >= 0.99 are accepted as a backward-compatibility no-op (no actual filtering applied)

-

topK

各トークンについて、上位 K 個のオプションからのみサンプリングします。Supported on Claude Opus 4.6 and earlier models only. Deprecated by Anthropic for models released after Claude Opus 4.6 (e.g. claude-opus-4-7); any value is rejected with HTTP 400 on those models

-

stopSequences

モデルの生成を停止させるカスタムシーケンス。

-

apiKey

認証に使用する API キー。設定されていない場合は、ANTHROPIC_API_KEY 環境変数から自動検出されます。

-

baseUrl

Anthropic API のベース URL。

api.anthropic.com (英語)

timeout

リクエストのタイムアウト期間。

60 秒

maxRetries

失敗したリクエストの最大再試行回数。

2

proxy

HTTP クライアントのプロキシ設定。

-

customHeaders

すべてのリクエストに含めるカスタム HTTP ヘッダー(クライアントレベル)。

-

httpHeaders

リクエストごとの HTTP ヘッダー。これらは MessageCreateParams.putAdditionalHeader() を介して個々の API 呼び出しに追加されます。リクエストレベルの追跡、ベータ版 API ヘッダー、ルーティングなどに便利です。

-

cacheOptions

プロンプトのキャッシュ動作を設定するためのオプション。キャッシュ戦略、マルチブロックキャッシュ、TTL(有効期限)、コンテンツ長の要件などが含まれます。

-

thinking

思考構成。便利なビルダー thinkingEnabled(budgetTokens)thinkingEnabled(budgetTokens, display)thinkingAdaptive()thinkingAdaptive(display) または thinkingDisabled() を使用するか、生の ThinkingConfigParam を渡します。display パラメーターは、レスポンスにおける思考コンテンツの表示方法を制御します。SUMMARIZED (要約) または OMITTED (編集済み、署名のみ)。

-

outputConfig

構造化出力(JSON スキーマ)および作業量制御のための出力構成。完全な制御には outputConfig(OutputConfig) を、便利なメソッドとして outputSchema(String) および effort(OutputConfig.Effort) を使用してください。claude-sonnet-4-6 以降のバージョンが必要です。

-

inferenceGeo

リクエストが処理される地理的領域を制御します。サポートされている値: useu。データ所在地のコンプライアンスに使用されます。spring.ai.anthropic.chat.inference-geo で設定可能です。

-

serviceTier

リクエストの容量ルーティングを制御します。優先容量を状況に応じて使用するには MessageCreateParams.ServiceTier.AUTO を、常に標準容量を使用するには STANDARD_ONLY を使用します。Service Tiers (英語) を参照してください。

-

ツール呼び出しオプション

オプション 説明 デフォルト

toolChoice

モデルが呼び出すツール(存在する場合)を制御します。ToolChoiceAutoToolChoiceAnyToolChoiceTool または ToolChoiceNone を使用してください。

AUTO

toolCallbacks

モデルに登録するツールコールバックの一覧。

-

disableParallelToolUse

この条件が満たされる場合、モデルはレスポンスごとに最大 1 つのツールを使用します。

false

モデル固有の AnthropicChatOptions [GitHub] (英語) に加えて、ChatOptions#builder() [GitHub] (英語) で作成されたポータブルな ChatOptions [GitHub] (英語) インスタンスを使用することもできます。

レート制限メタデータ

The Anthropic API includes rate limit headers (英語) on every response that report your current request and token budgets along with when each window resets. Spring AI exposes this data through the standard ChatResponseMetadata#getRateLimit() accessor, which returns an AnthropicRateLimit populated from the response headers.

ポータブルな RateLimit インターフェースは、以下のリクエストおよびトークンファミリーを公開します。

ChatResponse response = chatModel.call(prompt);

RateLimit rateLimit = response.getMetadata().getRateLimit();
rateLimit.getRequestsLimit();      // overall request ceiling
rateLimit.getRequestsRemaining();  // requests left in the current window
rateLimit.getRequestsReset();      // time until the request window resets

rateLimit.getTokensLimit();        // overall token ceiling
rateLimit.getTokensRemaining();    // tokens left in the current window
rateLimit.getTokensReset();        // time until the token window resets

Anthropic は、入力トークンと出力トークン用に別々のバケットも報告します。これらは、AnthropicRateLimit という具象型によって公開されます。

if (response.getMetadata().getRateLimit() instanceof AnthropicRateLimit anthropic) {
    anthropic.getInputTokensLimit();
    anthropic.getInputTokensRemaining();
    anthropic.getInputTokensReset();

    anthropic.getOutputTokensLimit();
    anthropic.getOutputTokensRemaining();
    anthropic.getOutputTokensReset();
}

Anthropic が特定のレスポンスに対してレート制限ヘッダーを返さない場合、getRateLimit() は代わりに EmptyRateLimit インスタンスを返します。これは、他の Spring AI プロバイダーが使用する慣例に合致しています。

レート制限メタデータは、同期型の call(Prompt) パスとストリーミング型の stream(Prompt) パスの両方に設定されます。ストリーミングレスポンスの場合、ヘッダーはストリーム開始時に一度読み取られ、最終的な使用状況を示すレスポンスチャンクに付加されるため、getRateLimit() はそこで設定済みの AnthropicRateLimit に解決されます。

レスポンスヘッダーを読み取るために、ストリーミングパスは Schedulers.boundedElastic() ワーカー上で Anthropic SDK のブロッキングストリームを消費するため、ストリーミング呼び出しはストリームの期間中、ワーカースレッドを保持します。

ツール呼び出し

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

AnthropicChatModel はツール呼び出しを内部的に実行しません。ツール実行は、サポートされている 2 つの方法のいずれかを使用して外部で処理する必要があります。

  • ChatClient と ToolCallingAdvisor — ほとんどのユースケースにおいて推奨されるアプローチです。ToolCallingAdvisor は自動的に登録され、ツール呼び出しループを透過的に管理します。

  • ユーザー制御によるツール実行 — ループを完全に制御する必要がある場合(たとえば、ツール呼び出しとプロンプトキャッシュを組み合わせる場合など)は、DefaultToolCallingManager を直接使用してください。

同期ツール実行とストリーミングツール実行の両方で、ChatClient と ToolCallingAdvisor を併用してください。ツールが存在する場合、ToolCallingAdvisor は自動的に登録されるため、アドバイザーの明示的な設定は不要です。

ToolCallback weatherCallback = FunctionToolCallback.builder("getCurrentWeather", new WeatherService())
    .description("Get the weather in location")
    .inputType(WeatherService.Request.class)
    .build();

// Synchronous
String response = ChatClient.create(chatModel)
    .prompt()
    .user("What's the weather in Paris, Tokyo, and New York?")
    .tools(weatherCallback)
    .call()
    .content();

// Streaming
Flux<String> stream = ChatClient.create(chatModel)
    .prompt()
    .user("What's the weather in Paris, Tokyo, and New York?")
    .tools(weatherCallback)
    .stream()
    .content();

ユーザー制御ツールの実行

Use this pattern when you need direct access to the ChatModel API — for example, when combining tool calling with prompt caching. Invoke ChatModel directly without ToolCallingAdvisor; check for tool calls yourself and drive the loop using ToolCallingManager.

ToolCallingManager toolCallingManager = ToolCallingManager.builder().build();

AnthropicChatOptions options = AnthropicChatOptions.builder()
    .toolCallbacks(ToolCallbacks.from(new WeatherService()))
    .build();

Prompt prompt = new Prompt("What's the weather in Paris, Tokyo, and New York?", options);
ChatResponse response = chatModel.call(prompt);

while (response.hasToolCalls()) {
    ToolExecutionResult result = toolCallingManager.executeToolCalls(prompt, response);
    prompt = new Prompt(result.conversationHistory(), options);
    response = chatModel.call(prompt);
}

ストリーミングの場合、各ストリーミングレスポンスを MessageAggregator で集約して、チャンクをまたいだツール呼び出しを検出します。

AtomicReference<ChatResponse> aggregatedRef = new AtomicReference<>();
new MessageAggregator()
    .aggregate(chatModel.stream(prompt), aggregatedRef::set)
    .collectList().block();

while (aggregatedRef.get().hasToolCalls()) {
    ToolExecutionResult result = toolCallingManager.executeToolCalls(prompt, aggregatedRef.get());
    prompt = new Prompt(result.conversationHistory(), options);
    aggregatedRef.set(null);
    new MessageAggregator()
        .aggregate(chatModel.stream(prompt), aggregatedRef::set)
        .collectList().block();
}

String content = aggregatedRef.get().getResult().getOutput().getText();

ツール選択オプション

toolChoice オプションを使用して、Claude が選択するツールを制御します。

import com.anthropic.models.messages.ToolChoiceAny;
import com.anthropic.models.messages.ToolChoiceTool;
import com.anthropic.models.messages.ToolChoiceNone;

// Force Claude to use any available tool
var options = AnthropicChatOptions.builder()
    .toolChoice(ToolChoiceAny.builder().build())
    .toolCallbacks(...)
    .build();

// Force Claude to use a specific tool
var options = AnthropicChatOptions.builder()
    .toolChoice(ToolChoiceTool.builder().name("getCurrentWeather").build())
    .toolCallbacks(...)
    .build();

// Prevent tool use entirely
var options = AnthropicChatOptions.builder()
    .toolChoice(ToolChoiceNone.builder().build())
    .toolCallbacks(...)
    .build();

Anthropic Java SDK は、一般的なツール選択に対応した便利な静的ファクトリメソッドを提供しており、コードをより簡潔に記述できます。

  • ToolChoice.auto() は ToolChoice.ofAuto(…​) の代わりに使用できます。

  • ToolChoice.any() は ToolChoice.ofAny(…​) の代わりに使用できます。

  • ToolChoice.none() は ToolChoice.ofNone(…​) の代わりに使用できます。

ストリーミング

Anthropic SDK モジュールは、同期レスポンスとストリーミングレスポンスの両方をサポートしています。ストリーミング機能により、Claude はレスポンスが生成されるたびに段階的にレスポンスを返すことができます。

Flux<ChatResponse> stream = chatModel.stream(new Prompt("Tell me a story"));

stream.subscribe(response -> {
    String content = response.getResult().getOutput().getContent();
    if (content != null) {
        System.out.print(content);
    }
});

拡張的思考

Anthropic および Claude モデルは、「思考」機能をサポートしており、最終的な回答を出す前に推論プロセスを表示できます。これは、数学、論理、分析などの段階的な推論を必要とする複雑な問題に特に役立ちます。

対応モデル

思考機能は、次の Claude モデルでサポートされています。

  • Claude 4 モデル (claude-opus-4-20250514claude-sonnet-4-20250514)

  • Claude 3.7 ソネット (claude-3-7-sonnet-20250219)

モデルの機能:

  • Claude 3.7 ソネット : 思考過程の全文を返します。

  • Claude 4 モデル : 要約された思考とツール統合の強化をサポートします。

API リクエスト構造はサポートされているすべてのモデルで同じですが、出力動作は異なります。

思考構成

思考を促すために、以下の設定を行ってください。

  1. Set a thinking budgetbudgetTokens は 1024 以上で、maxTokens 未満でなければなりません。

  2. Set temperature to 1.0 : 思考が可能な状況では必須です。

利便性を高めるビルド方法

AnthropicChatOptions.Builder は、構成を考えるための便利なメソッドを提供します。

// Enable thinking with a specific token budget
var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-20250514")
    .temperature(1.0)
    .maxTokens(16000)
    .thinkingEnabled(10000L)    // budget must be >= 1024 and < maxTokens
    .build();

// Let Claude adaptively decide whether to think
var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-20250514")
    .thinkingAdaptive()
    .build();

// Explicitly disable thinking
var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-20250514")
    .thinkingDisabled()
    .build();

生の SDK である ThinkingConfigParam を直接使用することもできます。

import com.anthropic.models.messages.ThinkingConfigParam;
import com.anthropic.models.messages.ThinkingConfigEnabled;

var options = AnthropicChatOptions.builder()
    .thinking(ThinkingConfigParam.ofEnabled(
        ThinkingConfigEnabled.builder().budgetTokens(10000L).build()))
    .build();

思考表示設定

デフォルトでは、思考プロセスの全出力がレスポンスに返されます。トークンコストを削減するには、display パラメーターを使用してこれを制御できます。

  • SUMMARIZED — Claude は思考プロセスを完全に把握しつつも、生の思考の流れではなく、簡潔な要約を返します。出力トークン数を削減しながらも、推論の根拠となる情報を提供します。

  • OMITTED — 思考プロセスは実行されるが、レスポンスからは完全に削除されます。返されるのは暗号署名のみである(複数ターンの継続性を確保するために必要)。出力トークンコストは最小となる。

import com.anthropic.models.messages.ThinkingConfigEnabled;
import com.anthropic.models.messages.ThinkingConfigAdaptive;

// Enabled thinking with summarized display
var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-20250514")
    .temperature(1.0)
    .maxTokens(16000)
    .thinkingEnabled(10000L, ThinkingConfigEnabled.Display.SUMMARIZED)
    .build();

// Enabled thinking with omitted display
var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-20250514")
    .temperature(1.0)
    .maxTokens(16000)
    .thinkingEnabled(10000L, ThinkingConfigEnabled.Display.OMITTED)
    .build();

// Adaptive thinking with summarized display
var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-20250514")
    .temperature(1.0)
    .maxTokens(16000)
    .thinkingAdaptive(ThinkingConfigAdaptive.Display.SUMMARIZED)
    .build();
表示設定は最終的な回答の質には影響しません。Claude は設定に関係なく同じ量の思考処理を行います。表示設定は、回答として返される思考内容のみを制御します。

非ストリーミングの例

var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-20250514")
    .temperature(1.0)
    .maxTokens(16000)
    .thinkingEnabled(10000L)
    .build();

ChatResponse response = chatModel.call(
    new Prompt("Are there an infinite number of prime numbers such that n mod 4 == 3?", options));

// The response contains multiple generations:
// - ThinkingBlock generations (with "signature" in metadata)
// - TextBlock generations (with the final answer)
for (Generation generation : response.getResults()) {
    AssistantMessage message = generation.getOutput();
    if (message.getMetadata().containsKey("signature")) {
        // This is a thinking block - contains Claude's reasoning
        System.out.println("Thinking: " + message.getText());
        System.out.println("Signature: " + message.getMetadata().get("signature"));
    }
    else if (message.getMetadata().containsKey("data")) {
        // This is a redacted thinking block (safety-redacted reasoning)
        System.out.println("Redacted thinking data: " + message.getMetadata().get("data"));
    }
    else if (message.getText() != null && !message.getText().isBlank()) {
        // This is the final text response
        System.out.println("Answer: " + message.getText());
    }
}

ストリーミングの例

思考機能はストリーミングモードで完全にサポートされています。思考デルタとシグネチャーデルタは到着次第送信されます。

var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-20250514")
    .temperature(1.0)
    .maxTokens(16000)
    .thinkingEnabled(10000L)
    .build();

Flux<ChatResponse> stream = chatModel.stream(
    new Prompt("Are there an infinite number of prime numbers such that n mod 4 == 3?", options));

stream.subscribe(response -> {
    Generation generation = response.getResult();
    AssistantMessage message = generation.getOutput();

    if (message.getMetadata().containsKey("thinking")) {
        // Incremental thinking content
        System.out.print(message.getText());
    }
    else if (message.getMetadata().containsKey("signature")) {
        // Thinking block signature (emitted at end of thinking)
        System.out.println("\nSignature: " + message.getMetadata().get("signature"));
    }
    else if (message.getText() != null) {
        // Final text content
        System.out.print(message.getText());
    }
});

レスポンス構造

思考機能が有効になっている場合、レスポンスにはさまざまな種類のコンテンツが含まれます。

コンテンツタイプ メタデータキー 説明

思考の行き詰まり

signature

Claude の推論テキストと暗号署名。同期モードでは、推論テキストは getText() に、署名は getMetadata().get("signature") に格納されます。

編集された思考

data

安全上の理由により、説明文は伏せられています。data マーカーのみが含まれており、テキストは表示されません。

シグネチャー (streaming)

signature

ストリーミングモードでは、署名は思考ブロックの最後に個別の差分として届きます。

デルタについて考える (streaming)

thinking

ストリーミング中のテキストチャンクの漸進的思考。thinking メタデータキーは true に設定されます。

テキストブロック

(なし)

getText() の最終解答テキスト。

マルチモーダルサポート

Anthropic SDK モジュールはマルチモーダル入力をサポートしており、プロンプトにテキストとともにイメージや PDF ドキュメントを送信できます。

イメージ入力

Media クラスを使用して解析を行うため、イメージを Claude に送信してください。

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

var userMessage = UserMessage.builder()
    .text("What do you see in this image?")
    .media(List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageResource)))
    .build();

ChatResponse response = chatModel.call(new Prompt(List.of(userMessage)));

対応イメージフォーマット: PNG、JPEG、GIF、WebP。イメージは以下の形式で提供できます。

  • Byte 配列 (automatically base64-encoded)

  • HTTPS URL (passed directly to the API)

PDF ドキュメント入力

Claude が分析するための PDF ドキュメントを送信してください。

var pdfResource = new ClassPathResource("/document.pdf");

var userMessage = UserMessage.builder()
    .text("Please summarize this document.")
    .media(List.of(new Media(new MimeType("application", "pdf"), pdfResource)))
    .build();

ChatResponse response = chatModel.call(new Prompt(List.of(userMessage)));

Multiple Media Items

You can include multiple images or documents in a single message:

var userMessage = UserMessage.builder()
    .text("Compare these two images.")
    .media(List.of(
        new Media(MimeTypeUtils.IMAGE_PNG, image1Resource),
        new Media(MimeTypeUtils.IMAGE_PNG, image2Resource)))
    .build();

引用

Anthropic の引用 API (英語) により、Claude はレスポンスを生成する際に、提供されたドキュメントの特定の部分を参照できます。プロンプトに引用ドキュメントが含まれている場合、Claude はソース資料を引用することができ、引用メタデータ(文字範囲、ページ番号、コンテンツブロック)がレスポンスメタデータに返されます。

引用は次のような改善に役立ちます:

  • 精度検証 : ユーザーは Claude の回答をソース資料と照らし合わせて検証できる

  • 透過性 : 回答の根拠となったドキュメントの正確な部分を確認する

  • 準拠 : 規制対象産業における情報源帰属の要件を満たす

  • 信頼 : 情報の出所を示すことで信頼を築く

対応モデル

引用は、Claude 3.7 Sonnet および Claude 4 モデル (Opus および Sonnet) でサポートされています。

ドキュメントタイプ

3 種類の引用ドキュメントがサポートされています。

  • プレーンテキスト : 文字レベルの引用を含むテキストコンテンツ

  • PDF : ページレベルの引用を含む PDF ドキュメント

  • カスタムコンテンツ : ブロックレベルの引用を含むユーザー定義のコンテンツブロック

引用ドキュメントの作成

AnthropicCitationDocument ビルダーを使用して、引用可能なドキュメントを作成します。

プレーンテキストドキュメント

AnthropicCitationDocument document = AnthropicCitationDocument.builder()
    .plainText("The Eiffel Tower was completed in 1889 in Paris, France. " +
               "It stands 330 meters tall and was designed by Gustave Eiffel.")
    .title("Eiffel Tower Facts")
    .citationsEnabled(true)
    .build();

PDF ドキュメント

// From file path
AnthropicCitationDocument document = AnthropicCitationDocument.builder()
    .pdfFile("path/to/document.pdf")
    .title("Technical Specification")
    .citationsEnabled(true)
    .build();

// From byte array
byte[] pdfBytes = loadPdfBytes();
AnthropicCitationDocument document = AnthropicCitationDocument.builder()
    .pdf(pdfBytes)
    .title("Product Manual")
    .citationsEnabled(true)
    .build();

カスタムコンテンツブロック

きめ細かな引用制御を行うには、カスタムコンテンツブロックを使用します。

AnthropicCitationDocument document = AnthropicCitationDocument.builder()
    .customContent(
        "The Great Wall of China is approximately 21,196 kilometers long.",
        "It was built over many centuries, starting in the 7th century BC.",
        "The wall was constructed to protect Chinese states from invasions."
    )
    .title("Great Wall Facts")
    .citationsEnabled(true)
    .build();

リクエストでの引用の使用

チャットオプションに引用ドキュメントを含めます。

ChatResponse response = chatModel.call(
    new Prompt(
        "When was the Eiffel Tower built and how tall is it?",
        AnthropicChatOptions.builder()
            .model("claude-sonnet-4-20250514")
            .maxTokens(1024)
            .citationDocuments(document)
            .build()
    )
);

複数のドキュメント

Claude が参照できるドキュメントを複数提供できます。

AnthropicCitationDocument parisDoc = AnthropicCitationDocument.builder()
    .plainText("Paris is the capital city of France with a population of 2.1 million.")
    .title("Paris Information")
    .citationsEnabled(true)
    .build();

AnthropicCitationDocument eiffelDoc = AnthropicCitationDocument.builder()
    .plainText("The Eiffel Tower was designed by Gustave Eiffel for the 1889 World's Fair.")
    .title("Eiffel Tower History")
    .citationsEnabled(true)
    .build();

ChatResponse response = chatModel.call(
    new Prompt(
        "What is the capital of France and who designed the Eiffel Tower?",
        AnthropicChatOptions.builder()
            .model("claude-sonnet-4-20250514")
            .citationDocuments(parisDoc, eiffelDoc)
            .build()
    )
);

引用へのアクセス

引用はレスポンスメタデータで返されます。

ChatResponse response = chatModel.call(prompt);

// Get citations from metadata
List<Citation> citations = (List<Citation>) response.getMetadata().get("citations");

// Optional: Get citation count directly from metadata
Integer citationCount = (Integer) response.getMetadata().get("citationCount");
System.out.println("Total citations: " + citationCount);

// Process each citation
for (Citation citation : citations) {
    System.out.println("Document: " + citation.getDocumentTitle());
    System.out.println("Location: " + citation.getLocationDescription());
    System.out.println("Cited text: " + citation.getCitedText());
    System.out.println("Document index: " + citation.getDocumentIndex());
    System.out.println();
}

引用の種類

引用には、ドキュメントの種類に応じて異なる場所の情報が含まれます。

キャラクターの位置 (プレーンテキスト)

プレーンテキストドキュメントの場合、引用には文字インデックスが含まれます。

Citation citation = citations.get(0);
if (citation.getType() == Citation.LocationType.CHAR_LOCATION) {
    int start = citation.getStartCharIndex();
    int end = citation.getEndCharIndex();
    String text = citation.getCitedText();
    System.out.println("Characters " + start + "-" + end + ": " + text);
}

ページの場所 (PDF)

PDF ドキュメントの場合、引用にはページ番号が含まれます。

Citation citation = citations.get(0);
if (citation.getType() == Citation.LocationType.PAGE_LOCATION) {
    int startPage = citation.getStartPageNumber();
    int endPage = citation.getEndPageNumber();
    System.out.println("Pages " + startPage + "-" + endPage);
}

コンテンツブロックの場所 (カスタムコンテンツ)

カスタムコンテンツの場合、引用は特定のコンテンツブロックを参照します。

Citation citation = citations.get(0);
if (citation.getType() == Citation.LocationType.CONTENT_BLOCK_LOCATION) {
    int startBlock = citation.getStartBlockIndex();
    int endBlock = citation.getEndBlockIndex();
    System.out.println("Content blocks " + startBlock + "-" + endBlock);
}

完全な例

引用の使用箇所を示す完全な例を以下に示します。

// Create a citation document
AnthropicCitationDocument document = AnthropicCitationDocument.builder()
    .plainText("Spring AI is an application framework for AI engineering. " +
               "It provides a Spring-friendly API for developing AI applications. " +
               "The framework includes abstractions for chat models, embedding models, " +
               "and vector databases.")
    .title("Spring AI Overview")
    .citationsEnabled(true)
    .build();

// Call the model with the document
ChatResponse response = chatModel.call(
    new Prompt(
        "What is Spring AI?",
        AnthropicChatOptions.builder()
            .model("claude-sonnet-4-20250514")
            .maxTokens(1024)
            .citationDocuments(document)
            .build()
    )
);

// Display the response
System.out.println("Response: " + response.getResult().getOutput().getText());
System.out.println("\nCitations:");

// Process citations
List<Citation> citations = (List<Citation>) response.getMetadata().get("citations");

if (citations != null && !citations.isEmpty()) {
    for (int i = 0; i < citations.size(); i++) {
        Citation citation = citations.get(i);
        System.out.println("\n[" + (i + 1) + "] " + citation.getDocumentTitle());
        System.out.println("    Location: " + citation.getLocationDescription());
        System.out.println("    Text: " + citation.getCitedText());
    }
} else {
    System.out.println("No citations were provided in the response.");
}

ベストプラクティス

  1. 説明的なタイトルを使用する : ユーザーが引用内のソースを識別できるように、引用ドキュメントに意味のあるタイトルを付けます。

  2. null 引用をチェックする : すべてのレスポンスに引用が含まれるわけではないため、アクセスする前に引用のメタデータが存在することを必ず検証してください。

  3. ドキュメントサイズを考慮する : ドキュメントが大きいほどコンテキストは多くなりますが、消費される入力トークンも多くなり、レスポンス時間に影響する可能性があります。

  4. 複数のドキュメントを活用する : 複数のソースにまたがる質問に答える場合は、複数回呼び出すのではなく、1 回のリクエストですべての関連ドキュメントを提供してください。

  5. 適切なドキュメント型を使用する : シンプルなコンテンツにはプレーンテキスト、既存のドキュメントには PDF、引用の粒度を細かく制御する必要がある場合はカスタムコンテンツブロックを選択します。

引用ドキュメントオプション

コンテキストフィールド

必要に応じて、引用はされないものの、Claude の理解を手助けするドキュメントのコンテキストを提供します。

AnthropicCitationDocument document = AnthropicCitationDocument.builder()
    .plainText("...")
    .title("Legal Contract")
    .context("This is a merger agreement dated January 2024 between Company A and Company B")
    .build();

引用の制御

デフォルトでは、すべてのドキュメントの引用は無効になっています(オプトイン動作)。引用を有効にするには、明示的に citationsEnabled(true) を設定します。

AnthropicCitationDocument document = AnthropicCitationDocument.builder()
    .plainText("The Eiffel Tower was completed in 1889...")
    .title("Historical Facts")
    .citationsEnabled(true)  // Explicitly enable citations for this document
    .build();

背景コンテキストについては、引用のないドキュメントを提供することもできます。

AnthropicCitationDocument backgroundDoc = AnthropicCitationDocument.builder()
    .plainText("Background information about the industry...")
    .title("Context Document")
    // citationsEnabled defaults to false - Claude will use this but not cite it
    .build();

Anthropic では、リクエスト内のすべてのドキュメントで一貫した引用設定が必要です。引用が有効になっているドキュメントと無効になっているドキュメントを同じリクエストに混在させることはできません。

プロンプトキャッシュ

Anthropic’s プロンプトキャッシュ (英語) reduces costs and latency by caching repeated context across API calls. The Anthropic SDK module supports prompt caching with configurable strategies, TTL, and per-message-type settings.

Caching Strategies

Five caching strategies are available via AnthropicCacheStrategy:

戦略 説明

NONE

No caching (default). No cache control headers are added.

SYSTEM_ONLY

Cache system message content. Uses 1 cache breakpoint.

TOOLS_ONLY

Cache tool definitions only. Uses 1 cache breakpoint.

SYSTEM_AND_TOOLS

Cache both system messages and tool definitions. Uses 2 cache breakpoints.

CONVERSATION_HISTORY

Cache system messages, tool definitions, and conversation messages. Uses up to 4 cache breakpoints.

Anthropic allows a maximum of 4 cache breakpoints per request. The implementation tracks breakpoint usage and stops adding cache control once the limit is reached.

基本的な使い方

var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-20250514")
    .maxTokens(1024)
    .cacheOptions(AnthropicCacheOptions.builder()
        .strategy(AnthropicCacheStrategy.SYSTEM_ONLY)
        .build())
    .build();

ChatResponse response = chatModel.call(
    new Prompt(List.of(
        new SystemMessage("You are an expert assistant with deep domain knowledge..."),
        new UserMessage("What is the capital of France?")),
        options));

Cache Configuration Options

AnthropicCacheOptions provides fine-grained control over caching behavior:

var cacheOptions = AnthropicCacheOptions.builder()
    .strategy(AnthropicCacheStrategy.SYSTEM_AND_TOOLS)
    .messageTypeTtl(MessageType.SYSTEM, AnthropicCacheTtl.ONE_HOUR)     // 1 hour TTL
    .messageTypeMinContentLength(MessageType.SYSTEM, 100)                   // Min 100 chars
    .multiBlockSystemCaching(true)                                          // Per-block caching
    .build();
オプション 説明 デフォルト

strategy

The caching strategy to use.

NONE

messageTypeTtl

TTL per message type. Available values: FIVE_MINUTESONE_HOUR.

FIVE_MINUTES for all types

messageTypeMinContentLength

Minimum content length required before caching a message type.

1

contentLengthFunction

Custom function to compute content length (e.g., token counting).

String::length

multiBlockSystemCaching

When true, each system message becomes a separate cacheable block; cache control is applied to the second-to-last block (static prefix pattern). When false, all system messages are joined into one block.

false

cacheToolResults

When true, a cache breakpoint is placed on the last tool result message of a request so tool outputs are cached across tool-calling rounds. Takes effect with CONVERSATION_HISTORY.

false

Caching Tool Results

When a turn triggers tool calls, each round appends an assistant tool_use message and a user tool_result message, and the growing history is sent back to Anthropic on every round. By default the CONVERSATION_HISTORY breakpoint lands on the last user message, so tool results — which are appended after it — fall outside every breakpoint and are billed as uncached input on each round. This is wasteful when tool outputs are large.

Enable cacheToolResults to place a breakpoint on the last tool result block of the request. On the next round Anthropic reads the previous round’s tool results from cache instead of reprocessing them:

var cacheOptions = AnthropicCacheOptions.builder()
    .strategy(AnthropicCacheStrategy.CONVERSATION_HISTORY)
    .cacheToolResults(true)
    .build();

The breakpoint moves to the latest tool result on each round, so the previous rounds' tool outputs are read from cache while the newest is written. This consumes one additional cache breakpoint (Anthropic allows up to four per request), leaving room for the tool, system, and last-user breakpoints under CONVERSATION_HISTORY. The TTL and minimum content length are configurable via messageTypeTtl(MessageType.TOOL, …​) and messageTypeMinContentLength(MessageType.TOOL, …​).

Multi-Block System Caching

When you have both a static system prompt and dynamic instructions, use multi-block system caching to cache only the static portion:

var cacheOptions = AnthropicCacheOptions.builder()
    .strategy(AnthropicCacheStrategy.SYSTEM_ONLY)
    .multiBlockSystemCaching(true)
    .build();

ChatResponse response = chatModel.call(
    new Prompt(List.of(
        new SystemMessage("You are an expert knowledge base assistant..."),  // Static (cached)
        new SystemMessage("Today's date is 2025-02-23. User timezone: PST"), // Dynamic
        new UserMessage("What are the latest updates?")),
        AnthropicChatOptions.builder()
            .model("claude-sonnet-4-20250514")
            .cacheOptions(cacheOptions)
            .build()));

Spring Boot の設定

Configure prompt caching via application.properties or application.yml:

spring.ai.anthropic.chat.cache-options.strategy=SYSTEM_AND_TOOLS
spring.ai.anthropic.chat.cache-options.multi-block-system-caching=true

Accessing Cache Token Usage

Cache token metrics are available through the native SDK Usage object:

ChatResponse response = chatModel.call(prompt);

com.anthropic.models.messages.Usage sdkUsage =
    (com.anthropic.models.messages.Usage) response.getMetadata().getUsage().getNativeUsage();
long cacheCreation = sdkUsage.cacheCreationInputTokens().orElse(0L);
long cacheRead = sdkUsage.cacheReadInputTokens().orElse(0L);

System.out.println("Cache creation tokens: " + cacheCreation);
System.out.println("Cache read tokens: " + cacheRead);

On the first request, cacheCreationInputTokens will be non-zero (tokens written to cache). On subsequent requests with the same cached prefix, cacheReadInputTokens will be non-zero (tokens read from cache at reduced cost).

会話履歴のキャッシュ

The CONVERSATION_HISTORY strategy caches the entire conversation context, including system messages, tool definitions, and the last user message. This is useful for multi-turn conversations where the growing context would otherwise be re-processed on every request:

var cacheOptions = AnthropicCacheOptions.builder()
    .strategy(AnthropicCacheStrategy.CONVERSATION_HISTORY)
    .build();

var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-20250514")
    .cacheOptions(cacheOptions)
    .build();

// First turn
ChatResponse response1 = chatModel.call(
    new Prompt(List.of(
        new SystemMessage("You are a helpful assistant."),
        new UserMessage("What is machine learning?")),
        options));

// Second turn - previous context is cached
ChatResponse response2 = chatModel.call(
    new Prompt(List.of(
        new SystemMessage("You are a helpful assistant."),
        new UserMessage("What is machine learning?"),
        new AssistantMessage(response1.getResult().getOutput().getText()),
        new UserMessage("Can you give me an example?")),
        options));

構造化された出力

Structured output constrains Claude to produce responses conforming to a JSON schema. The Anthropic SDK module also supports Anthropic’s effort control for tuning response quality vs speed.

Model Requirement

Structured output and effort control require claude-sonnet-4-6 or newer. Older models like claude-sonnet-4-20250514 do not support these features.

Schema Requirements

When using JSON schema output, Anthropic requires "additionalProperties": false for all object types in the schema.

JSON Schema Output

Constrain Claude’s responses to a specific JSON schema using the outputSchema convenience method:

var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-6")
    .outputSchema("""
        {
            "type": "object",
            "properties": {
                "name": {"type": "string"},
                "capital": {"type": "string"},
                "population": {"type": "integer"}
            },
            "required": ["name", "capital"],
            "additionalProperties": false
        }
        """)
    .build();

ChatResponse response = chatModel.call(new Prompt("Tell me about France.", options));
// Response text will be valid JSON conforming to the schema

Effort Control

Control how much compute Claude spends on its response. Lower effort means faster, cheaper responses; higher effort means more thorough reasoning.

Effort Level 説明

LOW

Fast and concise responses with minimal reasoning

MEDIUM

Balanced trade-off between speed and thoroughness

HIGH

More thorough reasoning and detailed responses

MAX

Maximum compute for the most thorough possible responses

var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-6")
    .effort(OutputConfig.Effort.LOW)
    .build();

ChatResponse response = chatModel.call(new Prompt("What is the capital of France?", options));

Combined Schema and Effort

You can combine JSON schema output with effort control:

var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-6")
    .outputSchema("""
        {
            "type": "object",
            "properties": {
                "answer": {"type": "integer"},
                "explanation": {"type": "string"}
            },
            "required": ["answer", "explanation"],
            "additionalProperties": false
        }
        """)
    .effort(OutputConfig.Effort.HIGH)
    .build();

ChatResponse response = chatModel.call(
    new Prompt("What is 15 * 23? Show your reasoning.", options));

Direct OutputConfig

For full control, use the SDK’s OutputConfig directly:

import com.anthropic.models.messages.OutputConfig;
import com.anthropic.models.messages.JsonOutputFormat;
import com.anthropic.core.JsonValue;

var outputConfig = OutputConfig.builder()
    .effort(OutputConfig.Effort.HIGH)
    .format(JsonOutputFormat.builder()
        .schema(JsonOutputFormat.Schema.builder()
            .putAdditionalProperty("type", JsonValue.from("object"))
            .putAdditionalProperty("properties", JsonValue.from(Map.of(
                "name", Map.of("type", "string"))))
            .putAdditionalProperty("additionalProperties", JsonValue.from(false))
            .build())
        .build())
    .build();

var options = AnthropicChatOptions.builder()
    .model("claude-sonnet-4-6")
    .outputConfig(outputConfig)
    .build();

ChatResponse response = chatModel.call(new Prompt("Tell me about France.", options));

StructuredOutputChatOptions インターフェース

AnthropicChatOptions implements the StructuredOutputChatOptions interface, which provides portable getOutputSchema() method. This allows structured output to work with Spring AI’s generic structured output infrastructure.

Service Tier

Anthropic offers different service tiers (英語) that control capacity routing for API requests. You can use AnthropicServiceTier.AUTO to opportunistically use priority capacity (lower latency) when available, or STANDARD_ONLY to always use standard capacity.

Via Spring Boot properties:

spring.ai.anthropic.chat.service-tier=auto

Or programmatically per-request:

var options = AnthropicChatOptions.builder()
    .serviceTier(AnthropicServiceTier.AUTO)
    .build();

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

Per-Request HTTP Headers

The Anthropic SDK module supports per-request HTTP headers, which are injected into individual API calls. This is distinct from customHeaders (which are set at the client level for all requests).

Per-request headers are useful for:

  • Request tracking : Adding correlation IDs or trace headers per request

  • Beta API access : Including beta feature headers for specific requests

  • ルーティング : Adding routing or priority headers for load balancing

var options = AnthropicChatOptions.builder()
    .httpHeaders(Map.of(
        "X-Request-Id", "req-12345",
        "X-Custom-Tracking", "my-tracking-value"))
    .build();

ChatResponse response = chatModel.call(new Prompt("Hello", options));
httpHeaders are per-request and set via MessageCreateParams.putAdditionalHeader(). They do not affect other requests. For headers that should apply to all requests, use customHeaders instead.

サンプルコントローラー

Here is an example of a simple @RestController class that uses the chat model for text generations:

@RestController
public class ChatController {

    private final AnthropicChatModel chatModel;

    public ChatController() {
        var options = AnthropicChatOptions.builder()
            .model("claude-sonnet-4-20250514")
            .maxTokens(1024)
            .apiKey(System.getenv("ANTHROPIC_API_KEY"))
            .build();
        this.chatModel = AnthropicChatModel.builder()
            .options(options)
            .build();
    }

    @GetMapping("/ai/generate")
    public Map<String, String> generate(
            @RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of("generation", 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 chatModel.stream(prompt);
    }
}

Accessing the Raw Response

The full Anthropic SDK Message object is available in the response metadata under the "anthropic-response" key. This provides access to any fields not explicitly mapped by Spring AI’s abstraction:

ChatResponse response = chatModel.call(new Prompt("Hello"));

com.anthropic.models.messages.Message rawMessage =
    (com.anthropic.models.messages.Message) response.getMetadata().get("anthropic-response");

// Access native SDK fields
rawMessage.stopReason();    // Optional<StopReason>
rawMessage.content();       // List<ContentBlock>
rawMessage.usage();         // Usage with cache token details
The raw response is available for synchronous calls only. Streaming responses do not include it.

スキル

Anthropic’s スキル API (英語) extends Claude’s capabilities with specialized, pre-packaged abilities for document generation. Skills enable Claude to create actual downloadable files — Excel spreadsheets, PowerPoint presentations, Word documents, and PDFs — rather than just describing what these documents might contain.

対応モデル

スキルは、Claude Sonnet 4、Claude Sonnet 4.5、Claude Opus 4 以降のモデルでサポートされています。

要件

  • スキルにはコード実行機能が必要 (automatically enabled by Spring AI when skills are configured)

  • リクエストごとに最大 8 つのスキル

  • 生成されたファイルは、ファイル API 経由で 24 時間ダウンロードできます。

プリビルド Anthropic スキル

Spring AI は、AnthropicSkill 列挙型を通じて Anthropic の事前構築されたスキルへの型安全なアクセスを提供します。

スキル 説明 生成されたファイルの種類

XLSX

Excel スプレッドシートの生成と操作

.xlsx (Microsoft Excel)

PPTX

PowerPoint プレゼンテーション作成

.pptx (Microsoft PowerPoint)

DOCX

Word ドキュメントの生成

.docx (Microsoft Word)

PDF

PDF ドキュメントの作成

.pdf (Portable Document Format)

基本的な使い方

Enable skills by adding them to your AnthropicChatOptions:

ChatResponse response = chatModel.call(
    new Prompt(
        "Create an Excel spreadsheet with Q1 2025 sales data. " +
        "Include columns for Month, Revenue, and Expenses with 3 rows of sample data.",
        AnthropicChatOptions.builder()
            .model(Model.CLAUDE_SONNET_4_5)
            .maxTokens(4096)
            .skill(AnthropicSkill.XLSX)
            .build()
    )
);

// Claude will generate an actual Excel file
String responseText = response.getResult().getOutput().getText();
System.out.println(responseText);
// Output: "I've created an Excel spreadsheet with your Q1 2025 sales data..."

Multiple Skills

You can enable multiple skills in a single request (up to 8):

ChatResponse response = chatModel.call(
    new Prompt(
        "Create a sales report with both an Excel file containing the raw data " +
        "and a PowerPoint presentation summarizing the key findings.",
        AnthropicChatOptions.builder()
            .model(Model.CLAUDE_SONNET_4_5)
            .maxTokens(8192)
            .skill(AnthropicSkill.XLSX)
            .skill(AnthropicSkill.PPTX)
            .build()
    )
);

Using AnthropicSkillContainer for Advanced Configuration

For more control over skill types and versions, use AnthropicSkillContainer directly:

AnthropicSkillContainer container = AnthropicSkillContainer.builder()
    .skill(AnthropicSkill.XLSX)
    .skill(AnthropicSkill.PPTX, "20251013") // Specific version
    .build();

ChatResponse response = chatModel.call(
    new Prompt(
        "Generate the quarterly report",
        AnthropicChatOptions.builder()
            .model(Model.CLAUDE_SONNET_4_5)
            .maxTokens(4096)
            .skillContainer(container)
            .build()
    )
);

Downloading Generated Files

When Claude generates files using Skills, the response contains file IDs that can be used to download the actual files via the Files API. Spring AI provides the AnthropicSkillsResponseHelper utility class for extracting file IDs and downloading files.

Extracting File IDs

import org.springframework.ai.anthropic.AnthropicSkillsResponseHelper;

ChatResponse response = chatModel.call(prompt);

// Extract all file IDs from the response
List<String> fileIds = AnthropicSkillsResponseHelper.extractFileIds(response);

for (String fileId : fileIds) {
    System.out.println("Generated file ID: " + fileId);
}

Downloading All Files

The AnthropicSkillsResponseHelper provides a convenience method to download all generated files at once. This requires the AnthropicClient instance (the same one used to create the chat model):

import com.anthropic.client.AnthropicClient;

@Autowired
private AnthropicClient anthropicClient;

// Download all files to a target directory
Path targetDir = Path.of("generated-files");
Files.createDirectories(targetDir);

List<Path> savedFiles = AnthropicSkillsResponseHelper.downloadAllFiles(
        response, anthropicClient, targetDir);

for (Path file : savedFiles) {
    System.out.println("Downloaded: " + file.getFileName() +
                       " (" + Files.size(file) + " bytes)");
}

コンテナー ID の抽出

For multi-turn conversations with Skills, you can extract the container ID for reuse:

String containerId = AnthropicSkillsResponseHelper.extractContainerId(response);

if (containerId != null) {
    System.out.println("Container ID for reuse: " + containerId);
}

完全な例

Here’s a complete example showing Skills usage with file download:

@Service
public class DocumentGenerationService {

    private final AnthropicChatModel chatModel;
    private final AnthropicClient anthropicClient;

    public DocumentGenerationService(AnthropicChatModel chatModel,
                                     AnthropicClient anthropicClient) {
        this.chatModel = chatModel;
        this.anthropicClient = anthropicClient;
    }

    public Path generateSalesReport(String quarter, Path outputDir) throws IOException {
        // Generate Excel report using Skills
        ChatResponse response = chatModel.call(
            new Prompt(
                "Create an Excel spreadsheet with " + quarter + " sales data. " +
                "Include Month, Revenue, Expenses, and Profit columns.",
                AnthropicChatOptions.builder()
                    .model(Model.CLAUDE_SONNET_4_5)
                    .maxTokens(4096)
                    .skill(AnthropicSkill.XLSX)
                    .build()
            )
        );

        // Extract file IDs from the response
        List<String> fileIds = AnthropicSkillsResponseHelper.extractFileIds(response);

        if (fileIds.isEmpty()) {
            throw new RuntimeException("No file was generated");
        }

        // Download all generated files
        List<Path> savedFiles = AnthropicSkillsResponseHelper.downloadAllFiles(
                response, anthropicClient, outputDir);

        return savedFiles.get(0);
    }
}

ベストプラクティス

  1. 適切なモデルを使用する : スキルは Claude Sonnet 4 以降のモデルで最も効果的に機能します。サポートされているモデルを使用していることをご確認ください。

  2. 十分な最大トークンを設定する : ドキュメント生成には大量のトークンが必要になる場合があります。複雑なドキュメントの場合は、maxTokens(4096) 以上のトークンを使用してください。

  3. プロンプトは具体的に: ドキュメントの構造、コンテンツ、書式設定に関する明確で詳細な指示を提供します。

  4. ファイルのダウンロードを迅速に処理する : 生成されたファイルは 24 時間後に期限切れになります。生成後すぐにファイルをダウンロードしてください。

  5. ファイル ID を確認する : ダウンロードを試みる前に、必ずファイル ID が返されていることを確認してください。一部のプロンプトでは、ファイルが生成されずにテキストレスポンスが表示される場合があります。

  6. 守備的なエラー処理を使用する : ネットワークの課題や期限切れのファイルを適切に処理するには、ファイル操作を try-catch ブロックで囲みます。

List<String> fileIds = AnthropicSkillsResponseHelper.extractFileIds(response);

if (fileIds.isEmpty()) {
    // Claude may have responded with text instead of generating a file
    String text = response.getResult().getOutput().getText();
    log.warn("No files generated. Response: {}", text);
    return;
}

try {
    List<Path> files = AnthropicSkillsResponseHelper.downloadAllFiles(
            response, anthropicClient, targetDir);
    // Process files...
} catch (IOException e) {
    log.error("Failed to download file: {}", e.getMessage());
}

Anthropic’s Web 検索 (英語) tool allows Claude to search the web during a conversation and use the results to generate cited responses.

  • Web search is a built-in server-side tool — no external tool callbacks are needed

  • Web search results automatically include citations with URLs

  • You can combine web search with other tools (function calling, code execution, skills) in the same request

基本的な使い方

Enable web search by adding an AnthropicWebSearchTool to your chat options:

var webSearch = AnthropicWebSearchTool.builder().build();

ChatResponse response = chatModel.call(
    new Prompt("What is the latest released version of Spring AI?",
        AnthropicChatOptions.builder()
            .webSearchTool(webSearch)
            .build()));

String answer = response.getResult().getOutput().getText();

構成オプション

オプション 説明 デフォルト

maxUses

Maximum number of web searches Claude can perform per request

-

allowedDomains

Restrict search results to these domains only

-

blockedDomains

Exclude these domains from search results

-

userLocation

Approximate user location for localizing results (city, country, region, timezone)

-

Domain Filtering

Restrict or exclude specific domains from search results:

var webSearch = AnthropicWebSearchTool.builder()
    .allowedDomains(List.of("docs.spring.io", "github.com"))
    .blockedDomains(List.of("example.com"))
    .maxUses(5)
    .build();

User Location

Provide approximate location to localize search results:

var webSearch = AnthropicWebSearchTool.builder()
    .userLocation("San Francisco", "US", "California", "America/Los_Angeles")
    .build();

Accessing Web Search Results

Web search results and citations are available in the response metadata:

ChatResponse response = chatModel.call(
    new Prompt("What happened in tech news today?",
        AnthropicChatOptions.builder()
            .webSearchTool(AnthropicWebSearchTool.builder().build())
            .build()));

// Get web search results
List<AnthropicWebSearchResult> results =
    (List<AnthropicWebSearchResult>) response.getMetadata().get("web-search-results");

if (results != null) {
    for (AnthropicWebSearchResult result : results) {
        System.out.println("Title: " + result.title());
        System.out.println("URL: " + result.url());
        System.out.println("Page age: " + result.pageAge());
    }
}

// Get web search citations
List<Citation> citations =
    (List<Citation>) response.getMetadata().get("citations");

if (citations != null) {
    for (Citation citation : citations) {
        if (citation.getType() == Citation.LocationType.WEB_SEARCH_RESULT_LOCATION) {
            System.out.println("Source: " + citation.getUrl());
            System.out.println("Title: " + citation.getDocumentTitle());
            System.out.println("Cited text: " + citation.getCitedText());
        }
    }
}

Spring Boot の設定

Configure web search via application.properties or application.yml:

spring.ai.anthropic.chat.web-search-tool.max-uses=5
spring.ai.anthropic.chat.web-search-tool.allowed-domains=docs.spring.io,github.com
spring.ai.anthropic.chat.web-search-tool.user-location.city=San Francisco
spring.ai.anthropic.chat.web-search-tool.user-location.country=US

可観測性

Spring AI は、Anthropic 呼び出しごとに 2 つのレイヤーで Micrometer 観測値を出力します。

  • チャットモデルレイヤーgen_ai.client.operation オブザーバビリティは、AnthropicChatModel.call(…​) または .stream(…​) へのすべての呼び出しをラップし、リクエストパラメーター、レスポンスメタデータ、トークンの使用状況を保持します。タグとメトリクスの全セットについては、オブザーバビリティのリファレンスを参照してください。

  • HTTP レイヤーokhttp.requests 観測は、HTTP メソッド、URI、ステータスコード、例外タグを伴って、Anthropic API へのすべての HTTP リクエストをラップします。各リクエストは、traceparent をネットワーク経由で下流のサービス(AI ゲートウェイ、OpenAI 互換推論サーバー、プロキシ)にも伝播します。

spring-boot-starter-actuator とトレーシングブリッジ(micrometer-tracing-bridge-otel または micrometer-tracing-bridge-brave)を備えた Spring Boot アプリケーションでは、両方のレイヤーが自動的にワイヤリングされます。オプトインは不要です。Boot 以外のアプリケーションの場合は、ObservationRegistry を AnthropicChatModel.builder() に渡します。

AnthropicChatModel chatModel = AnthropicChatModel.builder()
    .options(...)
    .observationRegistry(observationRegistry)
    .build();

接続プールのメトリクス (opt-in)

Spring AI は、OkHttp 接続プールゲージ(okhttp.pool.connection.count と state=active|idle および client.kind=sync|async)をアプリケーションの MeterRegistry にバインドすることもできます。これらは二次的なテレメトリであり、容量調整には役立ちますが、トレースやリクエストごとのレイテンシには必要ないため、デフォルトでは無効になっています。

Spring Boot アプリケーションで有効にするには:

spring.ai.anthropic.chat.connection-pool-metrics-enabled=true

Boot アプリケーション以外の場合は、MeterRegistry を直接ビルダーに渡してください。レジストリが指定されると、ゲージがバインドされます。

AnthropicChatModel chatModel = AnthropicChatModel.builder()
    .options(...)
    .observationRegistry(observationRegistry)
    .meterRegistry(meterRegistry)
    .build();

HTTP ディスパッチャー実行者 (高度な)

デフォルトでは、Spring AI は OkHttp ディスパッチャーのエグゼキュータ (SDK の標準動作を再現する無制限のプラットフォームスレッドプール) を管理します。HTTP の同時実行性が高いワークロード、または Java 21+ 仮想スレッドを活用するには、独自の ExecutorService を指定できます。

AnthropicChatModel chatModel = AnthropicChatModel.builder()
    .options(...)
    .dispatcherExecutor(Executors.newVirtualThreadPerTaskExecutor())
    .build();

同期クライアントと非同期(ストリーミング)クライアントの両方で同じエグゼキュータが使用されます。独自のエグゼキュータを指定すると、そのライフサイクルはユーザーが管理します。Spring AI は、そのエグゼキュータに対して shutdown() を呼び出すことはありません。省略した場合、内部エグゼキュータは自動的に作成およびクリーンアップされます。

ストリーミング HTTP 観測は、チャットモデルの観測には配置されません。

同期呼び出しの場合、okhttp.requests スパンは gen_ai.client.operation スパンに正しくネストされ、完全なトレースツリーが期待どおりに形成されます。

ストリーミング呼び出しの場合、okhttp.requests スパンが発火してレジストリに記録され、タイマーが MeterRegistry に記録され、traceparent は送信リクエストで引き続き伝播されますが、スパンはチャットモデルのスパンにネストされません。これは、Anthropic SDK の非同期ストリーミング実装が Spring AI の HTTP クライアントを呼び出す前に ForkJoinPool.commonPool() にジャンプし、その境界で呼び出しスレッドの観測コンテキストを破棄するためです。Spring AI は、HTTP クライアントラッパー内からコンテキストを復元できません。

トレース UI でストリーミング HTTP スパンを親チャットモデルスパンと関連付ける必要がある場合は、スパン名 okhttp.requests、ホスト api.anthropic.com でフィルタリングし、トレース ID またはタイムスタンプ範囲で対応する gen_ai.client.operation スパンに結合してください。ストリーミング用の組み込み親リンク機能は、Anthropic Java SDK で開発が進められています。

ログ

Enable SDK logging by setting the environment variable:

export ANTHROPIC_LOG=debug

制限

The following features are not yet supported:

  • Amazon Bedrock backend

  • Google Vertex AI backend

These features are planned for future releases.

HTTP クライアントのカスタマイズ

Spring AI uses the official anthropic-java SDK under the hood and configures its HTTP transport with a custom OkHttp client built by SpringAiAnthropicHttpClient.Builder. You can intercept that builder before the underlying OkHttpClient is created by exposing one or more AnthropicHttpClientBuilderCustomizer beans.

@FunctionalInterface
public interface AnthropicHttpClientBuilderCustomizer {
    void customize(SpringAiAnthropicHttpClient.Builder builder);
}

典型的な使用例としては、以下のようなものがあります。

  • OkHttp および Interceptor インスタンスの登録(認証、伝播ヘッダー、カスタムログ記録)

  • ディスパッチャー ExecutorService を交換します(たとえば、非同期 I/O を仮想スレッド経由でルーティングするため)。

  • プロキシ、SSL、ホスト名の検証、ビルダーによって公開される接続プールのサイズ設定。

When several customizer beans are present in the application context, they are applied in @Order / @Priority order, after Spring AI’s own defaults, so user code wins.

Each customizer is called twice per AnthropicChatModel — once for the synchronous client and once for the asynchronous client that back the model. Implementations should be idempotent (i.e. safe to call more than once).

The same hook is available when wiring the model manually via AnthropicChatModel.Builder. In that case the customizers are applied in registration order; @Order annotations have no effect outside of Spring’s bean container:

var chatModel = AnthropicChatModel.builder()
    .options(AnthropicChatOptions.builder().model("claude-sonnet-4-20250514").build())
    .httpClientBuilderCustomizer(myCustomizer)
    .build();