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 Deep Research Agent

Step 1 / 9

Learn AI system design by building a deep research agent step by step.

The numbers to beat1 laneper sub-researcherclean windowper lanefindings upnever transcripts

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

Search answers queries. Research answers questions.

"What's the capital of France?" is a search. "Which vector database should we bet on, and why?" is research: it decomposes into dozens of sub-questions, needs sources that disagree to be reconciled, and ends in a cited report — not a snippet. Every major lab shipped a "deep research" agent for exactly this gap. What has to exist between a search box and a trustworthy report?

Userasks a hard question
New in this step: User.

An orchestrated crew: a lead agent that plans and delegates, parallel sub-researchers with clean contexts, a shared evidence store of claims-with-sources, a budget that ends the loop, and a synthesis pass whose citations are verified, not decorative.

What the new pieces do

Userclient
Asks something no single search answers: "compare the top 5 vector DBs for our scale and recommend one, with evidence."

Step 1 · The skeleton

A lead that plans, not a loop that wanders

Hand the whole question to one agent with a search tool and it wanders: chases the first interesting thread, forgets half the question, and declares victory when the context fills. Research needs structure before it needs searches. What's the first component?

Userasks a hard questionResearch Leadplan · delegate
New in this step: Research Lead.

The user asks a broad, hard question. What happens first?

  1. Unplanned search produces a random walk through the internet. The agent burns its budget on whatever the first results made interesting, not what the question needs.

  2. "Compare vector DBs" becomes: performance benchmarks, pricing, operational maturity, ecosystem, migration cost — a checklist the rest of the system executes and audits against.

  3. Decomposition is the research skill. Making the user do it is making the user the researcher.

The Research Lead owns the question: it decomposes it into sub-questions, decides what "covered" looks like, and delegates. Planning first turns an open-ended wander into an auditable checklist — and gives every later component something to measure against.

Why this piece earns its place

The plan has to survive being read by something that did not write it, so write it as structured records — one record per sub-question, carrying a stable id — rather than prose the lead re-derives each round. Ids are what let a later round point at the same lane an earlier round filed its claims under, and what gives a re-run something to diff against; a decomposition that quietly rewords itself between rounds makes every comparison across rounds meaningless. The subtler job is deciding what travels into each record. The original question carries constraints the sub-questions do not — at our scale, we are on Postgres today — and a worker never sees anything but its own brief, so a constraint left behind in the phrasing reaches no lane at all and comes back as five lanes of well-researched, mildly wrong evidence. Copy it in at decomposition time. And the failure you cannot see is a plan that misses a dimension outright: every lane covered, the budget under, every citation verified, and the report confidently incomplete, with nothing anywhere in the trace to flag it. Which is why putting the plan in front of the user before dispatch is worth the extra turn.

What the new pieces do

Research Leadbackend
The orchestrating agent: decomposes the question, spawns sub-researchers, watches for gaps, and decides when the evidence is sufficient.

Step 2 · Divide the question

Parallel sub-researchers, isolated contexts

Five sub-questions, each needing dozens of searches and long documents read. Serially, that's slow. In one shared context, it's worse than slow: benchmarks drown pricing, pricing drowns ecosystem, and the window rots before the report starts. How is the work split?

Research Leadplan · delegateSub-Researchersparallel · isolated
New in this step: Sub-Researchers.

How should the five sub-questions be worked?

  1. Slow, and each sub-question inherits the context debris of the previous ones. By sub-question four, the window is a landfill.

  2. The sub-questions contaminate each other — retrieved pricing pages distract benchmark reasoning, and the window overflows long before coverage.

  3. Isolation is the point: each worker reads deeply within its lane and returns distilled findings. Fan-out buys speed; clean windows buy quality.

The lead spawns Sub-Researchers — one per sub-question, each with a fresh, task-scoped context. They run in parallel, dig deep in their lane, and report back findings. This is the isolate operation of context engineering, applied as an org chart.

Why this piece earns its place

Fan-out looks free and is not. Concurrency is bounded by the search API's rate limit and by spend, not by the number of sub-questions, so the lead is really a scheduler — a dispatch queue with a concurrency cap — rather than a loop that launches everything at once and finds the ceiling as 429s halfway through a round. Isolation also changes what a failure looks like on the way out. A worker that times out, loops, or returns nothing does not error the request: it produces a thin lane, which is exactly what an honestly researched dead end produces too. Nothing in the evidence tells those apart, and they want opposite responses — retry the crashed lane, but write the material here is genuinely scarce about the real one. So a worker's terminal state is recorded as a fact about the run, stored beside its claims rather than inferred from how few of them there are. Each brief also has to name its neighbours, so a worker that turns up somebody else's sub-question hands the thread over instead of following it: two workers half-answering one lane pay twice and leave both halves looking staffed.

  • 1 laneper sub-researcher
  • clean windowper lane
  • findings upnever transcripts

What the new pieces do

Sub-Researchersservice
Worker agents, each owning one sub-question with its own clean context. They search, read, and return findings — not transcripts.

Step 3 · The grind

Search, read, note — repeat

Inside one lane, what does a sub-researcher actually do? First results are rarely the answer: the good benchmark is on page two of a blog linked from a forum post. One-shot retrieval produces one-shot understanding.

Sub-Researchersparallel · isolatedSearch / Fetchweb · docs · APIs
New in this step: Search / Fetch.

How does a sub-researcher work its sub-question?

  1. That’s a search engine with extra steps. Snippets are teasers; the substance lives inside documents the first query didn’t even surface.

  2. Each round’s findings sharpen the next round’s queries — the agent follows leads like a human researcher, going deeper as its understanding compounds.

  3. Breadth without reading is noise, and 100 pages is a context-rot machine. Reading and distilling per-source is what turns pages into evidence.

Each worker runs the search-read-note loop: query the Search/Fetch tools, open the promising results, read them properly, extract claims, and let each finding refine the next query. Depth comes from iteration — queries get smarter as understanding compounds.

Why this piece earns its place

The tool layer lies more often than it errors. A fetch returns 200 with a body that is a consent wall, a JavaScript shell, a paywall preview or a not-found page the site renders as content, and a worker will extract clean, well-formed claims out of any of them — attributed to a real URL on a real domain, and sourced from a cookie banner. Nothing about that request looks wrong afterwards. So the fetch layer owes the worker a check on what came back before extraction runs, and a lane that cannot get past it should say the document was unreachable rather than quietly settle for the snippet it already had. The layer owes one more thing: a cache keyed by URL that holds the retrieved text, not a pointer to it. Lane boundaries partition the questions, not the web — one good review article is legitimately relevant to two lanes — and step 7 re-reads cited sources after the draft exists. Holding the text means each retrieval is paid for once, and it is what makes the trace replayable at all; a stored URL replays whatever that page says today.

What the new pieces do

Search / Fetchservice
The tool layer: search engines, site fetchers, internal doc stores, structured APIs. Every result carries its source URL.

Step 4 · Write it down

The evidence store: claims, with receipts

A worker just read thirty pages. What flows upward — and what survives the loop? Raw transcripts overflow every window, and "I remember reading somewhere that…" is how hallucinated citations are born.

Sub-Researchersfindings, not dumpsEvidence Storeclaims + sources
New in this step: Evidence Store.

What does a sub-researcher persist from its reading?

  1. Terabytes of context nobody re-reads. Storage isn’t the problem — attention is. Raw text buries the claims the report needs.

  2. "Qdrant p99 = 12ms at 10M vectors — [benchmark URL, 2026-03]" is usable, checkable and compact. The report gets built FROM this store, so citations are structural, not decorative.

  3. Summaries lose the pairing between specific claims and specific sources — exactly the linkage the citation checker needs later.

Workers write to a shared Evidence Store: atomic claims, each with source URL, quote, confidence and timestamp. Contradictions become visible (two claims, same topic, different numbers), and the eventual report can only say what the store can back.

Why this piece earns its place

The evidence store is the only place workers who share no context meet, so its defining property is concurrent writers, not size. Make it append-only: no worker edits or deletes another's claim, and a correction is a new row that supersedes the old one. That removes write coordination between lanes entirely — nothing to lock, nothing to merge — and it keeps the trace able to show what the report was built from at the moment it was written, which an edited row destroys. Then validate the schema at write time. A claim written without its quote costs nothing when it lands and surfaces three steps later as something nobody can check, and the repair is not an edit: it is a worker sent back to a source it finished reading rounds ago. Confidence deserves a definition rather than a number. Make it a property of the claim-source relation — the source states this directly, implies it, or the worker inferred it — because the honesty pass only ever asks whether a source supports a sentence, and an inferred claim cannot pass that question however sure the worker felt writing it.

What the new pieces do

Evidence Storestore
The shared notebook: atomic claims, each paired with its source, confidence and timestamp. The report is built from this, not from memory.

Step 5 · Know when to stop

Gap-driven iteration, under a budget

Research never feels finished — there's always one more source. Meanwhile every round costs real tokens and real minutes. Who decides between "keep digging" and "we know enough"?

Research LeadEvidence StoreDepth BudgetTrace / Evals
New in this step: Depth Budget, Trace / Evals. · swipe to pan the diagram

When does the research loop end?

  1. The internet never runs out of pages. Novelty-exhaustion is a stopping rule for crawlers, not researchers.

  2. Question difficulty varies wildly — a fixed count starves hard questions and gold-plates easy ones. The budget should be a ceiling, not the plan.

  3. Gap-driven iteration: "pricing lane is thin, benchmarks conflict — one more targeted round." The depth budget (rounds, tokens, dollars) caps it regardless.

Between rounds, the Lead reads the evidence store against its plan: covered, thin, or conflicting? Real gaps trigger targeted follow-up rounds; the Depth Budget — rounds, tokens, wall-clock, dollars — hard-caps the whole affair, with everything logged to the Trace.

Why this piece earns its place

A budget an agent is asked to respect in its prompt is not a budget. Tell a model it has spent enough and it will reason its way to one more round for a good cause, so the accounting belongs in the harness that dispatches tool calls and meters tokens, with the lead reading the remaining balance as an input to its next decision rather than being trusted to subtract. The ceiling itself belongs in the request, not the config: the same architecture has to serve a question worth a quick sweep and a question worth a long dig, and depth is the one knob a user should actually feel. Which forces the part teams skip — every point in the loop has to be shippable. Running out of budget cannot be an error, because the ceiling exists precisely to be hit. The terminal state is a report written from whatever the store holds, with the thin lanes named inside it: we found little on migration cost is a useful sentence and an honest one. A system that can only produce output after full coverage has a budget in name only.

What the new pieces do

Depth Budgetservice
Caps research rounds, token spend and wall-clock time. Research has diminishing returns; the budget decides when good enough is enough.
Trace / Evalsbus
Full record of queries, sources, notes and drafts — for debugging, cost tracking, and evaluating research quality over time.

Back of the envelope

coverage audit
each round: covered / thin / conflicting per lane
targeted follow-ups
new rounds only for real gaps
hard budget
rounds + tokens + $ + wall-clock ceilings
full trace
every query and claim, replayable

Step 6 · Write the report

Synthesis from evidence, not from memory

Time to write. The tempting shortcut: hand the model the question and let it write from everything it "learned along the way." That's how you get a beautiful report with claims nobody actually found.

Evidence Storeclaims + sourcesSynthesizerdraft with citations
New in this step: Synthesizer.

What does the synthesizer write FROM?

  1. Context memory blurs what was read with what was inferred. Claims mutate in transit; citations attach to the wrong facts.

  2. The report is a rendering of the store: structure from the coverage plan, claims from the evidence, disagreements surfaced explicitly with both sources shown.

  3. Re-reading raw sources at synthesis time re-introduces the context overload the whole pipeline was built to avoid — and drops the other forty sources on the floor.

The Synthesizer drafts the report from the Evidence Store: the coverage plan gives the structure, stored claims give the substance, and every sentence carries its citation. Where sources conflict, the report says so — presenting both, with dates and authority, instead of silently averaging.

Why this piece earns its place

A report long enough to be worth reading does not fit in one generation, and the store is bigger than the draft. So synthesis runs section by section, each one handed the claims for its lane and nothing from the others — the context discipline the workers used, applied at write time. That buys quality and creates one new problem: the seams. Sections written independently repeat each other, hedge the same finding two different ways, and build toward a conclusion nobody wrote. So a final pass reads the whole draft, and that pass may cut and rewrite, never add. A sentence it introduces carries no claim id, so nothing downstream can resolve it and it gets cut a step later, after you have paid to write it. Emitting citations as resolvable claim ids rather than prose attributions pays a second time when a follow-up round lands: the ids say which sections were built on the lane that just changed, so those get re-rendered and the rest of the draft is left alone. Without them, one more round on one lane means writing the whole report again.

What the new pieces do

Synthesizerservice
Writes the report from the evidence store — every claim traced to a stored source, contradictions surfaced rather than smoothed over.

Step 7 · The honesty pass

Verify every citation actually says that

The draft cites forty sources. Models are excellent at producing citations that look right — real URLs, plausible attributions — that don't quite say what the sentence claims. Ship that, and one wrong citation poisons trust in the other thirty-nine.

Synthesizerdraft with citationsCitation Checkclaims ↔ sources
New in this step: Citation Check.

The draft is written and cited. Ship it?

  1. Claims drift during writing: numbers get rounded, hedges get dropped, "one benchmark shows" becomes "benchmarks show." The last mile is where honesty leaks.

  2. A separate check re-reads the stored quote (or the live source) and asks one question per citation: does this actually support this sentence? Failures get cut, weakened, or re-researched.

  3. The author grading its own claims, holding the same context that produced the drift — a rubber stamp. Verification wants fresh eyes and a narrow question.

The Citation Check walks every claim-citation pair with a narrow prompt: does the source support the sentence? Unsupported claims are cut or sent back for another research round. Only then does the report — with its now-load-bearing citations — go to the user.

Why this piece earns its place

Two things nobody builds until they have been burned by them. The first is that this pass is the only diagnosis the system ever produces, and only if it records which of two comparisons failed. A citation has three parts — the sentence, the stored claim with its quote, and the source — so a failure is either the sentence having moved away from the claim it cites or the claim having never been supported by the source it names. One verdict per citation collapses those together, and they want opposite repairs: rewrite the sentence, or send that lane back to the source. Split the failures that way, by lane and by domain, and the number stops being a score and starts naming the step to go and fix. Second, a verifier that passes everything is indistinguishable from a verifier that is broken, and the symptom of a prompt regression here is silence: every citation approved, every report shipped, trust quietly gone. So plant known-unsupported pairs and confirm they still fail. The last note is budgetary. This is one call per citation, parallel and individually cheap but real in aggregate, and it runs after the research spend — reserve it up front, or the honesty pass becomes the thing that gets dropped when a question runs long.

  • every citationindependently re-checked
  • fail → cutor re-research, never ship
  • trustis the product

What the new pieces do

Citation Checkservice
The honesty pass: re-reads each cited source and confirms it supports the sentence citing it. Unsupported claims get cut or re-researched.

The payoff

You built a deep research agent

From a search box to a research organization: a lead that decomposes and audits, parallel sub-researchers with clean contexts, an iterative search-read-note grind, an evidence store of claims-with-receipts, gap-driven rounds under a hard budget, synthesis rendered from evidence, and citations that survive an independent check.

UserResearch LeadSub-ResearchersSearch / FetchEvidence StoreDepth BudgetSynthesizerCitation CheckTrace / Evals
The finished design, end to end. · swipe to pan the diagram

Now poison a source and watch the hygiene stack respond — source tracking, contradiction surfacing, authority weighting, and the citation check that refuses to let confident nonsense reach the report.

Everything you assembled, in order

  • Decompose first — the plan is the rubric everything audits against
  • Sub-researchers — parallel lanes, isolated contexts, findings up
  • Search-read-note — iterate; reading documents is the moat
  • Evidence store — atomic claims paired with sources, always
  • Gap-driven rounds — audit coverage, follow up only real gaps
  • Depth budget — rounds/tokens/$ ceilings end the endless
  • Synthesis = rendering — the report is a view over the evidence
  • Citation check — every claim re-verified against its source

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. Sub-researchers report "findings," not transcripts, to the lead. What gets lost, and is that ever a problem?

    Nuance and hedges can get lost — a finding like "Qdrant is faster" compresses away "faster on this specific benchmark, under these conditions, per one source." That’s a real cost, which is why findings still carry pointers back to the evidence store’s atomic claims rather than being pure prose summaries: the lead reads the compressed version to plan, but the synthesizer and citation checker still work from the uncompressed claims with their sources attached.

  2. Two sources disagree on a number — one benchmark says 12ms p99, another says 40ms. What does the report actually say?

    It surfaces the disagreement rather than picking a winner or averaging: "Reported p99 latency ranges from 12ms to 40ms depending on benchmark methodology and hardware [source A, source B]." Averaging would manufacture a number nobody measured; silently picking one hides real uncertainty. The evidence store’s claim-source pairing is what makes a contradiction visible in the first place — you can only surface a conflict you can see.

  3. How does "authority weighting" actually judge a source without a hardcoded whitelist of trusted domains?

    Signals like citation density (how often other credible sources reference this one), recency, whether it’s a primary source (the benchmark itself) versus a secondary aggregator repeating it, and consistency with the broader evidence set — a source claiming something no other independent source corroborates gets weighted down even without being on any blocklist. It’s closer to a trust score than a fixed list, which is what lets it handle domains nobody pre-registered.

  4. The citation check fails one claim that three different report sentences all cited. What happens?

    All three sentences get flagged, not just the first one found — because the underlying evidence store claim is what failed verification, and every sentence deriving from it inherits the same problem. This is another payoff of claims being atomic and centrally stored: a single bad claim is traceable to every place it was used, instead of needing to be caught three separate times.

  5. How would a "watch this topic and update me" mode change this architecture?

    The evidence store would need staleness tracking per claim (when was this last confirmed?), and instead of one synthesis pass, the lead would periodically re-run the coverage audit against fresh searches, flagging claims whose sources have since been contradicted or updated — turning the citation-verification pass from a one-time gate into a recurring freshness check on a live report.

Check yourself — the answers, and why

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

  1. Why do sub-researchers get isolated contexts?

    Isolation is the "isolate" operation of context engineering: one sub-question’s material per window, distilled findings upward.

  2. What lives in the evidence store?

    Claim-source pairing at write time is what makes citations checkable at ship time.

  3. When does the research loop stop?

    Gap-driven iteration measures coverage against the plan; the depth budget caps rounds, tokens and dollars regardless.

  4. The citation-verification pass exists because…

    Generation optimizes coherence, not truth. Fresh-context verification of each claim-citation pair is what keeps the report honest.

  5. One sub-researcher chases a rabbit hole while other lanes stay thin. What corrects it?

    The depth budget is a fairness mechanism across sub-questions, not just a global ceiling — coverage audits catch a lane consuming budget without proportional findings.

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.

  • Decompose: break a broad, hard question into sub-questions and a coverage plan.
  • Research in parallel: spawn a sub-researcher per sub-question, each with its own clean context.
  • Search, read, note: iterate — open promising sources, read them, extract claims, refine the next query.
  • Cite the report: synthesize from an evidence store so every sentence traces to a stored source.
  • Verify citations: re-check each cited source against the sentence citing it before shipping.

The qualities that shape everything

Each one names the mechanism that buys it.

Structure before searching, not a random walk
The research lead decomposes the question into sub-questions and a coverage plan, turning an open-ended wander into an auditable checklist.
Depth in one lane never crowds out another
Parallel sub-researchers each own one sub-question in a fresh, task-scoped context and report distilled findings, not raw transcripts.
Real depth, not page-one snippet-skimming
Each worker runs a search-read-note loop — open and read promising sources, extract claims, refine the next query — so queries sharpen as understanding compounds.
Checkable citations, not vibes with URLs
Workers persist atomic claims each paired with source, quote, confidence and date, so contradictions are visible and the report can only say what the store backs.
Know when to stop, and bound the cost
Between rounds the lead audits coverage against the plan and dispatches follow-ups only for real gaps, inside a hard budget of rounds, tokens, dollars and wall-clock.
The final report stays honest
A separate citation check re-reads each cited source with one narrow question — does it support the sentence? — cutting or re-researching unsupported claims.

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.

A lead that decomposes first over start searching immediately

Unplanned search is a random walk that burns the budget on the first interesting thread. The plan is the rubric — without it you can’t detect gaps, parallelize, or know when you’re done.

Parallel sub-researchers, isolated contexts over one agent with all sub-questions in a shared context

A shared window lets sub-questions contaminate each other — pricing pages distract benchmark reasoning — and overflows before coverage. Isolation buys quality; fan-out buys speed.

Atomic claims paired with sources over full text (or a vibe summary per source)

Raw text buries the claims and floods attention; a per-source summary loses the claim-to-source pairing. Pairing every claim with its receipt at write time is what makes verification possible at read time.

Gap-driven iteration under a hard budget over a fixed number of searches

Question difficulty varies wildly, so a fixed count starves hard questions and gold-plates easy ones, and "stop when no new pages" never terminates. Auditing coverage plus a budget ceiling ends the endless.

An independent citation-verification pass over trusting citations because they came from the evidence store

Claims drift during writing — numbers rounded, hedges dropped, "one benchmark shows" becomes "benchmarks show." A fresh-context check of each claim-citation pair catches the last-mile leak a self-grade won’t.

The answer, out loud

What a strong answer to “Design a Deep Research Agent” 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

    Pin down what we owe at the end

    I'd start by settling what the user gets handed, because that decides the shape. They don't want a page that probably contains the answer; they want a recommendation they can act on, with every sentence checkable against something we read. That isn't a search problem with more steps. The unit of work isn't a query; it's a question that has to be broken up, chased down several lanes at once, then defended. So what I'd draw is a small research organisation: something that plans, workers who dig, a place the findings live, and a pass at the end that tries to knock the report over.

  2. 3–8 min

    A lead that writes the plan down first

    The first component is a lead agent, and the first thing it does is not search. It reads the question and sets out what a defensible answer would have to cover — in writing, before we spend a token, for two reasons. It's the only thing the rest of the run can be measured against, and it's the cheapest moment in the system to be wrong: a bad plan costs seconds now and the whole budget later. Skip it and the agent follows the first promising thread and stops when it runs out of room, and I can't tell a finished report from an abandoned one.

    Built in step 1: A lead that plans, not a loop that wanders
  3. 8–14 min

    One worker per lane, each in its own head

    Then the lead hands each of those out to its own worker, with its own fresh context, and they run at the same time. If I'm pushed on why not one context, my answer isn't mainly speed. One window holding every lane ends up with each lane's material tugging at the reasoning on the others, and it fills well before the question is answered. Doing them one after another has the same problem more slowly: by the fourth lane the window still carries everything the first three read. What comes back up is what a worker concluded; the reading stays down in the lane.

    Built in step 2: Parallel sub-researchers, isolated contexts
  4. 14–19 min

    Inside a lane: search, open it, read it

    Inside one lane it's a loop. Search, decide which results are worth opening, actually open and read them, write down what they claim, and let that shape the next query. The reading is what I'd defend hardest — it's the difference between this and a summariser, because the number that settles the question is usually several links in, inside a document the first query never returned. I wouldn't fix that by pulling in a big pile of pages at once, because that relocates the problem into the window. Each source is read and reduced to claims before the next one is fetched.

    Built in step 3: Search, read, note — repeat
  5. 19–25 min

    Claims with receipts, written at the time

    What every worker writes goes to one shared store, the piece I'd spend the most time on. A row is one claim, its source, the words in that source that carry it, how directly the source says it, and when. Full text would be storing what nobody re-reads. One summary per source is worse: it throws away which sentence of ours rests on which source, and that link is what I need later. Then two sources disagreeing show up as two rows side by side, and the report gets a hard edge: it can say what the rows carry, nothing past it.

    Built in step 4: The evidence store: claims, with receipts
  6. 25–30 min

    Deciding the run is over

    Stopping needs a rule, and the two obvious ones are both wrong. Run until nothing new turns up and you never stop. Fix the number of searches and you spend the same on a question that's nearly answered and one that isn't. So between rounds the lead takes the plan back over the store and decides, lane by lane, whether it has enough, too little, or a real conflict, then sends another round only where there's a hole worth paying for. Over that sits a ceiling on rounds, tokens, money and wall-clock: the audit picks where the next spend goes, the ceiling guarantees a last round.

    Built in step 5: Gap-driven iteration, under a budget
  7. 30–35 min

    Write the report off the store

    The report gets written from those rows rather than the model's recollection of the run, section at a time, so no one generation holds the whole store. Where two sources genuinely disagree I'd show both with their dates instead of splitting the difference into a number nobody measured — an average reads more confident than either source deserves. Sections written separately need a pass over the seams, and that pass gets one rule: it can cut and rewrite, it can't introduce a sentence. Anything it adds arrives with nothing behind it.

    Built in step 6: Synthesis from evidence, not from memory
  8. 35–40 min

    Then try to knock it over

    Then I wouldn't ship it. I'd run one more pass over every cited sentence, in a clean context, asking one narrow thing: does this source hold this sentence up? It has to be separate, because the model that wrote the sentence still holds the context that produced it and will wave its own work through. What I'm hunting is small movement between the row and the sentence — a figure tidied up, a qualifier dropped, one study becoming the literature. Whatever fails gets cut, weakened, or sent back for another round, and only then does it go out.

    Built in step 7: Verify every citation actually says that
  9. 40–45 min

    Close on the trade-off

    So the trade-off I'd name is cost against trust. Separate contexts per lane, opening documents instead of skimming results, and a check on every citation all cost more than one agent with a search tool. That difference is the price of a report somebody can act on rather than re-verify. With more time I'd push on two things. The sources we can't reach — internal docs, anything behind a login — which is more a permissions problem than a research one. And how we'd evaluate it at all: a set of questions where we already know what a complete answer covers, so we can find out whether the coverage audit ever catches a dimension the plan missed, or only confirms what the plan thought of.

What this teaches

Learn AI system design by building a deep research agent step by step. An interactive guide covering query decomposition, parallel sub-researchers with isolated contexts, the search-read-note loop, an evidence store with claim-source pairs, gap-driven iteration under a depth budget, synthesis with citations, and the citation-verification pass that keeps the final report honest.

Key takeaways

  • Decompose first — the plan is the rubric everything audits against
  • Sub-researchers — parallel lanes, isolated contexts, findings up
  • Search-read-note — iterate; reading documents is the moat
  • Evidence store — atomic claims paired with sources, always
  • Gap-driven rounds — audit coverage, follow up only real gaps
  • Depth budget — rounds/tokens/$ ceilings end the endless
  • Synthesis = rendering — the report is a view over the evidence
  • Citation check — every claim re-verified against its source

Concepts covered

  • Search answers queries. Research answers questions.
  • A lead that plans, not a loop that wanders
  • Parallel sub-researchers, isolated contexts
  • Search, read, note — repeat
  • The evidence store: claims, with receipts
  • Gap-driven iteration, under a budget
  • Synthesis from evidence, not from memory
  • Verify every citation actually says that
RUN IT YOURSELF

The three sources that are one source

A research agent works a ranked queue of candidate sources under a fixed fetch budget, and a lot of that queue is the same claim restated — plus a lot of prose carrying no claim at all. This file runs the same queue, scheduler and budget twice — deduping by URL, then by normalized claim — prints what each run holds when the budget runs out, then counts corroboration over the URL run's own rows both ways. Change BUDGET at the top, hit Run, and watch the gap open and close.

HOW TO READ THE CODE — 5 IDEAS
  1. The fetch cache of step 3 is keyed by URL, so it pays for each page once — and the four pages carrying one benchmark number are four different pages. Same 14 fetches: 7 distinct claims deduping by URL, 9 deduping by claim.
  2. Claim dedupe is also the only signal that a lane has stopped paying: by URL, no fetch is ever redundant, so no lane can ever saturate. Two consecutive re-reads demote the benchmarks lane and the budget flows to the thin ones step 5's coverage audit is looking for — 2 of 4 lanes covered becomes 4 of 4.
  3. Two of the 14 rows are ordinary prose with no extractable claim. They are counted in their own column and are neutral: not a re-read, not a new claim, and they never touch the saturation counter — so only a duplicate claim can ever demote a lane.
  4. Over the same 14 rows, counting sources says a Milvus recall figure is backed by 3. Counting independent origins says 1 — two of them attribute the third or paste its sentence verbatim. That is why confidence belongs on the claim-source relation (step 4), not on a row count. A 4th row refutes the Qdrant latency figure, and only the polarity field in the key keeps it from being filed as a corroborating source.
  5. The residual is printed rather than hidden: one page restated the latency figure in its own words and credited nobody, so it still counts as a second origin. Neither signal — attribution, nor identical wording — reaches a paraphrase.
CPython · WebAssembly
built to be reasoned about, not memorized — make the calls, poison a source, run the quiz.
Finished this one? 0 / 65 AI System Designs done
NextDesign a Conversational AI Closest AI system design to this one

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