Streaming Reliability

LLMストリーミングの中断設計|途中表示を「完了」と扱わない、Abort・再接続・tool実行の分離【2026】

"LLMの逐次表示を本番運用するために、表示用stream、生成完了、利用者の中断、再接続、tool実行を分けて設計する方法を解説。OpenAI・Anthropic・Cloudflare Workersの仕様差と、二重実行を避ける最小構成を整理します。"

古野光太朗古野光太朗·2026.09.13·一次情報 6件
LLMストリーミングの途中表示、生成完了、tool外部効果を分離し、切断と再接続でも同じ実行を一度だけ確定する3段階の状態設計図

LLMの逐次表示は、待ち時間の印象を改善します。しかし、画面に数文字届いたこと、モデルが最後まで生成したこと、利用者が受け取ったこと、外部操作が確定したことは同じ出来事ではありません。スマートフォンの回線切替、ブラウザの「停止」、Workerのタイムアウト、tool呼び出しの途中切断を一つの「失敗」として扱うと、利用者には未完の文が残り、裏側では課金や更新だけが継続する、あるいは再接続時に二重実行する状態になります。

結論は、streamを表示の輸送路として扱い、業務上の完了は別の確定状態として持つことです。具体的には、(1) 途中deltaは表示専用、(2) providerの終端eventを受けて初めて生成完了、(3) toolや更新は完全な引数を検証してから一度だけ実行、(4) 再接続は同じ実行IDの状態を読みに行く、に分けます。これは9月12日のモデル切替設計とは別の論点です。あちらが「どのモデルへ切り替えるか」の契約なら、本稿は同じ実行を利用者へどう届け、いつ中断・確定するかの設計です。

deltaを業務データにしない

OpenAIのResponses APIはstream=trueでSSEを返し、response.output_text.deltaresponse.completederrorなどの型付きeventを送ります。したがって画面へdeltaを描画しても、response.completedを受けるまで回答を保存済み・送信可能とマークしません。AnthropicのMessages APIもSSEですが、最終はmessage_stopで、過負荷はstream内のerror eventとして届きます。さらにtoolの引数は途中では部分JSONであり、content_block_stop後に初めて完全なobjectとして扱えます。providerごとに終端eventとエラー表現が違うため、「接続が閉じたら成功」という共通化は危険です。

画面には、実行ID、現在の段階(生成中/tool待ち/確定/中断)、最後に検証済みのdelta番号だけを持たせます。生成中に切れても、利用者へは「回答を再接続中」か「中断しました」を明示し、本文を完成回答として会話履歴へ昇格させません。構造化出力やtool引数は、表示中の文字列から正規表現で取り出さず、providerの完了イベント後にschema検証します。

clientの切断を、上流の中断へ意図的に伝える

Cloudflare Workersはenable_request_signal互換フラグを有効にすると、clientがWorkerへのrequestを取り消したことをRequest.signalで検知できます。さらにrequest_signal_passthroughでは、そのAbortSignalをfetch()したsubrequestへ渡せます。これは「画面を閉じたら上流も必ず停止する」という自動保証ではなく、互換設定を含めた明示的な伝播経路です。利用者の停止を生成停止として扱いたい処理だけ、上流fetchへsignalを渡します。

Cloudflareの2025年5月22日付changelogも、clientによる取消しをRequest.signalのabort eventで検知する例を示しています。これはcancelを検知する入口の説明であり、toolや外部API側の処理が巻き戻る保証ではありません。

一方、切断後にも残すべきなのは、監査ログ、使用量の集計、実行状態の確定です。Cloudflareのctx.waitUntil()はresponse送信またはclient切断後に最大30秒まで延長できるものの、結果に必要な処理をそこへ逃がす用途ではありません。回答や書込みの成否をそこへ置けば、30秒上限や実行終了と競合します。確定が必要な処理はstream中にawaitし、長い処理はQueueやDurableな状態へ渡して、画面の接続寿命と切り離します。

再接続は「もう一度生成」ではなく、実行の継続確認にする

SSEのEventSourceには再接続とLast-Event-IDという仕組みがあります。ただし、これは配送されたeventの続きを要求できる仕組みであり、LLM providerが同じ生成を再開すること、toolを再実行しないことまでは保証しません。OpenAIとAnthropicでもevent名、終端、tool deltaの形式が異なります。そこでアプリ側にrun_id、連番、生成状態、最終イベント、tool実行状態、確定結果への参照を保存します。

再接続したclientはrun_idを送り、サーバーは未配信の表示deltaを返せるなら返し、返せない場合も確定済みの最終結果か明確な中断状態を返します。新しいprovider requestを作るのは、前の実行が「未開始」または安全に中断済みと確定した時だけです。外部操作にはrun_idとは別の冪等性キーを置き、tool_callを受けた時点ではなく、認可・引数・実行前条件を通してから確定結果を記録します。この分離が、再読込でメール送信やレコード更新が二度走る事故を避けます。

最小の状態遷移を先に決める

最初から複雑なresume機構は不要です。created → streaming → awaiting_tool → committing → completedと、どの段階からも入れるcancelledfailedを持つだけでよいでしょう。streamingの文字列は利用者向けの暫定表示、committingは変更を一度だけ確定する段階です。completed以外を業務完了として検索・通知・請求に流さない、と決めます。各遷移にrun ID、provider request ID、終了理由、送受信token、切断時刻だけを記録すれば、本文を無制限に残さず障害調査を始められます。

限界と確認範囲

streamingは応答開始を速く見せられますが、正答性や完了を速くする機能ではありません。provider側で生成が止まったか、接続だけが切れたか、既にtoolが実行済みかは製品・実装に依存します。外部送信、削除、支払い、権限変更は途中deltaを根拠に進めず、通常の認可・承認・冪等性・監査を別に適用してください。

導入時の最小チェックリスト

情報図解

結論: 「表示」「生成完了」「外部効果」を一本のstreamに混ぜない。

  1. 表示: deltaをrun_idと連番で配信し、切断時は暫定表示のまま止める。
  2. 確定: providerの終端event後にschema・終了理由を確認し、回答状態をcompletedにする。
  3. 効果: 完全なtool引数を認可・前提条件・冪等性キーで検証し、結果を一度だけ記録する。

制約: SSEの再接続は配送の再試行であり、LLM生成・tool実行の再開保証ではない。provider仕様とWorkerの互換フラグは実装時に再確認する。

一次根拠

一次情報と確認範囲

確認日:2026年9月13日。製品仕様・制度は更新されるため、導入時はリンク先の最新版を再確認してください。海外の制度・職業規範は日本へ直接適用せず、相違点と限界を本文に明記しています。

  1. OpenAI Responses APIは`stream=true`でSSEを使い、`response.output_text.delta`、`response.completed`、`error`を含む型付きeventを扱う
  2. Anthropicはstream内で`message_stop`、`error`、部分JSONのtool deltaを定義し、tool inputはblock停止後に完全objectになる
  3. Workersは`enable_request_signal`でclientによるrequest取消しを検知できる
  4. Cloudflareは`Request.signal`のabort eventでclient取消しを検知するWorker例を公開した
  5. Workersのstreamはresponse bodyが完了するかclientが切断するまで実行を進め、`waitUntil()`は切断後最大30秒の延長に使える
  6. SSEのEventSourceは再接続時に`Last-Event-ID`をrequest headerへ設定し得る
古野光太朗
古野光太朗 / 株式会社TechWorker 代表取締役 CEO兼CTO

上場企業を含む37社・2,500名の生成AI導入・研修支援で得た実務知をもとに、導入・運用・顧客理解を扱っています。この実績はTechWorkerの生成AI支援実績であり、個別製品の導入実績を示すものではありません。

LLMストリーミングの中断・再接続を設計する

表示delta、provider完了、tool実行を分け、切断時の二重実行と未完回答を防ぐ状態遷移を整理します。

AI基盤設計を相談する
← AI基盤ラボの記事一覧に戻る