精神を病むことなく、ストリーミングAIチャットクライアントを構築した話

AIがリアルタイムで応答するチャットインターフェースを作りたかった。あの滑らかなタイピングエフェクトが欲しかったのだ。

それは思ったよりも難しかった。問題はAIではなかった。APIとブラウザの間のパイプラインだった。

私はこれを解決するために、3つの異なる方法を試した。

  1. 待機メソッド APIを呼び出し、レスポンスがすべて返ってくるまで待ってから表示する方法だ。これは動作したが、UIが数秒間フリーズしてしまった。ユーザーはアプリが壊れたと思い、何度も「送信」をクリックしてしまった。これは最悪のユーザー体験だった。

  2. ポーリングメソッド サーバーにジョブIDを送信させ、クライアントが1秒ごとに更新を確認する方法を考えた。これには重いサーバー管理が必要になる。更新はバラバラな塊で表示され、滑らかではなかった。

  3. WebSocketメソッド Socket.IOを試した。これは複雑さを大幅に増大させた。再接続、ハートビート、状態の同期などを管理しなければならなかった。シンプルなチャットアプリにとって、WebSocketはオーバースペックだった。

解決策はもっとシンプルだった。Server-Sent Events (SSE) だ。

ほとんどのAI APIは、すでにHTTP経由のSSEでレスポンスを送信している。私は複雑なツールを探すのをやめ、ネイティブの fetch APIを使用した。

response.body.getReader() を使うことで、バイトストリームを直接読み取った。SSEプロトコルは自分でパースした。このアプローチにより、UIの応答性を維持しつつ、標準的なHTTPを利用できる。

なぜこれがうまくいくのか:

  • WebSocketサーバーが不要。
  • 複雑な再接続ロジックが不要。
  • SSEをサポートするあらゆるAPIで動作する。
  • AbortController を使用して、簡単にストリームを停止できる。

トレードオフもある:

  • リクエストなしでクライアントに更新をプッシュすることはできない。
  • 接続が切断されると、それまでの部分的なレスポンスが失われる。

チャットアプリを作るなら、双方向通信が必要でない限りWebSocketは避けるべきだ。HTTPストリーミングに絞るのがいい。その方がシンプルで信頼性が高い。

あなたのストリーミング戦略は何ですか?WebSocketを使いますか、それともSSEですか?コメントで教えてください。

Source: https://dev.to/__c1b9e06dc90a7e0a676b/i-built-a-streaming-ai-chat-client-without-losing-my-mind-3gi0