InterviewHubPRO
Section Overview
Q19

Question 19 of 50

Part 2: LLM Inference, Serving & Runtime Optimization

38%
AI Engineering & LLMs (50 Qs)•Part 2: LLM Inference, Serving & Runtime Optimization

Streaming Architecture: Server-Sent Events (SSE), WebSockets & The Vercel AI SDK Protocol

1. Why Streaming is Mandatory for LLM UX

Because autoregressive models generate text sequentially at ~30–80 tokens per second:

  • Non-streaming: User stares at a blank screen for 6–10 seconds until the entire 500-token paragraph completes.
  • Streaming: The user receives the first token in < 300 ms (Time-To-First-Token, TTFT), reading tokens in real time as they generate.

2. Transport Protocol Comparison

ProtocolConnection TypeMultiplexingBrowser OverheadIdeal Use Case
Server-Sent Events (SSE)Unidirectional (Server → Client) over HTTP/2High (reuses HTTP/2 connection)Very Low (EventSource or fetch with ReadableStream)Industry Standard for LLM chat completions
WebSocketsFull-Duplex (Bidirectional)Requires dedicated TCP connectionHigh (custom heartbeat & reconnect logic)Audio/Video Live API (e.g. Gemini Live, OpenAI Realtime)
HTTP Long PollingUnidirectional HTTP/1.1NoneVery HighObsolete for LLM applications

3. Production Fastify / Next.js SSE Streaming Implementation

typescript
// Next.js Route Handler (App Router: app/api/chat/route.ts)
import { OpenAIStream, StreamingTextResponse } from 'ai';
import OpenAI from 'openai';

const openai = new OpenAI();

export async function POST(req: Request) {
  const { messages } = await req.json();

  const response = await openai.chat.completions.create({
    model: 'gpt-4o',
    stream: true,
    messages,
  });

  // Convert raw generator into WHATWG ReadableStream
  const stream = new ReadableStream({
    async start(controller) {
      for await (const chunk of response) {
        const text = chunk.choices[0]?.delta?.content || '';
        if (text) {
          // SSE Data Framing Protocol
          controller.enqueue(new TextEncoder().encode(`data: ${JSON.stringify({ text })}\n\n`));
        }
      }
      controller.enqueue(new TextEncoder().encode('data: [DONE]\n\n'));
      controller.close();
    },
  });

  return new Response(stream, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache, no-transform',
      'Connection': 'keep-alive',
    },
  });
}