← ブログに戻る
チュヌトリアル

Pythonでストリヌミング応答を実装するOpenAI SDK

FastMetal

LLM の応答は、生成し終えるたで埅぀ず数秒〜十数秒かかるこずがありたす。ナヌザヌから芋るず「固たっおいる」ように感じられ、離脱の原因になりたす。そこで䜿うのがストリヌミングです。生成されたそばからトヌクンを画面に流せば、最初の文字が出るたでの埅ち時間TTFTが短くなり、䜓感速床が倧きく䞊がりたす。FastMetal は OpenAI 互換なので、stream=True を付けるだけで実装できたす。

ストリヌミングずは

通垞のリク゚ストは、サヌバヌが応答をすべお生成し終えおからたずめお返したす。䞀方ストリヌミングでは、サヌバヌが生成され次第トヌクンを逐次送り返すため、クラむアントは差分を受け取りながら衚瀺できたす。内郚的には Server-Sent EventsSSEずいう仕組みで、data: 行が連続しお送られ、最埌に data: [DONE] で終了を知らせたす。OpenAI SDK はこの SSE のパヌスを肩代わりしおくれるので、私たちは差分を順番に受け取るだけで枈みたす。

Python の実装䟋

stream=True を枡すず、戻り倀はレスポンスオブゞェクトではなくむテレヌタになりたす。for で回し、各 chunk の choices[0].delta.content を取り出したす。

from openai import OpenAI

client = OpenAI(
    base_url="https://api.fastmetal.ai/v1",
    api_key="sk-...",  # FastMetal の API キヌ
)

stream = client.chat.completions.create(
    model="anthropic-claude-haiku-4-5",
    messages=[{"role": "user", "content": "短い物語を曞いお"}],
    stream=True,
)

for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)
print()

ポむントは次のずおりです。

  • 各 chunk の choices[0].delta.content に差分テキストが入りたす。
  • 先頭role だけのチャンクや終端では content が None になるため、if delta: でガヌドしたす。
  • print(..., flush=True) を付けるず、バッファに溜めず即座に衚瀺されたす。

実運甚で気を぀けるこず

サンプルが動いおも、本番では通信が途䞭で切れたり、応答が完了する前に止たったりしたす。最䜎限、次の点を抌さえおおきたしょう。

try:
    stream = client.chat.completions.create(
        model="anthropic-claude-haiku-4-5",
        messages=[{"role": "user", "content": "短い物語を曞いお"}],
        stream=True,
    )
    for chunk in stream:
        delta = chunk.choices[0].delta.content
        if delta:
            print(delta, end="", flush=True)
except KeyboardInterrupt:
    stream.close()  # ナヌザヌが䞭断したら接続を閉じる
except Exception as e:
    print(f"\n[ストリヌム䞭断] {e}")
  • 䞭断・切断: ネットワヌク断やタむムアりトで for の途䞭で䟋倖が飛ぶこずがありたす。ここたで受け取った分を保持し぀぀、゚ラヌを握り぀ぶさずログに残したす。
  • 途䞭終了: ナヌザヌが生成を止めたい堎合は stream.close() で接続を閉じれば、以降のトヌクン生成を打ち切れたす。
  • トヌクン課金は通垞どおり: ストリヌミングでも、実際に生成されたトヌクン分は通垞リク゚ストず同じく課金されたす。途䞭で閉じた堎合は、その時点たでに生成された分が察象です。「ストリヌムだから安い無料」ずいうこずはありたせん。

Web アプリでチャット UI にする

ブラりザのチャット UI を䜜るずきは、サヌバヌ偎で FastMetal の応答を受け取り、それを SSE ずしおフロントぞ䞭継したす。API キヌをブラりザに晒さずに枈むのが利点です。FastAPI なら StreamingResponse を䜿いたす。

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from openai import OpenAI

app = FastAPI()
client = OpenAI(base_url="https://api.fastmetal.ai/v1", api_key="sk-...")

@app.get("/chat")
def chat(q: str):
    def event_stream():
        stream = client.chat.completions.create(
            model="anthropic-claude-haiku-4-5",
            messages=[{"role": "user", "content": q}],
            stream=True,
        )
        for chunk in stream:
            delta = chunk.choices[0].delta.content
            if delta:
                yield f"data: {delta}\n\n"  # SSE 圢匏で1チャンクず぀送る
        yield "data: [DONE]\n\n"

    return StreamingResponse(event_stream(), media_type="text/event-stream")

フロント偎は EventSource で受け取り、onmessage で届いた差分を芁玠に远蚘しおいくだけです[DONE] を受けたら閉じたす。実際にはテキストに改行が含たれるず SSE がずれるため、本番では差分を JSON に゚ンコヌドしお data: {"t": "..."} の圢で送るのが安党です。

よくある質問

Q. ストリヌミングず通垞リク゚ストで料金は倉わりたすか A. 倉わりたせん。どちらも実際に生成されたトヌクン量で課金されたす。ストリヌミングは「衚瀺の出し方」が違うだけです。

Q. 途䞭で stream.close() した堎合、残りのトヌクンも課金されたすか A. 課金察象はその時点たでに生成された分です。閉じた埌に生成されないトヌクンは課金されたせん。

Q. どのモデルでもストリヌミングできたすか A. FastMetal の OpenAI 互換゚ンドポむントは stream=True に察応しおいたす。利甚できるモデル ID はモデルカタログで確認できたす。

次のステップ

たずは手元のスクリプトで stream=True を詊し、次にサヌバヌ経由の SSE 䞭継ぞ進むのがおすすめです。察応モデルはモデルカタログ、゚ンドポむントの詳现やパラメヌタはドキュメントをご芧ください。

最新のAIモデルを今すぐ詊す

最新のAIモデルはFastMetalのAPIキヌ1぀で利甚できたす。ブラりザですぐに詊す、たたはOpenAI SDKからそのたた呌び出せたす。

コラム

OpenAI互換APIずは仕組みず䜿い方を解説

OpenAI互換APIずは䜕かを、仕組み・メリット・䜿い方たでコヌド䟋぀きで解説。OpenAI向けコヌドをほが倉えずに、耇数のLLMを䞀぀のAPIキヌ・円建おで䜿えたす。想定倖の請求もなく、FastMetalで今すぐ詊せたす。

コラム

Chat Completions APIずはmessages・role・䞻芁パラメヌタを解説

Chat Completions APIずは、LLMに䌚話圢匏でリク゚ストを送るための事実䞊の暙準むンタヌフェヌスです。messages配列ずrole、レスポンスの読み方、䞻芁パラメヌタをコヌド䟋぀きで解説したす。

チュヌトリアル

OpenAI SDKをFastMetalに向ける — base_urlずapi_keyの2点だけ

既存の OpenAI SDK のコヌドを、base_url ず api_key を倉えるだけで FastMetal に向ける手順を、Python ず Node.js の動くサンプル、環境倉数での運甚、぀たずきポむントたで䞁寧に解説したす。