RAGEngineering Hub
Chapter 6 · concept 3 of 3 · show all
  1. 1What RAG is, and why
    1. 1.1Why models need outside knowledge, and what hallucination means
    2. 1.2What RAG is: anatomy of a request
    3. 1.3RAG vs fine tuning vs long context and prompt caching
    4. 1.4Use cases and the quality, latency and cost triangle
    5. Chapter overview
  2. 2Tokens, cost and your first RAG
    1. 2.1Tokens and context windows for RAG
    2. 2.2The RAG lifecycle and your first RAG in miniature
    3. Chapter overview
  3. 3Getting documents in
    1. 3.1Content sources and file formats
    2. 3.2Parsing, layout and OCR
    3. 3.3Tables, images and mixed content
    4. 3.4Cleaning, normalization and quality gates
    5. 3.5Metadata, document identity and versioning
    6. 3.6Updates, deletes, reindexing and ingestion pipelines
    7. Chapter overview
  4. 4Chunking
    1. 4.1Why we chunk, and the main chunking strategies
    2. 4.2Structure aware chunking and tables
    3. 4.3Chunk size, overlap and token based sizing
    4. 4.4Contextual chunking and late chunking
    5. 4.5Parent child and multi representation indexing
    6. 4.6Chunk metadata, provenance and the chunking debugging playbook
    7. Chapter overview
  5. 5Embeddings
    1. 5.1Embeddings and similarity from first principles
    2. 5.2What embeddings cannot do
    3. 5.3Choosing an embedding model: size, cost, language
    4. 5.4Embedding model migration and index rebuilds
    5. Chapter overview
  6. 6Vector stores and scores
    1. 6.1Vector databases, ANN indexes and choosing a store
    2. 6.2Score calibration and thresholds
    3. 6.3Late interaction and multivector retrieval
    4. Chapter overview
  7. 7Finding the right chunks
    1. 7.1Query understanding, rewriting and expansion
    2. 7.2Dense retrieval and keyword search with BM25
    3. 7.3Hybrid retrieval and rank fusion
    4. 7.4topK, no good match, and metadata filtering
    5. 7.5Routing, diversity, deduplication and caching
    6. 7.6Reranking: two stage, cross encoder and LLM rerankers
    7. Chapter overview
  8. 8When retrieval fails
    1. 8.1Retrieval failure analysis playbook
    2. Chapter overview
  9. 9Building the answer
    1. 9.1Context selection, packing and citations
    2. 9.2Grounding prompts and abstention
    3. 9.3Lost in the middle and context management
    4. 9.4Conflicts, staleness and freshness rules
    5. 9.5Hallucination checks and answer verification
    6. 9.6Conversational RAG, answer UX and RAG APIs
    7. Chapter overview
  10. 10Measuring
    1. 10.1Why measure, and what to measure
    2. 10.2Building a golden dataset
    3. 10.3Retrieval metrics: precision, recall, MRR, nDCG
    4. 10.4Faithfulness and answer correctness
    5. 10.5LLM as judge, and judging the judge
    6. 10.6Offline and online evals, regression tests and slices
    7. Chapter overview
  11. 11Safety and operations
    1. 11.1Prompt injection and poisoned documents
    2. 11.2Access control, privacy and governance
    3. 11.3Index lifecycle operations
    4. 11.4Observability and tracing
    5. 11.5Latency, cost, caching and model routing
    6. 11.6Reliability, degraded modes and launch readiness
    7. Chapter overview
  12. 12Scale and advanced RAG
    1. 12.1Scaling, multi tenancy and enterprise architecture
    2. 12.2Choosing an architecture: naive, advanced, agentic, graph
    3. 12.3Agentic RAG and RAG as an MCP tool
    4. 12.4GraphRAG, structured data and multimodal RAG
    5. Chapter overview

Late interaction and multivector retrieval

Instead of one vector per chunk, keep many (per sentence, or per token as in ColBERT) and score by the best match. We tested the sentence version; it used 12 times the vectors for the same result.

A real question

A chunk talks about five things. Can one vector stand for all five?

One vector is an average, and the one sentence you need gets diluted. Multivector retrieval keeps a vector per sentence, or per token, and scores a chunk by its best match.

The problem

Why this matters

More vectors per chunk always find more answers.
The belief

More vectors per chunk always find more answers.

We stored one vector per sentence: 405 vectors instead of 33. Recall stayed at 44 of 47. It helps when chunks are long and mixed; ours are short and on one topic.
What really happens

We stored one vector per sentence: 405 vectors instead of 33. Recall stayed at 44 of 47. It helps when chunks are long and mixed; ours are short and on one topic.

Why not the simpler way

A 512-token chunk of a policy might cover scope, exceptions, deadlines and contacts. Its single vector is a blend of all four. A question about the deadline has to compete with that blend. Smaller chunks are one fix (RAG-15); keeping several vectors per chunk is another.

The idea

The idea in plain words

Single-vector (bi-encoder) retrieval: one vector per chunk, one per query, one dot product. Multivector retrieval: many vectors per chunk, scored by how well the best pieces match. Late interaction is the token-level version: query and document are encoded separately (so documents can be indexed ahead of time), and they "interact" only at search time, token by token.

A book's back cover summarizes the whole book. Its index lets you find the one page that mentions your word.

How it works

Step by step

  1. Embed each sentence, or in ColBERT each token, separately. A chunk now has many vectors.
    1

    Split into pieces

    Embed each sentence, or in ColBERT each token, separately. A chunk now has many vectors.

  2. Compare the question with every piece and keep the best (MaxSim). ColBERT sums the best match for each query token.
    2

    Score by best match

    Compare the question with every piece and keep the best (MaxSim). ColBERT sums the best match for each query token.

  3. 3

    Pay for it

    Storage and compute grow with the number of pieces. Systems compress the vectors and search in two passes.

In detail

Sentence MaxSim (what we tested): split each chunk into sentences, embed each, and give the chunk the highest sentence score. Simple, and it works with any embedding model.

ColBERT (Khattab and Zaharia, arXiv 2004.12832): a model trained to output a vector per token. The score is the sum, over query tokens, of each token's best match in the document. ColBERTv2 and PLAID compress the token vectors and use a first pass over centroids to keep it fast.

Multi-representation is a cousin: index a summary, a few hypothetical questions or the title as extra vectors pointing to the same chunk (RAG-17).

The code

Try it in Python

import re

def sentences(chunk: str) -> list[str]:
    return [s for s in re.split(r"(?<=[.!?])\s+|\n+", chunk) if len(s.strip()) > 20]

pieces = [(i, s) for i, c in enumerate(chunks) for s in sentences(c)]
piece_vecs = model.encode([s for _, s in pieces], normalize_embeddings=True)

def maxsim_search(q_vec, k=3):
    best = {}
    for (i, _), v in zip(pieces, piece_vecs):
        best[i] = max(best.get(i, -1.0), float(v @ q_vec))
    return sorted(best, key=best.get, reverse=True)[:k]

See it

What we measured

Measured · evidence recall@3

Polder corpus, 34 recursive 512 token chunks, bge-small. Sentence split on . ! ? and line breaks, sentences under 20 characters dropped. Chunk score = best sentence cosine.

One vector per chunk33 vectors44 of 47
One vector per sentence (MaxSim)405 vectors44 of 47

Measured 2026-11-04 with corpus/scripts/measure-parts-4-7.mts. ColBERT itself was not measured.

Try it on a real example

Same 34 chunks, 47 questions, bge-small

Vectors
1.33 vectors · 44 of 47Each chunk is one average of its meaning.✓

The baseline.

Choosing

Use it when, avoid it when

Use it when
  • Long, mixed-topic chunks you cannot make smaller
  • Cases where a reranker is too slow and recall is still low
Avoid it when
  • Short, single-topic chunks: no dilution to fix
  • Adding it before a reranker, which is easier to try

What it costs · Storage and embedding work grow with the number of pieces: 12 times here for sentences, more for tokens.

In production

Token-level indexes are several times larger than single-vector ones, and need a store that supports them. Try multivector when chunks are long, cover several topics, or when single-vector search ranks the right document low and smaller chunks are not an option. Measure against a reranker first (RAG-31): a reranker also reads token by token, only over the top candidates, and needs no new index.

Watch out

Common mistakes

  • Late interaction means late chunking. Late chunking (RAG-16) pools token vectors into one vector per chunk; late interaction keeps them separate.
  • Multivector is always better. It matched single-vector exactly on our corpus.
  • It needs a new embedding model. The sentence version works with the model you already have; ColBERT needs its own.

Check yourself

Remember this

Remember these

  • One vector per chunk averages everything the chunk says.
  • Multivector keeps many vectors and scores by the best match.
  • ColBERT does this per token, with compression to keep it affordable.
  • On our short chunks, 12 times the vectors gave the same 44 of 47.

Say it in an interview

  1. 01A single vector averages a chunk; multivector keeps many and scores by the best match.
  2. 02ColBERT does it per token with MaxSim and compresses the vectors to stay affordable.
  3. 03On my corpus, one vector per sentence used 405 vectors instead of 33 for the same 44 of 47.
  4. 04It pays off for long mixed chunks; I would try a reranker first.
  5. 05Late interaction keeps token vectors; late chunking pools them.

Quick quiz

Three questions

Question 1

Q1

How does a multivector score a chunk?

Question 2

Q2

What happened when we stored one vector per sentence on our corpus?

Question 3

Q3 · from RAG-22

Binary vectors plus rescoring is an example of what pattern?

Saved on this device. No account needed.