3行でいうと
- ストリーミングは、標準の「サーバー送信イベント(SSE)」で届きます。HTTPの状態が200で始まったあとにも、ストリームの中でエラーが届くことがあります。Anthropicのエラーの文書は、この場合のエラー処理は通常の仕組みに従わない、と書いています(HTTPエラー処理やSDKの再試行を名指ししてはいません)。
- 「切れたあとの再開」の作りは、3社で違います。Anthropicは、受け取った分を自分で保存して、続きを頼む形です。OpenAIは、バックグラウンド実行にして、イベントの番号から再開できます。Googleの新しいInteractions APIは、最後のイベントの番号を渡して再開する例があります。
- タイムアウトは、一つの数字ではありません。Anthropicの公式SDKは、既定で10分、再試行は2回。ほかに、接続の待ち時間、読み取りの待ち時間を分けて決められます。何を何秒にするかは、公式は決めておらず、設計する側が決めます。
この記事は、公式の文書を読んでまとめたもので、実際に使って確かめた記録ではありません。数字や仕様は2026年10月22日に確認しました。変わることがあります。
先に結論
- ストリーミングは、最初の文字が早く見えるだけでなく、長い処理の切断への対策でもあります。Anthropicのエラーの文書は、長い処理、とくに10分を超えるものには、ストリーミングかバッチの利用を検討するよう書いています。
- そのかわり、受け取る側は「途中で終わる」ことを前提に作る必要があります。切れ方は、3種類に分けて考えると整理しやすいです(あとの表)。
- 見立てです。ストリーミングの画面は、「出ている途中」「完了」「途中で終わった」の3状態を、最初から別々に作るのが無難です。これは公式の指示ではなく、公式の記述から僕らが引いた設計の線です。
前提:ストリーミングは何を運んでいるか
ふつうのAPIは、生成が終わってから、返事を丸ごと返します。ストリーミングは、できあがった分を細かく、順に送ります。多くのAIのAPIは、これにSSE(サーバー送信イベント)を使います。SSEはHTML標準の文書(WHATWG)に決まりがあり、サーバーからの一方向の送信を、text/event-streamという種類のHTTP応答で行います。
標準の文書の要点は次のとおりです。
- 1つのイベントは、
event(種類)、data(中身)、id(番号)、retry(再接続までの時間、ミリ秒)などの行からなり、空行で1つのイベントが完了します。 - コロンで始まる行はコメントで、受け取る側は無視します。書き手は、無通信の接続が切られないように、約15秒ごとにコメントを送ってもよい、とされています。
- 接続が切れると、受け取る側は一定時間待って再接続します。最後に受け取ったイベントの番号があれば、
Last-Event-IDというヘッダーで送り、サーバーが続きから送れるようにします。 - 応答の状態が200以外のときは、接続は失敗として扱われます。
注意が要るのは、これは標準が受け取る側に求める決まりだ、という点です。AIのAPIを、自分のサーバーのコードから呼ぶときは、各社のSDKや自作のコードが、この決まりのどこまでを実装するかは別です。たとえばAnthropicの文書が説明する再開は、あとで述べる「続きを頼む」方式で、Last-Event-IDは出てきません。
3社のストリーミングの比べ方
| Anthropic(Messages API) | OpenAI(Responses API) | Google(Gemini API) | |
|---|---|---|---|
| 有効にする | リクエストに"stream": true |
stream: true |
SDKでstreamをtrue。RESTは、URLにalt=sseを付けて本体でstreamをtrue(読んだのはInteractions APIの例) |
| イベントの構造 | message_start、各ブロックのcontent_block_start/content_block_delta/content_block_stop、message_delta、message_stop |
response.created、response.output_text.delta(繰り返し)、response.completed、error |
interaction.createdから、番号つきの「ステップ」(開始・差分・終了)、interaction.completed(RESTの例では最後にdone) |
| 無通信の確認 | pingイベントが、いつでも入りうる。内容はなく無視してよい |
読んだ範囲では記載なし | 読んだ範囲では記載なし |
| 途中のエラー | ストリーム内にerrorイベント(例:過負荷のoverloaded_error。通常の応答ではHTTP 529に当たる) |
errorイベント |
errorイベント |
| 未知のイベント | 新しい種類が足されうるので、知らないイベントは扱いを決めておく | 読んだ範囲では記載なし | 知らない種類は、記録して読み飛ばす |
| ツール呼び出しの引数 | input_json_deltaで、JSONの断片が届く。連結して、ブロックの終了で解析 |
イベントの種類(引数の差分と完了)は載っているが、扱い方は別のガイドとされ、読んでいない | 引数が断片で届き、連結してから解析 |
| 再開の方法 | 受け取った分を保存し、続きを新しいリクエストで頼む | background: trueとstream: trueを併用し、sequence_numberを目印にstarting_afterで再開 |
最後のイベントの番号を付けて、同じ「interaction」を再び要求する例がある |
Anthropic
公式文書によると、通常の流れは次のとおりです。message_startのあと、内容のブロックごとに、開始、1つ以上の差分、終了のイベントが来ます。message_deltaにはstop_reasonなど全体の変化が入ります。最後にmessage_stopが来ます。
差分には種類があり、文字はtext_delta、ツールの引数はinput_json_delta(JSONの断片)、思考はthinking_delta、思考の完全性を確かめる署名はsignature_deltaです。ツールの引数は、断片をつなげて、そのブロックのcontent_block_stopを受け取ってから解析します。文書によると、現行のモデルは、キーと値の1組を完成させてから出すので、イベントの間に間が空くことがあります。
SDKを使うと、イベントを自分で組み立てずに、最終のMessageを受け取れます。公式の例は次のとおりです(この記事では実行していません)。
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)
エラーからの回復について、同じ文書は次のように説明しています。Claude 4.5以前では、受け取れた分を保存し、それを助手の発言の書き出しとして含めた新しいリクエストを送って続きを受け取ります。Claude 4.6以降では、助手の書き出しではなく、利用者の発言として「前の返事は途中で中断された。ここまでが前の返事。続きから出して」という趣旨の文を、受け取れた分と一緒に送ります。ツールの呼び出しと思考のブロックは、途中から回復できないので、直近の文のブロックから再開します。
OpenAI
Responses APIの文書によると、stream: trueで、型のあるイベントが届きます。文書は、ストリーミングでは途中の文章を審査しにくい、と注意しています。審査のスコアを一緒に求めても、生成が全部終わってから届き、途中の差分には付かない、とも書かれています。
再開については、別のバックグラウンド実行の文書にあります。background: trueで長い処理を非同期にできます。ストリームも使うときは、backgroundとstreamの両方をtrueにし、各イベントのsequence_numberを覚えておけば、切れたときにstarting_afterで再開できます。ただし、再開できるのは、最初からstream=trueで作ったバックグラウンドの応答だけです。ストリームを使わず、状態を定期的に問い合わせる使い方もでき、取り消しの窓口もあります。最初の文字が出るまでの時間は、同期より長い、と書かれています。
Google(Gemini)
読んだ範囲では、Geminiのテキスト生成の文書のストリーミングの節は、Interactions APIの例でした。step.deltaというイベントに文字が入ります。ストリーミングの案内ページでは、ツールの引数は断片で届き、連結してから解析すること、ツールの実行が必要なときはrequires_actionの状態で終わり、結果を付けて次のリクエストを送ること、が書かれています。
「途中で終わる」3つのパターンと、見るもの
見立てです。公式の記述を、切れ方で並べ直しました。
| 切れ方 | 兆し | 公式が書いていること |
|---|---|---|
| 1. 接続が切れる・時間切れ | 通信の例外、無通信、504 | Anthropic:HTTP 504(timeout_error)が時間切れのエラー。長い処理(とくに10分超)には、ストリーミングかバッチを検討する |
| 2. ストリームの中のエラー | errorイベント |
200を返したあとでも起きる。エラー処理は通常の仕組みに従わない(SDKの再試行が効くかは、原文に明記なし) |
| 3. 完了のイベントが来ないまま終わる | message_stop、response.completed、interaction.completedが無い |
各社の文書にある完了のイベント。これが無いまま終わったら、「途中で終わった」と扱うのが無難(これは僕らの見立て) |
公式の文書は、message_deltaにstop_reasonなどの全体の変化が入る、と書いています。完了の理由の一覧は、今回読んだストリーミングのページには見つからなかったので、使うモデルの文書で確認してください。
タイムアウトの考え方(見立て)
公式の数字を材料に、層に分けて考えます。
- 全体の時間:Anthropicの公式SDKは、既定で10分です。長くなりそうな非ストリーミングのリクエストは、SDKが事前にエラー(
ValueError)にします。ストリーミングにするか、時間を明示して回避します。 - 読み取りの時間:SDKでは、全体、読み取り、書き込み、接続の4つを別々に決められます。公式の例は「全体60秒、読み取り5秒、書き込み10秒、接続2秒」です。ストリーミングでは、「全体の時間」より「次のイベントが来るまでの無音の長さ」で止める、という作り方もできますが、文書に決まった推奨値はありません。イベントの間隔は、ツールの引数を出すときなどに間が空くとも書かれています。
- 再試行:SDKは、接続の失敗、408、409、429、500以上を、既定で2回再試行します。0にもできます。ストリームの途中のエラーが、この再試行の対象になるかは、原文に明記がなく、確認できていません。
見立てです。無音の長さで止める場合は、モデルが長く考える場面や、ツールの引数が大きい場面で、誤って止めないように、余裕を持たせる必要があります。数字は、自分の使うモデルと用途で測って決めるしかありません。
公式の数値と上限の一覧(2026年10月22日に確認)
| 項目 | 内容 | 出どころ |
|---|---|---|
| Anthropic SDKの既定のタイムアウト | 10分。クライアント全体でも、リクエストごとでも変更できる | Anthropic Python SDKの文書 |
| 非ストリーミングの事前チェック | 約10分を超えると見込まれるとValueError。stream=Trueかtimeoutの明示で回避 |
同上 |
| 再試行 | 既定2回。接続エラー、408、409、429、500以上。max_retriesで変更、0で無効 |
同上、エラー文書 |
| TCPキープアライブ | SDKは既定で有効 | 同上 |
| リクエストの大きさ | Messages APIとToken Counting APIは32MB、Batch APIは256MB、Files APIは500MB。超えると413 | Anthropicのエラー文書 |
| 主なHTTPエラー | 504(timeout_error)、529(overloaded_error)、429(rate_limit_error。SDKの再試行の対象)。一覧には、400、401、402、403、404、409、413、429、500、504、529がある |
同上 |
| リクエストID | 応答のrequest-idヘッダーと、エラーの本文のrequest_id。問い合わせのときに伝える |
同上 |
| OpenAIのバックグラウンド応答 | プロジェクトの設定によっては、約10分だけ一時的に保存、または約10分後に削除される(条件は原文を確認) | OpenAIのバックグラウンドの文書 |
| SSEのコメントの間隔 | 約15秒ごとが、標準の文書にある書き手への提案 | WHATWGのSSE |
文書にあった、Anthropicの公式SDKの再試行の対象は、上の表のとおりです。ストリームの途中のエラーが含まれるかは、原文に明記がなく確認できていません。
よくある失敗・つまずき
- 一部の文字だけを受け取って「完了」と見なす。
message_stopなどの完了のイベントと、stop_reasonを確認します。 - ツールの引数の断片を、途中で解析する。公式は、ブロックの終了を待ってから解析する、と書いています。
- 知らないイベントで例外を出す。AnthropicもGoogleも、新しい種類が足されうるので、知らないものは読み飛ばす、と書いています。
- 200が返ったので成功と思い込む。ストリームの中でもエラーは来ます。
- ストリーミングの途中の文章を、そのまま審査なしで表示する。OpenAIは、途中の文章は審査しにくい、と注意しています。
- 続きを頼んだ結果が、元の文章と完全につながると思い込む。続きを頼む方式は新しい生成で、つながる保証は、読んだ文書には書かれていません。
気をつけること
- この記事は、実際に使って確かめた記録ではありません。コードは、公式文書の例を載せたもので、動作は確認していません。
- 読んだページは、ツールが要約を返す形で取得しています。文章は言い換えており、要約に混じった推論は事実として使っていません。
- OpenAIのストリーミングの文書には、再接続、無通信の確認、ツールの引数のストリームの詳しい説明は、別のガイドに案内されていて、読んでいません。「ない」とは断定できません。
- Googleは、Interactions APIの文書だけを読みました。従来のgenerateContentのストリーミング文書は読んでいません。Interactions APIのストリーミングの案内ページには、タイムアウトの詳しい説明がありませんでした。
- 再試行や再開で、料金がどう扱われるか、同じ処理が二重に実行されるか、は、読んだ文書では確認できていません。副作用のある処理(支払い、送信など)を再開で重ねないための設計は、自分で決める必要があります。
- 3社の数字(10分、2回、約10分など)は、変わりやすい値です。使う日の公式ページで確認してください。
- 「3状態の画面」「層ごとのタイムアウト」は、僕らの見立てです。公式の指示ではありません。
出典
- Streaming Messages(Claude Platform Docs、Anthropic、2026年10月22日確認)
- Errors(Claude Platform Docs、Anthropic、2026年10月22日確認)
- Python SDK(Claude Platform Docs、Anthropic、2026年10月22日確認)
- Streaming API responses(OpenAI API、OpenAI、2026年10月22日確認)
- Background mode(OpenAI API、OpenAI、2026年10月22日確認)
- Text generation(Gemini API、Google AI for Developers、Google、2026年10月22日確認)
- Interactions API streaming(Gemini API、Google AI for Developers、Google、2026年10月22日確認)
- Server-sent events(HTML Living Standard、WHATWG、2026年10月22日確認)
更新履歴
-
2026年10月25日 書き方を直しました。
- 前:運営者が使っていないと読める書き方 → いま:「この記事は、実際に使って確かめた記録ではありません」。公式の資料を読んでまとめた記事で、使い心地は書いていない、という意味に直した
-
2026年10月22日 公式の資料を読み直して、次の点を直しました。
- 前:リクエストの大きさは32MB/256MB/500MBで、対応は確認できていない → いま:Messages APIとToken Counting APIは32MB、Batch APIは256MB、Files APIは500MB。超えると413
- 前:HTTPエラー一覧の全体は確認できていない → いま:400、401、402、403、404、409、413、429、500、504、529の一覧を確認
- 前:429は再試行の対象 → いま:429は
rate_limit_errorで、SDKの再試行の対象 - 前:OpenAIの文書にツール引数のストリームの記載なし → いま:イベントの種類は載っているが、扱い方は別のガイドで、読んでいない
- 前:OpenAIの再接続などの説明は見つからなかった → いま:詳しい説明は別のガイドに案内されていて、読んでいない
