Trung BìnhAI Engineering iconAI Engineering

Streaming response trong LLM: cách triển khai và lợi ích?

LLM sinh token lần lượt (autoregressive). Streaming là stream từng token/chunk ra client ngay khi sinh, thay vì đợi hoàn thành → time to first token (TTFT) thấp, UX mượt.

Lợi ích:
- Perceived latency — user thấy output ngay (< 1s), dù total latency 10s vẫn "cảm giác" nhanh.
- Cancellable — user thấy kết quả sai có thể stop sớm → tiết kiệm cost.
- Bắt buộc cho chat UI, code editor, voice assistant.

Cơ chế server-side (OpenAI/Anthropic):

py
stream = client.chat.completions.create(
  model="gpt-4o", messages=[...], stream=True
)
for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta: yield delta

Provider trả về chunks qua HTTP chunked transfer / SSE.

Transport protocol:

1. Server-Sent Events (SSE)phổ biến nhất cho LLM streaming. HTTP/1.1 long-lived connection, server push data: {...}\n\n events. Chạy sau CDN/proxy ok. Format OpenAI dùng: data: {"choices":[...]}\n\ndata: [DONE]\n\n.

2. WebSocket — full-duplex. Dùng khi cần bidirectional (voice, interrupt mid-stream, user gõ trong khi model nói). Phức tạp hơn SSE, sticky session.

3. HTTP/2 Server Push / gRPC streaming — hiếm hơn, dùng trong microservice.

4. HTTP chunked + JSONL — đơn giản nhất, Transfer-Encoding: chunked + mỗi chunk 1 JSON line.

Implementation trong Next.js 15 App Router:

ts
export async function POST(req: Request) {
  const stream = await openai.chat.completions.create({ stream: true, ... });
  const readable = new ReadableStream({
    async start(ctrl) {
      for await (const chunk of stream) {
        const delta = chunk.choices[0]?.delta?.content;
        if (delta) ctrl.enqueue(new TextEncoder().encode(delta));
      }
      ctrl.close();
    },
  });
  return new Response(readable, { headers: { "Content-Type": "text/event-stream" } });
}

Frontend dùng Vercel AI SDK (useChat, useCompletion) để handle SSE parsing và state UI.

Thách thức production:

1. Parsing structured output khi stream — JSON mode/tool calling stream từng fragment, cần partial JSON parser (partial-json, streamText trong AI SDK).

2. Cache khó — stream không cache đơn giản như response fixed. Giải pháp: cache metadata (input hash → full response); lần sau replay.

3. Error mid-stream — đã gửi một phần response rồi gặp lỗi. Cần protocol báo lỗi trong stream (event: error) + client handle gracefully.

4. Cancellation propagation — user close tab → cần abort upstream API call để không bị charge tiếp. Dùng AbortController truyền xuống SDK.

5. Load balancer / CDN — Cloudflare, nginx có thể buffer SSE → phá streaming. Cần config X-Accel-Buffering: no, hoặc disable Cloudflare proxy.

6. Edge runtime limitations — Vercel Edge timeout 30s mặc định, Fluid Compute 300s. Lambda cold start ảnh hưởng TTFT.

7. Metrics — track TTFT (quan trọng hơn total latency), inter-token latency, dropped connection rate.

8. Token counting while streaming — mỗi chunk chỉ có partial; tally usage ở event cuối (finish_reason) hoặc ước lượng bằng tokenizer client.

Best practices:
- Hiện cursor/typing indicator trước khi token đầu về.
- Smooth rendering (không nhấp nháy): accumulate chunks, render mỗi 16ms.
- Scroll anchor cuối message khi token mới đến.
- Guardrail check có thể buffer → delay few token trước khi emit để check PII/toxicity (trade-off latency).

Xem toàn bộ AI Engineering cùng filter theo level & chủ đề con.

Mở danh sách AI Engineering