Vibe Engines
YouTube

Vibe Engines is free, interactive AI engineering & system design — runs in your browser. Pick a learning path

AI System Design

Design a Prompt A/B Platform

Step 1 / 9

Learn AI system design by building the platform that versions, evaluates, and safely A/B tests PROMPTS in a production LLM application — a much faster-moving artifact than model weights, often…

The numbers to beatprimary metricwhat the test aims to improveguardrail metricsmust never regressboth requiredfor promotion

The whole design, in writing

Every step of the build above, written out: the problem each piece solves, the option that was taken and the ones that were not, the numbers, and how it fails in production.

The big idea

Prompts change fast — the platform has to keep up

A prompt gets tweaked far more often than a model gets retrained — sometimes many times a day, often by someone who isn't a software engineer. Treat every prompt change like an emergency code deploy and iteration grinds to a halt; treat it too casually and an unvalidated change reaches every user instantly.

Prompt Engineeredits, tests
New in this step: Prompt Engineer.

We'll build the platform layer for prompts specifically: externalized, versioned config decoupled from deploys; offline eval before anything reaches users; live A/B testing because offline eval alone misses real effects; guardrail metrics that must never regress; and a review gate suited to non-engineer editors.

What the new pieces do

Prompt Engineerclient
Often not a software engineer — a PM, researcher, or specialist iterating on wording, examples, and instructions, wanting to test changes safely without needing a code deploy.

Step 1 · The baseline

Prompts hardcoded in application code

Simplest version: the prompt text lives directly in the application's source code. What happens when someone wants to test a wording change?

App RuntimeLLM Call
New in this step: App Runtime, LLM Call. · swipe to pan the diagram

Prompts are hardcoded in application source code. What's the cost of testing a wording change?

  1. A code change routine for an engineer is a genuinely high barrier for the people who most often want to iterate on prompt wording — and even for an engineer, it means a full build/test/deploy cycle for what might be a two-word tweak.

  2. Coupling prompt text to code deployment means the iteration speed on prompts is bottlenecked by the SLOWEST part of the stack (code review, build, deploy) even though prompt wording is conceptually a much lighter-weight thing to change — and it puts prompt editing behind a skill barrier (writing and deploying code) that doesn't match who actually has the best judgment about prompt wording.

  3. Editing prompt text has nothing to do with the model's weights — this conflates prompt engineering with model training, which are entirely different operations with different costs.

Hardcoded prompts couple a lightweight text change to a heavyweight code-deploy cycle, slowing iteration and locking out the people (often PMs or prompt specialists, not software engineers) who most directly understand prompt intent. Prompts need to be decoupled from code the way configuration typically is.

Why this piece earns its place

The cost people quote is deploy latency, but the expensive part is attribution. When prompt text lives in source, a prompt edit arrives inside a release alongside a batch of unrelated commits, so when quality drops on Tuesday the only honest answer is that something in that release did it, and you end up bisecting a deploy to find a two-word change. Externalizing is what gives a prompt its own change event, with its own timestamp and author — and every later step on this page reads from that event. Hardcoding does something else too: it multiplies the text. The same system instruction gets pasted into a batch job, a retry path and an internal tool, and the three copies drift, so a fix lands in one of them and the bug survives in the other two. When you would skip it: one prompt, one call site, and the only editor is the engineer who deploys. At that size a registry is ceremony. The moment there is a second editor or a second call site, the copies have already started.

What the new pieces do

App Runtimeclient
The live application making real LLM calls on behalf of real users — starts with prompts baked directly into its own code.
LLM Callservice
Where the assembled prompt actually gets sent to a model — the same call site regardless of which prompt version supplied the text.

Step 2 · Externalize as versioned config

Edit the prompt, not the code

Decouple prompt text from application code entirely.

Prompt Engineeredits, testsApp Runtimefetches versioned promptPrompt Registryversioned config
New in this step: Prompt Registry.

Prompts should be editable without a code deploy. What's the actual mechanism?

  1. A spreadsheet has no versioning discipline, no eval gate, no audit trail of who changed what and when — it solves the "no code deploy" problem but reintroduces every quality and safety problem a proper registry is meant to prevent.

  2. A registry gives prompts the same treatment as any other production configuration: versioned, auditable, and referenced by the application at runtime rather than baked into its source. Publishing a new prompt version becomes a fast, reviewable registry operation, completely independent of the application's own deploy cycle.

  3. Baking multiple variants into code still requires a deploy to add, remove, or adjust any of them — this doesn't actually solve the decoupling problem, it just hardcodes more options instead of one.

Introduce a Prompt Registry: every prompt is versioned config, and the application fetches the currently assigned version at runtime rather than having it compiled into its source. Publishing a new version is a registry operation — fast, auditable, and entirely decoupled from the application's own code-deploy cycle.

Why this piece earns its place

Fetching config at runtime puts the registry in the request path, so the first real question is what the app does when the registry is unreachable. The answer is a local cache with a last-known-good copy baked into the deploy: the app boots, serves what it had, and a registry outage degrades publishing rather than answering. That cache is also where rollback speed actually lives — repointing a version is instant in the registry and takes a TTL to become true everywhere, which makes the TTL a recovery-time decision, not a performance one. Two knobs belong in different places. Which version is active for a use case is registry state, owned by the platform. An override that pins one request to a specific version belongs in the request, so an engineer can exercise a draft against real inputs without publishing it — but it is an internal, authenticated path a caller cannot reach, and requests carrying it are tagged and dropped from every experiment and guardrail number. A bypass that also quietly polluted the evidence would be the worst of both. And every model call should log the exact version id it used, because without that the measurements taken later have nothing to attribute themselves to.

What the new pieces do

Prompt Registrygateway
The source of truth for every prompt version — decoupling "what prompt is live" from "what code is deployed," so edits don't require a redeploy.

Step 3 · Offline evaluation before rollout

Score it before anyone sees it

A new prompt version is drafted. Should it go straight to real users, or be validated first?

Prompt Registryversioned configOffline Eval Gatefails closed
New in this step: Offline Eval Gate.

A new prompt version is ready. Should it go directly to production traffic?

  1. Fast iteration and validated iteration aren't in conflict — skipping validation entirely just means users are the first to discover a regression, which is a worse trade than a quick, automated pre-check.

  2. An offline eval gate catches obvious regressions (broken output format, degraded task performance on known cases) cheaply and fast, before any real user is exposed to a bad candidate — the same "validate before it goes near production" principle used for model registry promotion, applied here to prompts.

  3. Manual spot-checking by one person catches only what that person happens to think to try — it's not a systematic, repeatable, or scalable substitute for running against a defined evaluation set.

Add an Offline Eval Gate: every candidate prompt version is scored against a fixed evaluation set before it's eligible for any real traffic, and the gate fails closed — no unvalidated candidate can be promoted while it's unavailable. This is the same eval-gate principle used for model promotion, applied to the much-higher-frequency artifact of prompts.

Why this piece earns its place

The gate is only as trustworthy as the set behind it, and prompt eval sets rot in a specific way. Most cases here are reference-based: the expected output is known, so scoring is a comparison, which is cheap, deterministic, and the reason the gate can afford to run on everything. But plenty of what you actually want to check has no single correct string: whether the tone held, whether a refusal was the right call, whether the answer stayed inside policy. Those need a model reading the output against a rubric, and the moment you add that mode the judge is itself a prompt, with its own version. Change the judge and every historical score moves, so a candidate can pass today and identical text fail next month with nothing about the candidate having changed. Version the judge alongside the set and freeze both, or today's score is not comparable to yesterday's and the gate is theatre. Cost follows the same split: a reference case is one model call, a judged case is two, and the bill is paid per candidate — while candidates arrive many times a day here rather than on a retraining cadence. A gate slow enough to interrupt someone gets routed around. So run a small smoke subset on every draft save and reserve the full frozen set for the moment a version asks for traffic.

What the new pieces do

Offline Eval Gateservice
Scores a candidate prompt against a fixed evaluation set before it's allowed anywhere near real production traffic.

Step 4 · A/B testing on live traffic

Offline eval alone can still miss real effects

The candidate passed offline evaluation. Is that sufficient confidence to fully replace the current production prompt?

App RuntimePrompt RegistryA/B Traffic Split
New in this step: A/B Traffic Split. · swipe to pan the diagram

A prompt candidate passed the offline eval set. Is that enough to fully roll it out to all users?

  1. An offline eval set is a fixed, historical snapshot — real user inputs, phrasing, and edge cases in live traffic can differ meaningfully from what the eval set captured, the same gap that makes shadow/canary deployment necessary for models, now applied to prompts.

  2. A/B testing exposes the candidate to actual live user inputs and measures actual outcomes, catching real-world effects — including ones the offline eval set never anticipated — before the candidate earns full rollout. This is the exact same principle as shadow/canary validation for models, reapplied here because the underlying reason (offline metrics aren't the whole story) is the same regardless of what's being tested.

  3. Repeating an identical evaluation against an identical static dataset can't reveal anything about real-world behavior the dataset itself doesn't already capture — it adds no new information.

Run genuine A/B tests on live traffic via the A/B Traffic Split engine: split a percentage of real requests between the current production prompt and the candidate, and measure real outcome metrics — not just the offline eval score — before considering full rollout.

Why this piece earns its place

The detail that decides whether a prompt test means anything is the assignment unit. Split per request and one conversation flips versions between turns, which breaks the experience and wrecks the measurement — each user contributes half an observation to each arm, the arms converge, and a real difference reads as noise. Assign sticky, by user or session, and analyse at the unit you assigned at. The second thing is statistical power. Task success is usually the common outcome rather than a rare one, so rarity is not the limit — the limit is that a wording change moves the rate by less than the traffic you have can resolve, and the metrics further down the same list, conversion especially, are rare enough to need far more traffic again. A test with no pre-committed stopping rule then gets stopped when the number looks good, which manufactures wins reliably. Decide the smallest effect worth shipping before the test starts, and accept that plenty of wording tweaks fall below it and should ship on judgment rather than on evidence that is not there. Also watch for concurrent experiments on the same call site: two tests over one prompt are testing the product of both, and neither result is clean unless assignment is coordinated.

What the new pieces do

A/B Traffic Splitservice
Runs two prompt versions concurrently on a split of real traffic, comparing real-world outcomes offline eval alone can't reveal.

Step 5 · Guardrail metrics, not just the headline number

A "win" on one metric can be a loss overall

An A/B test shows Variant B has a meaningfully better task-success rate than the current prompt. Should it be promoted based on that result alone?

App RuntimeLLM CallPrompt RegistryA/B Traffic SplitOutcome + Guardrail Metrics
New in this step: Outcome + Guardrail Metrics. · swipe to pan the diagram

A variant wins on the primary metric (task success). Is that alone sufficient to promote it?

  1. A variant could improve task success while simultaneously tripling cost per request, degrading latency, or increasing unsafe outputs — none of which the primary metric alone would reveal, and any of which could make the "win" a net negative in practice.

  2. Guardrail metrics catch exactly the failure mode where a prompt genuinely improves on what it's being optimized for while quietly regressing something equally important that wasn't the explicit target — cost, latency, and safety are common candidates for guardrails specifically because they're easy to overlook when focused on one headline number.

  3. A subjective feel-check isn't a repeatable or reliable substitute for tracking the actual metrics that matter — it's exactly the kind of ad-hoc judgment a rigorous testing platform is meant to replace.

Track guardrail metrics — cost, latency, safety/refusal rate — in the Outcome + Guardrail Metrics store alongside the primary metric being optimized. A variant is only eligible for promotion if it improves (or holds) the primary metric AND doesn't meaningfully regress any guardrail, regardless of how good the primary result looks in isolation.

Why this piece earns its place

A guardrail is only enforceable if it is computable per request and attributable to a version. Cost and latency are, because both fall out of what the call site already records — tokens in, tokens out, wall time. Refusal rate nearly is: the stop reason or moderation flag comes back with the completion, and a refusal has a shape you can match on, so counting it is a cheap check over data you already hold. Safety is the expensive one — deciding whether an output was actually harmful means running a classifier or another model over it, which makes it the one guardrail with a per-request bill, and therefore the one that quietly gets sampled down to nothing. Sample it deliberately and write the rate down, rather than discovering after an incident that the safety line on the dashboard was drawn from a handful of requests. Then define the denominator. Cost per request and cost per completed task are different metrics and can move in opposite directions — a variant that asks one clarifying question costs more per call while costing less per outcome, and which of those you wrote down decides whether that change reads as a breach or a win. Evaluate the guardrails continuously while the test runs, not once at the end: the damage accrues per request served.

  • primary metricwhat the test aims to improve
  • guardrail metricsmust never regress
  • both requiredfor promotion

What the new pieces do

Outcome + Guardrail Metricsdata
Tracks both the metric a test is trying to improve AND the metrics (cost, latency, safety) that must not get worse regardless of the primary result.

Step 6 · Routine, instant rollback

Not an emergency procedure — a daily tool

A promoted prompt version turns out to underperform in ways the test window didn't catch. How fast can you revert?

Prompt EngineerApp RuntimeLLM CallPrompt RegistryOffline Eval GateA/B Traffic SplitOutcome + Guardrail Metrics
The system as it stands at this step. · swipe to pan the diagram

Because every prompt version in the Registry is immutable and versioned, rollback is repointing the "currently active" reference back to the previous version — the same version-pointer mechanism as model registry rollback, but exercised far more routinely given how often prompts change. This isn't a rare emergency procedure here; it's treated as a normal, low-friction operation a prompt engineer might use several times in a week.

Why this piece earns its place

The hard half is the residue. Moving the pointer changes what the next request gets; it does nothing about what the bad version already produced and something else kept — cached responses, conversation summaries, extracted fields written to a table, memory carried into the next session. All of it is still wrong after the revert, and that is what separates a prompt rollback from a code rollback. So reverting is two operations — move the pointer, then decide what to invalidate — and the second is only possible if caches and derived records are keyed by the prompt version that produced them. Add that key early; retrofitting it during an incident is a migration. The other rule is that the way back must not run through the gates guarding the way forward. If reverting needs an approval and an eval run, it inherits their latency at the exact moment you cannot afford it. Any version that was previously active has already passed both, so returning to one is a pointer write while anything new is a fresh candidate — that asymmetry is what keeps rollback routine instead of an escalation.

Step 7 · A review gate built for non-engineers

Safe editing without requiring a code-review habit

Prompt engineers are often not software engineers, and may not have the instinct to flag "this edit accidentally removed the safety instruction" the way a code reviewer would catch a risky diff. What keeps an accidental unsafe edit from reaching real users?

Prompt EngineerPrompt RegistryOffline Eval GateReview / Approval
New in this step: Review / Approval. · swipe to pan the diagram

Require every prompt version to pass through a Review / Approval Gate before it can be eligible for eval and rollout — a lightweight, prompt-specific review step (not a full code review) that a peer or an automated check can use to catch obviously risky changes (removed safety instructions, changed output-format contracts other systems depend on) before they even reach the Eval Gate.

Why this piece earns its place

The hard part of reviewing a prompt is that a word-level diff of a long block of prose shows churn, not risk, and a human reading the whole thing every time is the bottleneck. Structure fixes it: keep the prompt in named sections — role, safety rules, output contract, examples — so the gate can report which section a candidate touched and route on that. An edit inside the examples is not the same risk as one that deletes a line from the safety block, and only a structured prompt lets a machine tell them apart. The checks worth automating are the ones with a machine-readable answer: run the candidate over a few fixed inputs and diff the parsed shape of the output, which catches a broken format contract that a downstream service depends on in seconds, with no human in the loop. One detail that bites: record the approval against the immutable version id, never the prompt name. Approve by name and a later edit inherits that approval and ships unreviewed — the exact failure the gate was installed to prevent.

What the new pieces do

Review / Approvalservice
A required approval step before a prompt edit can reach real users — a safety net specifically because prompts are often edited by people without a code-review habit.

Step 8 · The sharp edges

Injection regressions and prompt sprawl

Two subtler risks: a seemingly-innocuous prompt edit that inadvertently makes the model MORE susceptible to prompt injection, and, after months of active testing, genuine confusion about what prompt version is actually live for a given use case.

Prompt EngineerApp RuntimeLLM CallPrompt RegistryOffline Eval GateA/B Traffic SplitOutcome + Guardrail MetricsReview / Approval
The system as it stands at this step. · swipe to pan the diagram

Include a dedicated security/injection-resistance eval suite in the Eval Gate, distinct from task-success metrics — a prompt edit can pass every functional check while quietly weakening resistance to adversarial input, so security needs its own explicit test, not an assumption that functional correctness implies it. For prompt sprawl, the Registry maintains one clear, queryable single source of truth for "what's the currently active prompt version for this use case," regardless of how many draft versions or past experiments exist alongside it.

Why this piece earns its place

Injection resistance cannot be gated the way task success is, because the other side moves. A frozen adversarial suite decays into a regression test for attacks you already defeated — useful, and not the same thing as being safe. The suite has to be fed: attempted injections found in real traffic become new cases, and a pass means no known attack got through, which is the only claim the evidence supports. Say it in those words, because a security suite reported as a score invites everyone to read it as one. Sprawl has an unglamorous second half nobody writes down, and that is retention. Keep every version that was ever active — those are the rollback targets, and the only way to reconstruct what a complaint from three weeks ago actually saw — and garbage-collect drafts that never passed the gate. And watch use-case keys shared across features: two call sites reading one key means a change made for the first ships silently to the second, which surfaces as an unexplained regression in a team that never touched a prompt.

You did it

You just designed a prompt management platform.

Prompt EngineerApp RuntimeLLM CallPrompt RegistryOffline Eval GateA/B Traffic SplitOutcome + Guardrail MetricsReview / Approval
The finished design, end to end. · swipe to pan the diagram

Everything you assembled, in order

  • Hardcoded prompts couple a lightweight text change to a heavyweight deploy cycle — externalizing them as versioned config decouples iteration speed from code deployment.
  • An offline Eval Gate, failing closed, validates every candidate against a fixed set before it's eligible for real traffic.
  • Live A/B testing catches real-world effects an offline evaluation set — a fixed historical snapshot — structurally can't reveal.
  • Guardrail metrics (cost, latency, safety) must never regress, even when a variant wins on the primary metric being optimized.
  • Rollback is a routine, instant version-pointer change, exercised far more often than for models given how frequently prompts iterate.
  • A dedicated, non-engineer-friendly review gate catches prompt-specific risks (like an accidentally-removed safety instruction) before rollout.
  • Security/injection-resistance needs its own explicit eval, separate from task-success metrics, since the two can diverge.

Where an interviewer pokes next

Getting the boxes right is the easy half. These are the questions that separate a candidate who drew the diagram from one who has run the thing. Answer each one out loud before you open it.

  1. How is this different from the Model Registry design?

    Both are governance layers for a versioned artifact moving toward production, and deliberately share several mechanisms (versioning, eval gates, staged validation, rollback) because the underlying safety reasoning is the same. What differs is the artifact's nature: model weights change infrequently (a training run takes real time and compute), are edited exclusively by ML engineers, and a bad promotion is costly to reverse in terms of retraining. Prompts change many times a day, are often edited by non-engineers, and are cheap to iterate on — which is why THIS design leans harder on fast, routine rollback and a lightweight non-engineer review gate, while the model registry design leans harder on drift monitoring and reproducible lineage, reflecting each artifact's actual change frequency and editor population.

  2. Why run BOTH an offline eval gate AND a live A/B test, rather than picking one?

    They catch different failure classes, at different costs. The offline gate is fast, cheap, and catches obvious regressions immediately, before any real user is exposed — a useful first filter that makes the more expensive live-testing stage more efficient by screening out clearly broken candidates early. The live A/B test is slower (needs real traffic over time) but catches real-world distributional effects the offline set can't anticipate. Skipping the offline gate means even obviously-broken candidates consume live A/B testing capacity and briefly affect real users; skipping the A/B test means you only ever validate against a fixed historical snapshot. Using both is strictly more thorough than either alone, at a modest added cost.

  3. How would you decide the traffic split percentage for a new A/B test — why not always 50/50?

    The split is fundamentally a trade-off between how fast the test reaches statistical significance and how much traffic is exposed to an unproven candidate. A 50/50 split reaches significance fastest but exposes the maximum number of users to a candidate that might be worse. A smaller split (say 5-10%) limits exposure and blast radius if the candidate turns out badly, at the cost of needing more total traffic (and time) to reach the same statistical confidence. In practice, tests often START with a small, cautious split and RAMP UP toward a larger one as early guardrail metrics confirm nothing's obviously wrong — getting both fast initial safety signal and eventually efficient significance.

  4. What happens if two guardrail metrics conflict — say, a variant improves safety but slightly increases latency?

    This is exactly why guardrails need an explicitly defined ACCEPTABLE REGRESSION THRESHOLD per metric, decided in advance, rather than a blanket "zero regression allowed" rule that would make almost any change impossible to ship (some tiny latency cost is often an acceptable trade for a meaningful safety improvement). The platform typically defines, per guardrail metric, how much regression is tolerable (e.g. "latency may increase up to 5% if the primary metric improves by more than that") — turning what could be an ambiguous judgment call into an explicit, pre-agreed policy the A/B engine can evaluate mechanically rather than requiring a case-by-case human decision for every test.

  5. Could the review gate (Step 7) become a bottleneck that defeats the whole point of fast prompt iteration?

    This is a real tension, and the mitigation is scoping the review gate NARROWLY — it should catch specific, well-defined risk categories (removed safety language, broken output-format contracts other systems parse) via fast, often partially-automated checks, not function as a full, slow human review of every wording tweak. Many platforms tier this: low-risk edits (word choice, minor phrasing) might pass through an automated check in seconds, while edits that touch specifically flagged risk categories (safety instructions, output schema) require an actual human approval — keeping the gate fast for the common case while still catching the specific risks it exists to prevent.

Check yourself — the answers, and why

Nine steps in, these are the calls you should be able to make cold. Pick one, then read why.

  1. Hardcoding prompts in application code is problematic mainly because…

    Prompts change far more frequently than code and are often edited by people without a deploy workflow.

  2. A/B testing prompts on live traffic is necessary in addition to offline evaluation because…

    The same reasoning as shadow/canary deployment for models — offline metrics alone aren't the whole story.

  3. Guardrail metrics exist to…

    A metric win in isolation can hide an unacceptable side effect that guardrails are specifically designed to catch.

  4. Rollback for prompts is treated as…

    The same version-pointer mechanism as model rollback, exercised far more often given prompts' higher change frequency.

  5. A dedicated review gate for prompt edits exists because…

    The safety net needs to match who's actually editing — often not software engineers with that ingrained review habit.

How you’d open this design in an interview

Before any boxes: agree what it must do, pin the qualities that shape everything, then build — naming each trade-off as you make it. The walkthrough above is that exact order.

What it must do

Agree on these before drawing a single box.

  • Version prompts: externalize prompt text as versioned config so a non-engineer can edit it without a code deploy.
  • Gate before rollout: score each candidate against a fixed offline eval set before it touches real traffic.
  • A/B test live: split real traffic between the current prompt and a candidate, measuring real outcome metrics.
  • Guardrails hold: track cost/latency/safety that must never regress, blocking promotion even when the primary metric wins.
  • Rollback + review: instant version-pointer rollback, and a non-engineer-safe approval gate before an edit ships.

The qualities that shape everything

Each one names the mechanism that buys it.

Iterate without a code deploy
A Prompt Registry: prompts are versioned config the app fetches at runtime, so publishing a new version is a registry write, not a build/deploy cycle.
Nothing unvalidated reaches users
An Offline Eval Gate scores every candidate against a fixed evaluation set and fails closed — no unvalidated candidate advances while it’s unavailable.
Catch effects offline eval misses
A true A/B test on a slice of live traffic, measuring real outcomes (task success, satisfaction, conversion), not just the offline eval score.
A metric win can’t hide a hidden cost
Guardrail metrics — cost, latency, safety/refusal rate — tracked alongside the primary, with promotion blocked if any regresses meaningfully.
Recover from a bad prompt instantly
Immutable versioning makes rollback a repoint of the active-version reference to the previous version — a routine, low-friction operation.
A risky non-engineer edit is caught
A lightweight, prompt-specific Review/Approval gate before eval and rollout, catching removed safety instructions or broken output-format contracts.

The trade-offs you say out loud

Senior signal isn’t the boxes — it’s naming what you gave up and why it was the right price.

Externalized versioned config over prompts hardcoded in application code

Coupling a lightweight text change to a heavyweight build/deploy cycle slows iteration and locks out the PMs and prompt specialists who most directly understand prompt intent.

A Prompt Registry over a shared spreadsheet the app reads

A spreadsheet solves “no deploy” but reintroduces every quality and safety problem — no versioning discipline, no eval gate, no audit trail of who changed what and when.

An offline eval gate that fails closed over shipping a candidate straight to production

Skipping validation just means users are the first to discover a regression — a worse trade than a fast, automated pre-check against a known-good set.

A live A/B test over trusting the offline eval score alone

An eval set is a fixed historical snapshot; live traffic reveals distributional effects it never anticipated — the same reason a model gets shadow/canary rollout, not just an offline score.

Guardrail metrics that must not regress over promoting on the primary metric alone

A variant can improve task success while tripling cost per request or degrading safety — a “win” that’s a net loss, which the headline number in isolation would never reveal.

The answer, out loud

What a strong answer to “Design a Prompt Management & A/B Testing Platform” sounds like, first question to last trade-off. It is about 7 minutes of talking; the whiteboard and the interviewer fill the rest of the 45. Read it aloud once, then close the page and give it yourself.

  1. 0–3 min

    Start from what makes prompts different

    I'd start by naming what is actually being managed here, because it changes the whole design. A prompt is not a model. It gets edited many times a day, often by a PM or a prompt specialist rather than a software engineer, and it is a lightweight piece of text. So the platform has two jobs that pull against each other: make iteration fast enough that people actually use it, and safe enough that a casual edit cannot reach every user unvalidated. Most of what I am about to draw is a decision about where to spend the friction.

  2. 3–8 min

    The baseline, and why it fails

    The simplest version is prompts sitting in application source, and I'd put that on the board first because the problem is easy to see once it is drawn. A two-word wording change now costs a full build, review and deploy cycle, so iteration speed on the fastest-moving artifact in the system is capped by the slowest part of the stack. Worse, editing a prompt means writing and shipping code, which puts the work behind a skill barrier that does not match who has the best judgment about wording. The mismatch between how often the thing changes and how heavy its deployment mechanism is — that is the design flaw.

    Built in step 1: Prompts hardcoded in application code
  3. 8–14 min

    Externalize it into a registry

    So the first move is a Prompt Registry: prompts become versioned config the app fetches at runtime, and publishing is a registry write. The part I'd stress is that each version is immutable and carries an id, because every gate I'm about to add has to attach to something. A review approves a version, an eval scores a version, a rollback points back at one. If the prompt is a field somebody overwrites in place, none of that has anything to hold onto — which is also my answer to “why not a shared doc the app reads.” A doc gives you the edit without the identity.

    Built in step 2: Edit the prompt, not the code
  4. 14–20 min

    Gate it offline, and fail closed

    Now nothing stops a draft going straight to users, so next I'd add an Offline Eval Gate. Every candidate is scored against a fixed evaluation set before it is eligible for real traffic, and the gate fails closed — if it is unavailable, edits still save as drafts, but nothing unvalidated advances. That is deliberately the same principle as evaluating a candidate model before promotion. I am just applying it to an artifact that moves far faster. It is cheap, and it catches the obvious damage early: a broken output format, a drop on cases where we already know the right answer.

    Built in step 3: Score it before anyone sees it
  5. 20–26 min

    Offline passing is not shipping

    Passing the eval set is not the same as being better, though, and I'd be explicit about why. The set is a fixed historical snapshot. Real traffic carries phrasing and edge cases it never captured. So a candidate that passes earns an A/B test, not a rollout: the A/B Traffic Split engine runs it against the current production prompt on a slice of live traffic, and we measure real outcomes — task success, user satisfaction, downstream conversion — rather than the eval score again. Re-running the same offline set more times would add nothing, because the data has not changed.

    Built in step 4: Offline eval alone can still miss real effects
  6. 26–32 min

    Guardrails, not just the headline

    Then the variant wins on task success, and this is where I'd push back on my own design. The output is one artifact, so a prompt that moves one property almost always moves others. Tell the model to be more careful and it writes longer, which costs more. Tell it to be terser and it starts declining things it used to answer. Neither shows up in the headline number. So I'd track cost, latency and safety beside the primary metric, and make promotion need two conditions instead of one. Naming them before the test matters, because afterwards everyone can find a reason the other line does not count.

    Built in step 5: A "win" on one metric can be a loss overall
  7. 32–37 min

    Make going back boring

    Two more pieces. Rollback: every version is immutable, so reverting is repointing the active reference at the previous one, the same mechanism as a model registry but exercised far more often. I'd treat it as a daily tool rather than an emergency procedure, because fast iteration is only safe when going back is boring. Then a review step before eval, scoped to prompt-specific risks: a removed safety instruction, a changed output format something downstream parses. That gate exists because those failures are invisible to the person making the edit. Delete a line from the safety block and the prompt still works on everything the editor would think to try.

    Built in step 6: Not an emergency procedure — a daily tool
  8. 37–41 min

    Two sharp edges

    Two things I'd make explicit. The eval gate carries its own injection-resistance suite, scored separately, because functional quality and adversarial robustness are different properties and only one of them is what a task-success set measures — a wording change can leave every case passing and still make the model easier to talk out of its instructions. And drafts and losing variants pile up over months, so the registry has to answer “what is serving this use case right now” as one unambiguous lookup, not something you reconstruct from experiment history.

    Built in step 8: Injection regressions and prompt sprawl
  9. 41–45 min

    The trade-off, and what comes next

    The trade-off running through all of it is friction against safety. Every gate buys confidence and spends iteration speed, the thing externalizing prompts was meant to give back, so I'd keep the common path cheap and spend friction only where the risk is. With more time, two directions. Nothing here says who holds the pen: who may edit which use case, and who may approve, which matters more than it would in a code repo because the editors sit outside engineering. And I have treated a use case as one prompt, when it is usually several calling each other. Once that is true, the unit you version and put in an A/B arm is the set, not a single text.

What this teaches

Learn AI system design by building the platform that versions, evaluates, and safely A/B tests PROMPTS in a production LLM application — a much faster-moving artifact than model weights, often edited by non-engineers. An interactive guide covering why hardcoded prompts force a full deploy for every tweak, externalizing prompts as versioned config, an offline eval gate before rollout, live A/B testing because offline eval alone can miss real distributional effects, guardrail metrics that must not regress even when the primary metric improves, routine one-click rollback, and a review gate that keeps prompt edits from non-engineers safe.

Key takeaways

  • Hardcoded prompts couple a lightweight text change to a heavyweight deploy cycle — externalizing them as versioned config decouples iteration speed from code deployment.
  • An offline Eval Gate, failing closed, validates every candidate against a fixed set before it's eligible for real traffic.
  • Live A/B testing catches real-world effects an offline evaluation set — a fixed historical snapshot — structurally can't reveal.
  • Guardrail metrics (cost, latency, safety) must never regress, even when a variant wins on the primary metric being optimized.
  • Rollback is a routine, instant version-pointer change, exercised far more often than for models given how frequently prompts iterate.
  • A dedicated, non-engineer-friendly review gate catches prompt-specific risks (like an accidentally-removed safety instruction) before rollout.
  • Security/injection-resistance needs its own explicit eval, separate from task-success metrics, since the two can diverge.

Concepts covered

  • Prompts change fast — the platform has to keep up
  • Prompts hardcoded in application code
  • Edit the prompt, not the code
  • Score it before anyone sees it
  • Offline eval alone can still miss real effects
  • A "win" on one metric can be a loss overall
  • Not an emergency procedure — a daily tool
  • Safe editing without requiring a code-review habit
  • Injection regressions and prompt sprawl
RUN IT YOURSELF

The 5% that is really 32% because somebody kept refreshing

4,000 A/B tests in which both arms serve the identical prompt, running for real in your browser — so every "significant" result is a false win, and the only variable is when the number was read. Read once at the planned horizon it fires 5.0% of the time, exactly as promised; checked every 25 users it fires 31.8% of the time on the same data. Change BLOCK to 10, hit Run, and watch the peeking row climb while the corrected row does not.

HOW TO READ THE CODE — 5 IDEAS
  1. The read once at 1000 row printing 5.0% is the calibration — the alpha we asked for, recovered from the same paths every other row reads, to within its own Monte Carlo error. The line under the table is the other half of that audit: one look at n=25 is exactly 6.0%, not 5.0%, because the normal approximation is anti-conservative on a coarse lattice.
  2. Every row reads the same 4,000 simulated experiments. Nothing differs but the stopping rule, and the false-win rate goes 5.0 → 8.4 → 13.1 → 19.4 → 31.8% purely on how often someone looked. Net that 6.0% lattice effect out and 30.3% is left, so the stopping rule owns ~30 of the 32 points, not the toy.
  3. This is step 4's "a test with no pre-committed stopping rule gets stopped when the number looks good, which manufactures wins reliably" — with the number attached. A guardrail watched the same way (step 5) raises false alarms on the same curve.
  4. The fix is a different threshold, not a rule nobody follows: an always-valid bound (|z| > 5.01 at n=25, 3.05 at n=1000) looks all 40 times and still fires on only 1.6% of nothing. It is derived from BASE and MDE — the two numbers step 4 already says to commit before the test starts.
  5. Correctness is not free, and the last block prices it: against a real +8pp lift the bound detects 82.2% where the fixed test gets 96.5% — but let it run and it hits 100% with a median stop of 575 users/arm, 43% less traffic than the fixed horizon spends every single time.
CPython · WebAssembly
built so a prompt tweak that quietly triples cost gets caught before it ships to everyone — make the calls, blow up a guardrail, run the gauntlet.
Finished this one? 0 / 65 AI System Designs done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More AI System Designs