RAGEngineering Hub
Chapter 5 · concept 2 of 4 · 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

What embeddings cannot do

Embeddings blur negation, numbers and codes, and an English model barely links Dutch to English. Measured sentence pairs show where, and what to add.

A real question

“Reset the router” and “Do NOT reset the router”. Does search know the difference?

Hardly. Their vectors scored 0.939: almost the same point. Embeddings capture what a text is about, not every small word that flips its meaning.

The problem

Why this matters

A vector understands the text as well as a reader does.
The belief

A vector understands the text as well as a reader does.

Negation, prices and error codes barely move the vector. EUR 20.00 against EUR 21.00 scored 0.942; E4012 against E4021 scored 0.970.
What really happens

Negation, prices and error codes barely move the vector. EUR 20.00 against EUR 21.00 scored 0.942; E4012 against E4021 scored 0.970.

Why not the simpler way

After RAG-19 it is tempting to use vector search for everything. Then a user asks about error E4021, gets the E4012 row, and the answer is confidently wrong. Or the system retrieves "Do not reset the router" for "should I reset the router?" and a careless prompt summarizes it as advice to reset. Knowing the blind spots tells you which other tools to add.

The idea

The idea in plain words

An embedding compresses a whole chunk into 384 numbers. Compression keeps the gist and drops detail. The detail it drops first is exactly what makes business text precise: a "not", a digit, a product code, a date, a language.

A photo taken from far away shows that a sign is a speed limit sign. It does not let you read whether it says 30 or 80.

How it works

Step by step

  1. “not”, “never”, “except” change the meaning completely, but they are one token among many.
    1

    Small words, big meaning

    “not”, “never”, “except” change the meaning completely, but they are one token among many.

  2. 2

    Numbers and codes blur

    The model sees “a price” or “an error code”, not which one. Near-identical values get near-identical vectors.

  3. Keyword search (BM25) matches the exact code or number. The answer model then reads the real words.
    3

    Add exact matching

    Keyword search (BM25) matches the exact code or number. The answer model then reads the real words.

In detail

Negation and qualifiers. Training pairs teach the model that texts on the same topic belong together. "Do" and "do not" sentences are on the same topic, so they stay close.

Numbers and identifiers. Tokenizers split codes like E4012 into pieces, and the model learns little about which pieces matter. Values that differ by one digit end up next to each other.

Language. A model trained mostly on English places Dutch text in a different region. Multilingual models are trained on translated pairs so both languages share one space; e5-small did that here at 0.894. The catch: that model also scored our unrelated pair 0.780, so its scores sit higher across the board.

Long text. Our model reads at most 512 tokens; anything after that is cut off before embedding (RAG-13).

Hybrid retrieval: the question is searched by keyword (BM25) and by meaning (vectors); reciprocal rank fusion merges the two ranked lists by position; the top 3 chunks go into the prompt.Question“E4012?”Keyword · BM25exact words, codesVector searchsimilar meaningFuse · RRF1 / (60 + rank)Top 3into the promptranked list Aranked list B
Fusion uses only each chunk's position in the two lists, so a BM25 score of 9.7 and a cosine of 0.67 never need to be compared.

The code

Try it in Python

PAIRS = [
    ("Reset the router when the power light is solid red.",
     "Do not reset the router when the power light is solid red."),
    ("Error E4012 means mesh pairing failed.", "Error E4021 means mesh pairing failed."),
    ("Claims must be reported within 30 days.", "Claims must be reported within 30 days, except for theft."),
]
for a, b in PAIRS:
    va, vb = model.encode([a, b], normalize_embeddings=True)
    print(f"{float(va @ vb):.3f}  {a[:40]!r} vs {b[:40]!r}")
# If opposite meanings score close to your real matches, add keyword search and a reranker.

See it

What we measured

Measured · cosine similarity of sentence pairs

Sentence pairs we wrote for this test, embedded as passages. Xenova/bge-small-en-v1.5 and Xenova/multilingual-e5-small, q8, normalized.

Paraphrase (restart modem / reboot router)e5: 0.870bge: 0.796
Negation (reset / do not reset)e5: 0.962bge: 0.939
Price (EUR 20.00 / 21.00)e5: 0.979bge: 0.942
Days (30 / 3)e5: 0.966bge: 0.898
Code (E4012 / E4021)e5: 0.978bge: 0.970
English / Dutch translatione5: 0.894bge: 0.602
Unrelatede5: 0.780bge: 0.391

Measured 2026-11-04 with corpus/scripts/measure-parts-4-7.mts. Pairs are hand-written, not from the corpus. Compare scores within one model only: e5 scores are higher for everything.

Try it on a real example

Pairs of sentences we wrote, scored with bge-small-en-v1.5

Pair

Pair

Reset the router when the power light is solid red.
Do not reset the router when the power light is solid red.

0.939. Opposite advice, almost the same vector. The real manual says “Do not”; only reading the chunk tells you that.

Choosing

Use it when, avoid it when

Use it when
  • Vector search to find the right topic and paraphrases
  • A multilingual model when questions and documents differ in language
Avoid it when
  • Vector search alone for codes, prices and dates
  • Trusting a summary of a chunk without the exact words

What it costs · Testing blind spots takes a list of pairs and a few minutes. The guards (BM25, filters, a reranker) are covered in Part 5.

In production

Test your blind spots with a small set of pairs from your own domain: codes, prices, negations, other languages. If a pair scores above your top results for real questions, plan a guard. Typical guards are keyword search fused with vector search (RAG-28), metadata filters for versions and dates (RAG-29), a reranker that reads query and chunk together (RAG-31), and a prompt that tells the model to quote the exact value.

Watch out

Common mistakes

  • Higher similarity means the same meaning. It means the same topic; opposite advice scored 0.939.
  • Vector search cannot find codes. On our corpus it found all 4 code questions in the top 3. It just cannot tell close codes apart.
  • A multilingual model is always better. It linked Dutch well, but its unrelated pair scored 0.780, so its thresholds need retuning.

Check yourself

Remember this

Remember these

  • Negation barely changes a vector: 0.939 for opposite advice.
  • Prices, dates and codes that differ by one character score above 0.9.
  • An English-only model links a Dutch translation weakly: 0.602.
  • Pair vector search with keyword search, filters and a model that reads the chunk.

Say it in an interview

  1. 01Embeddings capture topic, not exact meaning: a negated sentence scored 0.94 with the original.
  2. 02Codes and prices that differ by a digit score above 0.9, so I add BM25 for exact terms.
  3. 03An English model linked a Dutch translation at 0.60; a multilingual one at 0.89.
  4. 04I test blind spots with hand-made pairs from the domain before trusting vector search.
  5. 05Retrieval finds the neighbourhood; the reranker and the answer model read the exact words.

Quick quiz

Three questions

Question 1

Q1

"Reset the router" and "Do not reset the router" scored 0.939. What does that tell you?

Question 2

Q2

Why did the English bge-small give a Dutch translation only 0.602?

Question 3

Q3 · from RAG-19

How did we find the unrelated pair's similarity on our model?

Saved on this device. No account needed.