Vibe Engines
YouTube
AI System Design

Design a Multimodal RAG System

Learn AI system design by building a multimodal RAG system that answers questions grounded in images, charts, tables and PDFs step by step.

The numbers to beattyped chunkstext · image · tablelayout-awarekeep structureasset refslink to originals

The whole design, in writing

Learn AI system design by building a multimodal RAG system that answers questions grounded in images, charts, tables and PDFs step by step. An interactive guide covering why text-only RAG loses visual information, parsing documents into multimodal chunks, unified multimodal embeddings vs convert-to-text, cross-modal retrieval, generation with a vision-language model that actually sees the content, asset storage, and the unhappy paths (modality gap, tables/charts, VLM cost, evaluation).

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 multimodal RAG?

Real documents aren't just text — they're charts, diagrams, tables, screenshots, photos and scanned pages. A financial report's key number is in a bar chart; a manual's answer is in a wiring diagram; the insight is in a table's layout. Text-only RAG can't see any of it: OCR and extraction flatten or lose the visual information, so the answer simply isn't in the text it retrieved.

Clienttext or image query
New in this step: Client.

Multimodal RAG retrieves and reasons over multiple modalities. It parses documents into multimodal chunks, embeds them into a shared space so a query can find visual content by meaning, and hands the retrieved images + text to a vision-language model (VLM) that actually sees them and answers, grounded and cited.

What the new pieces do

Clientclient
Asks a question whose answer may live in a figure, chart, table or photo — or even queries with an image.

Step 1 · Text-only loses the picture

Why plain RAG isn't enough

The obvious extension of RAG to a PDF with figures: OCR/extract the text, chunk and embed it, retrieve as usual. What critical information does this throw away?

Clienttext or image query
The system as it stands at this step.

Text-only RAG over OCR'd documents. What does it lose?

  1. A bar chart's trend, a diagram's spatial relationships, a photo's content, and a table's row/column structure carry meaning that OCR either loses entirely (no text) or flattens into a jumble. If the answer is "in the picture", text-only retrieval never had it to retrieve.

  2. Formatting is trivial. The real loss is semantic: information encoded visually (charts, diagrams, images, table structure) that has no faithful text representation is simply gone.

  3. It doesn't. Vast amounts of meaning in real documents live in figures, charts, tables and images; flattening to text discards it, so text-only RAG can't answer questions about that content.

Text extraction/OCR discards or flattens everything visual: a chart's trend, a diagram's spatial relationships, a photo's content, and a table's structure (which rows/columns relate). If the answer lives in a figure, text-only RAG never retrieved it because there was no faithful text to embed. To answer questions about visual content, retrieval and generation must both handle the modalities themselves, not a lossy text shadow of them.

Why this piece earns its place

Nobody files this as a bug, and that is the part to plan around. A user whose visual question came back as a plausible paragraph concludes the system does not do charts, and stops asking — so the queries that would have proved the gap drain out of your traffic, and the logs look healthiest exactly where coverage is worst. Demand you never served leaves no trace. So you go at it from the corpus side instead: sample pages at random, count how many carry a chart, a table or a diagram, and hand-write questions that can only be answered from those. That count is also the honest case for skipping all of this — over tickets, chat logs and code comments the visual share is near nothing, and everything that follows is cost for no answers gained. Establish it early, because the decision is expensive to reverse: going multimodal moves parsing, the index and the generator together, and each of those means re-processing the corpus rather than flipping a flag.

Step 2 · Parse into modalities

Multimodal ingestion

Before you can retrieve visual content, you have to extract it as distinct, typed pieces. What does ingestion produce from a rich document?

Clienttext or image queryMM-RAG Svcingest · query
New in this step: MM-RAG Svc.

Parse each document into typed multimodal chunks: text blocks, images/figures, tables, and charts — preserving layout and cross-references (which caption goes with which figure, which page). Use document-layout parsing (not just raw OCR) so a table stays a table and a figure stays a figure with its context. Each chunk keeps a reference to its source asset (the actual image) and location. Now you have a set of pieces in different modalities, ready to embed and index.

Why this piece earns its place

Parsing is the most expensive and most fragile stage here, and it deserves to be treated as its own cached artifact. Keep the parse output keyed by document hash plus parser version, because re-parsing a corpus of scanned PDFs costs far more than re-embedding it — and you will re-parse, since the layout model is the piece you swap most often. That version stamp matters for a second reason: a parser upgrade re-segments the page, so any chunk id derived from position silently becomes a different chunk, and re-ingesting appends a second copy of a figure rather than replacing the first. The quiet breakage to watch for is figure-caption association. A two-column layout hands a figure the neighbouring column's caption, and nothing downstream can detect it — the retrieved image is wrong in a way that is perfectly consistent, and the answer cites it confidently. Where a source is born-digital and already tagged, skip the layout model and read the structure you were given; layout parsing exists to recover structure that was thrown away at export.

  • typed chunkstext · image · table
  • layout-awarekeep structure
  • asset refslink to originals

What the new pieces do

MM-RAG Svcgateway
Ingests documents into multimodal chunks, and at query time retrieves across modalities and calls a vision-language model.

Step 3 · One space for all modalities

Embedding: unified vs convert-to-text

To retrieve a chart with a text query, the chart and the query must be comparable. There are two schools of thought for how to embed mixed modalities. What are they?

MM-RAG Svcingest · queryDoc Parsertext·img·table
New in this step: Doc Parser.

How do you make an image and a text query comparable for retrieval?

  1. That's text-only RAG again, blind to visuals. You need images to be retrievable, either by embedding them into a shared space with text or by describing them as text first.

  2. Unindexed images can't be found by a query. Images must be made retrievable — via multimodal embeddings or via generated text descriptions.

  3. Approach one uses a multimodal embedding model that maps images and text into the SAME vector space, so a text query directly retrieves relevant images by meaning (true cross-modal). Approach two generates text descriptions (image captions, table-to-text) and does ordinary text RAG over them. Unified preserves more visual nuance; convert-to-text is simpler and reuses text infra. Many systems combine both.

Two approaches (often combined). Unified multimodal embeddings: a model (CLIP-style) maps images and text into one shared space, so a text query directly retrieves relevant images by meaning — true cross-modal search. Convert-to-text: generate descriptions (caption images, linearize tables) with a VLM and run ordinary text RAG over them. Unified preserves visual nuance and needs no lossy captioning; convert-to-text is simpler and reuses text infrastructure but loses detail. Real systems frequently do both and fuse.

Why this piece earns its place

Two operational facts decide this choice more often than fidelity does. Convert-to-text is a model call per image at ingest, so ingestion becomes an inference bill and a backfill becomes a re-captioning run over the whole corpus. Those captions are model output, not source data — store each one with the model that wrote it, or the day retrieval quality shifts you will have no way to tell whether the corpus changed or the captioner did. Second: if you run both paths you have two vector spaces, and their scores are not on the same scale, so fuse by rank rather than by score. Averaging similarity numbers from two different models reads as principled and is arithmetic on incomparable units. One more thing worth saying in an interview — a shared space is a property of models trained together, not of matching dimensions. Bolting an off-the-shelf image encoder next to your text encoder gives you two unrelated spaces of the same width, and nearest-neighbour across them is noise that still returns results.

  • unifiedimage+text shared space
  • convert-to-textcaption then text RAG
  • often bothfuse the two

What the new pieces do

Doc Parserservice
Parses PDFs/docs into typed chunks — text blocks, images/figures, tables, charts — preserving layout and references.

Step 4 · Store the vectors

Multimodal index

With chunks embedded, where do the vectors live, and what must you record so retrieval and generation work across modalities?

Doc Parsertext·img·tableMM Embeddershared spaceVector Storemm embeddings
New in this step: MM Embedder, Vector Store.

Store the embeddings in a vector store, tagging each with its modality (text/image/table), a reference to the source asset, and location metadata. Whether unified or convert-to-text, the vectors share a comparable space so a single nearest-neighbor search spans modalities. The critical extra vs text RAG: keep a durable link from each vector to the actual image/asset, because generation will need the real pixels, not just the embedding.

Why this piece earns its place

The link from a vector to its asset crosses two systems with no transaction between them, and that seam is where this design actually breaks. Delete or overwrite an object and the vector survives, still ranked, still returned — and the fetch now fails on the critical path, mid-request, after retrieval has already spent its latency budget. So point at an immutable key, retire assets with a tombstone rather than a delete, and decide in advance what generation does when a fetch fails: drop that chunk and note it, rather than failing an answer the remaining chunks could have carried. The other thing to get right at write time is provenance — not what the chunk is, which the tags already say, but how it came to exist: which parser version cut it, and which box on the page it was cut from. Neither can be recovered from a row afterwards, both are free to write while the row is being written, and together they turn the question that eventually arrives — one parse run was bad, which vectors came out of it — from a re-ingest of the whole corpus into a filter over the index.

  • vector storeone comparable space
  • modality tagstext/image/table
  • asset linkback to pixels

What the new pieces do

MM Embedderservice
Embeds each chunk (image or text) into a shared multimodal space so a query can match content in any modality.
Vector Storedata
Stores the multimodal embeddings (with modality + source refs) for cross-modal nearest-neighbor search.

Step 5 · Retrieve across modalities

Cross-modal retrieval

A query arrives — maybe text ("show the revenue trend"), maybe an image ("find diagrams like this"). How do you find the right multimodal chunks?

MM-RAG SvcDoc ParserMM EmbedderRetrieverVector Store
New in this step: Retriever. · swipe to pan the diagram

Embed the query into the same shared space and run nearest-neighbor search to retrieve the most relevant chunks regardless of modality — a text query can surface a chart, an image query can surface similar figures or the text that describes them. Rerank and balance the results (you often want the key figure and its surrounding text), then fetch the actual assets for the ones you'll show the model. The retriever returns a connected multimodal context: the relevant images, tables and text passages.

Why this piece earns its place

Two things change once retrieval spans modalities. First, the modality mix belongs in the request, not the config. Show me the revenue trend wants figures; what does the warranty cover wants prose; one fixed quota serves one of them badly. Apply that mix as a quota over the ranked list rather than as a filter ahead of the search — filter first and a visual question comes back as the five best figures with none of the prose that explains them, and you threw away recall you had already paid for. Second, retrieval is no longer just the search. Once the shortlist is settled the assets still have to be pulled, and those object-store round trips sit on the critical path — the nearest-neighbour query was never the slow part here. Issue them concurrently rather than walking the shortlist one chunk at a time, and expect the tail to be set by the largest image in the set, not the average one. And measure recall per modality. An aggregate number stays healthy while figure recall collapses, because prose is the bulk of most corpora — the system quietly reverts to text-only RAG and no dashboard mentions it.

  • query → shared spacetext or image
  • cross-modaltext finds charts
  • fetch assetsfor generation

What the new pieces do

Retrieverservice
Query time: embeds the query and finds the most relevant multimodal chunks across text, images, tables and charts.

Step 6 · Answer from what it sees

Generation with a vision-language model

Retrieval found the right chart and table. Now the model must read the value off the chart and reason about it. A text-only LLM can't — it never sees the pixels. What generates the answer?

Retrievercross-modal + assetsVision-LLMsees + answersAsset Storeimages · files
New in this step: Vision-LLM, Asset Store.

Retrieval found the right chart. What must generate the answer, and why?

  1. The generator must be a multimodal LLM that is handed the real images (plus text) and can actually see them — reading a value off a chart, interpreting a diagram, describing a photo — to produce an answer grounded in the visual content, with citations to the sources. A text-only model given only captions can't do this.

  2. Captions are lossy — they can't convey every value in a chart or every relation in a diagram. For real visual reasoning the model must see the actual pixels, i.e. a VLM. (Captions help retrieval and as a fallback, but not for precise visual answers.)

  3. Returning the raw image punts the reasoning to the user. The point is for the model to interpret the visual content and answer the question, which requires a vision-capable model.

Generate with a vision-language model (VLM): hand it the actual retrieved images (the real pixels) alongside the text, and prompt it to answer from what it sees — reading values off charts, interpreting diagrams, describing photos — with citations to the source figures/passages. Only a model that truly sees the content can answer precise visual questions; a text-only model given captions is working from a lossy shadow. The VLM turns retrieved visuals into a grounded answer.

Why this piece earns its place

A visual citation is a different object from a textual one. Pointing a user at a page number does not let them check a value read off a chart — they need the exact picture the model was shown, so the response carries that asset reference beside the claim, and it has to still resolve when they click it. This is also the debugging story. A wrong visual answer has two obvious causes — retrieval fetched the wrong figure, or the model misread the right one — and you cannot tell them apart unless you logged which images went in and how they were prepared: the region cut out, and the size it was sent at. A third cause hides behind the second, because a figure shrunk until its axis labels blur produces exactly the symptom of a model that cannot read charts. One reliability note people learn the hard way: the vision path fails differently from the text path. A single oversized or unsupported image rejects the whole call, so validate dimensions and format at ingest, where one document fails, rather than at generation, where one user's request does.

  • VLMsees the pixels
  • answer from visualsread the chart
  • citesource figures

What the new pieces do

Vision-LLMservice
A multimodal LLM that receives the actual retrieved images + text and grounds its cited answer in what it sees.
Asset Storedata
Durable store of the original images/assets; the VLM is handed the actual pixels, not just a pointer.

Step 7 · Assets & delivery

Storing and serving the originals

Unlike text RAG, you're moving images around — into the index pipeline and into the model's context. Where do the originals live and how do they reach the VLM?

ClientMM-RAG SvcDoc ParserMM EmbedderRetrieverVision-LLMVector StoreAsset Store
The system as it stands at this step. · swipe to pan the diagram

Keep the original images/assets in durable object storage, referenced from each vector. At query time, retrieval fetches the actual assets for the top chunks and passes them (as image inputs) to the VLM. Manage size/cost — images are large and VLM image tokens are expensive — by storing sensible resolutions, cropping to the relevant figure, and limiting how many images go into a single generation. Cache popular assets and (as in any media system) serve via CDN where users view them.

Why this piece earns its place

What you hand the model is never the original — it is a rendition, a crop at a chosen resolution. Treat that set of renditions as its own cache and build it at ingest, or you pay a transcode on the critical path every time a popular figure is retrieved. The catch is that you have to choose sizes before you know what any question will need, so keep the original and treat a miss as something you generate once and then keep. The part that is easy to miss until a security review: these images get served to browsers, so the URL is the access boundary. A citation that links to a public bucket path is a permanent public link into a private document, sitting in a chat transcript forever — issue short-lived signed URLs instead. Retraction has to reach the renditions and not just the page they came from — a crop is not a thumbnail of a document, it is the part of it somebody reads. Retire them the way the original is retired, as a key marked gone rather than a key erased, so a citation written last month resolves to a withdrawn notice instead of a fetch that fails with nothing to say for itself.

  • object storedurable originals
  • right-sizecrop, resolution
  • limitimages per generation

Step 8 · The sharp edges

Modality gap, tables, cost & eval

Multimodal RAG has hard corners: the modality gap (image and text vectors not aligning perfectly), tables/charts that are neither pure image nor clean text, VLM cost for vision, and evaluation that's harder than text.

ClientMM-RAG SvcDoc ParserMM EmbedderRetrieverVision-LLMVector StoreAsset Store
The system as it stands at this step. · swipe to pan the diagram

Mitigate the modality gap (retrieval biasing toward one modality) with good multimodal models, hybrid unified+convert-to-text retrieval, and modality balancing. Handle tables/charts specially — extract structured data and keep the image, since some questions need the numbers and some need the visual. Control cost: vision tokens are pricey, so retrieve tightly, right-size images, and use a VLM only when a visual chunk is actually needed. And evaluate multimodally — check whether answers are truly grounded in the retrieved visuals, not hallucinated, which is harder to measure than text grounding.

Why this piece earns its place

Evaluation is the piece that actually stalls teams, and it is worth naming why. Checking whether an answer is grounded in a chart means the judge has to see the chart too — so your automated judge is itself a vision model, grading output from the same class of model that produced it and sharing its blind spots. Keep a small human-labelled anchor set and score the judge against it periodically; without one, a judge regression looks exactly like a system improvement. The modality gap does something quieter to your thresholds, too. Any cutoff that decides a result is too weak to use gets calibrated on whichever modality dominated the traffic you calibrated against, and it will then reject the other one at a different rate — so set that cutoff per modality, or you will be suppressing figures in the belief that you tuned for quality. And the cost shape is genuinely different from text RAG: per-query cost is bimodal, because a visual answer and a prose answer are not the same product, so an average tells you nothing and capacity planning has to run on the visual share of traffic. That share is not static. It grows as users discover the system can read their charts, which means a budget modelled on launch-week traffic is wrong in the direction that hurts.

You did it

You just designed a multimodal RAG system.

ClientMM-RAG SvcDoc ParserMM EmbedderRetrieverVision-LLMVector StoreAsset Store
The finished design, end to end. · swipe to pan the diagram

Everything you assembled, in order

  • Text-only RAG loses everything visual — charts, diagrams, photos, and table structure that OCR flattens.
  • Parse documents into typed multimodal chunks (text, images, tables) with layout and asset references.
  • Make modalities comparable via unified multimodal embeddings (shared space) and/or convert-to-text — often both.
  • Store vectors with modality tags and durable links back to the original assets.
  • Retrieve cross-modally: one query (text or image) finds the relevant chunks in any modality.
  • Generate with a vision-language model that receives the actual pixels and answers from what it sees, cited.
  • Store/serve originals deliberately (right-size, cap per answer); mind the modality gap, tables, VLM cost and eval.

Deep cut · 13:43

The model was never shown the chart.

The interactive build above lays out a multimodal RAG system: a reader that takes pages apart, a shelf that files every piece by meaning, a vault that keeps the originals, a model that can look, and a ration that caps how much it looks at. The film shows why each stop exists by following one wrong answer backwards. An analyst asks whether revenue crashed, the AI says yes, and the real report has a chart that climbs every month. The model never lied. The first station, the text reader, kept the chart labels and threw the shape away, so nobody ever showed the model the picture. Rebuild there, then pay the honest bill: more work at read-in, double storage for tables, and a look-budget that can hide the one chart you needed.

  • Watch the leak: a page rolls through a text-only reader, the chart bars slide off the belt, and a flat line of labels reaches the model, so it guesses the wrong direction.
  • Take it into the interview: name layout analysis, embedding pieces into one shared space, keeping originals and fetching them by ID, a vision model that sees the real picture, and a budget on tiles and crops. Ask first: where does the chart live after read-in?

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 text-only RAG fail on documents with charts, diagrams and tables?

    Because a huge amount of meaning in real documents is encoded visually, and text extraction or OCR either drops it entirely or flattens it into something unusable. A bar chart communicates a trend and specific values through its geometry, which OCR can't recover as text; a wiring or architecture diagram conveys spatial relationships that have no faithful linear text form; a photo's content is simply not text at all; and a table's meaning lives in its row and column structure, which naive extraction turns into a jumbled stream that loses which value belongs to which header. In text-only RAG, you embed and retrieve over this lossy text shadow, so if the answer lives in a figure, there was never any faithful text representing it to embed in the first place — retrieval literally cannot surface it, and even if it did, a text model couldn't read the value off the chart. To answer questions about visual content, both retrieval and generation must operate on the modalities themselves rather than a degraded text approximation, which is exactly what multimodal RAG adds.

  2. Unified multimodal embeddings vs convert-to-text — what's the tradeoff?

    They are two ways to make images and text comparable so a query can retrieve visual content, and they trade fidelity against simplicity. Unified multimodal embeddings use a model (in the CLIP family) that maps both images and text into a single shared vector space, so a text query and an image are directly comparable and a text query can retrieve a relevant chart or photo by meaning — true cross-modal search that preserves visual nuance because the image itself is embedded, with no lossy intermediate. Convert-to-text instead generates a textual description of each non-text element — captioning images, linearizing tables into text — and then runs ordinary text RAG over those descriptions; it's simpler to build, reuses your entire existing text retrieval stack, and makes everything human-readable, but the caption is a lossy bottleneck that can't capture every value in a chart or every relationship in a diagram, so detail is lost at indexing time. In practice many systems combine the two — unified embeddings for high-fidelity cross-modal recall plus generated text for interpretability and as a complementary retrieval signal — and fuse the results, because each covers the other's weakness.

  3. Why must the generator be a vision-language model and not a text LLM with captions?

    Because the defining capability of multimodal RAG is answering questions whose answer is in the pixels, and only a model that actually receives and reasons over those pixels can do that reliably. If you retrieve the correct chart but then hand a text-only LLM merely a caption or extracted text about it, the model is working from a lossy summary that cannot convey every value, axis, and trend in the chart, every spatial relationship in a diagram, or the precise content of a photo — so questions like "what was the exact Q3 figure in this chart?" or "what does this diagram show connecting A and B?" get vague or wrong answers. A vision-language model is given the real images alongside the text and can visually read a value off a chart, interpret a diagram, or describe an image, producing an answer genuinely grounded in the visual content, with citations back to the source figures. Captions and extracted text still have roles — they help retrieval and can serve as a fallback — but for precise visual reasoning the answer model must see the actual content, which is what separates true multimodal RAG from text RAG dressed up with extra preprocessing.

  4. What extra plumbing does moving images (vs text) introduce, and how do you manage its cost?

    Unlike text RAG, multimodal RAG has to move actual image assets through the pipeline — into ingestion and, crucially, into the model's context at generation time — which introduces storage and cost concerns text doesn't have. You keep the original images in durable object storage and store, alongside each embedding in the vector index, a reference back to that asset plus modality and location metadata, so that after retrieving by vector you can fetch the real pixels to pass to the vision-language model. The cost pressure is significant because images are large and VLM vision tokens are expensive — sending many high-resolution images into a single generation can be far costlier than text — so you're deliberate about it: store and pass sensibly-sized resolutions, crop to the relevant figure rather than the whole page, cap how many images go into any one answer, retrieve tightly so you only involve visuals that are actually needed, and invoke the VLM's vision path only when a retrieved chunk is genuinely visual. You also cache popular assets and, where users view images, serve them via CDN as in any media system. In short, the asset store and references are the plumbing that gets real pixels from index to model, and right-sizing plus limiting image count is how you keep the expensive vision path affordable.

  5. What are the main failure modes unique to multimodal RAG?

    Several hard corners come specifically from mixing modalities. The modality gap is the tendency of image and text embeddings not to align perfectly even in a shared space, which can bias retrieval toward one modality (say, always returning text and rarely surfacing the relevant figure); you mitigate it with better multimodal models, hybrid unified-plus-convert-to-text retrieval, and explicit modality balancing so results include the right mix of figures and text. Tables and charts are awkward because they're neither pure image nor clean text — some questions need the exact numbers (favoring structured extraction) and others need the visual form (favoring the image) — so the robust approach is to keep both a structured/text representation and the original image for each. Cost is a persistent concern because vision tokens are pricey, so you retrieve tightly, right-size and crop images, and use the VLM's vision capability only when a visual chunk is actually involved. And evaluation is genuinely harder than for text RAG: you must measure whether the answer is truly grounded in the retrieved visuals rather than hallucinated from the model's priors, and assessing visual grounding is more difficult and less standardized than checking text grounding. The through-line is that the visual world is richer and messier than text, so multimodal RAG deliberately accepts more cost and complexity in exchange for answering questions that text-only systems simply cannot.

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. Text-only RAG fails on rich documents because…

    If the answer lives in a figure, there was no faithful text to embed or retrieve.

  2. To make an image retrievable by a text query you use…

    A shared embedding space or a shared text representation makes modalities comparable.

  3. The multimodal index must additionally store…

    You retrieve by vector, then fetch the real image to feed the generator.

  4. The answer must be generated by…

    Only a model that truly sees the pixels can read a chart or interpret a diagram precisely.

  5. A cost concern unique to multimodal RAG is…

    Retrieve tightly, crop/right-size images, and use vision only when a visual chunk is needed.

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.

  • Ingest: parse rich documents into typed multimodal chunks — text, images/figures, tables, charts — with layout and asset references.
  • Embed: map images and text into a comparable space (unified embeddings and/or convert-to-text) so a query can find visual content.
  • Retrieve cross-modal: a text or image query surfaces the most relevant chunks in any modality.
  • Generate: hand the actual retrieved pixels to a vision-language model that answers from what it sees, with citations.
  • Serve assets: store the originals durably and pass right-sized images into generation.

The qualities that shape everything

Each one names the mechanism that buys it.

Nothing visual is lost at ingest
Layout-aware parsing into typed chunks (text, image, table) that keeps structure and cross-references, not a flat OCR text stream.
A query can find a chart by meaning
Unified multimodal embeddings (CLIP-style shared space) and/or convert-to-text descriptions make images and text comparable.
Generation can fetch the real image
Every vector keeps a durable link to its source asset in object storage, so retrieval hands the model real pixels, not just an embedding.
Retrieval never needs a modality guess
One nearest-neighbor search over a comparable space returns the relevant chunks regardless of modality — a text query surfaces charts, an image query surfaces figures.
The answer is grounded in the pixels
A vision-language model receives the actual retrieved images and reasons over them, citing the source figures — not a lossy caption.
Vision cost stays affordable
Right-size and crop images, cap images per answer, retrieve tightly, and invoke the VLM’s vision path only when a chunk is genuinely visual.

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.

Multimodal retrieval over text-only RAG over OCR

OCR flattens or drops a chart’s trend, a diagram’s spatial relations, and a table’s structure. If the answer lives in a figure, text-only never had it to retrieve — you must handle the modalities themselves.

Unified embeddings and/or convert-to-text over embedding only extracted text

Text-only embedding is blind to visuals. A shared image+text space (or generated descriptions) makes images retrievable — unified preserves nuance, convert-to-text reuses text infra; real systems fuse both.

A vision-language generator over a text LLM working from captions

A caption can’t convey every value in a chart or relation in a diagram. Only a model handed the real pixels can read a value off the chart — captions are a lossy shadow.

Keep both a table’s structure and its image over picking one representation

Some questions need exact numbers (favoring structured extraction), others the visual form. Tables and charts are neither pure text nor pure image, so store both and let retrieval choose.

Right-sized, capped images over passing full pages at full resolution

Vision tokens are expensive and images are large. Cropping to the relevant figure and limiting count per answer keeps the vision path affordable without losing what matters.

The answer, out loud

What a strong answer to “Design a Multimodal RAG System” 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

    Name what text-only RAG never had

    I'd start by pinning down what makes this different from ordinary RAG. The documents here aren't prose — they're reports with bar charts, manuals with wiring diagrams, pages of tables and screenshots and scans. The number someone is asking about lives in a figure. So the question isn't can the model recall this, it's did anything in our pipeline ever represent that figure at all. In a text-only pipeline the honest answer is no, because extraction and OCR flatten or drop the exact part that carries the meaning. That splits the job into two abilities I want to keep apart all the way through: being able to find visual content, and being able to read it. Plenty of designs solve one and quietly assume the other, so as I go I'll say which piece buys me which.

  2. 3–8 min

    Why OCR alone is not enough

    The tempting shortcut is to OCR everything and run normal RAG, and I want to say out loud why I'd reject it. A chart communicates a trend through its geometry. A diagram communicates spatial relationships. A table's meaning is in its rows and columns, and naive extraction turns that into a stream where you can't tell which value belongs to which header. None of that survives as text. And the failure doesn't look like a failure — you still get chunks, scores and a fluent cited answer, just built from the prose beside the figure instead of the figure.

    Built in step 1: Why plain RAG isn't enough
  3. 8–15 min

    Parse into typed chunks

    So ingestion is where I'd start building. I'd parse each document with a layout-aware parser rather than raw OCR, and have it emit typed chunks — text blocks, images and figures, tables, charts — keeping the layout and the cross-references, so a caption stays attached to its figure and a table stays a table. Every chunk keeps a reference back to its source asset and where it sat on the page. That reference is what the rest of the design leans on, so I'd get it right here: if a chunk can't name the pixels it came from, generation has nothing to look at later.

    Built in step 2: Multimodal ingestion
  4. 15–22 min

    Make images and text comparable

    Then the real decision — how does a text query find an image at all. Two ways. Unified multimodal embeddings put images and text in one shared space, so the query vector and the chart vector are directly comparable, which is true cross-modal search with nothing lossy in between. Or convert-to-text: caption the images, linearise the tables, and run ordinary text RAG over the descriptions. That's simpler, but the caption is the bottleneck — it can't carry every value in a chart. If I could only ship one first it'd be convert-to-text, because it rides on retrieval machinery I already have and I can read a caption myself when an answer goes wrong, which I can't do with a vector. Then I'd add the unified path for the precise questions captions keep missing, and fuse.

    Built in step 3: Embedding: unified vs convert-to-text
  5. 22–28 min

    Index the vectors, keep the pixels

    Those vectors go into a vector store, and I'd tag each one with its modality and a durable link to the original asset in object storage. The modality tag is what lets me filter or balance results later. The asset link is the part that doesn't exist in text RAG at all — retrieval finds a vector, but generation needs the real image, so the index has to hand me back actual pixels rather than just a number.

    Built in step 4: Multimodal index
  6. 28–34 min

    One query, any modality

    At query time I embed the question into that same shared space and run nearest-neighbour search, and because everything is comparable I never have to guess the modality first. A text question can surface a chart; an image query can surface similar figures, or the text that describes them. Then I'd rerank and deliberately balance the mix, because I usually want the key figure and the prose around it, not five more paragraphs. Once the ranking settles, fetch the assets for the chunks I'm actually going to show the model.

    Built in step 5: Cross-modal retrieval
  7. 34–40 min

    Hand the model the pixels

    Generation is a vision-language model, and this is the part I'd defend hardest. I hand it the actual retrieved images alongside the text and ask it to answer from what it sees — read the value off the chart, interpret the diagram — and cite the source figures. A text-only model working from captions can't do that; it's reasoning about a lossy shadow. It's also the one piece with no graceful fallback. If the vision path isn't available, answering from the text around the figure isn't a weaker version of the answer, it's a different and confident one — so for a visual question I'd rather the system said it can't answer that right now. That one swap, a model that sees, is what separates this from text RAG with extra steps.

    Built in step 6: Generation with a vision-language model
  8. 40–45 min

    What it costs, and what I would do next

    Which leaves cost, and the useful thing to say is that the bill has two halves that behave nothing alike. The corpus half — parsing and embedding every page — is paid up front and paid again in full whenever the parser or the embedding model changes, so I'd version both and treat a swap as a scheduled backfill, never a config change. The per-answer half is the vision tokens, and that one is set by how much of the page I send. The trade-off, plainly: more moving parts and more money per answer, in exchange for questions a text-only system simply cannot answer. With more time I'd go at the modality gap and at evaluation, because those are the two places I'd expect this to be weakest and I'd want numbers on both before putting it in front of anyone.

    Built in step 7: Storing and serving the originals

What this teaches

Learn AI system design by building a multimodal RAG system that answers questions grounded in images, charts, tables and PDFs step by step. An interactive guide covering why text-only RAG loses visual information, parsing documents into multimodal chunks, unified multimodal embeddings vs convert-to-text, cross-modal retrieval, generation with a vision-language model that actually sees the content, asset storage, and the unhappy paths (modality gap, tables/charts, VLM cost, evaluation).

Key takeaways

  • Text-only RAG loses everything visual — charts, diagrams, photos, and table structure that OCR flattens.
  • Parse documents into typed multimodal chunks (text, images, tables) with layout and asset references.
  • Make modalities comparable via unified multimodal embeddings (shared space) and/or convert-to-text — often both.
  • Store vectors with modality tags and durable links back to the original assets.
  • Retrieve cross-modally: one query (text or image) finds the relevant chunks in any modality.
  • Generate with a vision-language model that receives the actual pixels and answers from what it sees, cited.
  • Store/serve originals deliberately (right-size, cap per answer); mind the modality gap, tables, VLM cost and eval.

Concepts covered

  • What is multimodal RAG?
  • Why plain RAG isn't enough
  • Multimodal ingestion
  • Embedding: unified vs convert-to-text
  • Multimodal index
  • Cross-modal retrieval
  • Generation with a vision-language model
  • Storing and serving the originals
  • Modality gap, tables, cost & eval
RUN IT YOURSELF

The 0.59 head start that makes every figure unretrievable

One shared embedding space, a text half and an image half, running for real in your browser — and then step 5’s promise implemented literally: one nearest-neighbour search over everything. It prints what that search returns (0 figures out of 72 slots), then merges the two per-modality lists three ways — +raw, +z, +rrf — and prints top-1 recall split by whether the answer lives in prose or in pixels. Set MODALITY_GAP = 0.0, hit Run, and watch a retriever that was working all along start winning.

HOW TO READ THE CODE — 5 IDEAS
  1. Every vector is a unit semantic part plus a per-modality offset m. The denominator works out identical for both modalities, so the whole difference is an m² term in the numerator — a constant 0.59 every text chunk collects and no image can earn. That is step 8’s modality gap as arithmetic.
  2. It is not the retriever. The gold figure is rank 1 of its own modality on 6 of 6 visual queries, and the chart holding the answer scores 0.245 while the paragraph beside it — which contains no number — scores 0.724 and wins. Fluent, cited, wrong.
  3. +z is scale-free and rescues all six visual queries at this depth, then loses 2 of 6 textual ones: it divides by the list’s spread, so a retriever with nothing to say still shouts its best junk to the top. The mean and spread come from the cut, and that is the whole rescue — visual recall runs 0.83 / 1.00 / 1.00 / 0.00 at depth 3/6/10/20, so at depth 20 +z loses all six. +raw and +rrf are flat at every depth.
  4. +rrf is what step 3 recommends, and it is the one to distrust here: a chunk has one modality, so the two lists are disjoint and nothing ever sums. Rank 1 against rank 1 is the identical 1/(60+1) on 12 of 12 queries — sort the ids the other way and visual recall goes 0.83 → 0.17. RRF assumes the lists overlap.
  5. No score fusion fixes this. What step 5 actually asks for is a modality quota over the ranked list, plus per-modality recall — the “all 12” row reads 0.50 while the visual row reads 0.00.
CPython · WebAssembly
built to answer from the chart, not just the caption — make the calls, blind the model, 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