拡張思考は、複雑なタスクに対してClaudeに強化された推論能力を提供し、最終的な回答を提供する前に、段階的な思考プロセスに対してさまざまなレベルの透明性を提供します。

サポートされているモデル

拡張思考は以下のモデルでサポートされています:
  • Claude Sonnet 4.5 (claude-sonnet-4-5-20250929)
  • Claude Sonnet 4 (claude-sonnet-4-20250514)
  • Claude Sonnet 3.7 (claude-3-7-sonnet-20250219)
  • Claude Haiku 4.5 (claude-haiku-4-5-20251001)
  • Claude Opus 4.1 (claude-opus-4-1-20250805)
  • Claude Opus 4 (claude-opus-4-20250514)
APIの動作はClaude Sonnet 3.7とClaude 4モデル間で異なりますが、APIの形状は完全に同じです。詳細については、モデルバージョン間での思考の違いを参照してください。

拡張思考の仕組み

拡張思考が有効になると、Claudeは内部推論を出力するthinkingコンテンツブロックを作成します。Claudeは最終的な回答を作成する前に、この推論からの洞察を組み込みます。 APIレスポンスにはthinkingコンテンツブロック、続いてtextコンテンツブロックが含まれます。 デフォルトのレスポンス形式の例は以下の通りです:
{
  "content": [
    {
      "type": "thinking",
      "thinking": "Let me analyze this step by step...",
      "signature": "WaUjzkypQ2mUEVM36O2TxuC06KN8xyfbJwyem2dw3URve/op91XWHOEBLLqIOMfFG/UvLEczmEsUjavL...."
    },
    {
      "type": "text",
      "text": "Based on my analysis..."
    }
  ]
}
拡張思考のレスポンス形式の詳細については、Messages API Referenceを参照してください。

拡張思考の使用方法

Messages APIで拡張思考を使用する例は以下の通りです:
curl https://api.anthropic.com/v1/messages \
     --header "x-api-key: $ANTHROPIC_API_KEY" \
     --header "anthropic-version: 2023-06-01" \
     --header "content-type: application/json" \
     --data \
'{
    "model": "claude-sonnet-4-5",
    "max_tokens": 16000,
    "thinking": {
        "type": "enabled",
        "budget_tokens": 10000
    },
    "messages": [
        {
            "role": "user",
            "content": "Are there an infinite number of prime numbers such that n mod 4 == 3?"
        }
    ]
}'
拡張思考を有効にするには、thinkingオブジェクトを追加し、typeパラメータをenabledに設定し、budget_tokensを拡張思考用の指定されたトークン予算に設定します。 budget_tokensパラメータは、Claudeが内部推論プロセスに使用できるトークンの最大数を決定します。Claude 4モデルでは、この制限は完全な思考トークンに適用され、要約された出力には適用されません。より大きな予算により、複雑な問題に対してより徹底的な分析を可能にすることで、レスポンスの品質を向上させることができますが、特に32k以上の範囲では、Claudeが割り当てられた予算全体を使用しない場合があります。 budget_tokensmax_tokens未満の値に設定する必要があります。ただし、インターリーブ思考とツールを使用する場合、トークン制限が全体のコンテキストウィンドウ(200kトークン)になるため、この制限を超えることができます。

要約された思考

拡張思考が有効になっている場合、Claude 4モデル用のMessages APIは、Claudeの完全な思考プロセスの要約を返します。要約された思考は、誤用を防ぎながら、拡張思考の完全な知能の利点を提供します。 要約された思考に関する重要な考慮事項は以下の通りです:
  • 元のリクエストによって生成された完全な思考トークンに対して課金され、要約トークンに対してではありません。
  • 請求される出力トークン数は、レスポンスで表示されるトークン数と一致しません
  • 思考出力の最初の数行はより詳細で、プロンプトエンジニアリング目的に特に役立つ詳細な推論を提供します。
  • Anthropicが拡張思考機能の改善を求める中で、要約動作は変更される可能性があります。
  • 要約は、最小限の追加レイテンシでClaudeの思考プロセスの主要なアイデアを保持し、ストリーミング可能なユーザーエクスペリエンスとClaude Sonnet 3.7からClaude 4モデルへの簡単な移行を可能にします。
  • 要約は、リクエストでターゲットとするモデルとは異なるモデルによって処理されます。思考モデルは要約された出力を見ません。
Claude Sonnet 3.7は完全な思考出力を返し続けます。Claude 4モデルの完全な思考出力へのアクセスが必要な稀なケースでは、営業チームにお問い合わせください

思考のストリーミング

サーバー送信イベント(SSE)を使用して拡張思考レスポンスをストリーミングできます。 拡張思考でストリーミングが有効になっている場合、thinking_deltaイベントを介して思考コンテンツを受信します。 Messages APIを介したストリーミングの詳細なドキュメントについては、Streaming Messagesを参照してください。 思考でストリーミングを処理する方法は以下の通りです:
curl https://api.anthropic.com/v1/messages \
     --header "x-api-key: $ANTHROPIC_API_KEY" \
     --header "anthropic-version: 2023-06-01" \
     --header "content-type: application/json" \
     --data \
'{
    "model": "claude-sonnet-4-5",
    "max_tokens": 16000,
    "stream": true,
    "thinking": {
        "type": "enabled",
        "budget_tokens": 10000
    },
    "messages": [
        {
            "role": "user",
            "content": "What is 27 * 453?"
        }
    ]
}'
ストリーミング出力の例:
event: message_start
data: {"type": "message_start", "message": {"id": "msg_01...", "type": "message", "role": "assistant", "content": [], "model": "claude-sonnet-4-5", "stop_reason": null, "stop_sequence": null}}

event: content_block_start
data: {"type": "content_block_start", "index": 0, "content_block": {"type": "thinking", "thinking": ""}}

event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "Let me solve this step by step:\n\n1. First break down 27 * 453"}}

event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "\n2. 453 = 400 + 50 + 3"}}

// Additional thinking deltas...

event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "signature_delta", "signature": "EqQBCgIYAhIM1gbcDa9GJwZA2b3hGgxBdjrkzLoky3dl1pkiMOYds..."}}

event: content_block_stop
data: {"type": "content_block_stop", "index": 0}

event: content_block_start
data: {"type": "content_block_start", "index": 1, "content_block": {"type": "text", "text": ""}}

event: content_block_delta
data: {"type": "content_block_delta", "index": 1, "delta": {"type": "text_delta", "text": "27 * 453 = 12,231"}}

// Additional text deltas...

event: content_block_stop
data: {"type": "content_block_stop", "index": 1}

event: message_delta
data: {"type": "message_delta", "delta": {"stop_reason": "end_turn", "stop_sequence": null}}

event: message_stop
data: {"type": "message_stop"}
思考が有効になっているストリーミングを使用する場合、テキストが時々、より小さなトークンごとの配信と交互に、より大きなチャンクで到着することに気づくかもしれません。これは、特に思考コンテンツにとって期待される動作です。ストリーミングシステムは最適なパフォーマンスのためにコンテンツをバッチで処理する必要があり、これにより、ストリーミングイベント間で遅延が発生する可能性のある、この「チャンク状」の配信パターンが生じる可能性があります。私たちは継続的にこのエクスペリエンスの改善に取り組んでおり、将来のアップデートでは思考コンテンツがよりスムーズにストリーミングされることに焦点を当てています。

ツール使用での拡張思考

拡張思考はツール使用と併用でき、Claudeがツール選択と結果処理を通じて推論できるようになります。 拡張思考をツール使用と併用する場合、以下の制限事項に注意してください:
  1. ツール選択の制限: 思考を伴うツール使用はtool_choice: {"type": "auto"}(デフォルト)またはtool_choice: {"type": "none"}のみをサポートします。tool_choice: {"type": "any"}またはtool_choice: {"type": "tool", "name": "..."}を使用すると、これらのオプションがツール使用を強制するため、拡張思考と互換性がないため、エラーが発生します。
  2. 思考ブロックの保持: ツール使用中は、最後のアシスタントメッセージのためにthinkingブロックをAPIに戻す必要があります。推論の継続性を維持するために、完全な未修正ブロックをAPIに含めてください。
ツール結果を提供する際に思考ブロックを保持する方法を示す実用的な例は以下の通りです:
weather_tool = {
    "name": "get_weather",
    "description": "Get current weather for a location",
    "input_schema": {
        "type": "object",
        "properties": {
            "location": {"type": "string"}
        },
        "required": ["location"]
    }
}

# First request - Claude responds with thinking and tool request
response = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[weather_tool],
    messages=[
        {"role": "user", "content": "What's the weather in Paris?"}
    ]
)
APIレスポンスには思考、テキスト、およびtool_useブロックが含まれます:
{
    "content": [
        {
            "type": "thinking",
            "thinking": "The user wants to know the current weather in Paris. I have access to a function `get_weather`...",
            "signature": "BDaL4VrbR2Oj0hO4XpJxT28J5TILnCrrUXoKiiNBZW9P+nr8XSj1zuZzAl4egiCCpQNvfyUuFFJP5CncdYZEQPPmLxYsNrcs...."
        },
        {
            "type": "text",
            "text": "I can help you get the current weather information for Paris. Let me check that for you"
        },
        {
            "type": "tool_use",
            "id": "toolu_01CswdEQBMshySk6Y9DFKrfq",
            "name": "get_weather",
            "input": {
                "location": "Paris"
            }
        }
    ]
}
次に会話を続けてツールを使用しましょう
# Extract thinking block and tool use block
thinking_block = next((block for block in response.content
                      if block.type == 'thinking'), None)
tool_use_block = next((block for block in response.content
                      if block.type == 'tool_use'), None)

# Call your actual weather API, here is where your actual API call would go
# let's pretend this is what we get back
weather_data = {"temperature": 88}

# Second request - Include thinking block and tool result
# No new thinking blocks will be generated in the response
continuation = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[weather_tool],
    messages=[
        {"role": "user", "content": "What's the weather in Paris?"},
        # notice that the thinking_block is passed in as well as the tool_use_block
        # if this is not passed in, an error is raised
        {"role": "assistant", "content": [thinking_block, tool_use_block]},
        {"role": "user", "content": [{
            "type": "tool_result",
            "tool_use_id": tool_use_block.id,
            "content": f"Current temperature: {weather_data['temperature']}°F"
        }]}
    ]
)
APIレスポンスにはテキストのみが含まれるようになります
{
    "content": [
        {
            "type": "text",
            "text": "Currently in Paris, the temperature is 88°F (31°C)"
        }
    ]
}

思考ブロックの保持

ツール使用中は、thinkingブロックをAPIに戻す必要があり、完全な未修正ブロックをAPIに含める必要があります。これは、モデルの推論フローと会話の整合性を維持するために重要です。
以前のassistantロールターンからthinkingブロックを省略することはできますが、マルチターン会話では常にすべての思考ブロックをAPIに戻すことをお勧めします。APIは:
  • 提供された思考ブロックを自動的にフィルタリングします
  • モデルの推論を保持するために必要な関連する思考ブロックを使用します
  • Claudeに表示されるブロックの入力トークンのみを請求します
Claudeがツールを呼び出すとき、外部情報を待つためにレスポンスの構築を一時停止しています。ツール結果が返されると、Claudeはその既存のレスポンスの構築を続行します。これにより、いくつかの理由でツール使用中に思考ブロックを保持する必要があります:
  1. 推論の継続性: 思考ブロックは、ツールリクエストにつながったClaudeの段階的推論をキャプチャします。ツール結果を投稿するとき、元の思考を含めることで、Claudeが中断したところから推論を続けることができます。
  2. コンテキストの維持: ツール結果はAPI構造ではユーザーメッセージとして表示されますが、継続的な推論フローの一部です。思考ブロックを保持することで、複数のAPI呼び出しにわたってこの概念的フローを維持します。コンテキスト管理の詳細については、コンテキストウィンドウに関するガイドを参照してください。
重要: thinkingブロックを提供する場合、連続するthinkingブロックの全体のシーケンスは、元のリクエスト中にモデルによって生成された出力と一致する必要があります。これらのブロックのシーケンスを再配置または変更することはできません。

インターリーブ思考

Claude 4モデルでのツール使用を伴う拡張思考は、インターリーブ思考をサポートしており、Claudeがツール呼び出し間で思考し、ツール結果を受信した後により洗練された推論を行うことができます。 インターリーブ思考により、Claudeは以下のことができます:
  • 次に何をするかを決定する前に、ツール呼び出しの結果について推論する
  • 間に推論ステップを挟んで複数のツール呼び出しを連鎖させる
  • 中間結果に基づいてより微妙な決定を行う
インターリーブ思考を有効にするには、APIリクエストにベータヘッダー interleaved-thinking-2025-05-14を追加します。 インターリーブ思考に関する重要な考慮事項は以下の通りです:
  • インターリーブ思考では、budget_tokensは1つのアシスタントターン内のすべての思考ブロック全体の総予算を表すため、max_tokensパラメータを超えることができます。
  • インターリーブ思考はMessages APIを介して使用されるツールでのみサポートされています。
  • インターリーブ思考は、ベータヘッダーinterleaved-thinking-2025-05-14を使用してClaude 4モデルでのみサポートされています。
  • Claude APIへの直接呼び出しでは、任意のモデルへのリクエストでinterleaved-thinking-2025-05-14を渡すことができ、効果はありません。
  • サードパーティプラットフォーム(例:Amazon BedrockおよびVertex AI)では、Claude Opus 4.1、Opus 4、またはSonnet 4以外のモデルにinterleaved-thinking-2025-05-14を渡すと、リクエストが失敗します。
import anthropic

client = anthropic.Anthropic()

# Define tools
calculator_tool = {
    "name": "calculator",
    "description": "Perform mathematical calculations",
    "input_schema": {
        "type": "object",
        "properties": {
            "expression": {
                "type": "string",
                "description": "Mathematical expression to evaluate"
            }
        },
        "required": ["expression"]
    }
}

database_tool = {
    "name": "database_query",
    "description": "Query product database",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "SQL query to execute"
            }
        },
        "required": ["query"]
    }
}

# First request - Claude thinks once before all tool calls
response = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[calculator_tool, database_tool],
    messages=[{
        "role": "user",
        "content": "What's the total revenue if we sold 150 units of product A at $50 each, and how does this compare to our average monthly revenue from the database?"
    }]
)

# Response includes thinking followed by tool uses
# Note: Claude thinks once at the beginning, then makes all tool decisions
print("First response:")
for block in response.content:
    if block.type == "thinking":
        print(f"Thinking (summarized): {block.thinking}")
    elif block.type == "tool_use":
        print(f"Tool use: {block.name} with input {block.input}")
    elif block.type == "text":
        print(f"Text: {block.text}")

# You would execute the tools and return results...
# After getting both tool results back, Claude directly responds without additional thinking
インターリーブ思考なしのこの例では:
  1. Claudeはタスクを理解するために最初に一度思考します
  2. すべてのツール使用決定を事前に行います
  3. ツール結果が返されると、Claudeは追加の思考なしに即座にレスポンスを提供します
import anthropic

client = anthropic.Anthropic()

# Same tool definitions as before
calculator_tool = {
    "name": "calculator",
    "description": "Perform mathematical calculations",
    "input_schema": {
        "type": "object",
        "properties": {
            "expression": {
                "type": "string",
                "description": "Mathematical expression to evaluate"
            }
        },
        "required": ["expression"]
    }
}

database_tool = {
    "name": "database_query",
    "description": "Query product database",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "SQL query to execute"
            }
        },
        "required": ["query"]
    }
}

# First request with interleaved thinking enabled
response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[calculator_tool, database_tool],
    betas=["interleaved-thinking-2025-05-14"],
    messages=[{
        "role": "user",
        "content": "What's the total revenue if we sold 150 units of product A at $50 each, and how does this compare to our average monthly revenue from the database?"
    }]
)

print("Initial response:")
thinking_blocks = []
tool_use_blocks = []

for block in response.content:
    if block.type == "thinking":
        thinking_blocks.append(block)
        print(f"Thinking: {block.thinking}")
    elif block.type == "tool_use":
        tool_use_blocks.append(block)
        print(f"Tool use: {block.name} with input {block.input}")
    elif block.type == "text":
        print(f"Text: {block.text}")

# First tool result (calculator)
calculator_result = "7500"  # 150 * 50

# Continue with first tool result
response2 = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[calculator_tool, database_tool],
    betas=["interleaved-thinking-2025-05-14"],
    messages=[
        {
            "role": "user",
            "content": "What's the total revenue if we sold 150 units of product A at $50 each, and how does this compare to our average monthly revenue from the database?"
        },
        {
            "role": "assistant",
            "content": [thinking_blocks[0], tool_use_blocks[0]]
        },
        {
            "role": "user",
            "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use_blocks[0].id,
                "content": calculator_result
            }]
        }
    ]
)

print("\nAfter calculator result:")
# With interleaved thinking, Claude can think about the calculator result
# before deciding to query the database
for block in response2.content:
    if block.type == "thinking":
        thinking_blocks.append(block)
        print(f"Interleaved thinking: {block.thinking}")
    elif block.type == "tool_use":
        tool_use_blocks.append(block)
        print(f"Tool use: {block.name} with input {block.input}")

# Second tool result (database)
database_result = "5200"  # Example average monthly revenue

# Continue with second tool result
response3 = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    tools=[calculator_tool, database_tool],
    betas=["interleaved-thinking-2025-05-14"],
    messages=[
        {
            "role": "user",
            "content": "What's the total revenue if we sold 150 units of product A at $50 each, and how does this compare to our average monthly revenue from the database?"
        },
        {
            "role": "assistant",
            "content": [thinking_blocks[0], tool_use_blocks[0]]
        },
        {
            "role": "user",
            "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use_blocks[0].id,
                "content": calculator_result
            }]
        },
        {
            "role": "assistant",
            "content": thinking_blocks[1:] + tool_use_blocks[1:]
        },
        {
            "role": "user",
            "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use_blocks[1].id,
                "content": database_result
            }]
        }
    ]
)

print("\nAfter database result:")
# With interleaved thinking, Claude can think about both results
# before formulating the final response
for block in response3.content:
    if block.type == "thinking":
        print(f"Final thinking: {block.thinking}")
    elif block.type == "text":
        print(f"Final response: {block.text}")
インターリーブ思考を伴うこの例では:
  1. Claudeは最初にタスクについて思考します
  2. 計算機の結果を受信した後、Claudeはその結果が何を意味するかについて再び思考できます
  3. Claudeは最初の結果に基づいてデータベースをクエリする方法を決定します
  4. データベースの結果を受信した後、Claudeは最終的なレスポンスを策定する前に両方の結果についてもう一度思考します
  5. 思考予算はターン内のすべての思考ブロックに分散されます
このパターンにより、各ツールの出力が次の決定を知らせる、より洗練された推論チェーンが可能になります。

プロンプトキャッシュを伴う拡張思考

思考を伴うプロンプトキャッシュにはいくつかの重要な考慮事項があります:
拡張思考タスクは完了するのに5分以上かかることがよくあります。より長い思考セッションとマルチステップワークフローにわたってキャッシュヒットを維持するために、1時間のキャッシュ期間の使用を検討してください。
思考ブロックのコンテキスト削除
  • 以前のターンからの思考ブロックはコンテキストから削除され、キャッシュブレークポイントに影響を与える可能性があります
  • ツール使用で会話を続ける場合、思考ブロックはキャッシュされ、キャッシュから読み取られる際に入力トークンとしてカウントされます
  • これによりトレードオフが生じます:思考ブロックは視覚的にはコンテキストウィンドウスペースを消費しませんが、キャッシュされた場合は入力トークン使用量にカウントされます
  • 思考が無効になった場合、現在のツール使用ターンで思考コンテンツを渡すとリクエストが失敗します。他のコンテキストでは、APIに渡された思考コンテンツは単に無視されます
キャッシュ無効化パターン
  • 思考パラメータの変更(有効/無効または予算割り当て)により、メッセージキャッシュブレークポイントが無効になります
  • インターリーブ思考は、複数のツール呼び出し間で思考ブロックが発生する可能性があるため、キャッシュ無効化を増幅します
  • システムプロンプトとツールは、思考パラメータの変更やブロック削除にもかかわらずキャッシュされたままです
思考ブロックはキャッシュとコンテキスト計算のために削除されますが、特にインターリーブ思考を使用してツール使用で会話を続ける場合は保持する必要があります。

思考ブロックキャッシュ動作の理解

拡張思考をツール使用と併用する場合、思考ブロックはトークンカウントに影響する特定のキャッシュ動作を示します: 仕組み:
  1. キャッシュは、ツール結果を含む後続のリクエストを行う場合にのみ発生します
  2. 後続のリクエストが行われると、以前の会話履歴(思考ブロックを含む)をキャッシュできます
  3. これらのキャッシュされた思考ブロックは、キャッシュから読み取られる際に使用量メトリクスで入力トークンとしてカウントされます
  4. ツール結果以外のユーザーブロックが含まれる場合、以前のすべての思考ブロックは無視され、コンテキストから削除されます
詳細な例のフロー: リクエスト1:
User: "What's the weather in Paris?"
レスポンス1:
[thinking_block_1] + [tool_use block 1]
リクエスト2:
User: ["What's the weather in Paris?"], 
Assistant: [thinking_block_1] + [tool_use block 1], 
User: [tool_result_1, cache=True]
レスポンス2:
[thinking_block_2] + [text block 2]
リクエスト2はリクエストコンテンツ(レスポンスではない)のキャッシュを書き込みます。キャッシュには元のユーザーメッセージ、最初の思考ブロック、ツール使用ブロック、およびツール結果が含まれます。 リクエスト3:
User: ["What's the weather in Paris?"], 
Assistant: [thinking_block_1] + [tool_use block 1], 
User: [tool_result_1, cache=True], 
Assistant: [thinking_block_2] + [text block 2], 
User: [Text response, cache=True]
ツール結果以外のユーザーブロックが含まれたため、以前のすべての思考ブロックは無視されます。このリクエストは以下と同じように処理されます:
User: ["What's the weather in Paris?"], 
Assistant: [tool_use block 1], 
User: [tool_result_1, cache=True], 
Assistant: [text block 2], 
User: [Text response, cache=True]
重要なポイント:
  • このキャッシュ動作は、明示的なcache_controlマーカーなしでも自動的に発生します
  • この動作は、通常の思考またはインターリーブ思考を使用するかどうかに関係なく一貫しています
from anthropic import Anthropic
import requests
from bs4 import BeautifulSoup

client = Anthropic()

def fetch_article_content(url):
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')

    # Remove script and style elements
    for script in soup(["script", "style"]):
        script.decompose()

    # Get text
    text = soup.get_text()

    # Break into lines and remove leading and trailing space on each
    lines = (line.strip() for line in text.splitlines())
    # Break multi-headlines into a line each
    chunks = (phrase.strip() for line in lines for phrase in line.split("  "))
    # Drop blank lines
    text = '\n'.join(chunk for chunk in chunks if chunk)

    return text

# Fetch the content of the article
book_url = "https://www.gutenberg.org/cache/epub/1342/pg1342.txt"
book_content = fetch_article_content(book_url)
# Use just enough text for caching (first few chapters)
LARGE_TEXT = book_content[:5000]

SYSTEM_PROMPT=[
    {
        "type": "text",
        "text": "You are an AI assistant that is tasked with literary analysis. Analyze the following text carefully.",
    },
    {
        "type": "text",
        "text": LARGE_TEXT,
        "cache_control": {"type": "ephemeral"}
    }
]

MESSAGES = [
    {
        "role": "user",
        "content": "Analyze the tone of this passage."
    }
]

# First request - establish cache
print("First request - establishing cache")
response1 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 4000
    },
    system=SYSTEM_PROMPT,
    messages=MESSAGES
)

print(f"First response usage: {response1.usage}")

MESSAGES.append({
    "role": "assistant",
    "content": response1.content
})
MESSAGES.append({
    "role": "user",
    "content": "Analyze the characters in this passage."
})
# Second request - same thinking parameters (cache hit expected)
print("\nSecond request - same thinking parameters (cache hit expected)")
response2 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 4000
    },
    system=SYSTEM_PROMPT,
    messages=MESSAGES
)

print(f"Second response usage: {response2.usage}")

# Third request - different thinking parameters (cache miss for messages)
print("\nThird request - different thinking parameters (cache miss for messages)")
response3 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 8000  # Changed thinking budget
    },
    system=SYSTEM_PROMPT,  # System prompt remains cached
    messages=MESSAGES  # Messages cache is invalidated
)

print(f"Third response usage: {response3.usage}")
from anthropic import Anthropic
import requests
from bs4 import BeautifulSoup

client = Anthropic()

def fetch_article_content(url):
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')

    # Remove script and style elements
    for script in soup(["script", "style"]):
        script.decompose()

    # Get text
    text = soup.get_text()

    # Break into lines and remove leading and trailing space on each
    lines = (line.strip() for line in text.splitlines())
    # Break multi-headlines into a line each
    chunks = (phrase.strip() for line in lines for phrase in line.split("  "))
    # Drop blank lines
    text = '\n'.join(chunk for chunk in chunks if chunk)

    return text

# Fetch the content of the article
book_url = "https://www.gutenberg.org/cache/epub/1342/pg1342.txt"
book_content = fetch_article_content(book_url)
# Use just enough text for caching (first few chapters)
LARGE_TEXT = book_content[:5000]

# No system prompt - caching in messages instead
MESSAGES = [
    {
        "role": "user",
        "content": [
            {
                "type": "text",
                "text": LARGE_TEXT,
                "cache_control": {"type": "ephemeral"},
            },
            {
                "type": "text",
                "text": "Analyze the tone of this passage."
            }
        ]
    }
]

# First request - establish cache
print("First request - establishing cache")
response1 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 4000
    },
    messages=MESSAGES
)

print(f"First response usage: {response1.usage}")

MESSAGES.append({
    "role": "assistant",
    "content": response1.content
})
MESSAGES.append({
    "role": "user",
    "content": "Analyze the characters in this passage."
})
# Second request - same thinking parameters (cache hit expected)
print("\nSecond request - same thinking parameters (cache hit expected)")
response2 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 4000  # Same thinking budget
    },
    messages=MESSAGES
)

print(f"Second response usage: {response2.usage}")

MESSAGES.append({
    "role": "assistant",
    "content": response2.content
})
MESSAGES.append({
    "role": "user",
    "content": "Analyze the setting in this passage."
})

# Third request - different thinking budget (cache miss expected)
print("\nThird request - different thinking budget (cache miss expected)")
response3 = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=20000,
    thinking={
        "type": "enabled",
        "budget_tokens": 8000  # Different thinking budget breaks cache
    },
    messages=MESSAGES
)

print(f"Third response usage: {response3.usage}")
スクリプトの出力は以下の通りです(若干異なる数値が表示される場合があります)
First request - establishing cache
First response usage: { cache_creation_input_tokens: 1370, cache_read_input_tokens: 0, input_tokens: 17, output_tokens: 700 }

Second request - same thinking parameters (cache hit expected)

Second response usage: { cache_creation_input_tokens: 0, cache_read_input_tokens: 1370, input_tokens: 303, output_tokens: 874 }

Third request - different thinking budget (cache miss expected)
Third response usage: { cache_creation_input_tokens: 1370, cache_read_input_tokens: 0, input_tokens: 747, output_tokens: 619 }
この例は、キャッシュがメッセージ配列に設定されている場合、思考パラメータの変更(budget_tokensが4000から8000に増加)によりキャッシュが無効になることを示しています。3番目のリクエストはcache_creation_input_tokens=1370cache_read_input_tokens=0でキャッシュヒットがないことを示し、思考パラメータが変更されるとメッセージベースのキャッシュが無効になることを証明しています。

拡張思考でのmax tokensとコンテキストウィンドウサイズ

古いClaudeモデル(Claude Sonnet 3.7以前)では、プロンプトトークンとmax_tokensの合計がモデルのコンテキストウィンドウを超えた場合、システムは自動的にmax_tokensをコンテキスト制限内に収まるように調整していました。これは、大きなmax_tokens値を設定でき、システムが必要に応じてそれを静かに削減することを意味していました。 Claude 3.7および4モデルでは、max_tokens(思考が有効な場合は思考予算を含む)は厳格な制限として強制されます。プロンプトトークン + max_tokensがコンテキストウィンドウサイズを超える場合、システムは検証エラーを返すようになりました。
より徹底的な詳細については、コンテキストウィンドウに関するガイドをお読みください。

拡張思考でのコンテキストウィンドウ

拡張思考が有効な場合のコンテキストウィンドウ使用量を計算する際に、注意すべき考慮事項があります:
  • 以前のターンからの思考ブロックは削除され、コンテキストウィンドウにカウントされません
  • 現在のターンの思考は、そのターンのmax_tokens制限にカウントされます
以下の図は、拡張思考が有効な場合の特殊なトークン管理を示しています: 拡張思考でのコンテキストウィンドウ図 有効なコンテキストウィンドウは以下のように計算されます:
context window =
  (current input tokens - previous thinking tokens) +
  (thinking tokens + encrypted thinking tokens + text output tokens)
特にマルチターン会話で思考を含む場合、特定の使用ケースに対して正確なトークン数を取得するためにトークンカウントAPIを使用することをお勧めします。

ツール使用を伴う拡張思考でのコンテキストウィンドウ

拡張思考をツール使用と併用する場合、思考ブロックは明示的に保持され、ツール結果と一緒に返される必要があります。 ツール使用を伴う拡張思考の有効なコンテキストウィンドウ計算は以下のようになります:
context window =
  (current input tokens + previous thinking tokens + tool use tokens) +
  (thinking tokens + encrypted thinking tokens + text output tokens)
以下の図は、ツール使用を伴う拡張思考のトークン管理を示しています: ツール使用を伴う拡張思考でのコンテキストウィンドウ図

拡張思考でのトークン管理

拡張思考Claude 3.7および4モデルでのコンテキストウィンドウとmax_tokensの動作を考慮すると、以下が必要になる場合があります:
  • トークン使用量をより積極的に監視および管理する
  • プロンプト長が変化するにつれてmax_tokens値を調整する
  • トークンカウントエンドポイントをより頻繁に使用する可能性
  • 以前の思考ブロックがコンテキストウィンドウに蓄積されないことを認識する
この変更は、特に最大トークン制限が大幅に増加したため、より予測可能で透明な動作を提供するために行われました。

思考の暗号化

完全な思考コンテンツは暗号化され、signatureフィールドで返されます。このフィールドは、APIに戻される際に思考ブロックがClaudeによって生成されたことを検証するために使用されます。
拡張思考でツールを使用する場合にのみ、思考ブロックを戻すことが厳密に必要です。それ以外の場合は、以前のターンから思考ブロックを省略するか、戻す場合はAPIに削除させることができます。思考ブロックを戻す場合は、一貫性を保ち、潜在的な問題を回避するために、受け取ったものをすべて戻すことをお勧めします。
思考の暗号化に関する重要な考慮事項は以下の通りです:
  • レスポンスをストリーミングする場合、署名はcontent_block_stopイベントの直前にcontent_block_delta内のsignature_deltaを介して追加されます。
  • signature値は、以前のモデルよりもClaude 4モデルで大幅に長くなります。
  • signatureフィールドは不透明なフィールドであり、解釈や解析すべきではありません。検証目的のためだけに存在します。
  • signature値はプラットフォーム間(Claude API、Amazon Bedrock、およびVertex AI)で互換性があります。1つのプラットフォームで生成された値は別のプラットフォームと互換性があります。

思考の編集

時々、Claudeの内部推論が安全システムによってフラグが立てられることがあります。これが発生すると、thinkingブロックの一部またはすべてを暗号化し、redacted_thinkingブロックとして返します。redacted_thinkingブロックは、APIに戻される際に復号化され、Claudeがコンテキストを失うことなくレスポンスを続けることができます。 拡張思考を使用する顧客向けアプリケーションを構築する場合:
  • 編集された思考ブロックには、人間が読めない暗号化されたコンテンツが含まれていることを認識してください
  • 「Claudeの内部推論の一部が安全上の理由で自動的に暗号化されました。これはレスポンスの品質には影響しません。」のような簡単な説明を提供することを検討してください
  • 思考ブロックをユーザーに表示する場合、通常の思考ブロックを保持しながら編集されたブロックをフィルタリングできます
  • 拡張思考機能を使用すると、時々一部の推論が暗号化される可能性があることを透明にしてください
  • UIを壊すことなく編集された思考を適切に管理するための適切なエラーハンドリングを実装してください
通常の思考ブロックと編集された思考ブロックの両方を示す例は以下の通りです:
{
  "content": [
    {
      "type": "thinking",
      "thinking": "Let me analyze this step by step...",
      "signature": "WaUjzkypQ2mUEVM36O2TxuC06KN8xyfbJwyem2dw3URve/op91XWHOEBLLqIOMfFG/UvLEczmEsUjavL...."
    },
    {
      "type": "redacted_thinking",
      "data": "EmwKAhgBEgy3va3pzix/LafPsn4aDFIT2Xlxh0L5L8rLVyIwxtE3rAFBa8cr3qpPkNRj2YfWXGmKDxH4mPnZ5sQ7vB9URj2pLmN3kF8/dW5hR7xJ0aP1oLs9yTcMnKVf2wRpEGjH9XZaBt4UvDcPrQ..."
    },
    {
      "type": "text",
      "text": "Based on my analysis..."
    }
  ]
}
出力で編集された思考ブロックを見ることは期待される動作です。モデルは安全ガードレールを維持しながら、この編集された推論を使用してレスポンスを知らせることができます。アプリケーションで編集された思考処理をテストする必要がある場合は、プロンプトとしてこの特別なテスト文字列を使用できます:ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB
マルチターン会話でAPIにthinkingおよびredacted_thinkingブロックを戻す場合、最後のアシスタントターンのために完全な未修正ブロックをAPIに含める必要があります。これは、モデルの推論フローを維持するために重要です。すべての思考ブロックを常にAPIに戻すことをお勧めします。詳細については、上記の思考ブロックの保持セクションを参照してください。
この例は、Claudeの内部推論が安全システムによってフラグが立てられたコンテンツを含む場合にレスポンスに表示される可能性のあるredacted_thinkingブロックの処理方法を示しています:
import anthropic

client = anthropic.Anthropic()

# Using a special prompt that triggers redacted thinking (for demonstration purposes only)
response = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    max_tokens=16000,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    },
    messages=[{
        "role": "user",
        "content": "ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB"
    }]
)

# Identify redacted thinking blocks
has_redacted_thinking = any(
    block.type == "redacted_thinking" for block in response.content
)

if has_redacted_thinking:
    print("Response contains redacted thinking blocks")
    # These blocks are still usable in subsequent requests

    # Extract all blocks (both redacted and non-redacted)
    all_thinking_blocks = [
        block for block in response.content
        if block.type in ["thinking", "redacted_thinking"]
    ]

    # When passing to subsequent requests, include all blocks without modification
    # This preserves the integrity of Claude's reasoning

    print(f"Found {len(all_thinking_blocks)} thinking blocks total")
    print(f"These blocks are still billable as output tokens")

モデルバージョン間での思考の違い

Messages APIは、主に編集と要約動作において、Claude Sonnet 3.7とClaude 4モデル間で思考を異なって処理します。 簡潔な比較については、以下の表を参照してください:
機能Claude Sonnet 3.7Claude 4モデル
思考出力完全な思考出力を返す要約された思考を返す
インターリーブ思考サポートされていないinterleaved-thinking-2025-05-14ベータヘッダーでサポート

価格設定

拡張思考は標準のトークン価格設定スキームを使用します:
モデルベース入力トークンキャッシュ書き込みキャッシュヒット出力トークン
Claude Opus 4.1$15 / MTok$18.75 / MTok$1.50 / MTok$75 / MTok
Claude Opus 4$15 / MTok$18.75 / MTok$1.50 / MTok$75 / MTok
Claude Sonnet 4.5$3 / MTok$3.75 / MTok$0.30 / MTok$15 / MTok
Claude Sonnet 4$3 / MTok$3.75 / MTok$0.30 / MTok$15 / MTok
Claude Sonnet 3.7$3 / MTok$3.75 / MTok$0.30 / MTok$15 / MTok
思考プロセスでは以下に対して料金が発生します:
  • 思考中に使用されるトークン(出力トークン)
  • 後続のリクエストに含まれる最後のアシスタントターンからの思考ブロック(入力トークン)
  • 標準のテキスト出力トークン
拡張思考が有効な場合、この機能をサポートするために特殊なシステムプロンプトが自動的に含まれます。
要約された思考を使用する場合:
  • 入力トークン: 元のリクエストのトークン(以前のターンからの思考トークンを除く)
  • 出力トークン(請求): Claudeが内部的に生成した元の思考トークン
  • 出力トークン(表示): レスポンスで表示される要約された思考トークン
  • 料金なし: 要約の生成に使用されるトークン
請求される出力トークン数は、レスポンスで表示されるトークン数と一致しません。表示される要約ではなく、完全な思考プロセスに対して請求されます。

拡張思考のベストプラクティスと考慮事項

思考予算の操作

  • 予算の最適化: 最小予算は1,024トークンです。最小値から開始し、使用ケースに最適な範囲を見つけるために思考予算を段階的に増やすことをお勧めします。より高いトークン数により、タスクに応じて収穫逓減のトレードオフでより包括的な推論が可能になります。予算を増やすことで、レイテンシの増加のトレードオフでレスポンスの品質を向上させることができます。重要なタスクでは、最適なバランスを見つけるために異なる設定をテストしてください。思考予算は厳格な制限ではなく目標であることに注意してください。実際のトークン使用量はタスクに基づいて変動する場合があります。
  • 開始点: 複雑なタスクには大きな思考予算(16k+トークン)から開始し、ニーズに基づいて調整してください。
  • 大きな予算: 32kを超える思考予算については、ネットワークの問題を回避するためにバッチ処理の使用をお勧めします。32kトークンを超えて思考するようにモデルをプッシュするリクエストは、システムタイムアウトと開いている接続制限に対して実行される可能性のある長時間実行リクエストを引き起こします。
  • トークン使用量の追跡: コストとパフォーマンスを最適化するために思考トークンの使用量を監視してください。

パフォーマンスの考慮事項

  • レスポンス時間: 推論プロセスに必要な追加処理のため、レスポンス時間が長くなる可能性があることを準備してください。思考ブロックの生成により全体のレスポンス時間が増加する可能性があることを考慮してください。
  • ストリーミング要件: max_tokensが21,333を超える場合、ストリーミングが必要です。ストリーミング時は、到着する思考とテキストコンテンツブロックの両方を処理する準備をしてください。

機能の互換性

  • 思考はtemperaturetop_kの変更、および強制ツール使用と互換性がありません。
  • 思考が有効な場合、top_pを1から0.95の間の値に設定できます。
  • 思考が有効な場合、レスポンスを事前入力することはできません。
  • 思考予算の変更により、メッセージを含むキャッシュされたプロンプトプレフィックスが無効になります。ただし、キャッシュされたシステムプロンプトとツール定義は、思考パラメータが変更されても引き続き機能します。

使用ガイドライン

  • タスクの選択: 数学、コーディング、分析など、段階的推論の恩恵を受ける特に複雑なタスクに拡張思考を使用してください。
  • コンテキストの処理: 以前の思考ブロックを自分で削除する必要はありません。Claude APIは以前のターンからの思考ブロックを自動的に無視し、コンテキスト使用量を計算する際に含まれません。
  • プロンプトエンジニアリング: Claudeの思考能力を最大化したい場合は、拡張思考プロンプティングのヒントをご確認ください。

次のステップ