1:1 mentoring with Big Tech AI engineers
System DesignFree

System Design 101

The seven classic primitives on one request path, read as an LLM system: streamed answers, percentiles and their tails, the caches, the shared provider ceiling, and queues for slow work.

Last updated

After this section you can

  • Place the seven primitives on one request path, and name what a model changes in each
  • Read p50, p95 and p99, and predict how a task's tail compounds over sequential calls
  • Name the limit that binds first as traffic grows, and the step that moves it
01

System Design 101

The seven primitives every architecture diagram uses, placed on one request path, and what changes when the server is a language model.

Key idea

An LLM system is the same seven web parts. The model changes their numbers: answers stream for seconds, the slowest 1% is what users feel, limits are shared, cost is per token, and slow work needs a queue.

One support question through the seven parts: a cache hit skips the model
Client app or browser POST + JSON Load balancer health-checked N replicas Server replica checks identity then the cache Data stores SQL rows, vector index Model API one limit per model class 1 2 5 6 Cache keyed by tenant 3 4 hit: answer returns, no model call answer streams back, token by token 7 Queue jobs wait here Worker calls the model 8 9 10

Blue request, teal servers, purple state, amber model, green answer. Dashed purple: slow work.

One request, one streamed answer

One streamed question, on the wire
app
POST /v1/messages
{
  "model": "claude-sonnet-5-5",
  "max_tokens": 1024,
  "stream": true,
  "messages": [
    {
      "role": "user",
      "content": "Order status?"
    }
  ]
}
One method, one JSON body.
assistant
HTTP/1.1 200 OK

Text arrives as deltas; the closing message_delta carries stop_reason and usage.

error
event: error
data: {"type": "error", "error": {"type": "overloaded_error", "message": "Overloaded"}}
0.8 sto the first token (assumed)
5.8 sto the last token, at 65 tokens a second (assumed)
$0.00533per question on Sonnet 5.5, list price

The 200 only says the stream started. Read blocks by type, not content[0].text: on Sonnet 5.5 adaptive thinking is on by default, and the first block can be a thinking block. Branch on stop_reason, and leave max_tokens room for thinking. The call is Messages API's.

The reference question is 1,040 input and 325 output tokens: the older 800 and 250, plus about 30% for the Claude 4.7 tokenizers. Count your own with the token counting endpoint, not a words-per-token rule.

CodeMeansRetry?
200Stream started; it can still failNot needed
400, 401, 403Bad request, key or permissionNo: fix it
413Body over 32 MBNo: shrink it
429A rate limit, or the spend capAfter retry-after
500, 504Server error, or timeoutYes, with backoff
529Overloaded: high traffic on the APIYes, with backoff

Per million tokens, 1,040 input at $2 and 325 output at $10 is $0.00533 on Sonnet 5.5, before thinking tokens. Haiku 5.5, the smallest current model, is $0.000267 for the same question: 20 times less.

The mean hides the slow answer

Interactive: count the squares for one task length.

CallsShare hit
1 call1%
5 calls4.9%
12 calls11.4%
20 calls18.2%
50 calls39.5%

A percentile is the value that p% of requests are at or below. A task of n sequential calls meets a call from the slowest 1% with probability 1 − 0.99n, so agents live in the tail.

The script makes 1,020 synthetic latencies: 1,000 with a median of 60 ms, and 20 slow ones.

# A mean hides the tail (synthetic data, in ms).
import math
import random
random.seed(7)  # same numbers every run
fast = [random.lognormvariate(math.log(60), 0.3)
        for _ in range(1000)]
slow = [random.uniform(1500, 5000)
        for _ in range(20)]
latencies = fast + slow
def percentile(data, p):
    """The p-th percentile, nearest rank."""
    ranked = sorted(data)
    k = math.ceil(p / 100 * len(ranked))
    return ranked[k - 1]
mean = sum(latencies) / len(latencies)
print(f"n = {len(latencies)}")
print(f"mean = {mean:.0f} ms")
for p in (50, 95, 99):
    v = percentile(latencies, p)
    print(f"p{p} = {v:.0f} ms")
n = 1020
mean = 122 ms
p50 = 60 ms
p95 = 104 ms
p99 = 2950 ms

The mean, 122 ms, is slower than at least 95 requests in 100 (the p95 is 104 ms). The p99 is 2,950 ms, almost three seconds. A p99 needs at least 100 samples. The mean suits a bill, not a wait.

Latency sets how many requests are in flight

480questions a minute at 8 a second
46open at once: 8 a second times 5.8 s
0.8open at once for a 100 ms call

Little's law: requests in flight equal the arrival rate times the time each spends in the system. A slow model keeps more requests open at the same rate. Slot sizing is Scaling the Agent Runtime's.

Three caches, three different risks

A cache stores a value under a key for a time to live: a hit returns it, a miss computes and stores it. The LLM caches differ in their keys.

Exact match same bytes
  • Key: the whole request, hashed.
  • Catches: the same request again.
  • Risk: free text rarely repeats exactly.
Semantic match same meaning
  • Key: an embedding of the question.
  • Catches: questions with the same meaning.
  • Risk: a similar question, a different answer. Semantic Caching owns the rules.
Provider prefix the provider's cache
  • Key: the exact bytes of tools, system and messages.
  • Catches: the repeated start of every prompt.
  • Risk: one changed byte early misses everything after it.

Rule of thumb: take the prefix cache first; it changes the bill, not the answer. “Where is my order?” is never served from a shared cache.

Prefix reads: 0.05× on Sonnet 5.5 and Opus 5.5, 0.025× on Fable 5.1, 0.1× on Haiku 5.5. Writes cost 1.25× for 5 minutes or 2× for 1 hour. Prompt Caching has the economics.

More servers, same provider ceiling

Interactive: slide the questions a minute against the RPM line.

QuestionsOf the RPM
40040%, 600 spare
1,000100%: the line
1,200120%: 200 over

Stateless replicas add capacity in your code, not at the provider. Every replica draws on one organisation-level bucket per model class, with three meters: requests (RPM), input tokens (ITPM) and output tokens (OTPM).

At Start, Opus 5.5 and Sonnet 5.5 each allow 1,000 requests, 2M input and 400K output tokens a minute (Haiku 5.5 matches). For the reference question: 1,000 questions on RPM, 1,923 on ITPM, 1,231 on OTPM. The lowest binds first.

TierBinds firstPer minute
StartRPM1,000
BuildOTPM3,077
ScaleOTPM6,154

At the reference shape, checked 2026-10-08.

OTPM counts generated tokens, so a high max_tokens costs nothing against it. Cache reads are not in ITPM: 2M ITPM at an 80% hit rate serves 10M input tokens a minute.

A 429 is a meter over its line (with retry-after), an acceleration limit after a sharp ramp, or the spend cap: $500 a month at Start, with no retry-after, reset at 00:00 UTC on the first unless you request more.

The SDK retries twice and honours retry-after. With your own loop, three attempts of three make 9 calls per question on one meter.

Pick the store by the question it answers

SQL
  • Holds: rows of one shape.
  • Guarantees: transactions.
  • Bot keeps: orders.
Document or key-value
  • Holds: records of any shape.
  • Guarantees: a read by key.
  • Bot keeps: sessions.
Vector index
  • Holds: embeddings of text.
  • Guarantees: near neighbours, not exact.
  • Bot keeps: help articles.

Rule of thumb: pick the store by the question the data must answer.

A vector index is approximate, and a new article is findable only once embedded. Which store to run is Vector Indexes & Stores's question.

Move slow work off the request path

  1. Enqueue. A handler writes a job with an id to the queue.
  2. Return 202. The client gets 202 Accepted and the id at once.
  3. Work. A worker runs the job and writes the result.
  4. Collect. The client polls, or a webhook reports back.
At-least-once
A job can arrive twice.
Idempotent
A repeat leaves the same result.
Dead-letter queue
Where jobs go when their retries run out.

An agent run lasts minutes, so it cannot wait in a web request. The model API gives no idempotency key: keep one per side effect in your code (Agent Durability). Work nobody waits for can use the Batch API, at 50% off. Queue mechanics are Event-Driven Async's.

Sources, checked 2026-10-08: Streaming, Errors, Rate limits, Pricing and Models overview.

Common mistakes
  • Reading the mean: a p99 from 20 samples is a latency no request had.
  • Adding replicas to fix 429s: every replica draws on one bucket.
  • A shared cache checked before identity: the next customer gets the first answer.
Interview angle

“Your support bot is slow, and it returns 429s after you add servers. What do you check first?” The trap is adding replicas.

  • Junior: names the seven parts and walks the path.
  • Senior: reads p99, names the binding meter (RPM at Start), knows the SDK retries.
  • Staff: owns the shared provider ceiling across tenants, and bounds the cost per task.
Check yourself
p50 is 300 ms and p99 is 12 s, and a task makes 12 sequential calls. What share of tasks meet the slow tail, and what does it do to the design?

1 − 0.9912 is 11.4%: about one task in nine. A good p50 says nothing about them. Put a timeout on each call and a budget on each task, and show progress.

Traffic doubled, you doubled the replicas, and 429s got worse on Start. Which meter binds, why do replicas add nothing, and what changes first?

RPM. Start allows 1,000 a minute per organisation and model class, and every replica draws on that bucket. Smooth and queue the load, jitter the retries, then request a tier increase if the load is real.

A shared semantic cache is asked “Where is my order?”. What goes wrong, and what must the key include?

It serves one customer's order status to a similar question from another: a cross-tenant leak. The key needs the tenant, the permissions and the versions that change the answer. Semantic Caching has the key.

Recap
  • Seven parts on one path, from client to queue.
  • In flight equals arrival rate times time in system: 8 a second at 5.8 s keeps about 46 open.
  • At Start, RPM binds first, at 1,000 a minute.
  • Key the cache by tenant; return 202 for slow work.

Next: AI Vocabulary: Every Term at Its Stop on the Request Path — each term from this page, defined in one line

Related

More in System Design

Get full access to all 149 sections with code examples, diagrams, and interactive animations.

Unlock Premium