LLMストリーミングレスポンスの実装|UXを劇的に改善するストリーム処理テクニック
LLMストリーミングレスポンスの実装|UXを劇的に改善するストリーム処理テクニックこんにちは、橋本裕也です。ChatGPTやClaudeなどの大規模言語モデル(LLM)を使ったアプリケーション開発にお
LLMストリーミングレスポンスの実装|UXを劇的に改善するストリーム処理テクニック
こんにちは、西岡章です。
ChatGPTやClaudeといったLLMを使ったアプリケーション開発をしていると、応答の待ち時間がユーザー体験を大きく左右することに気づかされます。正直に言えば、数秒〜数十秒の間、ユーザーは画面を見つめているだけという状況は避けたいものです。本記事では、ストリーミングレスポンスという手法を使って、この体感時間を劇的に短縮する方法をご紹介します。
ストリーミングレスポンスとは
従来のLLM API呼び出しは、モデルが応答を完全に生成し終わってから、まとめて一度にクライアントに返す仕組みでした。ユーザーは数秒〜数十秒待たされた後、突然テキストが表示される。これが標準的な動きでした。
一方、ストリーミングレスポンスは、LLMが生成したテキストをトークン単位で逐次的に送り返す仕組みです。ユーザーはすぐにテキストが出現する様子を目で確認できるようになります。「なんか動いてるな」という感覚がユーザーに与えられるわけです。結果として、応答時間が実際よりも短く感じられ、対話的でリアルタイム性の高いUXが実現されるという実感があります。
Pythonでの実装例
まず、OpenAI APIを使ったPythonでのストリーミング実装から始めましょう。
基本的なストリーミング実装
import openai
def stream_chat_completion(prompt: str, model: str = "gpt-3.5-turbo"):
"""ストリーミングレスポンスを実装したチャット関数"""
client = openai.OpenAI(api_key="your-api-key")
with client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
stream=True # ストリーミングを有効化
) as response:
for chunk in response:
# delta.contentに部分的なテキストが含まれる
if chunk.choices[0].delta.content:
text = chunk.choices[0].delta.content
print(text, end="", flush=True)

# 使用例
stream_chat_completion("Pythonの非同期処理について教えてください")
実装のポイント
ここで重要なのは stream=True パラメータです。これを指定することでストリーミングモードが有効になり、レスポンスがチャンク単位で返されてきます。flush=True を付けることで、出力がバッファに溜まらず即座に画面に表示されるようになります。この2つを抑えるだけで、基本的なストリーミングは実装できます。
JavaScriptでのフロントエンド実装
Web上でストリーミングを使う場合、JavaScriptの力は欠かせません。フロントエンドでどう処理するかが、ユーザー体験を左右する重要な要素になります。
fetch APIを使用したストリーミング実装
async function streamChatResponse(prompt) {
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt })
});