AI Engineering

Latency Optimization Guide

Making AI systems fast in production — streaming, parallel retrieval, model selection, speculative decoding, edge caching, and latency budgets per pipeline stage.

55 min readIntermediateLast reviewed: 21 July 2026

Quick Summary

LLM latency optimization reduces TTFT and total response time by streaming, parallelizing pre-LLM work, routing to faster models, and setting per-stage budgets — trading against cost and quality deliberately.

One Analogy

Waiting for the full essay before showing the first sentence is reading a book with the cover glued shut — stream the first page while the rest prints.

Engineering Rule

Measure TTFT and per-stage latency; never skip quality gates on degraded paths without sampling eval.

TL;DR

  • Users perceive latency at first token, not total completion — streaming cuts perceived wait from 3s to ~500ms even when full response takes longer.

  • LLM generation dominates p95 latency — retrieval and reranking are hundreds of ms; generation is seconds. Parallelize everything before the LLM call.

  • Smaller models and shorter context reduce TTFT — route latency-sensitive paths to GPT-5.6 Luna, Haiku 4.5, or Gemini 3.7 Flash; keep GPT-5.6 Terra / Claude Sonnet 5 for balanced quality; reserve GPT-5.6 Sol for hard work that can tolerate slower TTFT. Never a permanent single default.

  • Never block the critical path on non-essential work — log traces, run eval sampling, and persist sessions asynchronously after streaming starts.

  • Define per-stage latency budgets — embed 50ms, retrieve 100ms, rerank 150ms, TTFT 800ms, full response 3s — alert when any stage regresses.

On this page

Why This Matters

A 4-second wait feels broken in chat. A 1-second wait with streaming tokens feels responsive. Latency is a product metric, not just infrastructure — drop-off rates correlate with time-to-first-token (TTFT).

Production incidents often manifest as "the bot is slow" while error rates stay at zero. Without stage-level latency visibility, teams guess: upgrade the model (wrong), add servers (useless if the provider queue is the bottleneck), or cache blindly.

Latency optimization aligns with cost optimization — shorter context and smaller models are faster and cheaper. It conflicts with quality when reranking or large context is skipped — tradeoffs must be measured. Caching and semantic caching are the largest latency wins on repeated traffic.

The Problem Latency Optimization Solves

End-to-end RAG latency stacks sequentially by default:

embed (50ms) + search (80ms) + rerank (200ms) + LLM TTFT (600ms) + generation (2000ms)
  ≈ 2.9s to first token if not streaming
  ≈ 4.9s total

Users experience the sum. Agents multiply this by step count. Synchronous logging, guardrails, and session writes on the critical path add more.

Latency optimization parallelizes independent work, streams partial results, caches hot paths, and trims work on the path to first token — without guessing which stage to cut.

How We Got Here

Early Completions APIs returned full strings. Chat UIs trained users to expect typing. Provider streaming (SSE) made TTFT the product metric. RAG then stacked embed → retrieve → rerank before generation, and agents multiplied round-trips.

Diagram: Latency became a product metric

timeline
    title From full-buffer responses to TTFT SLOs
    2020-2022 : Sync completions
              : Wait for full string
    2023 : Streaming chat UIs
              : TTFT becomes UX
    2024 : RAG + rerank stacks
              : Pre-LLM budgets matter
    2025-2026 : Degraded modes + routing
              : Skip stages under budget

Streaming fixed perceived wait; production systems still needed budgets, parallelism, and routing.

Era Dominant tactic Gap
Buffer everything Return full answer Spinner UX
Stream tokens SSE / WebSocket Guardrails harder
Parallel RAG asyncio / fan-out Race conditions
Budgeted pipelines Timeouts + degrade Quality on degraded path

What Is LLM Latency Optimization?

LLM latency optimization is the practice of reducing time-to-first-token and total response time for AI features while meeting quality SLOs.

Metric Definition Typical target (interactive chat)
TTFT Time from request to first streamed token 500ms–1.5s p95
TBT Total time to complete response 2–4s p95
Stage latency Per-component timing Budget per layer
Tail ratio p99 / p50 <3× ideal
TTUC Time to useful content (sources, outline) Often before TTFT

Techniques: streaming, parallel retrieval, async pipelines, model tier selection, caching, prefetch, edge deployment for embedders, speculative decoding (self-hosted).

How Latency Optimization Works

Critical path analysis

Map the synchronous chain from request to first byte sent to client. Everything else moves off-path. Generation usually dominates; before that, rerank and cold connections are common culprits.

Streaming

OpenAI, Anthropic, and Google support SSE streaming. Send tokens as generated; record TTFT on first delta.

async def stream_answer(llm, messages, start):
    first_token_at = None
    async for chunk in llm.stream(messages):
        if first_token_at is None:
            first_token_at = time.time()
            metrics.record("ttft_ms", (first_token_at - start) * 1000)
        yield chunk.delta

UX pattern: Show retrieved sources immediately while generation streams — masks retrieval + rerank time.

Parallelism

Run independent operations concurrently:

query_vec, history_summary = await asyncio.gather(
    embedder.embed(query),
    session.summarize_if_needed(session_id),
)
chunks = await vector_store.search(query_vec, top_k=20)

Do not parallelize rerank after retrieve — dependency exists. Parallelize embed with session load, or hybrid BM25 with vector search if the index supports it.

Model and context selection for speed

Goal Prefer Avoid as default
Lowest TTFT GPT-5.6 Luna, Haiku 4.5, Gemini 3.7 Flash Always Sol
Balanced GPT-5.6 Terra, Claude Sonnet 5 Mini on hard agents
Max quality GPT-5.6 Sol Sol for every FAQ
  • Shorter context — fewer retrieved chunks, summarized history.
  • Skip rerank for cache hits or high-confidence FAQ matches.
  • Provider region — nearest API region; avoid cross-region on every request.

Speculative decoding (self-hosted)

A draft model proposes tokens; the target model verifies in batch — higher tokens/sec on your GPUs. Rare in managed API workflows; useful with vLLM / TGI when you control inference. Do not confuse with "faster API tier" marketing.

Connection reuse and warm paths

Cold connections add 50–150ms per request to vector DBs and HTTP LLM clients. Pool per process; reuse AsyncOpenAI / httpx clients. Warm-up on deploy: health check runs embed + dummy vector search + LLM ping before traffic. Readiness probes should hit this path, not just /health.

Architecture

Place time budgets in the orchestrator — if retrieval exceeds 200ms, skip rerank and proceed with top-5 vector results (degraded mode).

Diagram: Latency-optimized RAG architecture

flowchart TB
    subgraph Edge [Edge / Gateway]
        Auth[Auth + rate limit]
        Exact[Exact cache]
    end
    subgraph PreLLM [Pre-LLM parallel]
        Emb[Embed]
        Sess[Session load]
        Ret[Retrieve]
        RR[Rerank optional]
    end
    subgraph Gen [Generation]
        Route[Model route]
        Stream[SSE stream]
    end
    subgraph OffPath [Off critical path]
        Log[Async logs]
        Eval[Eval sample]
    end
    Auth --> Exact
    Exact -->|miss| Emb
    Emb --> Sess
    Emb --> Ret --> RR --> Route --> Stream
    Stream --> Log
    Stream --> Eval

Cache and parallelize before generation; move logging off the path to first token.

Stage Latency tactic
Gateway Edge auth, rate limit without DB round-trip
Cache Sub-ms Redis lookup before any ML
Retrieval ANN index tuning, read replicas, connection pooling
Rerank Smaller reranker; skip on low-stakes routes
Generation Streaming; Luna/Flash for speed; max_tokens cap
Guardrails Fast rules first; parallel NLI if needed
Observability Async span export

Perceived latency UX patterns

Pattern Effect
Progressive disclosure Show sources, then stream answer — masks 200–400ms rerank
Skeleton UI Placeholder while embed runs
Optimistic UI Echo user message instantly
Partial answers Stream outline first — user reads while details generate

Step-by-Step Flow

Diagram: Budgeted stream with degraded retrieval

sequenceDiagram
    participant U as User
    participant API as API
    participant Cache as Cache
    participant Ret as Retriever
    participant LLM as LLM
    U->>API: Query
    API->>Cache: Exact lookup
    alt hit
        Cache-->>U: Replay / stream cached
    else miss
        par Parallel prep
            API->>Ret: Embed + search
            API->>API: Load session
        end
        alt within budget
            API->>Ret: Rerank
        else timeout
            API->>API: Degrade top-k
        end
        API-->>U: sources event
        API->>LLM: Stream (Luna/Terra/Sol)
        LLM-->>U: token deltas
        API->>API: Async log
    end

Emit sources before generation; degrade under budget rather than blocking forever.

  1. Measure TTFT and per-stage latency in production (p50, p95, p99).
  2. Enable streaming on all user-facing chat endpoints.
  3. Show intermediate UI state — "Searching…", source cards, then streamed answer.
  4. Parallelize embed + session fetch + cache lookup.
  5. Tune retrieval — index params (ef_search), warm connections, regional replica.
  6. Conditional rerank — skip when cache hit or top vector score > threshold.
  7. Route latency-sensitive endpoints to Luna / Haiku / Flash; escalate only on retry.
  8. Move logging, eval, session write to background after stream completes.
  9. Set alerts on TTFT p95 regression >20% week-over-week.
  10. Sample eval on degraded-mode traffic so quality does not silently rot.

Real Production Example

FastAPI endpoint with streaming, parallel retrieval, and degraded-mode timeout:

import asyncio
import json
import time
from fastapi import FastAPI
from fastapi.responses import StreamingResponse

app = FastAPI()
RETRIEVAL_BUDGET_MS = 250
RERANK_BUDGET_MS = 150
# Prefer Luna/Flash for TTFT; escalate via router elsewhere.
FAST_MODEL = "gpt-5.6-luna"


class LatencyOptimizedRAG:
    def __init__(self, embedder, store, reranker, llm, cache):
        self.embedder = embedder
        self.store = store
        self.reranker = reranker
        self.llm = llm
        self.cache = cache

    async def answer_stream(self, query: str, tenant_id: str):
        t0 = time.perf_counter()

        cached = await self.cache.get_exact(query, tenant_id)
        if cached:
            for token in cached.split():
                yield f"data: {token} \n\n"
            return

        try:
            query_vec = await asyncio.wait_for(
                self.embedder.embed(query), timeout=0.08
            )
        except asyncio.TimeoutError:
            yield "data: [ERROR: embed timeout]\n\n"
            return

        retrieve_start = time.perf_counter()
        chunks = await asyncio.wait_for(
            self.store.search(query_vec, tenant_id, top_k=15),
            timeout=RETRIEVAL_BUDGET_MS / 1000,
        )

        elapsed_retrieve = (time.perf_counter() - retrieve_start) * 1000
        if elapsed_retrieve < RETRIEVAL_BUDGET_MS and len(chunks) > 5:
            try:
                chunks = await asyncio.wait_for(
                    self.reranker.rerank(query, chunks, top_n=5),
                    timeout=RERANK_BUDGET_MS / 1000,
                )
            except asyncio.TimeoutError:
                chunks = chunks[:5]  # degraded: vector order only

        sources = [c.metadata.get("title", c.id) for c in chunks[:5]]
        yield f"event: sources\ndata: {json.dumps(sources)}\n\n"

        messages = self._build_messages(query, chunks)
        ttft_recorded = False
        async for event in self.llm.stream(model=FAST_MODEL, messages=messages):
            if not ttft_recorded:
                metrics.record("ttft_ms", (time.perf_counter() - t0) * 1000)
                ttft_recorded = True
            if event.delta:
                yield f"data: {event.delta}\n\n"

        asyncio.create_task(self._async_log(query, tenant_id, chunks))


@app.post("/chat/stream")
async def chat_stream(body: ChatRequest):
    async def gen():
        async for chunk in rag.answer_stream(body.query, body.tenant_id):
            yield chunk
    return StreamingResponse(gen(), media_type="text/event-stream")

Streaming masks generation tail latency. Sources event masks rerank wait. Timeouts prevent one slow stage from blocking the fleet.

Design Decisions

Decision Option A Option B When to choose
Streaming Always on Buffer full response Always on for chat UX
Rerank Always Conditional skip Skip on cache hit or high vector score
Degraded retrieval Timeout → fewer chunks Fail request Degrade for interactive; fail for compliance-critical
Model Luna/Flash default Sol default Luna for p95 latency; Sol on escalation
Connection pooling Pooled gRPC/HTTP New connection per request Always pool
Speculative decoding Enabled (self-host) Disabled Self-hosted only
Guardrails Buffer full JSON Incremental / post-stream Buffer structured; stream prose carefully

Comparisons

Tactic TTFT impact Cost impact Quality risk
Streaming Perceived ↓↓ Neutral Guardrail complexity
Exact / semantic cache ↓↓↓ on hit ↓↓ Stale if bad keys
Mini / Flash route ↓↓ ↓↓ Hard queries fail
Skip rerank ↓ 100–300ms ↓ slightly Recall/precision drop
Shorter context Missing evidence
Parallel pre-LLM Neutral Ordering bugs
Speculative decoding Tokens/sec ↑ GPU cost Self-host ops
Frontier Sol always ↑↑ Lowest (quality)

Latency vs cost vs quality

Priority Prefer Accept
Consumer chat TTFT Luna/Flash + stream + cache Occasional escalation
B2B doc Q&A Terra/Sonnet + sources-first UI TTFT 2–3s
Hard agents Sol + step cap Higher TTFT
Offline jobs Batch; ignore TTFT Hours of latency

Diagram: Trade-off decision tree

flowchart TD
    Need[Latency SLO tight?] -->|No| Quality[Prefer Terra/Sonnet or Sol]
    Need -->|Yes| Cache{Repeat traffic?}
    Cache -->|Yes| Hit[Exact + semantic cache]
    Cache -->|No| Simple{Simple intent?}
    Simple -->|Yes| Fast[Luna / Haiku / Flash]
    Simple -->|No| Bal[Terra / Sonnet + stream]
    Fast --> Eval[Eval sample weekly]
    Bal --> Eval
    Quality --> Eval

Chase TTFT with cache and volume models; keep quality routes explicit and measured.

Common Mistakes

  1. Waiting for full LLM response before sending bytes. Users stare at spinner for 3s+.
  2. Sequential embed → search → rerank without timeouts. One slow dependency blows p99.
  3. Synchronous trace export before response. Export async.
  4. Oversized context for speed-critical paths. Every extra 1K tokens adds TTFT.
  5. Ignoring provider cold starts. Warm with health pings.
  6. No connection pooling to vector DB. TLS handshake per request adds 50–100ms.
  7. Running heavy guardrails before first token. Lightweight input checks only; full output rails on buffer or post-stream.
  8. Optimizing total HTTP duration while TTFT stays at 3s. Users feel TTFT.

Where It Breaks Down

Streaming complicates output guardrails — buffer for JSON validation or validate incrementally.

Parallelism race conditions — session summary and user message ordering; use version tokens.

Global provider latency — your code is fast; the API queue is not. Multi-provider fallback adds complexity.

Agents — multi-step loops inherit sum of latencies; hard to stream meaningfully mid-plan. Cap steps; stream partial reasoning if product allows.

Mobile/slow clients — backpressure on SSE; cancel in-flight LLM calls on client abort.

Degraded mode without eval — skipping rerank forever becomes the new normal and quality drifts.

When NOT to Chase Latency

Do not cut stages aggressively when:

  • Compliance requires full retrieval + verification before any token — legal/medical attestations.
  • Structured JSON must be valid before delivery — buffer; do not stream invalid partials to machines.
  • Quality SLO is stricter than latency SLO — prefer Terra/Sonnet or Sol with honest wait UI.
  • You lack stage metrics — you will cut the wrong stage.
  • Traffic is already cache-dominated — invest in invalidation, not micro-optimizing miss path.
  • Speculative decoding without GPU ops maturity — managed APIs are simpler until self-host is justified.

Warning

Latency cuts that skip rerank or shrink context may hurt faithfulness. Sample eval on degraded paths.

Running in Production

Best Practice

Instrument TTFT and per-stage histograms. Stream by default. Pool connections. Eval degraded modes.

Dimension Consideration
Scaling Stateless API scales horizontally. Pool connections per pod. Watch provider rate limits before adding pods.
Latency Target TTFT p95 <1.5s for consumer chat. B2B doc Q&A may tolerate 2–3s with source preview.
Cost Faster often means smaller model — aligned with cost. Escalation paths add a second LLM call.
Monitoring TTFT, TBT, per-stage histograms, stream disconnect rate, degraded-mode frequency.
Evaluation Latency cuts that skip rerank may hurt quality — sample eval on degraded paths.
Security Do not skip auth on cache fast path. Cancel streams still bill partial generation — rate limit.

Production checklist

  • Streaming on all chat surfaces; TTFT metric on first token
  • Per-stage budgets with degraded fallback
  • Connection pools + warm readiness probe
  • Workload routing for speed (Luna/Flash) vs quality (Terra/Sonnet/Sol)
  • Exact + semantic cache ahead of embed
  • Async logging / eval / session write
  • Client disconnect cancels in-flight generation
  • Weekly eval sample on degraded traffic

Efficiency cluster:

Adjacent:

  • RAG — retrieval and rerank dominate pre-LLM latency
  • Observability — per-span latency for tuning
  • Evaluation — quality on degraded paths

Tools: OpenAI · Claude · LangChain

Diagram: Latency learning path

flowchart LR
    CO[Cost opt] --> C[Caching]
    C --> L[Latency opt]
    L --> SC[Semantic cache]
    L --> Obs[Observability]

Cost and cache levers unlock latency; observe stages so you cut the right work.

Interview Questions

  1. What is TTFT and why does it matter?
    Time to first streamed token — primary driver of perceived chat responsiveness.

  2. Why is streaming important?
    Users start reading while the model generates; perceived wait drops to roughly pre-LLM work + first token.

  3. Which stage is usually slowest?
    LLM generation. Before that, rerank often adds 100–300ms; retrieval 50–150ms with tuned indexes.

  4. How do you parallelize RAG safely?
    Concurrent cache/embed/session; rerank only after retrieve; use timeouts and degraded modes.

  5. When should you skip reranking?
    Cache hits, high top-1 vector score, or latency SLO breach with measured quality impact.

  6. What is speculative decoding?
    Draft model proposes tokens; target verifies in batch — self-hosted inference speedup, not a managed-API default.

  7. How do agents affect latency?
    Each step adds a full round-trip. Cap steps; parallelize independent tools; stream final synthesis.

  8. Latency vs cost vs quality — how do you choose?
    Route by workload: Luna/Flash for TTFT, Terra/Sonnet balanced, Sol when quality dominates; eval every cut.

Key Takeaways

  • Optimize TTFT with streaming — users feel first token, not total generation time.
  • Parallelize embed, cache, and session work; set per-stage timeouts and degraded modes.
  • Route volume traffic to Luna/Haiku/Flash; escalate to Terra/Sonnet/Sol when needed.
  • Move logging, eval, and persistence off the critical path.
  • Instrument per-stage latency and alert on TTFT regressions, not just HTTP duration.

FAQs

What is time-to-first-token (TTFT)?

Milliseconds from user request to first streamed token received. Primary driver of perceived chat responsiveness.

Why is streaming important for latency?

Users start reading while the model generates. Perceived wait drops to roughly embed + retrieve + rerank + first token — not full completion time.

Which pipeline stage is usually slowest?

LLM generation (TTFT + token generation). Before that, reranking often adds 100–300ms.

How do I parallelize RAG?

Concurrent: cache lookup + embed start; session load parallel with embed. Rerank after retrieve completes.

When should I skip reranking?

Cache hits, high top-1 vector score, or latency SLO breach with degraded-mode policy. Measure quality impact.

Does a smaller model always reduce latency?

Generally yes for TTFT and tokens/sec. Exception: overloaded mini tier vs idle frontier — measure empirically.

How do I handle a slow vector DB?

Connection pooling, regional replicas, ANN tuning, timeout with degraded top-k, cache hot queries.

What is speculative decoding?

Draft model proposes tokens; target model verifies in batch. Rare in managed API workflows today.

Should guardrails block streaming?

Run fast input rails pre-LLM. Output rails: stream prose after lightweight scan, or buffer JSON until validated.

How do agents affect latency?

Each step adds a full round-trip. Cap steps; parallelize independent tool calls; stream final synthesis only.

How do I cancel in-flight LLM on client disconnect?

Propagate client abort to close SSE and cancel provider generation if available.

What latency SLO is reasonable?

Consumer chat: TTFT p95 <1.5s, total <4s. Internal tools: 2–5s may be acceptable. Define per surface.

How does regional routing affect latency?

Call LLM and vector DB in the same region as API pods. Cross-region adds 100–300ms RTT per hop.

Should I use edge functions for embed?

Only if the embed model runs edge-side (small ONNX). API-based embed still round-trips to cloud.

How do I profile latency in staging?

Replay production payloads with stage timers. Load test at 2× peak with concurrent streams.

How do I reduce rerank latency without skipping it?

Smaller cross-encoders, GPU batching, retrieve top-15 not top-50 before rerank. Validate on your corpus.

What about CDN caching for AI APIs?

Avoid CDN-caching authenticated LLM responses unless keys include auth scope and TTL is short. Prefer Redis origin cache for invalidation control.

Should every latency-sensitive path use GPT-5.6 Sol?

No. Sol is slower and costlier. Prefer Luna/Flash for TTFT-critical volume; escalate when quality fails.

References

Further Reading

Next Topics

Learning Path

Continue Learning

Related Guides

Related companies

  • NVIDIA

    Foundation of AI infrastructure, accelerated computing, and inference.

Related models

  • Gemini Flash

    Google’s Gemini 3.7 Flash workhorse — fast, token-efficient multimodal model for agentic workflows, coding, and high-throughput apps where latency and cost matter. Succeeds 3.6 Flash (GA Jul 2026).

  • Muse Glimmer

    Meta Superintelligence Labs’ Muse Glimmer — Apache-2.0 ~30B dense multimodal agent model for on-device and single-GPU local agents. Sibling to closed Muse Spark; distinct from Llama 4.

  • Phi

    Microsoft’s Phi family of small language models — high capability per parameter for on-device, edge, and cost-sensitive deployments.

Related Tools

ToolCategoryPurposeWebsiteBest For
LangChain
PopularOpen SourceAPI
frameworksFramework for building LLM-powered applications and workflows.langchain.comRAG systems
Ollama
Open SourceAPI
servingLocal model runner with simple command and HTTP interface.ollama.aiLocal LLM development
Inferless
APICloud
DeploymentServerless ML inference platform with fast cold starts and custom runtimes.inferless.comLow-latency serverless inference
CTranslate2
Open SourceSelf-hosted
servingFast inference engine for Transformer models with quantization and batching.opennmt.netTranslation serving