Loading...
System Design and AI Engineering, by Roni Das. 980 interactive lessons.
Start LearningSystem design interview guide
in this guide
7 parts open to everyone · 3 with a free account · 3 with the course
It is the cleanest way to find out whether a candidate understands that serving a large language model breaks the assumptions behind ordinary web architecture. The instincts that work everywhere else mislead here. Requests are not uniform, they occupy a GPU for seconds and hold memory that grows the whole time. Load balancing on request count or CPU is wrong, because the real measure of how full a server is is KV cache occupancy. Autoscaling in seconds is impossible, because loading a hundred gigabytes of weights takes minutes. Caching a response by request hash almost never hits, but caching the prefix of a prompt hits constantly. An interviewer can watch a candidate discover, or fail to discover, that the binding constraint is memory rather than compute, and that latency has two separate numbers, time to first token and time per output token, which are governed by different phases and pull against each other. It also rewards honest cost reasoning, because at these volumes the difference between a well-batched cluster and a poorly batched one is a very large amount of money, and it forces the candidate to talk about safety and abuse in a system whose output is generated rather than retrieved.
This page is the free part.
₹499 in India$49 everywhere elseonce, for the whole course
The System Design course covers the ChatGPT design across a run of lessons, not one page. These 4 alone are about 76 minutes of step-by-step reading, every one with a quiz.
Live from the course bench
Real interview questions, live diagrams and measured lab results, pulled at random from the lessons. A new set every time you come back.
Always clarify these in the first 5 minutes of the interview. Do not start drawing boxes until both lists are agreed.
This guide is built on these 5 lessons. Each one teaches one piece of the ChatGPT design above, step by step.
Lifetime access for ₹499 in India or $49 elsewhere. Interactive diagrams, quizzes, and 20 capstone projects to practise on.
Two courses by the author of this page:
770 lessons · 18 free to read
₹499 in India · $49 elsewhere, once
Get System DesignYou own this course
210 lessons · 10 free to read
₹999 in India · $49 elsewhere, once
Get AI EngineeringYou own this course
Save your progress and get the AI Engineering cheat sheet PDF
ChatGPT has to answer a question in the second or two before a user feels the pause, and it has to do that for a userbase OpenAI put at about 900 million weekly actives in February 2026, sending on the order of 2.5 billion messages a day. That averages to nearly 30,000 messages a second before you account for peaks. The hard part is not the web tier, it is that every one of those messages occupies a GPU for several seconds while the model emits tokens one at a time, and the memory that holds each conversation's attention state grows with every token generated. A large model does not even fit on one card: a 70B-class model's weights alone are about 140 GB, so it is served across a node of several GPUs, and after the weights are loaded the memory that is left is what holds the per-conversation KV cache. A single 8K-token conversation can hold about 2.5 GB of that cache, so the node runs out of memory long before it runs out of compute. Capacity, latency, and cost in this system are all decided by how well you manage GPU memory.
Designing ChatGPT looks like designing a chat app until you notice the model is stateless and the GPU is the entire problem. Every turn resends the whole conversation, so the model reprocesses the full history to produce the next reply, and the cost of a conversation grows as it gets longer. Inference itself splits into two phases with opposite bottlenecks: prefill reads the prompt in parallel and saturates compute, while decode emits one token at a time and is limited by memory bandwidth, because each token has to re-read the model weights. That asymmetry drives nearly every decision. The KV cache that makes decode affordable is also what fills the GPU, so PagedAttention borrows virtual-memory paging to stop fragmentation from wasting most of the card, and continuous batching swaps finished sequences out at each iteration instead of waiting for the slowest one. Prefix caching turns a shared system prompt and a repeated conversation history into a cache hit rather than recomputation. Speculative decoding exploits the fact that verifying several tokens costs about the same as generating one. Then the product layer adds its own constraints: streaming so the answer starts before it is finished, moderation on both the input and the streaming output, token-based quotas rather than request-based ones, and routing that treats a GPU holding long conversations as full even when its request count looks low. The chat CRUD is a weekend project. The interview is about GPU memory, batching, and the latency budget.
Where it shows up
Asked at OpenAI, Anthropic, Google, Meta, Microsoft, NVIDIA, Databricks, Perplexity, and the large set of companies now serving their own LLM products or internal assistants. It appears as a standalone AI infrastructure question, as an inference-serving question for platform and performance roles, and as the generation half of broader designs such as an AI agent platform or an enterprise copilot.
Spec sheetChatGPT
worked through below, with the maths
The hard parts of this design are taught step by step in the AI Engineering course: LLM Inference Optimization: Serving More Tokens Per GPU, LLM Guardrails and Safety: Wrapping the Model So It Can Ship and Evaluating LLMs in Production: Grading Answers That Have No Right Answer.
Stateless authentication using signed tokens instead of server-side sessions.
Continuous real-time WAL streaming, no waiting for files to fill up.
A self-filling cache fills itself out of users. Measured on a cold start, 13,259 of them paid the slow path, and warming the 200 most popular keys removed exactly 200.
Attach a travel itinerary to the message itself, each service processes it and forwards to the next stop.
all part of
System Design Masterclass
770 lessons · about 283 hours · 18 free to read
₹499in India, by UPI
$49everywhere else, by PayPal
You own this course
Continue with Token-Based Authenticationpay once,
yours for life
Show your math. Pulling numbers from thin air signals you have not thought about the load.
User and message volume
~900M weekly actives, ~2.5B messages/day
OpenAI put weekly actives at about 900 million in February 2026, and has separately stated roughly 2.5 billion messages a day. That averages to roughly 29,000 messages per second, and real traffic peaks well above its average, so the cluster must be sized for a multiple of that.
Concurrent generations
~450K concurrent streams at average load
At the interactive latency target of about 30ms per output token, a typical 500-token reply occupies a GPU slot for roughly 15 seconds. 29,000 new messages per second times a 15 second hold is on the order of 450,000 sequences generating at any instant, and several times that at peak. This is Little's Law: concurrency is arrival rate times how long each request stays in the system.
KV cache per conversation
~320 KB per token, ~2.5 GB at 8K context
For a 70B-class model with 80 layers using grouped-query attention with 8 KV heads and a head dimension of 128 at FP16: 2 (K and V) x 80 x 8 x 128 x 2 bytes is 320 KB per token. An 8,000 token conversation therefore holds about 2.5 GB, which is why GPU memory, not FLOPs, sets the concurrency limit.
GPU fleet floor
~2,000 8-GPU nodes, on the order of ten thousand GPUs, for decode alone
An 8-GPU node serving a quantized 70B has roughly a couple of hundred concurrent sequences worth of KV cache after the weights are loaded. 450,000 concurrent streams divided by ~200 per node is on the order of 2,000 nodes, so roughly ten thousand GPUs, just to hold the KV cache, before peak headroom, prefill capacity, and redundancy. Halve the batching efficiency and you double that number, which is why batching is worth so much money.
Cost per million output tokens
order of $0.50 at cost, versus dollars at list
Ten thousand H100s at a rough $2 per GPU-hour is about $20,000 an hour. If that fleet sustains on the order of 10 million output tokens a second across all its batches, an hour produces tens of billions of tokens, which lands the raw serving cost in the region of a dollar or less per million output tokens against a list price measured in dollars. The exact figure depends entirely on batching efficiency, which is the same point the fleet estimate makes: the gross margin on inference is almost entirely a function of how full the batches run.
A reasoning request holds a slot far longer
minutes, not the ~15 seconds of a chat reply
A reasoning request can emit tens of thousands of hidden thinking tokens before it produces a visible answer. At the same ~30ms per token that is minutes of GPU occupancy for a single request, tens of times a normal chat turn, so a small fraction of reasoning traffic can consume a large fraction of the fleet and has to be scheduled as its own class.
The product tier looks conventional and is deliberately kept that way. A client opens a streaming connection, an API gateway authenticates the user, checks their tier and token quota, and applies input moderation. A conversation service loads the message history from a database, assembles the prompt, and hands the request to the inference layer, then persists the completed response and updates usage accounting. Everything interesting is behind that handoff. An inference router picks a serving replica, and its scheduling input is not request count or CPU but KV cache occupancy, because a replica holding a few long conversations is genuinely fuller than one holding many short ones. The router also prefers a replica that already holds the prefix of this conversation in its cache, so session affinity turns the repeated history into a cache hit instead of recomputation. Inside a replica the model is sharded across GPUs with tensor parallelism inside a node, where NVLink makes the per-layer all-reduce cheap, and the serving engine runs continuous batching: at every decode iteration it admits newly arrived requests and evicts finished ones, rather than locking a batch until its slowest member completes. KV cache memory is managed by PagedAttention in fixed-size blocks so a long conversation does not need one contiguous reservation, and blocks holding an identical shared prefix are referenced by several sequences at once. Prefill and decode either run on separate GPU pools, so a long prompt cannot stall other users' token streams, or are interleaved with chunked prefill on the same pool. Generated tokens stream back through the gateway over server-sent events, passing an output moderation classifier as they go, and a cancelled stream immediately frees its GPU slot and KV blocks. Around all of this sits the ordinary but necessary machinery: conversation storage, usage metering for billing and quotas, feedback capture for evaluation, and capacity management that has to be predictive because a new replica takes minutes to load its weights.
In a real interview, sketch this on the whiteboard before diving into any single box.
Walk through each service. The interviewer wants to hear what each one owns, not just the names.
Terminates the client connection, authenticates, enforces tier and token quota, and streams tokens back over server-sent events. It matters more than it looks: it must propagate cancellation promptly, because an abandoned stream that keeps generating is pure wasted GPU, and it must hold a very large number of mostly-idle long-lived connections cheaply.
Owns history and prompt assembly. Because the model is stateless, this service resends the conversation on every turn and decides what to do when the history outgrows the context window: truncate the oldest turns, summarize them, or retrieve only the relevant ones. It is also where branching from an edited message is handled, which makes a conversation a tree rather than a list.
Chooses a replica using KV cache occupancy and prefix locality rather than round-robin, since the ordinary load signals are actively misleading here. Routing a follow-up turn to the replica that already holds the conversation's prefix converts an expensive prefill into a cache hit, so affinity is a throughput feature and not just a nicety.
The core. It runs iteration-level scheduling so requests join and leave the batch every decode step, and manages KV cache as fixed-size pages so memory is not fragmented by variable-length conversations. These two techniques together are the difference between a GPU fleet that is mostly busy and one that is mostly idle.
Shards the model with tensor parallelism inside a node and pipeline parallelism only when a model cannot fit in one node, since pipeline stages introduce bubbles, the idle gaps while one stage waits for the one before it. Quantization to FP8 or INT8 shrinks the weights and frees memory for more KV cache. It speeds up decode too, though the gain is modest once the batch is large, because at that point each sequence's own KV read, not the shared weight read, is the bigger part of the memory traffic.
Keeps the KV state of shared prompt prefixes so the system prompt and the conversation history are not recomputed on every turn. This is the cache that actually hits in an LLM product, unlike a response cache keyed on the whole request, and it is why providers can offer a discount on cached input tokens.
Classifies the input before it reaches a GPU, which is also a cheap way to reject abuse before paying for it, and screens the output while it streams, which is harder because tokens have already been sent. In practice you buffer a small window before emitting so a violation can be caught before the user sees it, trading a little latency for the ability to stop mid-answer.
Counts tokens rather than requests, because a request can be a hundred tokens or a hundred thousand and only tokens map to cost. It also captures feedback and samples conversations for offline evaluation, so a change to the model, the prompt, or the truncation policy can be measured instead of guessed at.
Runs the loop when the model decides to call a tool. It pauses generation, executes the web search, retrieval, or sandboxed code, and feeds the result back so generation resumes. The design question it forces is what happens to the KV cache during a multi-second tool call: hold it and the memory sits idle destroying occupancy, or evict it and pay a re-prefill, which the prefix cache makes survivable.
A vision encoder turns an image into tokens that enter the prompt, and voice mode adds a low-latency speech path with its own duplex and barge-in requirements. Each is a separate pool with its own scaling, and image tokens count as prefill cost, so a picture is not free context, it is a chunk of the compute budget before a single output token is produced.
conversations. One row per thread, indexed by user and recency for the sidebar. Deletion has to cascade for real, since users expect a deleted conversation to be gone rather than…
Every table for ChatGPT, its keys, and which store fits it and why.
Prefill and decode have opposite bottlenecks. Inference runs in two phases that behave nothing alike, and one mechanical fact explains the difference. A forward pass has to read every weight in the model once. In…
15 deep dives on the parts that break at scale: Prefill and decode have opposite bottlenecks; The KV cache is the real capacity limit; PagedAttention: virtual memory for the KV cache.
Route on KV cache occupancy rather than request count. Requests are wildly unequal in the memory and time they consume, so request-based load balancing sends work to a replica that looks idle and is actually nearly full…
8 decisions an interviewer expects you to defend, each with the alternative and why it loses here.
One GPU in a tensor-parallel group dies while 200 answers are mid-stream. What does the user see, and how do you recover?
4 follow-up questions with model answers, the interview scorecard for this question, and a mock interview on Design ChatGPT with the AI tutor.
OpenAI does not publish ChatGPT's serving architecture, so treat the specific topology above as a reasoned design rather than a description of their internals. What is public and well documented is the inference science that any such system must obey, and it is unusually open. PagedAttention and continuous batching come from the vLLM paper by Kwon et al. at SOSP 2023, which measured that naive KV cache allocation wastes most of the memory and showed the throughput gain from fixing it; iteration-level scheduling was introduced earlier by Orca at OSDI 2022. Speculative decoding with its rejection sampling proof of distributional equivalence is from Leviathan et al. in 2023. The prefill and decode interference problem and the disaggregation answer are documented in DistServe (OSDI 2024) and Splitwise, and the chunked prefill alternative in Sarathi-Serve. Prefix caching with a radix tree is from SGLang. Grouped-query attention, the reason the KV cache numbers above are merely large instead of impossible, is from Ainslie et al. in 2023 and is used by Llama and most current open models. The mixture-of-experts discussion generalizes the sparse-routing idea from Switch Transformers (Fedus et al., 2021); the specific expert counts and routing behavior of any given frontier model are not public, so treat that section as the shape of the problem rather than a description of one vendor's model. The cost arithmetic uses round public numbers for GPU rental and known token economics to show the method, not to price any specific provider. The user-facing figures cited here come from different public snapshots and should be read with their dates: OpenAI stated about 900 million weekly actives in February 2026, and separately about 2.5 billion messages a day in mid 2025. The prompt caching discount on cached input tokens is documented in OpenAI's own API docs, which is a useful confirmation that prefix caching is running in production at that scale.
Sources
If any of these topics are fuzzy, the interviewer will catch it. Each lesson is 15 to 60 minutes with diagrams, code, and a quiz.
interview readiness
Three questions from this guide. Answer them without scrolling up, the way you would have to in the room.
The concepts were explained in a clear and structured way, with practical examples that made even complex system design topics easier to understand. I especially liked the focus on real-world architecture, scalability, trade-offs. The content was well designed, engaging, and highly useful for anyone looking to strengthen their system design skills. Highly recommended for software engineers preparing for system design interviews or wanting to build a stronger foundation in designing scalable systems.