Anthropic モジュールを公式 Java SDK に移行する

2.0.0-M3 では、spring-ai-anthropic が公式の com.anthropic:anthropic-java SDK をベースに書き直され、手作業で実装されていた RestClient / WebClient が置き換えられました。以前の AnthropicApi クラスは、47 個のネストされた DTO レコードを含む 2,300 行のファイルでした。

新しいモジュールは、並列 API ではなく、SDK 上の薄いアダプターです。Spring AI の価値は、ChatModelChatClient、アドバイザー、可観測性、自動構成といった独自の抽象化と、プロバイダ間で連携する機能にあります。SDK がすでにカバーしている機能(キャッシュ制御モデリング、ストリーミング、レート制限処理など)については、以前のモジュールのラッパーは引き継がれず削除されたため、アプリケーションは SDK の型を直接使用します。これにより、Anthropic が新しい SDK リリースを提供しても、対象領域が小さく保たれ、互換性の喪失を防ぐことができます。

Maven の座標、spring-ai-starter-model-anthropic の Boot スターター、spring.ai.anthropic.* の設定プロパティはすべて変更されていません。ChatClient の API も変更されていません。ChatModel.call(Prompt) と ChatModel.stream(Prompt) はシグネチャーを維持します。AnthropicChatOptions は既存のフィールドをすべて維持し、スキル、Web 検索、サービスティア、推論ジオ、構造化出力用の新しいフィールドを追加します。

何が変わったのか

エリア 変更

AnthropicChatModel construction

Public constructors removed. Use AnthropicChatModel.builder().

org.springframework.ai.anthropic.api.AnthropicApi and its nested DTOs

Removed. For direct API access, use the SDK’s com.anthropic.client.AnthropicClient.

AnthropicCacheOptions, AnthropicCacheStrategy, AnthropicCacheTtl, CacheBreakpointTracker, CacheEligibilityResolver

org.springframework.ai.anthropic.api (および api.utils)からルートパッケージである org.springframework.ai.anthropic に移動しました。列挙型の値は変更されていません。

CitationDocument

AnthropicCitationDocument に名称変更されました。

AnthropicCacheType, StreamHelper, metadata.AnthropicRateLimit

後継機種なしで撤去されました。

デフォルトの maxTokens

500 から 4096 に変更されました。

推移的 com.squareup.okhttp3:okhttp

com.anthropic:anthropic-java によって引き込まれた新しい情報です。

ChatClient または ChatModel のみを使用する場合

コードが以下のようになっている場合は、移行は不要です。

@Autowired ChatClient.Builder builder;

String response = builder.build()
    .prompt("Tell me a joke")
    .call()
    .content();

自動構成により、新しい SDK ベースの実装に接続された AnthropicChatModel Bean が生成されます。呼び出し元のコードには影響はありません。

注意すべき動作変更点は、新しいデフォルト値である maxTokens の値です(Default maxTokens is now 4096 を参照)。

AnthropicChatModel をプログラムで構築する場合

コンストラクターを直接使用する代わりに、ビルダーを使用してください。

// Before
AnthropicApi anthropicApi = new AnthropicApi(apiKey);
AnthropicChatModel chatModel = new AnthropicChatModel(anthropicApi,
    AnthropicChatOptions.builder().model("claude-haiku-4-5").maxTokens(2048).build(),
    retryTemplate,
    toolCallingManager);

// After
AnthropicChatModel chatModel = AnthropicChatModel.builder()
    .apiKey(apiKey)
    .defaultOptions(AnthropicChatOptions.builder()
        .model("claude-haiku-4-5")
        .maxTokens(2048)
        .build())
    .toolCallingManager(toolCallingManager)
    .build();

ビルダーは baseUrltimeoutmaxRetriesproxycustomHeadersobservationRegistryobservationConvention も受け入れます。retryTemplate ビルダーメソッドはありません。再試行は SDK によって処理されるようになりました (Retry uses SDK maxRetries, not RetryTemplate を参照)。

キャッシュまたは引用型をインポートした場合

キャッシュおよび引用ヘルパークラスは、api (および api.utils)サブパッケージからルートパッケージである org.springframework.ai.anthropic に移動されました。インポートを以下のように更新してください。

古いインポート品 新規インポート

org.springframework.ai.anthropic.api.AnthropicCacheOptions

org.springframework.ai.anthropic.AnthropicCacheOptions

org.springframework.ai.anthropic.api.AnthropicCacheStrategy

org.springframework.ai.anthropic.AnthropicCacheStrategy

org.springframework.ai.anthropic.api.AnthropicCacheTtl

org.springframework.ai.anthropic.AnthropicCacheTtl

org.springframework.ai.anthropic.api.utils.CacheBreakpointTracker

org.springframework.ai.anthropic.CacheBreakpointTracker

org.springframework.ai.anthropic.api.utils.CacheEligibilityResolver

org.springframework.ai.anthropic.CacheEligibilityResolver

org.springframework.ai.anthropic.api.CitationDocument

org.springframework.ai.anthropic.AnthropicCitationDocument

AnthropicCacheStrategy (NONETOOLS_ONLYSYSTEM_ONLYSYSTEM_AND_TOOLSCONVERSATION_HISTORY) および AnthropicCacheTtl (FIVE_MINUTESONE_HOUR) の列挙値は変更されていません。plainText(…​)pdf(…​)customContent(…​) ファクトリメソッドは、名前が変更された AnthropicCitationDocument にも引き続き存在します。

AnthropicApi を直接使用した場合

AnthropicApi、そのネストされた DTO レコード、AnthropicCacheType は削除されました。SDK クライアントを使用する前に、AnthropicChatModel がこれまで行っていた作業をカバーしているかどうかを検討してください。通常はカバーしており、フレームワークとの統合を維持できます。

AnthropicChatModel は、生の AnthropicClient に以下を追加します。

  • プロバイダに依存しないリクエストおよびレスポンス型(PromptChatResponseGenerationUsage)により、アプリケーションコードは com.anthropic.* に依存しません。

  • ツール呼び出しは ToolCallback および ToolCallingManager ループと統合されており、自動的な複数ターン実行も含まれています。

  • SDK のコールバックベースの AsyncStreamResponse ではなく、Reactor Flux<ChatResponse> としてストリーミングします。

  • 戦略モデリング、TTL 制御、4 ブレークポイント強制による迅速なキャッシング(AnthropicCacheOptions)。

  • Citation には、ChatResponseMetadata で 4 つの位置変異が発見された。

  • スキル、組み込みの Web 検索、サービス階層、推論地理、構造化出力は、AnthropicChatOptions フィールドとして、すべて spring.ai.anthropic.chat.* からバインド可能です。

  • Spring Boot の自動構成と Micrometer の監視。

  • モデルより上位の ChatClient パイプライン(アドバイザー、メッセージテンプレート、RAG、会話メモリ、構造化出力コンバーター)。

  • プロバイダーのポータビリティ: 同じ ChatClient コードは、OpenAI、Bedrock、Google GenAI、およびその他の GenAI に対して実行されます。

For typical chat usage, switch to AnthropicChatModel.builder() (see If You Construct AnthropicChatModel Programmatically ):

// Before
AnthropicApi api = new AnthropicApi(apiKey);
AnthropicApi.ChatCompletionRequest req = new AnthropicApi.ChatCompletionRequest(
    AnthropicApi.ChatModel.CLAUDE_HAIKU_4_5.getValue(),
    List.of(new AnthropicApi.AnthropicMessage(List.of(new AnthropicApi.ContentBlock("hello")), AnthropicApi.Role.USER)),
    null, 1024, null, 0.7, null, null, null, null, false);
ResponseEntity<AnthropicApi.ChatCompletionResponse> resp = api.chatCompletionEntity(req);

// After
AnthropicChatModel chatModel = AnthropicChatModel.builder()
    .apiKey(apiKey)
    .defaultOptions(AnthropicChatOptions.builder()
        .model("claude-haiku-4-5")
        .maxTokens(1024)
        .temperature(0.7)
        .build())
    .build();
ChatResponse response = chatModel.call(new Prompt("hello"));

If you genuinely need an Anthropic API surface that AnthropicChatModel doesn’t expose (a beta endpoint, files API, custom skills CRUD), drop to the SDK client. You’re outside the framework at that point — no observability, no provider neutrality, no ChatClient pipeline:

import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

AnthropicClient client = AnthropicOkHttpClient.builder().apiKey(apiKey).build();
MessageCreateParams params = MessageCreateParams.builder()
    .model(Model.CLAUDE_HAIKU_4_5)
    .maxTokens(1024)
    .temperature(0.7)
    .addUserMessage("hello")
    .build();
com.anthropic.models.messages.Message message = client.messages().create(params);

The hand-rolled record types have direct analogues in the SDK under com.anthropic.models.messages.*:

Removed type (old AnthropicApi.*)SDK replacement (com.anthropic.models.messages.*)

ChatCompletionRequest

MessageCreateParams

ChatCompletionResponse

Message

AnthropicMessage

MessageParam

ContentBlock

ContentBlock (sealed union: TextBlock, ToolUseBlock, ThinkingBlock, RedactedThinkingBlock, ServerToolUseBlock, WebSearchToolResultBlock, ContainerUploadBlock, …​)

Tool

Tool

ToolChoiceAuto / ToolChoiceAny / ToolChoiceTool / ToolChoiceNone

ToolChoice (sealed union with ToolChoiceAuto, ToolChoiceAny, ToolChoiceTool, ToolChoiceNone variants)

Source (image / PDF media)

Base64ImageSource, UrlImageSource, Base64PdfSource, UrlPdfSource

MessageStartEvent, ContentBlockStartEvent, ContentBlockDeltaEvent, MessageDeltaEvent, …​

RawMessageStreamEvent (sealed union)

ToolUseBlock.input() returns the SDK’s JsonValue, not a JSON string. Calling .toString() on a JsonValue produces Java map syntax ({key=value}) that looks like JSON but is not. Walk it with JsonValue.Visitor<T> or serialize via Jackson to get a real JSON string.

Removed in Favor of SDK Equivalents

These types were dropped because the SDK already exposes the same concept. Use the SDK type directly.

Removed Use instead

org.springframework.ai.anthropic.api.AnthropicCacheType

com.anthropic.models.messages.CacheControlEphemeral. The old enum carried only the literal ephemeral value, which is also the only cache-control type the API supports.

org.springframework.ai.anthropic.api.StreamHelper

com.anthropic.core.http.AsyncStreamResponse<RawMessageStreamEvent>. StreamHelper was the internal SSE-merging helper for the old WebClient streaming path; the SDK now delivers stream events natively, and Spring AI bridges them to a Reactor Flux internally. Code calling ChatModel.stream(Prompt) is unaffected.

org.springframework.ai.anthropic.metadata.AnthropicRateLimit

com.anthropic.errors.RateLimitException (thrown by the SDK after retries are exhausted), plus the headers on the SDK’s response objects. Replace code that read rate-limit metadata off ChatResponseMetadata with exception handling.

Behavior Changes

Prompt-level options no longer merge with model defaults

The previous module merged prompt-level AnthropicChatOptions into the model-level defaults via ModelOptionsUtils.copyToTarget(…​) and ModelOptionsUtils.merge(…​), so model, temperature, and any other unset fields were filled in from the model’s defaults:

// Before: only maxTokens set; model + temperature inherited from defaults.
Prompt prompt = new Prompt(
    "Tell me a joke",
    AnthropicChatOptions.builder().maxTokens(2048).build());
chatModel.call(prompt);

The new module does not merge. A prompt-level options instance is used as-is; if the prompt has no options, the model defaults are used.

// After: prompt-level options must be "full", or null.
Prompt prompt = new Prompt(
    "Tell me a joke",
    chatModel.getOptions().mutate().maxTokens(2048).build());
chatModel.call(prompt);

This is a forward port of the broader change in Upgrading to 2.0.0-M5 — ChatOptions Handling, landed early for Anthropic. ChatClient performs its own merging before reaching the model, so callers using ChatClient are not affected.

Default maxTokens is now 4096

AnthropicChatOptions defaults maxTokens to 4096 instead of 500. The previous default routinely truncated responses; the new value matches the other Spring AI chat modules.

If you relied on 500 to bound costs, set it explicitly:

spring.ai.anthropic.chat.max-tokens=500

Retry uses SDK maxRetries, not RetryTemplate

The previous module took a Spring Retry RetryTemplate in its constructor. Retries are now handled by the SDK and configured through maxRetries (default 2):

spring.ai.anthropic.max-retries=5

Any RetryTemplate bean wired specifically for the Anthropic module can be removed. For finer control, configure the SDK client through a custom AnthropicSetup.

Streaming thinking events

Two changes affect anyone subscribed to the raw Flux<ChatResponse> stream (rather than letting ChatClient or MessageAggregator collapse it).

The previous module bundled the text and signature of a thinking block into a single Generation. The SDK delivers them as separate events, and the new module forwards them that way: a Generation with properties.signature arrives after the thinking-text deltas, before any subsequent text deltas. MessageAggregator and `ChatClient’s built-in aggregation absorb the extra chunk transparently.

Thinking-text deltas now also include properties.thinking = Boolean.TRUE. The previous module emitted them as plain content, leaving callers no reliable way to distinguish thinking text from response text mid-stream.

The full set of streaming metadata keys:

Block Generation carries

Thinking text delta

content = <thinking text>, properties.thinking = true (new in M3)

Thinking signature delta

empty content, properties.signature = <signature>

Redacted thinking block

empty contentproperties.data = <data>

Sync thinking block (non-streaming)

content = <thinking text>properties.signature = <signature> (single Generation)

Prompt caching changes

Three behaviors to know about if you configured AnthropicCacheOptions:

  • The 4-breakpoint limit is enforced in Spring AI, not at the API。Anthropic permits at most 4 cache breakpoints per request. The previous module passed markers through and let the API reject excess. CacheBreakpointTracker now keeps count and silently skips additions past 4, logging a one-time WARN. The most likely way to hit the cap is SYSTEM_AND_TOOLS combined with multi-block system caching and citation documents. Requests that previously failed with an API error can now succeed with reduced caching, so check your cache hit rate after the upgrade.

  • AnthropicCacheStrategy.NONE means "unset", not "disabled"。Setting NONE at the prompt level falls back to the model default. To turn caching off when the model default has it on, build a second AnthropicChatModel with AnthropicCacheOptions.disabled() as its default.

  • Tool cache TTL is taken from MessageType.SYSTEMresolveToolCacheControl looks up messageTypeTtl(MessageType.SYSTEM) regardless of strategy. Setting messageTypeTtl(MessageType.USER, ONE_HOUR) has no effect on tool caching.

Citation document consistency is validated client-side

The Anthropic API requires every DocumentBlockParam with citation configuration in a single request to share the same citations.enabled value. AnthropicChatOptions.validateCitationConsistency() now enforces this and throws IllegalArgumentException before the request is sent. The previous module let the API return an HTTP 400. Tests or call sites that mixed enabled and disabled citation documents will now fail at build time instead of on the network call.

New OkHttp Transitive Dependency

com.anthropic:anthropic-java pulls in com.squareup.okhttp3:okhttp. Most applications will not notice; if you have strict dependency-convergence rules or an existing OkHttp pin, you may need a <dependencyManagement> entry.

New Capabilities

The migration also enables several Anthropic features. See Anthropic チャット for the full reference.

  • Native skills (AnthropicSkillAnthropicSkillContainer).

  • Built-in web search tool (AnthropicWebSearchTool).

  • Service tier selection (AnthropicServiceTier).

  • Inference geo for data residency (useu).

  • Native structured output through JsonOutputFormat and Effort (requires claude-sonnet-4-6 or newer).

  • Extended-thinking display modes (summarized / omitted).

  • Citation type with four location variants (CHAR_LOCATIONPAGE_LOCATIONCONTENT_BLOCK_LOCATIONWEB_SEARCH_RESULT_LOCATION).

  • Per-request HTTP headers on AnthropicChatOptions#httpHeaders, distinct from client-level customHeaders on AbstractAnthropicOptionscustomHeaders is set once on the client and applies to every request; httpHeaders is set per Prompt and merged in at request-build time. Useful for request tracing, beta-API toggles, and routing.

Things That Fail Silently

The compile errors are easy. These don’t throw; they produce different output instead.

  • Partial prompt-level optionsnew Prompt(text, AnthropicChatOptions.builder().maxTokens(2048).build()) no longer inherits modeltemperature, etc. from the model’s defaults (see Prompt-level options no longer merge with model defaults ). No compile error, no exception; the request runs with different values. If output drifts after the upgrade and you call ChatModel directly, look here first.

  • If costs climb after the upgrade, check whether you were relying on the old 500 -token maxTokens default to cap responses.

  • Cache breakpoints dropped past four。Stacking multi-block system caching with tools and citation documents can push past Anthropic’s 4-breakpoint cap. CacheBreakpointTracker skips the extras and logs WARN once. Cache hit rate drops without an error.

  • Stale org.springframework.ai.anthropic.api.AnthropicCache* imports are the source of most compile errors after the upgrade. A project-wide find-and-replace fixes them.