Design Perplexity (RAG Search with Citations)
Problem statement
Design a Perplexity-style search product — the 5-stage RAG pipeline (search → fetch → rerank → synthesize → render), inline citations that stay anchored as tokens stream, cache+freshness, and the clean frontend/backend boundary. Mentor-tone walkthrough with four flow diagrams.
Asked In
Key Challenges
- ·A five-stage pipeline (query understanding → search → fetch → re-rank → synthesize) where each stage has its own latency and failure mode
- ·Citations that stay anchored to specific sentences as the LLM streams tokens — and resolve to the right source even when the answer is half-rendered
- ·Cache + freshness: 'Who won the World Cup' stays cached for years; 'AAPL stock price' must always be live
- ·Latency masking: cold query takes 4–8 seconds end-to-end — the user must see meaningful progress within 500ms
- ·Hallucinated citations — the LLM occasionally emits [4] when only 3 sources exist; the UI must degrade gracefully
2-Minute Answer — High-Level TL;DR
Read this before your interview
HLD Interview Focus
I would not design Perplexity as ChatGPT with a search badge. It is a five-stage pipeline — search, fetch, re-rank, synthesize, render — and the UI is a progress surface over that pipeline. The user types a question; within ~500ms they should see Searching the web…, then source cards appearing as source_found events land, then Synthesizing…, then streamed answer text with inline [1][2] citations wired to a sources panel. Embeddings and vector search stay on the backend. The frontend owns stage progress, citation resolution, hallucinated-citation fallback, Stop via AbortController, and cache_status handling so evergreen queries feel instant while live queries never pretend to be fresh when they are not. Trust is the product: every claim should be checkable against a real URL.
My Approach: Building the Solution
How to think about this problem
I'll draw the five-stage pipeline on the whiteboard first — every later decision points back to it — then mark the frontend boundary in ink: retrieval is not our job. After that I layer progress events for latency masking, the streamed answer with citations, the sources panel, cache/freshness, and follow-ups in the same thread.
Why This Approach?
Most candidates design a chat app that happens to call a search API. That answer collapses when the interviewer asks what the user sees for four seconds before the first token, or what happens when the model cites [4] and only three sources exist. Strong answers treat the pipeline as the product: each stage emits UI, citations are structured events not decoration, and the librarian work stays off-stage on the backend.
Asking Perplexity is like asking a librarian. She walks to shelves (search), pulls books (fetch), picks the best pages (re-rank), and writes a short answer with footnotes (synthesize). The frontend does not choose the shelves — it makes her work visible: which books she pulled, which sentence came from which book, and a clear path when a footnote points at a book that was never on the desk.
Requirements: What Makes a Great Solution?
Clarify scope before designing anything
Requirements Exploration Questions
Ask your interviewer these questions to refine requirements
What is the scope of search?
- ·Live web search vs internal knowledge base (e.g. company docs, codebase RAG)
- ·Image and video answers, or text only?
- ·Follow-up questions in the same thread (carries context)?
- ·Search restricted to a domain (`site:example.com`) or globally?
Which content categories?
- ·News (live, fresh) vs evergreen knowledge (encyclopedic) vs both
- ·Code (search GitHub, NPM, MDN) vs general web
- ·Academic papers, financial filings, Wikipedia — different sources, different trust signals
- ·Personalization: search history, location, preferred sources
What citation behavior?
- ·Inline numeric citations [1] [2] (Perplexity-style) vs end-of-paragraph footnotes (Anthropic-style)
- ·Click behavior: smooth-scroll to source row, open in new tab, or both?
- ·Hover preview cards — show snippet, title, favicon, fetched-at timestamp?
- ·Per-sentence vs per-paragraph attribution
What are the latency expectations?
- ·First useful UI signal in <500ms ('Searching the web…')
- ·TTFT for streamed answer in <2s p50, <4s p99
- ·End-to-end p95 <8s for a typical query
- ·Cached query: <300ms total (CDN edge cache)
What about reliability and fallback?
- ·If search returns 0 results, what does the UI show?
- ·If LLM hallucinates a citation [4] when only 3 sources exist, how do we handle?
- ·If one source URL is unreachable mid-fetch, do we still synthesize?
- ·Rate limits: free tier vs paid; surface remaining quota in UI
Functional Requirements
Must Have — MVP
- ✓Query box with autosize textarea and send button
- ✓Streamed answer with inline numeric citations [1] [2] [3]
- ✓Sources panel: list of cited URLs with title, favicon, snippet
- ✓Citation click → smooth-scroll to source row + highlight + open original in new tab
- ✓Per-stage progress UI: 'Searching the web…', 'Reading 3 sources…', 'Synthesizing answer…'
- ✓Follow-up question in the same thread, with context-carry
- ✓Markdown rendering in the answer (lists, code blocks, tables)
- ✓Stop button to cancel mid-stream
Advanced (If Time Permits)
- +Pro Search — multi-step decomposition: query is broken into sub-queries, each runs the pipeline
- +Image & video answers (carousel of cited media)
- +Related questions ('People also asked') below the answer
- +Source quality voting / 'this citation doesn't match the claim' feedback
- +Private workspaces with organization-specific RAG
- +PDF / document upload as additional context
Non-Functional Requirements
Performance Targets
- ·First UI signal <500ms (typing indicator + first stage label)
- ·TTFT <2s p50, <4s p99
- ·End-to-end p95 <8s, p99 <15s
- ·Cached query <300ms (CDN edge response)
- ·Citation click → scroll + highlight in <100ms (purely client-side)
Scale & Cost
- ·Embedding cache hit-rate >70% on typical queries (saves $/query)
- ·Search-result CDN cache 5-min TTL with stale-while-revalidate
- ·Reranker only runs on top-50 from vector DB, not all results
- ·Source URL prefetch budget — cap at top 5 to avoid bandwidth spike
Reliability & Fallback
- ·0 search results → 'No sources found' empty state with reformulation suggestions
- ·LLM hallucinated citation → render as plain text [4] without anchor; log event
- ·1+ source fetch failures → still synthesize from remaining; mark missing source as '(unavailable)'
- ·Network drop mid-stream → 'reconnecting' inline with resume via Last-Event-ID
Accessibility
- ·Each citation is a real <a> with descriptive aria-label ('Source 3: nytimes.com')
- ·Sources panel is role='complementary' with a heading 'Sources'
- ·Streamed answer in role='log' aria-live='polite'
- ·Keyboard: number keys 1-9 jump to that source while answer panel is focused
Privacy & Trust
- ·Surface fetched-at timestamp on each source so user knows freshness
- ·Show 'sponsored' or 'Wikipedia' or 'official docs' badges where applicable
- ·Search history is per-user encrypted; option to disable
- ·Don't leak prompt-system messages or retrieval scores to client
Observability
- ·Per-stage latency dashboards (search, fetch, rerank, synthesize)
- ·Citation click-through rate (signal of source quality)
- ·Hallucinated-citation rate (regression alert)
- ·End-to-end p95 latency by query category (live vs evergreen)
The full solution is part of HelloFrontend Pro
The question above is free to read in full. Upgrade to unlock the interactive workspace and the senior-level walkthrough that go with it.
- Full RADIO-framework walkthrough with architecture diagrams
- Data model, API design, and rendering strategy trade-offs
- Performance, accessibility, and offline sections plus a model answer
Already a member? Log in to open the workspace.