📖 推定読了時間:約6分
ChatGPT、Claude、Geminiといった生成AIサービスの画面で、質問を送信すると、AIが考えながら「1文字ずつ、サラサラと滑らかに文章を紡ぎ出していく様子(ストリーミング出力)」はおなじみの光景となりました。もし回答がすべて生成されるまで数十秒も真っ白な画面で待たされたら、ユーザー体験は最悪なものになってしまうでしょう。
では、このリアルタイムな文字ストリーミングは、どのような通信技術で実現されているのでしょうか?Webでリアルタイム通信といえば、真っ先に「WebSocket」を思い浮かべるエンジニアが多いかもしれません。しかし実際には、OpenAIをはじめとする主要なAIプロバイダーは、WebSocketではなく、はるか昔から存在する「Server-Sent Events(SSE)」を標準採用しています。なぜ、双方向通信の代表格であるWebSocketではなく、地味な「サーバーからの一方向通信」であるSSEが選ばれるのでしょうか?
この記事のポイント
- AIの回答は「クライアントからの送信(1回)」と「サーバーからの連続返信(複数回)」の一方向で完結する
- WebSocket特有のプロトコルアップグレード、プロキシ遮断、ハートビート死活監視の運用負荷を完全回避
- 標準的なHTTP/2・HTTP/3の上でそのまま動き、ブラウザに「自動再接続」が最初から組み込まれている
WebSocketが抱える「AIストリーミングにおける過剰さ」
WebSocketは、オンラインゲームやチャットアプリ、金融取引の板情報など、「クライアントとサーバーの双方が、いつでも瞬時にデータを送り合いたい双方向リアルタイム通信」のために開発されたプロトコルです。
しかし、LLMのチャットボットのユースケースを冷静に分解してみると、通信の流れは極めてシンプルです。
- ユーザーがプロンプト(質問文)を送信する(クライアントからサーバーへの1回のリクエスト)
- AIがトークンを次々と生成して順次送り返す(サーバーからクライアントへの一方向データストリーム)
- 回答が終われば通信は終了する
つまり、「サーバーからクライアントへデータが流れている最中に、クライアントから追加のバイナリデータを頻繁に割り込み送信する」という双方向性は、そもそも全く必要ないのです。必要のない機能のためにWebSocketを採用すると、かえって数々の運用上の地雷を踏むことになります。
クラウドインフラやマイクロサービス設計において、APIプロトコル(REST、gRPC、GraphQL、SSE等)を適材適所で選定するアーキテクチャ設計手法を深く学びたい方には、分散システムの教科書である クラウドネイティブマイクロサービス設計解説書 が非常に役立ちます。ステートレス設計と通信負荷軽減の勘所が掴めます。
徹底比較:なぜSSEはこれほどまでにシンプルで強いのか?
Server-Sent Events(SSE)は、特別な通信プロトコルではありません。「ごく普通のHTTP通信」のヘッダーに Content-Type: text/event-stream と指定し、レスポンスのコネクションを開きっぱなしにして、テキストデータを改行区切りで流し込み続けるだけの極めてシンプルな仕組みです。
| 比較項目 | WebSocket | Server-Sent Events(SSE) |
|---|---|---|
| 通信の方向性 | 双方向(Full-Duplex) | 一方向(サーバー → クライアント) |
| 使用プロトコル | 独立したプロトコル(ws://, wss://) | 標準HTTP(http://, https://)そのもの |
| プロキシ・CDN・ロードバランサー | 社内プロキシやCDNで弾かれやすく、設定が複雑 | 普通のHTTP通信なので、既存のCDNやWAFを無加工で通過 |
| 自動再接続とイベントID | 自前で再接続ロジックやPing-Pong実装が必要 | ブラウザの標準機能(EventSource)に自動再接続が内蔵 |
| HTTP/2・HTTP/3との相性 | 別コネクションとなり、多重化の恩恵が薄い | 単一のTCP/QUICコネクション内で他の通信と相乗り可能 |
企業のオフィスネットワークなどでよくあるのが、「セキュリティの厳しいプロキシサーバーやファイアウォールが、怪しいWebSocketのハンドシェイク(Connection: Upgrade)を問答無用で遮断してしまう」というトラブルです。しかしSSEは、誰がどう見ても「単なるHTTPSのGET/POSTリクエスト」にしか見えないため、世界中どんな企業ネットワークやCDNを経由しても、ブロックされることなく確実に届きます。
モダンJavaScriptにおける非同期処理(Async/Await、Fetch API、ReadableStream、Async Iterator)の内部仕様や最新構文を徹底マスターしたいWebエンジニアには、基礎から応用までを体系的に網羅した JavaScript新仕様実践ガイドブック が手元にあると、ストリーミング処理の実装に迷いがなくなります。
Fetch APIとReadableStreamによる現代のSSE実装
かつてSSEといえばブラウザ組み込みの EventSource オブジェクトを使うのが定番でしたが、現代のWeb開発(React、Next.js等)では 標準の fetch() と ReadableStream を組み合わせた実装が主流です。
fetch() を使えば、通常のPOSTリクエストのbodyにユーザーの巨大なプロンプトやチャット履歴(JSON)を乗せて送信し、レスポンスの response.body.getReader() から到着したトークンをリアルタイムにデコードして画面に反映できます。認証ヘッダー(Bearerトークン)の付与も、普段のREST API呼び出しと完全に同じコードで記述できるため、開発者の認知的負荷が極めて小さくて済みます。
HTTP/2・HTTP/3による多重化の威力
古いHTTP/1.1では「ブラウザから同一ドメインへ張れる接続数は最大6本まで」という厳しい制限があり、SSEで接続を占有すると他の画像などが読み込めなくなる欠点がありました。しかしHTTP/2やHTTP/3が普及した現在では、1本の接続の中に何十ものストリームを相乗りさせられるため、接続枯渇の問題は完全に過去のものとなりました。
まとめ:道具は「目的に対して最もシンプルなもの」を選ぶ
最新の技術や多機能なプロトコルが、常にベストな選択肢とは限りません。「AIが生成したテキストをブラウザに流し込む」という明確な要件に対して、SSEは必要最小限の機能、枯れた信頼性、そして圧倒的な運用のしやすさを提供してくれます。
誇大広告に惑わされず、アーキテクチャの本質を見抜いて最も堅牢な技術を選ぶ。Server-Sent EventsがAI時代に果たした鮮やかな復活劇は、すべてのエンジニアにとって「優れたシステム設計とは何か」を教えてくれる最高のケーススタディと言えるでしょう。



0 件のコメント:
コメントを投稿