Intermediate

Streaming LLM Responses

Stream AI model outputs token by token using Server-Sent Events (SSE) and WebSockets. Build real-time inference APIs like ChatGPT with FastAPI.

Server-Sent Events (SSE)

SSE is the most common pattern for streaming LLM responses. The server pushes tokens to the client as they are generated:

Python - SSE Streaming
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import asyncio, json

app = FastAPI()

async def generate_stream(prompt: str):
    # Simulate LLM streaming (replace with real model)
    for token in ["Hello", " there", "!", " How", " can", " I", " help", "?"]:
        data = json.dumps({"token": token})
        yield f"data: {data}\n\n"
        await asyncio.sleep(0.1)
    yield "data: [DONE]\n\n"

@app.post("/chat/stream")
async def stream_chat(prompt: str):
    return StreamingResponse(
        generate_stream(prompt),
        media_type="text/event-stream"
    )

Streaming with OpenAI

Python
from openai import AsyncOpenAI

client = AsyncOpenAI()

async def openai_stream(prompt: str):
    stream = await client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}],
        stream=True,
    )
    async for chunk in stream:
        if chunk.choices[0].delta.content:
            data = json.dumps({"token": chunk.choices[0].delta.content})
            yield f"data: {data}\n\n"
    yield "data: [DONE]\n\n"

@app.post("/chat")
async def chat(prompt: str):
    return StreamingResponse(openai_stream(prompt), media_type="text/event-stream")

WebSocket for Real-Time

Python
from fastapi import WebSocket, WebSocketDisconnect

@app.websocket("/ws/chat")
async def websocket_chat(ws: WebSocket):
    await ws.accept()
    try:
        while True:
            prompt = await ws.receive_text()
            # Stream response back
            async for token in generate_tokens(prompt):
                await ws.send_json({"token": token})
            await ws.send_json({"done": True})
    except WebSocketDisconnect:
        print("Client disconnected")

Client-Side Consumption

JavaScript - SSE Client
const response = await fetch("/chat/stream", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ prompt: "Hello" })
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const text = decoder.decode(value);
  // Parse SSE data and update UI
}

Background Tasks

Python
from fastapi import BackgroundTasks

async def log_inference(prompt: str, result: str):
    # Save to database, send metrics, etc.
    await db.save_log(prompt=prompt, result=result)

@app.post("/predict")
async def predict(input: TextInput, background_tasks: BackgroundTasks):
    result = model.predict(input.text)
    background_tasks.add_task(log_inference, input.text, result)
    return {"result": result}  # Returns immediately
SSE vs WebSocket: Use SSE for one-directional streaming (server to client), like LLM responses. Use WebSocket for bidirectional real-time communication, like interactive chat with typing indicators.

What's Next?

Now let's secure our API with authentication, API keys, and rate limiting.

Ready to Go Deeper?

Live instructor-led courses from our partners. Affiliate disclosure.