InterviewKata
System design · Module 29 of 29 · Level 5: Production and architecture

Designing AI systems

A product built on a large language model is still a distributed system: requests, queues, caches, databases, rate limits, failures. But one component behaves differently from anything before it: it's slow, expensive per call, priced and limited in tokens, non-deterministic, and can be steered by its own input. This module applies the whole course to AI features: the request path, cost and capacity, serving models yourself, retrieval, agents, and making it safe and measurable. For the AI concepts themselves, this site's AI engineering track goes deeper.

1. The idea

Imagine adding a brilliant but expensive consultant to a call centre. Each question costs money by the word, answers take seconds and arrive word by word, the consultant sometimes confidently gets things wrong, can only handle so many questions a minute, and will follow instructions hidden in a document a caller hands over. You'd build a process around them: give them the right files, check their work, cache common answers, route easy questions to a cheaper colleague, and never let them sign cheques unsupervised.
ComponentJobRelates to
AI gatewayAuth, per-user token budgets and rate limits, routing between models and providers, retries and fallbacks, logging and cost trackingModules 08, 24
Prompt assemblyBuilds the request: instructions, retrieved context, conversation history, tool definitionsAI track 05
Retrieval (RAG)Finds relevant documents for the question, respecting permissionsModules 12, 13; AI track 15
ModelA provider's API, or self-hosted inference on GPUsAI track 14
Tools and agentsLets the model call your functions and APIs, in a loop, with limitsModule 22; AI track 06, 07, 10
Evals and observabilityTraces of every model and tool call, token and cost metrics, quality evalsModule 25; AI track 17, 19

2. How it works

One question to a document assistant

Press Play: a user asks an internal assistant a question about company policy.

Making it cheaper and faster

Serving models yourself

Self-hosting an open-weight model trades a per-token bill for a GPU bill and operational work. The dominant constraint is GPU memory: model weights (parameters × bytes per parameter: a 70-billion-parameter model at 16-bit precision is 140 GB) plus the KV cache, which grows with context length and the number of requests being served at once. Inference servers such as vLLM use PagedAttention to manage that cache efficiently and continuous batching to add new requests to a running batch, which raises GPU utilisation dramatically. Quantisation (8-bit or 4-bit weights) cuts memory at some cost in quality. Try the sizing calculator in section 3.

Agents: models that act

An agent is a loop: the model decides on a tool call, your code runs it, the result goes back to the model, repeat until done (AI track 07). As a system, that means: bound the loop (maximum steps, tokens, time and money), run long tasks as durable workflows so a crash doesn't restart them (Module 22), make tool calls idempotent, and give the agent only the permissions the task needs, with a human approval step for irreversible actions. The Model Context Protocol (MCP) standardises how agents connect to tools and data.

Security: the lethal trifecta

An AI system becomes dangerous when it combines three things: access to private data, exposure to untrusted content (which may carry injected instructions), and the ability to communicate externally (send email, call URLs, render links or images). With all three, an attacker's hidden instruction can make it leak the data. Remove at least one leg for any flow, and enforce permissions in your code, never in the prompt (AI track 18).

3. Try it yourself

Cost and capacity of an AI feature

The prices are example values, not any provider's current list: type in the real ones from your provider's pricing page.

How many GPUs to hold the model?

70B parameters
+40%

Rough sizing: weights = parameters × bytes per parameter; the KV cache and activations need extra memory that grows with context length and concurrent requests. Real deployments benchmark with their own traffic.

4. Trade-offs

API vs self-hosting

APIs: the strongest models, no GPUs to run, pay per token, data leaves your environment (under the provider's terms). Self-hosting: control, data stays put, predictable cost at high steady volume, but you buy or rent GPUs and run the serving stack.

Bigger model vs better system

Better retrieval, clearer instructions, tools and evals often beat a bigger model, at a fraction of the cost and latency.

RAG vs long context

Very long context windows can hold whole document sets, but every call pays for every token and quality can drop in the middle. Retrieval keeps prompts small and fresh, and respects per-user permissions.

Autonomy vs control

More autonomous agents finish more tasks unattended and fail in more surprising ways. Start narrow: few tools, read-only where possible, approval for side effects.

5. In real systems

In an interview (design ChatGPT-like chat, an AI support agent, a RAG search), cover: streaming over SSE; an AI gateway with per-user token limits and model fallbacks; conversation storage; retrieval with permission filters; a queue for long agent tasks; cost per request estimated in tokens; evals and tracing; and prompt-injection boundaries. Design D23 works one through.

The technologies up close

The default answer in an interviewFor an AI product, say the pipeline in one breath: requests go through an LLM gateway (budgets, fallbacks, logging); retrieval is hybrid with permission filters and a re-ranker; answers stream over SSE; long agent tasks run on a queue; tools are exposed through MCP with per-user authorization; an eval set gates every prompt or model change. Then go deep on retrieval quality, cost or safety, whichever the prompt stresses.

Vector search: HNSW, IVF and quantization

The default retrieval building block

Text, images and code are turned into embedding vectors (hundreds to a few thousand numbers) so that similar meaning means nearby vectors. Vector search finds the nearest ones; exact search over millions is too slow, so indexes find approximately nearest neighbours.

How it works

IndexHow it worksTrade-off
HNSWA layered graph: greedy hops on sparse upper layers, refined on dense lower onesFast, high recall; memory-hungry, slower to build
IVFCluster vectors (k-means); search only the closest few clustersLess memory; recall depends on how many clusters you probe
Product / binary quantizationCompress each vector (e.g. 1,536 floats = 6 KB down to tens of bytes), then re-score the top candidates exactlyMuch less memory; some accuracy lost
DiskANN-styleGraph index on SSD with compressed vectors in memoryBillions of vectors per machine
  • Recall is a dial: HNSW's ef_search or IVF's nprobe trades latency for finding more of the true nearest neighbours. Measure recall@k against exact search.
  • Filters are the hard part: "nearest documents this user may see" needs filtering during the search, not after, or results come back empty.

Status today (checked October 2026)

pgvector adds HNSW and IVFFlat indexes to PostgreSQL and covers many products; dedicated engines (Pinecone, Qdrant, Weaviate, Milvus) and search engines (OpenSearch, Elasticsearch, Vespa) scale further. Amazon S3 Vectors, generally available since December 2025, stores up to 2 billion vectors per index at much lower cost, with around 100 ms queries when frequently used.

Use it when

  • Semantic search and RAG
  • Recommendations and deduplication by similarity

In the interview

Chunks are embedded and indexed with HNSW in pgvector, filtered by tenant and permissions inside the query; past ~50 million vectors I'd move to a dedicated engine.

🚩 Red flags
  • Post-filtering permissions after a top-10 search: users see nothing, or worse, leaked titles.
  • Mixing embedding models in one index.

Hybrid search and re-rankers

The default for good retrieval

Run keyword search (BM25) and vector search together, merge the two ranked lists, then let a slower, more accurate re-ranker model reorder the top few dozen. Each step fixes the other's blind spots.

How it works

  • Why both: vectors catch paraphrases ("reset password" ≈ "forgot login"); keywords catch exact terms that embeddings blur ("ERR_4012", product codes, names).
  • Reciprocal rank fusion (RRF): each document scores Σ 1 / (k + rank) across the lists, with k usually 60. It needs no score calibration between the two systems.
  • Re-rankers are cross-encoders: they read the query and each candidate together, so they judge relevance far better than embeddings, but cost a model call per pair. Re-rank the top 50–100, keep the top 5–10.
60

Status today (checked October 2026)

Elasticsearch, OpenSearch, Vespa, Weaviate and Qdrant support hybrid queries with RRF; re-rankers are available from Cohere, Voyage and others, or as open models (BGE, Jina) you host.

Use it when

  • Any RAG or search over real documents
  • Domains full of codes, names and jargon

In the interview

Hybrid retrieval: BM25 and vectors fused with RRF, top 50 re-ranked by a cross-encoder, best 8 chunks into the prompt.

🚩 Red flags
  • Vector-only search for error codes or part numbers.
  • Re-ranking thousands of candidates per query: latency and cost explode.

Serving models: vLLM and friends

Situational · self-hosted models

Inference servers that run open-weight models on GPUs efficiently. The tricks that matter: batching many requests together, and managing the KV cache (each conversation's attention state) without wasting GPU memory.

How it works

  • Continuous batching: new requests join the running batch at every generation step instead of waiting for the batch to finish, which raises throughput several-fold.
  • PagedAttention (vLLM): the KV cache is stored in fixed-size blocks like virtual-memory pages, so little memory is wasted and shared prefixes can be stored once.
  • Prefix caching: requests sharing a system prompt reuse its cached KV blocks (SGLang's RadixAttention does this across requests).
  • Speculative decoding: a small draft model proposes tokens, the big model checks several at once.
  • Prefill vs decode: reading the prompt is compute-bound; generating tokens is memory-bandwidth-bound. Large deployments run them on separate GPU pools (disaggregated serving).

Status today (checked October 2026)

vLLM (part of the PyTorch Foundation) and SGLang are the leading open-source servers; NVIDIA offers TensorRT-LLM, Triton and Dynamo; Hugging Face TGI and llama.cpp/Ollama cover smaller setups. Managed alternatives: Bedrock, Vertex AI, Azure AI Foundry and hosted-inference providers.

Use it when

  • Open-weight models for cost, privacy or customisation at steady high volume

In the interview

We serve the fine-tuned 8B model on vLLM with continuous batching and prefix caching for the shared system prompt, autoscaling on queue depth and KV-cache usage.

🚩 Red flags
  • Autoscaling GPUs on CPU utilisation.
  • One request per GPU with no batching.

LLM gateways

The default in front of model APIs

A proxy between your services and model providers: one API, with keys, quotas, routing, fallbacks, caching, logging and cost tracking in one place.

How it works

  • Routing and fallback: send each request to a model by task or tier; on errors, rate limits or timeouts, retry another region or model.
  • Limits per user and team in tokens, not just requests, since one request can cost a thousand times another.
  • Caching: exact-match response caching, and passing through providers' prompt caching; semantic caching only where a slightly different answer is acceptable.
  • Observability: tokens, latency (time to first token), cost and errors per feature; prompts logged with redaction.

Status today (checked October 2026)

Open-source and commercial options include LiteLLM, Portkey, Kong AI Gateway, Envoy AI Gateway and Cloudflare AI Gateway; cloud platforms offer their own routing.

Use it when

  • More than one team or model calling LLMs
  • Any production feature with cost or rate limits to enforce

In the interview

All model calls go through a gateway that enforces per-tenant token budgets, falls back to a second provider on 429s and logs cost per feature.

🚩 Red flags
  • Provider keys spread across services.
  • Request-count rate limits on a token-priced resource.

Evals and guardrails

The default · how you know it works

Evals measure quality before and after every change; guardrails check inputs and outputs at runtime. Without evals you're shipping by vibes; without guardrails, one bad input can make the model do something harmful.

How it works

  • Offline evals: a versioned set of real questions with expected answers or rubrics, scored by code (exact match, JSON validity), by an LLM judge checked against human labels, or by people. Run on every prompt or model change, like tests.
  • Online: thumbs, edits, escalations, task success, and sampled traces reviewed weekly.
  • Guardrails: input checks (prompt injection, abuse), output checks (personal data, policy, grounded in the retrieved sources), and structural ones (schema validation, allow-listed tools, human confirmation before irreversible actions).
  • Prompt injection is the top risk (LLM01 in the OWASP Top 10 for LLM Applications): text in a document or web page can instruct the model. The real defence is limiting what the model's tools can do, not filters alone.

Status today (checked October 2026)

Eval and tracing tools include Braintrust, LangSmith, Langfuse, Arize Phoenix and promptfoo; guardrail options include Llama Guard, NVIDIA NeMo Guardrails, Bedrock Guardrails and Azure AI Content Safety.

Use it when

  • Every LLM feature in production

In the interview

A 300-question eval set runs in CI on every prompt change; outputs are checked for grounding and PII; tools that change data need user confirmation.

🚩 Red flags
  • No eval set: "it looked good when I tried it".
  • Relying on the system prompt to stop prompt injection.

MCP: connecting models to tools

Situational · tools for agents

The Model Context Protocol is an open standard for exposing tools, data and prompts to AI applications. Write an MCP server once and any MCP-capable client (assistants, IDEs, agents) can use it.

How it works

  • Servers expose tools (actions with JSON-schema inputs), resources (readable data) and prompts. Clients inside the AI app list them, and the model decides which tool to call.
  • Transports: stdio for local servers; HTTP for remote ones, with OAuth-based authorization.
  • Since the 2026-07-28 spec the core is stateless: each request carries its protocol version and client capabilities, with no session handshake, so remote servers can sit behind ordinary load balancers. Long-running work moved to a tasks extension; the older HTTP+SSE transport is deprecated.
  • Security is yours: a tool runs with whatever permissions you give it. Scope tokens per user, allow-list tools, and confirm destructive actions.

Status today (checked October 2026)

Introduced by Anthropic in November 2024 and now hosted by the Linux Foundation's Agentic AI Foundation; supported by the major AI assistants, IDEs and agent frameworks, with SDKs in TypeScript, Python, Go, C# and more.

Use it when

  • Letting assistants and agents use your product's data and actions
  • Reusing one integration across many AI clients

In the interview

We expose search and ticket creation as an MCP server; it authenticates the user with OAuth and only offers tools their role allows.

🚩 Red flags
  • A tool server with an admin token shared by every user.
  • Trusting tool output as instructions (injection).

6. Remember it

Memory hook: "An expensive, slow, brilliant, gullible dependency"Budget it in tokens, stream it, cache and route around it, measure it with evals, and never give it more power than you'd give text from a stranger.
How this hook works: what "expensive, slow, brilliant, gullible" means

What the slogan means, word by word

"expensive"
Priced per token: estimate tokens per request, cache prefixes, route easy work to small models, use batch APIs for what can wait.
"slow"
Seconds per answer: stream tokens, set timeouts, run long work as background jobs or durable workflows.
"brilliant"
Capable enough to be worth all this, but non-deterministic: measure quality with evals, not anecdotes.
"gullible dependency"
It follows instructions in whatever it reads and fails like any remote API: least privilege, permission checks in code, and the usual reliability patterns.

Why this picture fits: it's the consultant in the call centre. You'd never hand them the company chequebook because their answers are usually good; the same caution belongs in the architecture.

The story → the concept

The consultantThe system
Paid by the wordToken-based pricing and budgets
Answers word by wordStreaming; time to first token
The briefing folderRetrieved context (RAG) and the system prompt
A cheaper colleague for easy callsModel routing
Checking their workEvals and human review
A note in a caller's document saying "wire me money"Prompt injection

Watch it on an example

  1. A support assistant answers customers using help-centre articles and the customer's own order history.
  2. Expensive: 2,000 input tokens per question, most of them a stable system prompt, so it's cached; simple "where's my order" questions go to a small model.
  3. Slow: answers stream over SSE; refunds are proposed by the model but executed by a workflow only after a rules check.
  4. Gullible: order data is retrieved for the signed-in customer only, and the assistant has no tool that sends data anywhere except the customer's own chat.

The trap it saves you from

Treating the model as a trusted, fast, free function: unbounded costs, timeouts under load, and an assistant that can be talked into leaking data.

It still works when…

The model runs on your own GPUs: "expensive" becomes GPU-hours and memory, "slow" becomes batching and capacity planning, and the rest is unchanged.

7. Common mistakes

Permissions in the prompt"Only show the user their own data" in a system prompt isn't access control. Filter what the model can retrieve and do in code, per user.
No token budgetsA runaway agent loop or one heavy user can burn a month's budget in a day. Limit tokens and steps per request, per user and per day.
Waiting for the whole answerTen seconds of blank screen feels broken. Stream tokens and show progress for tool calls.
Shipping prompt changes without evalsA small wording change can break cases you didn't look at. Run an eval set before every prompt or model change.
One provider, no fallbackProvider outages and rate limits happen. Route through a gateway that can fail over to another model.

8. Design exercise (40 minutes)

  1. Design a document Q&A assistant for a company with 50,000 employees and 2 million documents with per-team permissions. Draw ingestion, retrieval, generation, and where permissions are enforced.
  2. Estimate cost: 20,000 questions a day, 3,000 input and 500 output tokens each, 60% of input cacheable. Use the calculator with your provider's current prices.
  3. Plan capacity: at peak, 50 questions a second. What token-per-minute limit do you need from the provider? What happens when you hit it?
  4. Close the trifecta: the assistant can also send email summaries. Which leg would you remove or restrict, and how?
  5. Write it down: the gateway's responsibilities, and the four words of the memory hook.

9. Self-check quiz

A model takes 12 seconds to write a full answer. What's the first thing to do for the user experience?

Users see the answer forming within the time to first token instead of staring at a spinner.

How should a prompt be ordered to benefit from prompt caching?

Caching reuses an identical prefix; anything that changes early in the prompt breaks it.

Where should "users may only see documents they have access to" be enforced in a RAG system?

The model only sees what retrieval gives it; filter there, with the user's real permissions.

Roughly how much memory do a 70-billion-parameter model's weights need at 16-bit precision?

70 × 10⁹ parameters × 2 bytes = 140 GB, before the KV cache.

Why combine keyword and vector search?

Each covers the other's blind spot; RRF merges them without calibrating scores.

What does vLLM's PagedAttention improve?

Storing the KV cache in pages wastes little memory, which raises batch size and throughput.

10. Go deeper

ResourceTimeWhy
AI engineering track on this site, especially modules 15 (RAG), 18 (security) and 19 (cost, latency, observability)3 hThe AI side of this module, step by step, with labs.
Efficient Memory Management for LLM Serving with PagedAttention (the vLLM paper)1 hWhy KV-cache memory dominates serving, and how paging and batching fix it.
Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks45 minThe paper that named RAG.
The lethal trifecta for AI agents (Simon Willison)10 minThe clearest explanation of when prompt injection becomes data theft.
Prompt caching (Anthropic docs) and Model Context Protocol45 minHow a provider implements prefix caching, and the standard for connecting tools to agents.

11. Under the hood (optional)

Not needed for most interviews; open it when you want to know how the products really do it. All the deep dives are listed on the Under the hood page.

Model serving internalsTokens, prefill and decode, a KV-cache memory lab with real Llama 3.1 shapes, batching, quantization, speculative decoding, parallelism and MoEabout 20 min

LLM serving is mostly a memory problem. The weights must fit on the GPUs, and every active conversation keeps a growing cache of attention keys and values. How many users one GPU can serve, and how fast, follows from a little arithmetic.

Tokens, prefill and decode

  • Tokenization: text is split into sub-word tokens (byte-pair encoding and similar), roughly 3–4 characters of English each. Prices, context limits and speed are all in tokens.
  • Prefill: the whole prompt is processed in one parallel pass, which is compute-bound and sets the time to first token.
  • Decode: each new token needs a full pass over the weights, one token at a time per sequence, which is memory-bandwidth-bound and sets tokens per second. Batching many sequences shares each pass over the weights, which is why batching multiplies throughput.
  • The KV cache: to avoid recomputing attention over the past, each layer stores a key and a value vector per token per KV head. It grows with every token of every active sequence.

Will it fit? KV-cache arithmetic

KV bytes per token = 2 (key and value) × layers × KV heads × head dimension × bytes per value. Pick a model and a workload:

Making it faster and cheaper

TechniqueWhat it doesCost
Continuous batchingSequences join and leave the batch at every stepScheduler complexity (built into vLLM, SGLang, TensorRT-LLM, TGI)
PagedAttentionKV cache in fixed-size pages, so memory isn't reserved for the maximum lengthIndirection in the attention kernel
Prefix cachingReuse KV pages for a shared system prompt or documentMemory held for popular prefixes
QuantizationWeights in 8 or 4 bits (GPTQ, AWQ, FP8) instead of 16; KV cache in 8 bitsSome quality loss, measured with evals
Speculative decodingA small draft model proposes several tokens; the big model verifies them in one passExtra model; gains depend on acceptance rate
Grouped-query attentionSeveral query heads share one KV head (Llama 3 uses 8 KV heads), shrinking the KV cacheA model-architecture choice, not a serving knob
Tensor / pipeline parallelismSplit each layer (tensor) or the layer stack (pipeline) across GPUs when weights don't fitFast interconnect needed (NVLink within a node)
Mixture of expertsEach token uses only a few expert sub-networks, so compute per token is a fraction of total parametersAll experts must still sit in memory; routing imbalance
Disaggregated prefill and decodeSeparate GPU pools for the compute-bound and bandwidth-bound phases, handing over the KV cacheKV transfer between machines

Say it in the interview

Answers that show depth
  • "How many concurrent chats can one GPU serve?" Memory left after the weights, divided by KV cache per conversation: for an 8B model in 16-bit on one 80 GB GPU, about 56 GB is left after the weights and runtime overhead, and a 4K-token chat holds about 0.54 GB of KV cache, so roughly 100 conversations, before considering throughput targets.
  • "Why is time to first token slow for long prompts?" Prefill processes the whole prompt; prefix caching and chunked prefill help, and very long contexts may need their own pool.

What usually limits decode speed for one sequence?

Batching many sequences amortises each read of the weights.

Sources