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 の接続とチャットオプションを設定します。
| プロパティ | 説明 | デフォルト |
|---|---|---|
| Anthropic API キー | - |
| API ベース URL | |
| Anthropic クライアントのリクエストがタイムアウトしました |
|
| 失敗したリクエストに対する最大再試行回数 |
|
| すべての Anthropic クライアントリクエストに追加するカスタム HTTP ヘッダー | - |
| モデル名 |
|
| 最大トークン数 |
|
| サンプリング温度 | - |
| トップ p サンプリング | - |
| トップ k サンプリング | - |
| 使用するキャッシュ戦略 |
|
| システムメッセージごとに個別のブロックを使用する |
|
| 個々の API 呼び出しに渡すリクエストごとの HTTP ヘッダー。 | - |
| リクエストが処理される地理的領域 ( | - |
| リクエストあたりの Web 検索の最大回数 | - |
| 検索結果を絞り込むドメインをカンマ区切りで指定します | - |
| 検索結果から除外するドメインをカンマ区切りで指定します | - |
| 検索結果をローカライズする都市 | - |
| ISO 3166-1 アルファ 2 国コード | - |
| 領域または状態 | - |
| IANA タイムゾーン識別子 | - |
| 容量ルーティング: | - |
手動構成
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();ランタイムオプション
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 モデルの名前。モデルには、 |
|
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. | - |
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. | - |
stopSequences | モデルの生成を停止させるカスタムシーケンス。 | - |
apiKey | 認証に使用する API キー。設定されていない場合は、 | - |
baseUrl | Anthropic API のベース URL。 | |
timeout | リクエストのタイムアウト期間。 | 60 秒 |
maxRetries | 失敗したリクエストの最大再試行回数。 | 2 |
proxy | HTTP クライアントのプロキシ設定。 | - |
customHeaders | すべてのリクエストに含めるカスタム HTTP ヘッダー(クライアントレベル)。 | - |
httpHeaders | リクエストごとの HTTP ヘッダー。これらは | - |
cacheOptions | プロンプトのキャッシュ動作を設定するためのオプション。キャッシュ戦略、マルチブロックキャッシュ、TTL(有効期限)、コンテンツ長の要件などが含まれます。 | - |
thinking | 思考構成。便利なビルダー | - |
outputConfig | 構造化出力(JSON スキーマ)および作業量制御のための出力構成。完全な制御には | - |
inferenceGeo | リクエストが処理される地理的領域を制御します。サポートされている値: | - |
serviceTier | リクエストの容量ルーティングを制御します。優先容量を状況に応じて使用するには | - |
ツール呼び出しオプション
| オプション | 説明 | デフォルト |
|---|---|---|
toolChoice | モデルが呼び出すツール(存在する場合)を制御します。 | 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 resetsAnthropic は、入力トークンと出力トークン用に別々のバケットも報告します。これらは、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 経由のツール呼び出し (推奨)
同期ツール実行とストリーミングツール実行の両方で、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 は、一般的なツール選択に対応した便利な静的ファクトリメソッドを提供しており、コードをより簡潔に記述できます。
|
ストリーミング
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 モデルでサポートされています。
モデルの機能:
API リクエスト構造はサポートされているすべてのモデルで同じですが、出力動作は異なります。 |
思考構成
思考を促すために、以下の設定を行ってください。
Set a thinking budget :
budgetTokensは 1024 以上で、maxTokens未満でなければなりません。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());
}
});レスポンス構造
思考機能が有効になっている場合、レスポンスにはさまざまな種類のコンテンツが含まれます。
| コンテンツタイプ | メタデータキー | 説明 |
|---|---|---|
思考の行き詰まり |
| Claude の推論テキストと暗号署名。同期モードでは、推論テキストは |
編集された思考 |
| 安全上の理由により、説明文は伏せられています。 |
シグネチャー (streaming) |
| ストリーミングモードでは、署名は思考ブロックの最後に個別の差分として届きます。 |
デルタについて考える (streaming) |
| ストリーミング中のテキストチャンクの漸進的思考。 |
テキストブロック | (なし) |
|
マルチモーダルサポート
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)));引用
Anthropic の引用 API (英語) により、Claude はレスポンスを生成する際に、提供されたドキュメントの特定の部分を参照できます。プロンプトに引用ドキュメントが含まれている場合、Claude はソース資料を引用することができ、引用メタデータ(文字範囲、ページ番号、コンテンツブロック)がレスポンスメタデータに返されます。
引用は次のような改善に役立ちます:
精度検証 : ユーザーは Claude の回答をソース資料と照らし合わせて検証できる
透過性 : 回答の根拠となったドキュメントの正確な部分を確認する
準拠 : 規制対象産業における情報源帰属の要件を満たす
信頼 : 情報の出所を示すことで信頼を築く
対応モデル 引用は、Claude 3.7 Sonnet および Claude 4 モデル (Opus および Sonnet) でサポートされています。 ドキュメントタイプ 3 種類の引用ドキュメントがサポートされています。
|
引用ドキュメントの作成
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.");
}ベストプラクティス
説明的なタイトルを使用する : ユーザーが引用内のソースを識別できるように、引用ドキュメントに意味のあるタイトルを付けます。
null 引用をチェックする : すべてのレスポンスに引用が含まれるわけではないため、アクセスする前に引用のメタデータが存在することを必ず検証してください。
ドキュメントサイズを考慮する : ドキュメントが大きいほどコンテキストは多くなりますが、消費される入力トークンも多くなり、レスポンス時間に影響する可能性があります。
複数のドキュメントを活用する : 複数のソースにまたがる質問に答える場合は、複数回呼び出すのではなく、1 回のリクエストですべての関連ドキュメントを提供してください。
適切なドキュメント型を使用する : シンプルなコンテンツにはプレーンテキスト、既存のドキュメントには 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:
| 戦略 | 説明 |
|---|---|
| No caching (default). No cache control headers are added. |
| Cache system message content. Uses 1 cache breakpoint. |
| Cache tool definitions only. Uses 1 cache breakpoint. |
| Cache both system messages and tool definitions. Uses 2 cache breakpoints. |
| 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();| オプション | 説明 | デフォルト |
|---|---|---|
| The caching strategy to use. |
|
| TTL per message type. Available values: |
|
| Minimum content length required before caching a message type. |
|
| Custom function to compute content length (e.g., token counting). |
|
| When |
|
| When |
|
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=trueAccessing 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 Schema Requirements When using JSON schema output, Anthropic requires |
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 schemaEffort Control
Control how much compute Claude spends on its response. Lower effort means faster, cheaper responses; higher effort means more thorough reasoning.
| Effort Level | 説明 |
|---|---|
| Fast and concise responses with minimal reasoning |
| Balanced trade-off between speed and thoroughness |
| More thorough reasoning and detailed responses |
| 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));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=autoOr 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 以降のモデルでサポートされています。 要件
|
プリビルド Anthropic スキル
Spring AI は、AnthropicSkill 列挙型を通じて Anthropic の事前構築されたスキルへの型安全なアクセスを提供します。
| スキル | 説明 | 生成されたファイルの種類 |
|---|---|---|
| Excel スプレッドシートの生成と操作 |
|
| PowerPoint プレゼンテーション作成 |
|
| Word ドキュメントの生成 |
|
| PDF ドキュメントの作成 |
|
基本的な使い方
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)");
}完全な例
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);
}
}ベストプラクティス
適切なモデルを使用する : スキルは Claude Sonnet 4 以降のモデルで最も効果的に機能します。サポートされているモデルを使用していることをご確認ください。
十分な最大トークンを設定する : ドキュメント生成には大量のトークンが必要になる場合があります。複雑なドキュメントの場合は、
maxTokens(4096)以上のトークンを使用してください。プロンプトは具体的に: ドキュメントの構造、コンテンツ、書式設定に関する明確で詳細な指示を提供します。
ファイルのダウンロードを迅速に処理する : 生成されたファイルは 24 時間後に期限切れになります。生成後すぐにファイルをダウンロードしてください。
ファイル ID を確認する : ダウンロードを試みる前に、必ずファイル ID が返されていることを確認してください。一部のプロンプトでは、ファイルが生成されずにテキストレスポンスが表示される場合があります。
守備的なエラー処理を使用する : ネットワークの課題や期限切れのファイルを適切に処理するには、ファイル操作を 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());
}Web 検索
Anthropic’s Web 検索 (英語) tool allows Claude to search the web during a conversation and use the results to generate cited responses.
|
基本的な使い方
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=trueBoot アプリケーション以外の場合は、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 観測は、チャットモデルの観測には配置されません。 同期呼び出しの場合、 ストリーミング呼び出しの場合、 トレース UI でストリーミング HTTP スパンを親チャットモデルスパンと関連付ける必要がある場合は、スパン名 |
制限
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();