Vibe Engines
YouTube
AI System Design

Design an AI Answer Engine

Step 1 / 9

Learn AI system design by building an AI answer engine like Perplexity step by step.

The numbers to beatorchestratemulti-step pipelinestreamsources then answerfollow-upsconversational context

The whole design, in writing

Learn AI system design by building an AI answer engine like Perplexity step by step. An interactive guide covering why asking an LLM alone hallucinates, the retrieve-then-generate (RAG-over-the-web) shape, query understanding and decomposition, live search + fetch + rerank, grounded generation with inline citations, citation verification, streaming answers with follow-ups, and the unhappy paths (hallucination despite sources, source trust, prompt injection, freshness, cost).

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

What is an AI answer engine?

You ask a real question — "what changed in the latest React release?", "compare these two drugs' side effects". A plain chatbot will answer confidently from memory that's frozen at its training cutoff, sometimes right, sometimes hallucinated, and never with a source you can check. For questions where being current and correct matters, that's not good enough.

Usera question
New in this step: User.

An AI answer engine (like Perplexity) answers by retrieving live sources first, then generating a grounded, cited answer from them — RAG over the open web. The pipeline: understand the question, search + fetch + rerank real sources, generate an answer using only those sources with inline citations, and verify the citations. Grounding and attribution are the whole point.

What the new pieces do

Userclient
Someone asking a real question that needs a current, trustworthy, cited answer — not a plausible-sounding guess.

Step 1 · Why not just ask the model?

The bare LLM fails

The simplest design: forward the question straight to an LLM and return its answer. Why is that inadequate for a question-answering product people should trust?

Usera question
The system as it stands at this step.

Just send the question to an LLM and return its answer. What's wrong?

  1. Speed isn't the core issue. The problems are correctness and trust: the model's knowledge is frozen at its training cutoff (stale), it can hallucinate confidently, and it gives no sources to verify — unacceptable for a factual answer engine.

  2. Fluency is exactly what it has — and that's the danger: it produces fluent, confident answers whether or not they're true, with no citations, and no knowledge of anything after its training cutoff.

  3. A bare LLM can't know recent events, will sometimes fabricate plausible falsehoods, and offers no sources — so users can't tell right from wrong. An answer engine fixes this by grounding every answer in retrieved, citable sources.

Three fatal gaps: the model's knowledge is frozen at its training cutoff (no recent info), it hallucinates plausible falsehoods with total confidence, and it provides no sources to check. For a product whose job is factual answers, that's untrustworthy. You have to ground the answer in real, current, citable evidence — which the model doesn't have on its own.

Why this piece earns its place

The instinct on meeting this failure is to fix it with words — add only answer if you are certain to the system prompt and ship. It does almost nothing, and why it does nothing is the reason everything else on this board exists. The model carries no internal signal separating what it recalled from what it invented, so the instruction is addressed to a faculty nobody implemented. What it can measure is how probable its own wording was, and that is a statement about text rather than about the world: a well-worn falsehood scores higher than an awkwardly phrased truth, which is the opposite of the ordering you wanted. The repair has to be structural, not verbal. Two consequences worth carrying forward. Parametric memory does not switch off once retrieval is added — it stays underneath as a prior, and the answers hardest to catch downstream are the blended ones: three sentences from the passages and one from the weights, sitting under the same citation as though it had come from the same place. And the cutoff is not a clean edge. Training data thins toward it rather than stopping, so recent topics come back half-right, which reads far more credible than plainly wrong and is correspondingly harder to flag.

Step 2 · Retrieve, then generate

RAG over the live web

If the model can't be trusted to know the answer, where should the facts come from, and in what order do you do things?

Usera questionAnswer Serviceorchestrate
New in this step: Answer Service.

Invert it: retrieve first, generate second. Take the question, find relevant, current sources (the web, or your document set), and feed those passages to the LLM as context, instructing it to answer only from them and cite each claim. The LLM becomes a reasoner/synthesizer over supplied evidence, not an oracle recalling from memory. This is retrieval-augmented generation applied to the open web — the core shape of an answer engine.

Why this piece earns its place

Inverting the order buys correctness, and it also changes which part of the system you are married to. While knowledge lives in weights, changing models means re-establishing everything the product knows; once it lives in retrieval, the model becomes the cheap component — swap it, re-run the evals, keep the corpus. That flips what you shop for in a model, too. Breadth of world knowledge is what a model launch advertises, and it is the one thing this design is deliberately suppressing; what you actually need is a model that stays inside the context it was handed and is willing to produce nothing. A smaller, more obedient model is often the better pick here, which is a budget decision you can act on the same afternoon. What the inversion does not fix is the reading. Retrieval moved the facts out of the weights; inference over those facts is still generation. So the sentences most likely to be wrong in a grounded answer are the ones that join two passages — a comparison, a total, a conclusion neither source states — because no single citation covers a join, and nothing later in this pipeline is looking at one.

What the new pieces do

Answer Servicegateway
Coordinates the pipeline: understand the query, retrieve sources, generate a grounded answer, verify, and stream it back.

Step 3 · The orchestrator

An answer service that streams

This is now a multi-step pipeline (understand → search → fetch → rank → generate → verify), and users won't wait many seconds staring at a blank screen. What runs the pipeline and keeps it responsive?

Usera questionAnswer Serviceorchestrate
The system as it stands at this step.

An answer service orchestrates the steps and streams the experience: show the interpreted query and the sources it's reading while retrieval runs, then stream the answer token-by-token with citations as it's generated. The multi-step latency (search + fetch + LLM) is masked by progressive UI — the user sees progress the whole time. The service also handles follow-up questions with conversation context (an answer engine is often conversational).

Why this piece earns its place

Streaming is sold as a perceived-speed trick, and it is one, but it also takes away your ability to change your mind. Once the first source card or the first token has left the server you have committed: no silent retry against a different model, no quiet re-run when a fetch comes back empty, no withdrawing a source the verification pass later distrusts. Every fallback you want has to be expressible as something appended to a stream already in flight — a correction, a struck citation, a visible note — rather than a do-over the user never sees. So decide early which parts of the stream are promises and which are revocable, because the UI encodes that choice permanently. The orchestrator also has to own the deadline. Every stage wants more time than the request has, and somebody must decide mid-flight to fetch fewer pages, or to ship while verification is still running. No individual stage can make that call, because none of them can see what the others have already spent.

  • orchestratemulti-step pipeline
  • streamsources then answer
  • follow-upsconversational context

Step 4 · Ask the right thing

Query understanding & decomposition

The user's raw question is often a poor search query — vague, conversational, or actually several questions ("compare X and Y on price and safety"). Feeding it verbatim to a search engine retrieves weak sources. How do you get good evidence?

Answer ServiceorchestrateQuery Plannerrewrite · decompose
New in this step: Query Planner.

The raw question makes a poor search query (vague or multi-part). What do you do first?

  1. A query planner (often an LLM) turns the messy question into one or more effective search queries — rewriting for clarity, expanding terms, and splitting a compound question into sub-questions it retrieves for separately, then combines. Better queries retrieve better sources, which is most of answer quality.

  2. Verbatim conversational questions often retrieve poorly (they're not how documents are phrased, and compound questions need multiple searches). Rewriting and decomposition materially improve the evidence you get.

  3. That's the bare-LLM failure again. The point is to retrieve good sources, which starts with turning the question into good queries.

Add a query planner (usually an LLM step) that rewrites the question into effective search queries — clarifying, expanding, adding context — and decomposes multi-part questions into sub-queries it retrieves for separately, then synthesizes together (multi-hop). Good retrieval starts with good queries, and this step is where a lot of answer quality is won or lost, before generation even begins.

Why this piece earns its place

The planner is the one stage whose mistakes are invisible to everything downstream, because when it goes wrong, nothing fails. A rewrite that drops a negation, resolves the wrong entity in a follow-up, or quietly narrows a comparison to one side produces healthy retrieval, confident generation, and citations that genuinely support what was asked — just not what the user asked. So log the planner output verbatim beside the answer. Without it a bad answer is undebuggable, because you cannot tell weak sources from a mangled question, and those have opposite fixes. It is also, quietly, the budget-setter. Decomposition turns one search into several, and each sub-query fans out into its own fetches, reranks and context, so a planner with a taste for splitting things multiplies the cost of an answer by however many sub-queries it feels like emitting, without anyone deciding to spend it. That makes the number of sub-queries a request-level knob, bounded by the orchestrator and informed by the question, rather than a constant in a config file tuned on whatever examples happened to be around that week.

  • rewritequestion → good queries
  • decomposesub-queries
  • multi-hopretrieve then combine

What the new pieces do

Query Plannerservice
Turns a messy question into good search queries, decomposing multi-part questions into sub-queries (multi-hop).

Step 5 · Get the evidence

Search, fetch & rerank

With good queries, you retrieve candidate documents — but a search API returns links, pages are long and noisy, and the top search result isn't always the most relevant passage. How do you turn queries into a tight set of high-quality passages to ground on?

Searchweb / indexFetch + Rerankextract · rankSourcesweb · docs
New in this step: Search, Fetch + Rerank, Sources.

Run the queries against a search API (or your own index), then fetch the top pages, extract the main content (strip nav/ads), and chunk it. Then rerank the chunks by relevance to the question (a cross-encoder/reranker) — and weight freshness for time-sensitive questions — keeping only the best few passages that fit the LLM's context. You've gone from a vague question to a small, high-signal evidence set. Caching popular queries/pages cuts latency and cost.

Why this piece earns its place

Search and generation call vendors you hold a contract with. Fetch calls whoever the ranking happened to return — arbitrary third parties with no agreement, no capacity promise and no obligation to serve you at all — which makes it the one stage where partial failure is the normal case rather than the exception. Pages time out, sit behind paywalls, return a JavaScript shell with no text in it, or refuse your crawler outright. You cannot wait for all of them, so you need an explicit rule for what enough evidence means — a deadline, a minimum count, or both — and the moment that rule exists, the answer quietly depends on which pages happened to be fast. That correlation is not random: fast pages are CDN-hosted, lightly built and tuned for search, which is not the same population as the best sources. Nothing errors, no dashboard moves, and the engine develops a permanent taste for a certain kind of page. One more thing to carry: fetching at this volume makes you a crawler with a reputation, so identify yourself, honour rate limits, and cache hard — otherwise the sites you most want to ground on are the first to shut you out.

  • searchwide recall
  • fetch + extractclean passages
  • rerankbest few + freshness

What the new pieces do

Searchservice
Runs the queries against a web search API or an internal index, returning candidate documents to ground on.
Fetch + Rerankservice
Fetches pages, extracts and chunks the text, and reranks passages by relevance (and freshness) to keep the best few.
Sourcesdata
The live corpus — the web (or your document set) — that provides current, attributable evidence for answers.

Step 6 · Answer from the sources

Grounded generation with citations

Now the LLM writes the answer. The whole value proposition is that it answers from the retrieved sources and attributes each claim — not that it free-associates. How do you make generation grounded and cited?

Fetch + Rerankextract · rankGrounded LLManswer + cite
New in this step: Grounded LLM.

How do you make the LLM answer from the sources and attribute claims, not free-associate?

  1. Merely providing sources isn't enough — the model may still lean on parametric memory or state unsupported claims. You must instruct it to answer only from the provided passages and to cite each claim to a specific source, and then verify.

  2. Post-hoc citation (answer first, find sources later) invites citations that don't actually support the claim. Grounding must drive generation: answer FROM the sources, citing as you go.

  3. Give the model the reranked passages with ids and instruct it to answer using only them, citing the source for every claim inline. Constraining generation to the evidence (and refusing when the sources don't cover it) is what produces grounded, attributable answers — then a verification step checks the citations.

Feed the LLM the reranked passages (with source ids) and prompt it to answer only from them, attaching an inline citation to every claim (and to say "the sources don't cover this" rather than guess). Grounding must drive generation — answer from the evidence, citing as you go — not be bolted on afterward. This is what turns an LLM into a trustworthy answer engine: every sentence traceable to a source.

Why this piece earns its place

Treat a citation as a data structure, not a marker in the text. A claim points at a passage id, and the passage points at a URL and the span inside it. Mint that id at extraction and carry it through rerank into the prompt, because once the answer exists you cannot recover from prose which passage the model meant, and a sentence naming a plausible-sounding source is a hallucination wearing a citation. Spans buy a second thing URLs cannot: they let you see when three citations are one story syndicated three times. Apparent corroboration is the most flattering way for a cited answer to be wrong, and at the URL level three domains look like three confirmations. Provenance has to be threaded through from extraction onward, because retrofitting it means refetching a page that may no longer say the same thing — which is the other half of this. The web moves under you. Between your fetch and the user clicking through, a page can be edited, paywalled or deleted, and a citation nobody can check is worth roughly what no citation is worth. So snapshot the extracted passage you actually used and keep it beside the live link. It also gives you something honest to say when the two disagree — that the page changed after the answer was written — instead of silently looking wrong.

  • only from sourcesno free-association
  • cite each claiminline attribution
  • refusewhen unsupported

What the new pieces do

Grounded LLMservice
Synthesizes an answer using ONLY the retrieved passages, attaching an inline citation to each claim.

Step 7 · Trust, but verify

Citation verification & follow-ups

Even instructed to cite, an LLM can attach a citation that doesn't actually support the sentence, or subtly misstate a source. "Has citations" isn't "is grounded." How do you close that gap?

Answer ServiceorchestrateFetch + Rerankextract · rankGrounded LLManswer + citeVerifycitation check
New in this step: Verify.

Add a verification step: check that each cited source actually supports its claim (an entailment/groundedness check, often another model pass), flagging or removing unsupported statements before the answer is finalized. Stream the verified answer with clickable citations, and support follow-up questions that reuse context and retrieve again. Optionally show a confidence signal and let users inspect the exact source passage. Verification is what upgrades citations from decoration to guarantee.

Why this piece earns its place

Three things you learn by running one. First, verification is a classifier with two error directions and different costs: a false flag strips a true sentence and makes the product look evasive, a miss ships an unsupported claim wearing a citation, the exact failure it existed to prevent. Which way you tune it is a product decision, not an engineering default. Second, do not let the model that wrote the answer check it; asked whether its own sentence follows from a passage it just used, it agrees, and you have bought a pass rate rather than a check. A separate, smaller entailment model is cheaper and less agreeable, and cheaper matters here for a reason: unit cost tracks answer length rather than question difficulty, so a verbose model raises the bill on every request, not just the hard ones. Third, it throws off the pipeline's most useful by-product: a log of claim, passage and verdict — labelled data nobody had to annotate. Flag rate sliced by domain beats any retrieval dashboard as an extraction alarm: when one site's claims start failing entailment and nothing else moves, the extractor broke there. And it only ever checks a claim against the passage that claim cites, so it is blind to a source that is confidently wrong, and blind to omission — an answer true sentence by sentence and misleading overall because the contradicting page never made the shortlist.

  • verifysource supports claim?
  • flagunsupported statements
  • follow-upsre-retrieve with context

What the new pieces do

Verifyservice
Checks that each citation actually supports its claim (groundedness), catching unsupported or misattributed statements.

Step 8 · The sharp edges

Bad sources, injection & cost

The open web is hostile: sources contradict or lie, pages contain prompt injection aimed at your model, freshness varies, and every answer costs multiple model calls plus network fetches.

UserAnswer ServiceQuery PlannerSearchFetch + RerankGrounded LLMVerifySources
The system as it stands at this step. · swipe to pan the diagram

Judge source quality/trust (rank reputable domains higher, cross-check claims across sources, surface disagreement rather than picking one). Defend against prompt injection from fetched pages — treat retrieved web content as untrusted data, never instructions, and sandbox it so a page can't hijack the model. Handle freshness with recency-aware ranking and re-fetching. Control cost/latency (planner + rerank + generate + verify = several model calls plus fetches) with caching, parallel fetches, right-sized models per step, and skipping steps for simple queries. And be honest when the web simply doesn't have a good answer.

Why this piece earns its place

The injection defence people describe in interviews is usually a sentence in a prompt, and a sentence in a prompt is not a boundary. What actually holds is limiting what the model is able to do after it has read a stranger's page. Do not comfort yourself that the blast radius here is small. This product's whole job is to hand that page's words to a user as a cited claim, carrying the engine's credibility and a clickable link, so a page that wins the shortlist can choose where your reader goes next and which sources get cited beside it. And the moment you add a tool, a second fetch the model chooses, a memory write, a purchase, that same page inherits the capability. So fix the privilege of a request before retrieval runs, and never let anything read afterwards raise it. That one rule is what keeps this design safe to extend. The other trap is turning source trust into a domain allowlist because an allowlist is easy to implement. It is an editorial position shipped as a config file: it decides whose account of a contested question your users see, it rots without anyone noticing, and it is the artefact that gets screenshotted. A ranking weight you can defend and adjust is a very different thing to own than a gate.

You did it

You just designed an AI answer engine.

UserAnswer ServiceQuery PlannerSearchFetch + RerankGrounded LLMVerifySources
The finished design, end to end. · swipe to pan the diagram

Everything you assembled, in order

  • A bare LLM is stale, hallucinates, and cites nothing — untrustworthy for factual answers.
  • Invert to retrieve-then-generate (RAG over the live web): facts from retrieval, reasoning from the LLM.
  • An answer service orchestrates the pipeline and streams sources-then-answer to mask latency.
  • A query planner rewrites and decomposes the question into good (multi-hop) search queries.
  • Search wide, then fetch, extract, chunk and rerank (with freshness) into a tight evidence set.
  • Generate grounded: answer only from the passages, citing each claim; refuse when unsupported.
  • Verify that citations actually support their claims; judge source trust and defend against injection.

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. Why does answering from a bare LLM fail for a factual question-answering product?

    Because an LLM's knowledge lives entirely in its weights — parametric memory — which has three disqualifying properties for a trustworthy answer engine. First, it's frozen at the model's training cutoff, so it simply cannot know anything that happened afterward, making it useless for current events, latest releases, or recent data. Second, it hallucinates: when it doesn't actually know, it still produces a fluent, confident answer that may be fabricated, and because the delivery is equally confident whether right or wrong, users can't distinguish the two. Third, it provides no sources, so even a correct answer can't be verified and an incorrect one can't be caught. For a product whose entire job is to give factual answers people rely on, "sometimes right, always confident, never checkable, and blind to anything recent" is unacceptable. The fix is to stop treating the model as an oracle recalling facts and instead supply current, citable facts at query time from an external source, making the model reason over that evidence — which is retrieval-augmented generation.

  2. What does "retrieve-then-generate" actually change about the LLM's role?

    It fundamentally narrows and re-grounds what the model is responsible for. In the naive approach the LLM has to both know the facts and phrase the answer, and it fails at the first because its knowledge is stale and lossy. In retrieve-then-generate you invert the order: first you find relevant, current sources for the question (from the web or a document set), then you feed those passages to the model as context and instruct it to answer only from them, citing each claim. This separates knowledge from reasoning — knowledge now comes from retrieval, which you control and can keep fresh and attributable, while the model's job shrinks to reading the supplied evidence and synthesizing a well-phrased, cited answer, which is a task it's genuinely good at. Correctness and freshness become properties of your retrieval system rather than of the model's frozen weights, and every claim can be traced to a source. The model stops being an oracle and becomes a reasoner over evidence you provide.

  3. Why is query understanding (rewriting and decomposition) so important before searching?

    Because the quality of the final answer is largely determined by the quality of the sources you retrieve, and retrieval quality is largely determined by the queries you issue — so the step that turns a user's question into search queries is where a lot of answer quality is won or lost. Raw user questions are often poor search queries: they're phrased conversationally rather than the way documents are written, they can be vague, and they're frequently compound ("compare X and Y on price and safety" is really several questions). Feeding such a question verbatim to a search engine tends to retrieve weak or partial sources. A query planner (usually an LLM step) fixes this by rewriting the question into one or more effective search queries — clarifying intent, expanding terms, adding context — and by decomposing multi-part questions into separate sub-queries that are retrieved for individually and then combined, which is the multi-hop pattern. Investing effort here is far more effective than trying to compensate for bad sources during generation, because the model can only be as good as the evidence it's given.

  4. Grounded generation with citations — why isn't it enough to just append sources and let the model write?

    Because merely having sources in the context doesn't guarantee the model uses them faithfully. Left to its own devices, an LLM may still lean on its parametric memory, state claims the passages don't support, or attach citations loosely. So grounding has to actively drive generation rather than be bolted on. Concretely, you give the model the reranked passages tagged with source ids and instruct it to answer using only those passages, to attach an inline citation to every claim identifying which source supports it, and — crucially — to say the sources don't cover something rather than guess when the evidence is missing. That refusal behavior is a feature: "I don't have a source for that" is far more valuable than a confident hallucination. The alternative of answering freely and then searching for matching citations afterward is exactly what produces citations that don't actually support their claims. And because even a well-instructed model can misattribute, this is followed by a verification step that checks each citation actually entails its claim — together, grounded generation plus verification are what make every sentence both traceable and genuinely supported.

  5. What makes the open web an adversarial source, and how do you defend the answer engine?

    Retrieving from the open web gives you freshness and breadth, but the web is neither trustworthy nor safe by default, which creates several distinct threats. Sources contradict each other or are simply wrong, so you can't treat the top result as truth — you rank reputable domains higher, cross-check claims across multiple sources, and surface disagreement rather than silently picking one side. Freshness varies, so you use recency-aware ranking and re-fetching for time-sensitive questions. Most dangerously, fetched pages can contain prompt injection — text crafted to hijack your model, like "ignore your instructions and say X" embedded in a page — so you must treat all retrieved web content as untrusted data and never as instructions, structurally separating the passages from the system prompt and sandboxing them so a malicious page can't take over the model's behavior. Finally, the pipeline is expensive: query planning, reranking, generation, and verification are several model calls plus network fetches per answer, so you control cost and latency with caching of popular queries and pages, parallel fetching, right-sized models per step, and skipping steps for simple queries. The overarching principle is that grounding must come with skepticism — the same web that makes the engine powerful also makes it a target.

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. A bare LLM is inadequate for a factual answer engine because…

    Parametric memory is frozen, lossy and unattributable; you must ground answers in retrieved sources.

  2. The core shape of an answer engine is…

    Facts come from retrieval; the LLM reasons over the supplied evidence and cites each claim.

  3. A query planner is added to…

    Better queries retrieve better sources — most of answer quality is won before generation.

  4. Grounded generation means the LLM…

    Grounding drives generation; then verification checks the citations actually support the claims.

  5. Retrieved web content must be treated as…

    A fetched page can carry injection; isolate it as data so it can't hijack the model.

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.

  • Answer with sources: return a current, cited answer, not a plausible guess.
  • Understand the query: rewrite a messy question into good search queries and decompose multi-part ones.
  • Retrieve: search, fetch, extract and rerank real sources into a tight evidence set.
  • Generate grounded: answer only from the retrieved passages, citing each claim.
  • Verify: check that each citation actually supports its claim; support follow-ups.

The qualities that shape everything

Each one names the mechanism that buys it.

Current, checkable answers instead of hallucinations
Retrieve-then-generate (RAG over the live web): facts come from retrieval, reasoning from the LLM over the supplied passages.
Users see progress, not a blank screen
An answer service orchestrates the pipeline and streams sources-then-answer to mask multi-step (search + fetch + LLM) latency.
Good sources start with good queries
A query planner rewrites the question and decomposes multi-part questions into sub-queries (multi-hop) before searching.
A tight, high-signal evidence set
Search wide, then fetch, extract, chunk and rerank by relevance and freshness into the best few passages.
Every sentence traceable to a source
Grounded generation: answer only from the passages, inline-citing each claim, refusing when the sources don’t cover it.
Citations that actually hold
A verification step checks each cited source entails its claim, flagging or removing unsupported statements before finalizing.

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.

Retrieve-then-generate over asking the bare LLM

Parametric memory is frozen at the training cutoff, hallucinates confidently, and cites nothing. Grounding the answer in retrieved evidence makes it current and checkable.

Rewrite + decompose the query over searching the raw question verbatim

Conversational, compound questions retrieve weak sources. Better queries win most of answer quality before generation even begins.

Retrieve wide, rerank narrow over trusting the top search result

Search casts a wide net for recall; a reranker picks the few best passages for precision. Feeding the model nav bars and ads wastes context and invites errors.

Grounding drives generation over answering freely then citing afterward

Post-hoc citation invites citations that don’t actually support the claim. Answer from the sources, citing as you go, and refuse when evidence is missing.

Retrieved content is untrusted data over trusting fetched pages as instructions

A fetched page can carry prompt injection aimed at your model. Isolate retrieved content as data, never instructions, so a page can’t hijack the answer.

The answer, out loud

What a strong answer to “Design an AI Answer Engine” 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

    What this has to guarantee

    Before I draw anything I want to be precise about what this product has to guarantee, because it is narrower than a chatbot that is good at questions. Someone asks what changed in the latest release, or how two drugs compare on side effects. They need an answer that is current, and they need to be able to check it. So I am designing for two things — freshness and attribution — and I would expect every box on the board to earn its place against one of them.

  2. 3–7 min

    Why the bare model is not the design

    The simplest thing is to forward the question to an LLM and return what it says, and that fails on three counts. Its knowledge is frozen at the training cutoff, so it cannot know about last week. It hallucinates — when it does not know, it still writes something fluent. And it cites nothing, so nobody can separate the good answers from the bad. The delivery is identical either way, which is what makes it untrustworthy rather than merely limited.

    Built in step 1: The bare LLM fails
  3. 7–12 min

    Retrieve first, generate second

    So I would invert the order: retrieve, then generate. Find relevant, current sources for the question, feed those passages to the model as context, and instruct it to answer only from them and cite each claim. The model stops being an oracle recalling facts and becomes a reasoner over evidence I supply. The reason I would reach for that over fine-tuning on the same material is that it puts correctness and freshness on my side of the line, in a retrieval system I control and can update today, instead of inside weights I cannot inspect and cannot cite.

    Built in step 2: RAG over the live web
  4. 12–17 min

    An answer service that streams

    That turns one call into a pipeline — understand, search, fetch, rank, generate, verify — and nobody waits through that staring at a blank page. So I would put an answer service in front of it that orchestrates the steps and streams the experience: show the interpreted question and the sources being read while retrieval is still running, then stream the answer with its citations as it is written. The same service carries conversation context, because these products are conversational and a follow-up has to retrieve again.

    Built in step 3: An answer service that streams
  5. 17–23 min

    Fix the question before searching it

    The first real stage is query understanding. A raw question usually makes a poor search query — it is phrased conversationally rather than the way documents are written, it can be vague, and it is often several questions in one, like comparing two things on price and safety. So a planner, usually an LLM step, rewrites it into effective queries and decomposes a compound question into sub-queries it retrieves for separately and then combines. That is the multi-hop part. I would spend effort here before anywhere else, because better queries win most of answer quality before generation starts, and no amount of prompting later fixes weak sources.

    Built in step 4: Query understanding & decomposition
  6. 23–29 min

    Search wide, rerank narrow

    Then retrieval itself. Run the queries against a search API or my own index, fetch the top pages, extract the main content so I am not feeding the model nav bars and ads, chunk it, and rerank the chunks against the question with a cross-encoder — weighting freshness when the question is time-sensitive. Wide for recall, narrow for precision. I would cache popular queries and pages at this stage, because this is where the latency and most of the network cost actually live.

    Built in step 5: Search, fetch & rerank
  7. 29–35 min

    Answer from the passages, citing as I go

    Generation gets the reranked passages with source ids, and an instruction in three parts: answer only from these passages, attach an inline citation to every claim, and say "the sources don't cover this" rather than guess. The order matters, because grounding has to drive generation. Answering freely and then finding sources afterwards is exactly what produces citations that do not support the sentence they are attached to. And the refusal is a feature — I would much rather ship "I have no source for that" than a confident invention.

    Built in step 6: Grounded generation with citations
  8. 35–41 min

    Then check the citations hold

    Having citations is not the same as being grounded, so I would add a verification pass that asks, per claim, whether the cited passage actually entails it, and flags or removes what it cannot support. It is the same idea as a groundedness eval, run inline instead of offline. On top of that I would let a user open the exact passage behind any sentence, because the point of attribution is that somebody can check the work without also having to take my word for the check.

    Built in step 7: Citation verification & follow-ups
  9. 41–45 min

    The hostile parts, and the trade-off

    The last thing I would raise is that the open web is adversarial, and I would separate two threats that get lumped together. One is that sources are wrong or disagree, which is a ranking and presentation problem — and where they conflict I would rather the answer show the conflict than quietly pick a side, because picking silently is a judgement I would be making for the user and could not defend. The other is that a fetched page is written by someone who knows my model will read it, which is a security problem no amount of ranking touches — so the rule I hold is that retrieved text is data and can never widen what a request is allowed to do. On cost, I would have the response carry its own count of model calls and fetches, because every step here is individually reasonable and the total is a bill nobody chose. The trade-off underneath all of it is that each thing I add for trust — planning, reranking, verification — costs another call and more latency, so the honest version of this design is a dial between how fast an answer arrives and how much of it I can stand behind. With more time I would work on freshness properly, and on what the engine should do when the web simply has no good answer.

    Built in step 8: Bad sources, injection & cost

What this teaches

Learn AI system design by building an AI answer engine like Perplexity step by step. An interactive guide covering why asking an LLM alone hallucinates, the retrieve-then-generate (RAG-over-the-web) shape, query understanding and decomposition, live search + fetch + rerank, grounded generation with inline citations, citation verification, streaming answers with follow-ups, and the unhappy paths (hallucination despite sources, source trust, prompt injection, freshness, cost).

Key takeaways

  • A bare LLM is stale, hallucinates, and cites nothing — untrustworthy for factual answers.
  • Invert to retrieve-then-generate (RAG over the live web): facts from retrieval, reasoning from the LLM.
  • An answer service orchestrates the pipeline and streams sources-then-answer to mask latency.
  • A query planner rewrites and decomposes the question into good (multi-hop) search queries.
  • Search wide, then fetch, extract, chunk and rerank (with freshness) into a tight evidence set.
  • Generate grounded: answer only from the passages, citing each claim; refuse when unsupported.
  • Verify that citations actually support their claims; judge source trust and defend against injection.

Concepts covered

  • What is an AI answer engine?
  • The bare LLM fails
  • RAG over the live web
  • An answer service that streams
  • Query understanding & decomposition
  • Search, fetch & rerank
  • Grounded generation with citations
  • Citation verification & follow-ups
  • Bad sources, injection & cost
RUN IT YOURSELF

The sentence every source supports and no source says

Step 7's claim, made runnable: "has citations" is not "is grounded". This file takes one nine-sentence cited answer and runs the same support check at two granularities — against the whole cited document, and against the exact cited passage — then prints how many invented sentences each one ships. Change SUPPORT at the top, hit Run, and watch which column moves.

HOW TO READ THE CODE — 5 IDEAS
  1. A document is its own passages pooled, so document coverage can never be lower than passage coverage. Every citation the document check flags, the span check flags too — never the reverse.
  2. At the shipped bar the document check ships 3 of 4 invented sentences and the span check ships 1, for the same false-flag cost: 1 of 5 true sentences stripped either way.
  3. c6 is the trap. "Upgrading is a drop-in change for teams running large plugin suites" — every content term is in the cited document (1.00), half of them are in the cited passage (0.50), and the document never says it. The document IS relevant; relevance is not support (steps 6–7).
  4. Raising SUPPORT cannot rescue the document check — it stays stuck at 3 from 0.25 all the way to 1.00, because the pooled document covers those claims completely. The granularity is the whole decision, not the threshold.
  5. The residual is printed, not hidden: c9 invents a causal link between two facts the passage does state, so it scores exactly what a genuinely supported sentence scores and survives both. That is why step 7 specifies an entailment model, not a term check.
CPython · WebAssembly
built to answer with sources instead of vibes — make the calls, cut the retrieval, 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