Skip to content

LLM System Design

System design is the part of the interview that separates junior from senior candidates. These questions test whether you can reason about tradeoffs — latency vs cost, accuracy vs throughput, simplicity vs scalability.


Q1: What components does every production LLM system need?

Show answer

A production LLM system needs more than just an API call. The minimal production-grade architecture:

Client
API Gateway / Auth Layer        ← rate limiting, authentication, request validation
Application Server (FastAPI)    ← business logic, prompt assembly, response formatting
Cache Layer                     ← exact-match or semantic cache to avoid redundant LLM calls
LLM Provider (OpenAI/Anthropic) ← the actual inference
Observability (LangSmith/logs)  ← traces, latency, cost, quality metrics

Additional components for RAG systems: - Vector database (ChromaDB, Pinecone, Qdrant) for retrieval - Ingestion pipeline for document processing and embedding - Reranker for retrieval precision

Additional components for agent systems: - Tool execution layer with sandboxing - State store / checkpointer (Redis, Postgres) - Queue for long-running jobs (Celery, RQ)


Q2: How do you handle latency requirements for a real-time LLM feature?

Show answer

LLM inference is slow (1–10 seconds). Strategies to make it acceptable:

Streaming — don't wait for the full response. Send tokens as they generate. Users perceive streaming as fast even when total latency is the same.

Caching — for predictable queries (FAQ, common search terms), cache responses. Cache hits return in < 10ms.

Model selectiongpt-4o-mini at 500ms beats gpt-4o at 2s if quality is acceptable. Benchmark both before assuming you need the larger model.

Parallel retrieval — for RAG, embed the query and retrieve from the vector DB concurrently with any other setup work.

Request timeout + fallback — set a hard timeout (e.g., 8 seconds). On timeout, return a cached response, a simplified answer, or a graceful error — never leave the user waiting indefinitely.

import asyncio, os
from openai import AsyncOpenAI

aclient = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))

async def answer_with_timeout(query: str, timeout: float = 8.0) -> str:
    try:
        response = await asyncio.wait_for(
            aclient.chat.completions.create(model="gpt-4o-mini", messages=[{"role": "user", "content": query}]),
            timeout=timeout,
        )
        return response.choices[0].message.content
    except asyncio.TimeoutError:
        return "I'm taking longer than expected. Please try again or contact support."

Q3: How do you design for high availability with LLM APIs?

Show answer

LLM APIs have rate limits, occasional outages, and variable latency. A highly available LLM service must handle all three.

Multi-provider fallback: primary on OpenAI, fallback to Anthropic on 5xx errors or rate limits.

import os
from openai import OpenAI, RateLimitError, APIError
from anthropic import Anthropic

oai = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
ant = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

def resilient_completion(prompt: str) -> str:
    try:
        response = oai.chat.completions.create(
            model="gpt-4o", messages=[{"role": "user", "content": prompt}]
        )
        return response.choices[0].message.content
    except (RateLimitError, APIError):
        # Fallback to Anthropic
        response = ant.messages.create(
            model="claude-sonnet-4-6", max_tokens=1024,
            messages=[{"role": "user", "content": prompt}]
        )
        return response.content[0].text

Circuit breaker: track error rate; stop calling a provider if error rate exceeds threshold; resume after a cooldown period. This prevents cascading failures from a degraded provider.

Retry with exponential backoff: for transient errors (429, 503), retry with increasing delays.


Q4: How do you handle PII in an LLM pipeline?

Show answer

PII (Personally Identifiable Information) entering an LLM API is a compliance and privacy risk — you're potentially sending customer data to a third party.

Layered approach:

1. Detect before sending — use presidio-analyzer to identify PII entities:

from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine

analyzer = AnalyzerEngine()
anonymizer = AnonymizerEngine()

def anonymize_pii(text: str) -> tuple[str, list]:
    results = analyzer.analyze(text=text, language="en")
    anonymized = anonymizer.anonymize(text=text, analyzer_results=results)
    return anonymized.text, results  # return mapping for de-anonymization

clean_text, pii_map = anonymize_pii(user_input)
# Send clean_text to LLM; restore PII in response if needed

2. Data residency — for strict compliance (HIPAA, GDPR), use Anthropic or OpenAI's data processing agreements and zero-data-retention options, or run a self-hosted model.

3. Logging — never log raw user input. Log anonymized or hashed versions.

4. User consent — inform users their input is processed by a third-party LLM API. Provide opt-out for sensitive use cases.


Q5: What's your approach to fallback and degradation for LLM services?

Show answer

LLM features should degrade gracefully, not fail completely. Design a degradation ladder:

Level Condition Response
Normal LLM responds < 3s Full AI-generated answer
Slow LLM responds > 3s Stream tokens (perceived as fast)
Cache hit Same/similar query seen recently Cached response, no LLM call
LLM degraded > 5% error rate in last 5 min Simplified prompt on smaller model
LLM down Provider outage Rule-based or template responses
Full failure All providers down Static FAQ page + human escalation

Implement with a feature flag so you can switch degradation modes without a deployment:

import os

DEGRADATION_LEVEL = os.getenv("LLM_DEGRADATION_LEVEL", "normal")

async def answer(query: str) -> str:
    if DEGRADATION_LEVEL == "fallback":
        return static_faq_lookup(query) or "Please contact support."
    if DEGRADATION_LEVEL == "lite":
        return await call_llm(query, model="gpt-4o-mini")
    return await call_llm(query, model="gpt-4o")

Previous: Cost Optimization | Next: RAG Architecture