ストリーミング応答
Streaming Response
概要(サマリー)
ストリーミング応答とは、LLMの出力を、全文ができてからまとめて受け取るのではなく、できた断片から順に受け取る方式である。
チャット画面で文字が少しずつ増えていくのは、この方式であることが多い。OpenAIでは stream を有効にし、HTTPの Server-Sent Events で断片を受け取る。
待ち時間が短く感じられるだけで、消費するトークンが減るわけではない。全文の生成が終わるまで、応答は未完成である。
詳細解説
まとめて返す方式との違い
ストリーミングを切ると、APIは出力を最後まで作ってから、1つのHTTPレスポンスで返す。長い回答では、最初の文字が見えるまで時間がかかる。
ストリーミングを入れると、生成の途中経過が順に届く。利用者は、完了前に内容を読み始められる。アプリは、届いた断片を画面へ足していく。
OpenAIのResponses APIでは、断片に種類がある。文章の続きは response.output_text.delta、完了は response.completed、失敗は error のように分かれる。見たい種類だけを拾い、それ以外は無視できる。
stream = client.responses.create(
model="使用するモデル名",
input="この関数が何をするか、3行で説明してください。",
stream=True,
)
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="")
delta は、その時点で増えた差分である。前の断片とつなげて、初めて文章になる。
料金と上限は減らない
早く見え始めることと、安くなることは別である。出力トークンは、ストリーミングでも同じように数える。途中で画面を閉じても、サーバー側の生成が続く実装がある。不要になったら、アプリ側で接続を明示的に閉じる。閉じた時点までに生成された分が課金されるかどうかは、サービスの説明で確認する。
ツール呼び出しも、引数のJSONが断片で届くことがある。断片の時点ではJSONとして閉じていない。パースして実行するのは、引数が完成してからにする。
エラーの出るタイミング
リクエストが拒否されるエラーは、ストリームが始まる前にHTTPステータスで返ることがある。一方、生成が始まったあとの失敗は、ストリームの中のイベントとして届く。
始まる前の失敗は、同じ依頼を送り直せる場合がある。断片をすでに画面へ出したあとの失敗は、送り直すと二重に表示される。どこまで利用者へ見せたかを持ってから、再試行するかを決める。
検査が遅れる
OpenAIは、ストリーミングすると出力の検査が難しくなると説明している。断片だけでは、完成後に問題になる文面かを判断しにくい。OpenAIには、有害な表現かどうかを点数で返す検査(モデレーション)を生成と同時に頼む機能がある。ただし、その点数は全文ができてから届き、途中の断片には付かない。
公開アプリで、不適切な出力を出さないことが要件なら、断片を仮表示するか、完成後に検査してから確定表示するかを先に決める。仮表示した文字は、あとから消す処理も要る。
WebSocketとの違い
WebSocketは、ブラウザとサーバーが接続を保ったまま双方向にメッセージを送る通信方式である。ストリーミング応答は、「1回の生成結果を分割して届ける」という受け取り方である。
OpenAIは、通常のストリーミングを Server-Sent Events で説明し、接続を保って追加入力する用途には別のWebSocketモードがあると分けている。動画のストリーミング配信とも、言葉は似ているが対象が違う。こちらはモデルの文章出力の届け方である。
AIコーディングとの関係
エディタのチャットで提案が一行ずつ出るのは、完成を待たずに差分を描いているからである。生成が遅いモデルでも、最初の数行で方向が違えば、その時点で止められる。
止めずに最後まで待ってから差分へ適用する実装もある。途中の文章は、コードとしてまだ閉じていない。括弧や文字列が欠けた断片を、その場でファイルへ保存しない。
AIにストリーミング対応のコードを書かせるときは、完成イベントとエラーイベントの両方を指定する。「文字が出れば成功」と書くと、途中の切断を成功扱いしがちである。
よくある勘違い
ストリーミングにすると安い?
料金の計算が変わる方式ではない。最初の文字が早く見える。トークン数は、生成した量で数える。
WebSocketを使うということ?
一般的なHTTPストリーミングは、サーバーからクライアントへの一方向のイベントである。双方向のWebSocketとは別の方式として説明されている。
途中まで見えたら、その内容で確定?
断片は未完成である。あとから続く文で意味が変わり、エラーで止まることもある。確定した応答は、完了イベントのあとである。
動画配信のストリーミングと同じ?
言葉は共通でも、ここではモデルの出力トークンを順に届けるAPIの話である。映像の配信方式ではない。
まとめ
- ストリーミング応答は、生成AIの出力を断片ごとに受け取る方式である
- 体感の待ち時間は短くなるが、トークン料金が減るわけではない
- 文章、完了、エラーは別のイベントとして届く
- 途中の断片はJSONとしても文章としても未完成なことがある
- 有害な出力の検査は、全文がそろってからでないと判定しにくい
情報ソース
より詳しくAIに聞いてみよう
- ストリーミング応答を、手紙を書きながら渡すたとえで説明してください。
- まとめて返す方式と、断片で返す方式の違いを整理してください。
- ストリーミングしてもAPI料金が減らない理由を説明してください。
- 途中で接続が切れたとき、画面に残った文章をどう扱うべきか教えてください。
- AIに、完了とエラーを分けて受け取るストリーミング処理の骨格を書かせる指示文を作ってください。