メッセージのストリーミング
server-sent eventsを使用して、テキスト、ツール使用、拡張思考のデルタを含むMessages APIのレスポンスを段階的にストリーミングします。
Messageを作成する際に、"stream": trueを設定すると、server-sent events(サーバー送信イベント)、すなわちSSEを使用してレスポンスを段階的にストリーミングできます。
SDKを使用したストリーミング
Python SDKとTypeScript SDKは、複数の「streaming」(ストリーミング)方法を提供しています。PHP SDKはcreateStream()を通じてストリーミングを提供します。Python SDKでは同期ストリームと非同期ストリームの両方が利用できます。詳細については各SDKのドキュメントを参照してください。
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
model="claude-opus-5-5",
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)イベントを処理せずに最終メッセージを取得する
到着したテキストを逐次処理する必要がない場合、SDKは内部的にストリーミングを使用しながら、.create()が返すものと同一の完全なMessageオブジェクトを返す方法を提供しています。これは、HTTPタイムアウトを回避するためにSDKがストリーミングを必要とする、大きなmax_tokens値を持つリクエストで特に便利です。
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=128000,
messages=[{"role": "user", "content": "Write a detailed analysis..."}],
model="claude-opus-5-5",
) as stream:
message = stream.get_final_message()
for block in message.content:
if block.type == "text":
print(block.text).stream()の呼び出しはserver-sent eventsによってHTTP接続を維持し、その後.get_final_message()(Python)または.finalMessage()(TypeScript)がすべてのイベントを蓄積して完全なMessageオブジェクトを返します。Goでは、ストリームループ内でmessage.Accumulate(event)を呼び出して同じ完全なMessageを構築します。Javaでは、MessageAccumulator.create()を使用し、各イベントに対してaccumulator.accumulate(event)を呼び出します。C#では、ストリームの.Aggregate()拡張メソッドをawaitして完全なMessageを取得するか、MessageContentAggregatorを.CollectAsync()に渡してイベントを処理しながら集約します。Rubyでは、ストリームに対して.accumulated_messageを呼び出します。PHP SDKでは、ストリームイベントを手動で反復処理してレスポンスを蓄積します。
イベントタイプ
各server-sent eventには、名前付きのイベントタイプと関連するJSONデータが含まれます。各イベントはSSEイベント名(例:event: message_stop)を使用し、データ内に対応するイベントtypeを含みます。
各ストリームは次のイベントフローを使用します。
message_start:空のcontentを持つMessageオブジェクトを含みます。thinking-binding-controls-2026-08-01ベータヘッダーを使用している場合、このMessageオブジェクトにはinput_transformations配列も含まれます。ストリーム途中でのサーバーサイドフォールバックの後、最後のmessage_deltaイベントには、実際に応答したモデルのエントリを含む配列が再度含まれます。- 一連のコンテンツブロック。それぞれに
content_block_start、1つ以上のcontent_block_deltaイベント、およびcontent_block_stopイベントがあります。各コンテンツブロックには、最終的なMessageのcontent配列内のインデックスに対応するindexがあります。例外が1つあります。サーバーサイドフォールバックレスポンス中は、各モデル境界でfallbackコンテンツブロックが、間にデルタを挟まないcontent_block_startとcontent_block_stopのペアとして到着します。 - 1つ以上の
message_deltaイベント。最終的なMessageオブジェクトに対するトップレベルの変更を示します。 - 最後の
message_stopイベント。
Pingイベント
イベントストリームには、任意の数のpingイベントが含まれる場合もあります。
エラーイベント
APIはイベントストリーム内でエラーを送信することがあります。例えば、使用量が多い期間にはoverloaded_errorを受け取ることがあります。これは非ストリーミングのコンテキストでは通常HTTP 529に相当します。
event: error
data: {"type": "error", "error": {"type": "overloaded_error", "message": "Overloaded"}}その他のイベント
バージョニングポリシーに従い、新しいイベントタイプが追加される可能性があるため、コードは未知のイベントタイプを適切に処理できるようにしておく必要があります。
コンテンツブロックデルタのタイプ
各content_block_deltaイベントには、指定されたindexのcontentブロックを更新するタイプのdeltaが含まれます。
テキストデルタ
textコンテンツブロックのデルタは次のようになります。
event: content_block_delta
data: {"type": "content_block_delta","index": 0,"delta": {"type": "text_delta", "text": "ello frien"}}入力JSONデルタ
tool_useコンテンツブロックのデルタは、ブロックのinputフィールドの更新に対応します。最大限の粒度をサポートするため、デルタは部分的なJSON文字列ですが、最終的なtool_use.inputは常にオブジェクトです。
文字列デルタを蓄積し、content_block_stopイベントを受信した時点でJSONを解析できます。Pydanticのようなライブラリを使用して部分的なJSON解析を行うか、解析済みの増分値にアクセスするヘルパーを提供するSDKを使用してください。
tool_useコンテンツブロックのデルタは次のようになります。
event: content_block_delta
data: {"type": "content_block_delta","index": 1,"delta": {"type": "input_json_delta","partial_json": "{\"location\": \"San Fra"}}}注:現在のモデルは、inputから一度に1つの完全なキーと値のプロパティを出力することのみをサポートしています。そのため、ツールを使用する際、モデルが処理している間はストリーミングイベント間に遅延が生じる場合があります。inputのキーと値が蓄積されると、将来のモデルでより細かい粒度を自動的にサポートできる形式とするため、チャンク化された部分的なJSONを含む複数のcontent_block_deltaイベントとして出力されます。
思考デルタ
ストリーミングを有効にして思考を使用する場合、thinking_deltaイベントを通じて思考コンテンツを受け取ります。これらのデルタはthinkingコンテンツブロックのthinkingフィールドに対応します。
思考コンテンツの場合、content_block_stopイベントの直前に特別なsignature_deltaイベントが送信されます。この署名は思考ブロックの整合性を検証するために使用されます。
思考の設定でdisplay: "omitted"が設定されている場合、思考テキストはストリーミングされません。思考ブロックが開き、空のthinking文字列を持つthinking_deltaを受け取り、続いて単一のsignature_deltaを受け取ってから閉じます。display: "updates"(ベータ)では、推論ブロックは同じ方法でストリーミングされ、一部のモデルがツール呼び出しの間に書き込む進捗更新のみが、テキストを含むthinking_deltaイベントをストリーミングします。思考表示の制御を参照してください。
典型的な思考デルタは次のようになります。
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "I need to find the GCD of 1071 and 462 using the Euclidean algorithm.\n\n1071 = 2 × 462 + 147"}}署名デルタは次のようになります。
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "signature_delta", "signature": "EqQBCgIYAhIM1gbcDa9GJwZA2b3hGgxBdjrkzLoky3dl1pkiMOYds..."}}完全なHTTPストリームレスポンス
ストリーミングモードを使用する際はクライアントSDKを使用してください。ただし、直接APIと統合する場合は、これらのイベントを自分で処理する必要があります。
ストリームレスポンスは次の要素で構成されます。
message_startイベント- 複数になる可能性のあるコンテンツブロック。それぞれに以下が含まれます。
content_block_startイベント- 複数になる可能性のある
content_block_deltaイベント content_block_stopイベント
- 1つ以上の
message_deltaイベント message_stopイベント
レスポンス全体にpingイベントが散在する場合もあります。形式の詳細についてはイベントタイプを参照してください。
基本的なストリーミングリクエスト
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-5-5",
messages=[{"role": "user", "content": "Hello"}],
max_tokens=256,
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)event: message_start
data: {"type": "message_start", "message": {"id": "msg_1nZdL29xx5MUA1yADyHTEsnR8uuvGzszyY", "type": "message", "role": "assistant", "content": [], "model": "claude-opus-5-5", "stop_reason": null, "stop_sequence": null, "usage": {"input_tokens": 25, "output_tokens": 1}}}
event: content_block_start
data: {"type": "content_block_start", "index": 0, "content_block": {"type": "text", "text": ""}}
event: ping
data: {"type": "ping"}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "Hello"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "!"}}
event: content_block_stop
data: {"type": "content_block_stop", "index": 0}
event: message_delta
data: {"type": "message_delta", "delta": {"stop_reason": "end_turn", "stop_sequence":null}, "usage": {"output_tokens": 15}}
event: message_stop
data: {"type": "message_stop"}
ツール使用を伴うストリーミングリクエスト
このリクエストは、Claudeにツールを使用して天気を報告するよう求めます。
client = anthropic.Anthropic()
tools = [
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}
},
"required": ["location"],
},
}
]
with client.messages.stream(
model="claude-opus-5",
max_tokens=1024,
tools=tools,
tool_choice={"type": "any"},
messages=[
{"role": "user", "content": "What is the weather like in San Francisco?"}
],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)event: message_start
data: {"type":"message_start","message":{"id":"msg_014p7gG3wDgGV9EUtLvnow3U","type":"message","role":"assistant","model":"claude-opus-5","stop_sequence":null,"usage":{"input_tokens":472,"output_tokens":2},"content":[],"stop_reason":null}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: ping
data: {"type": "ping"}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Okay"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":","}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" let"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"'s"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" check"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" the"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" weather"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" San"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Francisco"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":","}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" CA"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":":"}}
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":"tool_use","id":"toolu_01T1x1fJ34qAmk2tNTrN7Up6","name":"get_weather","input":{}}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"{\"location\":"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" \"San"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" Francisc"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"o,"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" CA\"}"}}
event: content_block_stop
data: {"type":"content_block_stop","index":1}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"output_tokens":89}}
event: message_stop
data: {"type":"message_stop"}思考を伴うストリーミングリクエスト
このリクエストはストリーミングで思考を有効にします。display: "summarized"設定は、完全な思考の連鎖ではなく、Claudeの推論の要約版をストリーミングします。
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-5-5",
max_tokens=20000,
thinking={"type": "adaptive", "display": "summarized"},
messages=[
{
"role": "user",
"content": "What is the greatest common divisor of 1071 and 462?",
}
],
) as stream:
for event in stream:
if event.type == "content_block_delta":
delta = event.delta
match delta.type:
case "thinking_delta":
print(delta.thinking, end="", flush=True)
case "text_delta":
print(delta.text, end="", flush=True)event: message_start
data: {"type": "message_start", "message": {"id": "msg_01...", "type": "message", "role": "assistant", "content": [], "model": "claude-opus-5-5", "stop_reason": null, "stop_sequence": null}}
event: content_block_start
data: {"type": "content_block_start", "index": 0, "content_block": {"type": "thinking", "thinking": "", "signature": ""}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "I need to find the GCD of 1071 and 462 using the Euclidean algorithm.\n\n1071 = 2 × 462 + 147"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "\n462 = 3 × 147 + 21"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "\n147 = 7 × 21 + 0"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "\nThe remainder is 0, so GCD(1071, 462) = 21."}}
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": "The greatest common divisor of 1071 and 462 is **21**."}}
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"}Web検索ツール使用を伴うストリーミングリクエスト
このリクエストは、Claudeに現在の天気情報をWebで検索するよう求めます。
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-5-5",
max_tokens=1024,
tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 5}],
messages=[
{"role": "user", "content": "What is the weather like in New York City today?"}
],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)event: message_start
data: {"type":"message_start","message":{"id":"msg_01G...","type":"message","role":"assistant","model":"claude-opus-5-5","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":2679,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":3}}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"I'll check"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" the current weather in New York City for you"}}
event: ping
data: {"type": "ping"}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"."}}
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":"server_tool_use","id":"srvtoolu_014hJH82Qum7Td6UV8gDXThB","name":"web_search","input":{}}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"{\"query"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"\":"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" \"weather"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" NY"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"C to"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"day\"}"}}
event: content_block_stop
data: {"type":"content_block_stop","index":1 }
event: content_block_start
data: {"type":"content_block_start","index":2,"content_block":{"type":"web_search_tool_result","tool_use_id":"srvtoolu_014hJH82Qum7Td6UV8gDXThB","content":[{"type":"web_search_result","title":"Weather in New York City in May 2025 (New York) - detailed Weather Forecast for a month","url":"https://world-weather.info/forecast/usa/new_york/may-2025/","encrypted_content":"Ev0DCioIAxgCIiQ3NmU4ZmI4OC1k...","page_age":null},...]}}
event: content_block_stop
data: {"type":"content_block_stop","index":2}
event: content_block_start
data: {"type":"content_block_start","index":3,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":"Here's the current weather information for New York"}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":" City:\n\n# Weather"}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":" in New York City"}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":"\n\n"}}
...
event: content_block_stop
data: {"type":"content_block_stop","index":17}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":10682,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":510,"server_tool_use":{"web_search_requests":1}}}
event: message_stop
data: {"type":"message_stop"}エラーからの回復
Claude 4.5以前
Claude 4.5以前のモデルでは、ネットワークの問題、タイムアウト、その他のエラーによって中断されたストリーミングリクエストを、ストリームが中断された箇所から再開することで回復できます。このアプローチにより、レスポンス全体を再処理する必要がなくなります。
基本的な回復戦略は次のとおりです。
- 部分的なレスポンスを取得する: エラーが発生する前に正常に受信されたすべてのコンテンツを保存します。
- 継続リクエストを構築する: 部分的なアシスタントレスポンスを新しいアシスタントメッセージの冒頭として含む、新しいAPIリクエストを作成します。
- ストリーミングを再開する: 中断された箇所からレスポンスの残りを引き続き受信します。
Claude 4.6以降
Claude 4.6以降のモデルでも、同じ取得と再開の戦略が適用されますが、ステップ2が変わります。部分的なレスポンスをアシスタントメッセージに配置する代わりに、中断した箇所から続けるようモデルに指示するユーザーメッセージを追加します。
- 部分的なレスポンスを取得する: エラーが発生する前に正常に受信されたすべてのコンテンツを保存します。
- 継続リクエストを構築する: 部分的なレスポンスと続行の指示を含むユーザーメッセージを持つ新しいAPIリクエストを作成します。例:
Sample prompt
Your previous response was interrupted and ended with [previous_response]. Continue from where you left off. - ストリーミングを再開する: 中断された箇所からレスポンスの残りを引き続き受信します。
エラー回復のベストプラクティス
- SDKの機能を使用する: SDKに組み込まれたメッセージ蓄積機能とエラー処理機能を活用します。
- コンテンツタイプを処理する: メッセージには複数のコンテンツブロック(
text、tool_use、thinking)が含まれる可能性があることに注意してください。ツール使用ブロックと拡張思考ブロックは部分的に回復できません。最新のテキストブロックからストリーミングを再開できます。
次のステップ
ストリームが完了したら、各stop_reason値を処理します。
サーバーサイドのバッファリングなしでツール入力JSONをストリーミングし、レイテンシを低減します。
thinking_deltaおよびsignature_deltaイベントで思考出力をストリーミングします。
ストリーミング、蓄積、再接続を処理してくれる公式SDKを使用します。
リアルタイムのレスポンスが不要な場合に、大量のリクエストを非同期で処理します。
Was this page helpful?