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
- Tokens are the unit of everything. Price, rate limits, context size and latency are all counted in tokens (roughly ¾ of an English word). Input and output tokens are priced separately; output is slower and usually costs more.
- Latency has two parts: time to first token (TTFT: reading the prompt) and output speed (tokens per second). A 600-token answer at 60 tokens a second takes 10 seconds, so stream it (SSE, Module 19).
- Calls fail and get throttled. Providers enforce limits in requests and tokens per minute and return overload errors under load. Treat a model API like any flaky dependency: timeouts, retries with backoff, fallbacks (Module 24).
- Outputs vary. The same input can give different answers. You test with evals over many examples, not one run.
- Inputs can attack. Text the model reads (a web page, an email, a document) can contain instructions: prompt injection. Design permissions assuming the model can be talked into anything.
| Component | Job | Relates to |
|---|---|---|
| AI gateway | Auth, per-user token budgets and rate limits, routing between models and providers, retries and fallbacks, logging and cost tracking | Modules 08, 24 |
| Prompt assembly | Builds the request: instructions, retrieved context, conversation history, tool definitions | AI track 05 |
| Retrieval (RAG) | Finds relevant documents for the question, respecting permissions | Modules 12, 13; AI track 15 |
| Model | A provider's API, or self-hosted inference on GPUs | AI track 14 |
| Tools and agents | Lets the model call your functions and APIs, in a loop, with limits | Module 22; AI track 06, 07, 10 |
| Evals and observability | Traces of every model and tool call, token and cost metrics, quality evals | Module 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
- Prompt caching: providers can reuse the processed form of a repeated prompt prefix (system instructions, tool definitions, a long document). Put stable content first and variable content last. Cached input is cheaper and faster to process; the exact discount and rules differ by provider, so check their docs.
- Model routing: send easy requests (classification, short extraction) to a small, cheap model and hard ones to a large one. A classifier or simple rules decide.
- Response caching: cache full answers to identical requests; "semantic caching" by embedding similarity is riskier, because similar questions can need different answers.
- Batch APIs: for work that can wait (nightly summarisation, evals), providers offer asynchronous batch processing at lower prices.
- Trim the context: retrieve fewer, better chunks; summarise long histories. Every token in the prompt is paid for on every call.
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?
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
- Providers (Anthropic, OpenAI, Google and others) offer prompt caching, streaming, batch APIs and structured outputs; details and prices change often, so the AI track's model API module and each provider's docs are the place to check.
- Inference servers: vLLM, SGLang and NVIDIA's TensorRT-LLM / Triton serve open-weight models with continuous batching; managed platforms (cloud AI services, hosted inference providers) run them for you.
- GPU memory: NVIDIA's H100 has 80 GB (94 GB in the NVL version); newer data-centre GPUs carry more. Large models are split across several GPUs with tensor or pipeline parallelism.
- Vector search: pgvector inside PostgreSQL covers many products; dedicated vector databases and search engines with vector support (OpenSearch, Elasticsearch) scale further. Combine vector and keyword (hybrid) search, then rerank.
- Observability: OpenTelemetry's generative-AI conventions name fields such as the model and token counts; dedicated LLM tracing tools capture prompts, tool calls and costs per request, with care for sensitive data.
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
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 blockText, 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
| Index | How it works | Trade-off |
|---|---|---|
| HNSW | A layered graph: greedy hops on sparse upper layers, refined on dense lower ones | Fast, high recall; memory-hungry, slower to build |
| IVF | Cluster vectors (k-means); search only the closest few clusters | Less memory; recall depends on how many clusters you probe |
| Product / binary quantization | Compress each vector (e.g. 1,536 floats = 6 KB down to tens of bytes), then re-score the top candidates exactly | Much less memory; some accuracy lost |
| DiskANN-style | Graph index on SSD with compressed vectors in memory | Billions of vectors per machine |
- Recall is a dial: HNSW's
ef_searchor IVF'snprobetrades 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
Skip it when
- Exact lookups (IDs, SKUs, error codes): keyword search wins
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.
- 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 retrievalRun 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.
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
Skip it when
- Tiny corpora where you can put everything in the prompt
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.
- 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 modelsInference 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
Skip it when
- Low or spiky volume: a provider API is cheaper than idle GPUs
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.
- Autoscaling GPUs on CPU utilisation.
- One request per GPU with no batching.
LLM gateways
The default in front of model APIsA 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
Skip it when
- A prototype calling one model
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.
- Provider keys spread across services.
- Request-count rate limits on a token-priced resource.
Evals and guardrails
The default · how you know it worksEvals 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
Skip it when
- Never skip evals; scale guardrails to the harm the feature can do
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.
- 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 agentsThe 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
Skip it when
- One fixed tool call inside your own backend: a normal function call is simpler
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.
- A tool server with an admin token shared by every user.
- Trusting tool output as instructions (injection).
6. Remember it
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 consultant | The system |
|---|---|
| Paid by the word | Token-based pricing and budgets |
| Answers word by word | Streaming; time to first token |
| The briefing folder | Retrieved context (RAG) and the system prompt |
| A cheaper colleague for easy calls | Model routing |
| Checking their work | Evals and human review |
| A note in a caller's document saying "wire me money" | Prompt injection |
Watch it on an example
- A support assistant answers customers using help-centre articles and the customer's own order history.
- 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.
- Slow: answers stream over SSE; refunds are proposed by the model but executed by a workflow only after a rules check.
- 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
8. Design exercise (40 minutes)
- 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.
- 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.
- 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?
- Close the trifecta: the assistant can also send email summaries. Which leg would you remove or restrict, and how?
- 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?
How should a prompt be ordered to benefit from prompt caching?
Where should "users may only see documents they have access to" be enforced in a RAG system?
Roughly how much memory do a 70-billion-parameter model's weights need at 16-bit precision?
Why combine keyword and vector search?
What does vLLM's PagedAttention improve?
10. Go deeper
| Resource | Time | Why |
|---|---|---|
| AI engineering track on this site, especially modules 15 (RAG), 18 (security) and 19 (cost, latency, observability) | 3 h | The AI side of this module, step by step, with labs. |
| Efficient Memory Management for LLM Serving with PagedAttention (the vLLM paper) | 1 h | Why KV-cache memory dominates serving, and how paging and batching fix it. |
| Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks | 45 min | The paper that named RAG. |
| The lethal trifecta for AI agents (Simon Willison) | 10 min | The clearest explanation of when prompt injection becomes data theft. |
| Prompt caching (Anthropic docs) and Model Context Protocol | 45 min | How 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
| Technique | What it does | Cost |
|---|---|---|
| Continuous batching | Sequences join and leave the batch at every step | Scheduler complexity (built into vLLM, SGLang, TensorRT-LLM, TGI) |
| PagedAttention | KV cache in fixed-size pages, so memory isn't reserved for the maximum length | Indirection in the attention kernel |
| Prefix caching | Reuse KV pages for a shared system prompt or document | Memory held for popular prefixes |
| Quantization | Weights in 8 or 4 bits (GPTQ, AWQ, FP8) instead of 16; KV cache in 8 bits | Some quality loss, measured with evals |
| Speculative decoding | A small draft model proposes several tokens; the big model verifies them in one pass | Extra model; gains depend on acceptance rate |
| Grouped-query attention | Several query heads share one KV head (Llama 3 uses 8 KV heads), shrinking the KV cache | A model-architecture choice, not a serving knob |
| Tensor / pipeline parallelism | Split each layer (tensor) or the layer stack (pipeline) across GPUs when weights don't fit | Fast interconnect needed (NVLink within a node) |
| Mixture of experts | Each token uses only a few expert sub-networks, so compute per token is a fraction of total parameters | All experts must still sit in memory; routing imbalance |
| Disaggregated prefill and decode | Separate GPU pools for the compute-bound and bandwidth-bound phases, handing over the KV cache | KV transfer between machines |
Say it in the interview
- "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?