Course · Part 3, Memory · Lesson 3.3 · 14 min

Knowledge retrieval: the answer grounded in the wrong document

The answer cited a real page from a real policy document; the document had been superseded a year earlier and the index did not know.

Before you read: find the line

Read the run below once. Decide which line is the mistake. The lesson tells you.

Help agent answering a policy question from an index
  1. 1userHow long do I have to return a laptop I bought online?
  2. 2llmsearch(q="laptop return window online purchase", k=3)
  3. 3tool[1] returns-policy-2023.pdf p2 "Laptops may be returned within 30 days of delivery" 0.81 [2] returns-policy-2025.pdf p1 "Laptops and tablets: 14 days from delivery" 0.79 [3] faq.md "Keep your receipt for any return" 0.62
  4. 4llmanswer: "You have 30 days from delivery to return a laptop [1]."
  5. 5toolsend_reply(body=answer) -> sent
  6. 6donestatus: success, citations: 1

What broke

A help agent answers policy questions from the company's documents. It searches an index, takes the top chunks, writes an answer, and cites the chunk it used. That last part was supposed to make it safe. A customer asked how long they had to return a laptop. The agent answered 30 days and cited returns-policy-2023.pdf, page 2. The current policy, in force since January 2025, says 14 days for laptops and tablets. The customer came back on day 21 with the chat transcript.

The answer was grounded. It was cited. It was wrong. Look at line 3 of the trace: the 2023 chunk came back first with a score of 0.81, the 2025 chunk second at 0.79. Both were in the index. Nothing marked one as current.

Why it broke

Retrieval is a pipeline and each stage can fail on its own. Chunking cuts documents into pieces of a few hundred tokens. If a chunk loses its heading, it loses the fact that it belongs to the 2023 policy. Ranking scores chunks by similarity to the question: by embedding, by keyword (BM25), or both. Similarity does not know about dates. A superseded page that uses the same words as the question scores as well as the current one, and often better, because old pages are longer and repeat themselves. Citation then points at whatever won. A citation proves the model did not invent the text. It does not prove the text is the right text.

Anthropic measured one piece of this in 2024. Adding a short context line to each chunk before indexing, with embeddings and BM25 together, cut the top-20 retrieval failure rate by 49 percent, and adding a reranker on top cut it by 67 percent. That is the chunking stage and the ranking stage, each improved on its own. Neither would have fixed this run, because the 2023 page is a good match for the question. This run needed a filter.

The field splits on how much of this to do with embeddings and how much with plain metadata. My view: anything with a date, a version or an owner is metadata and belongs in a filter, not in the vector.

What a senior engineer does

Fix the index before the prompt. Every chunk carries its document id, the document version, an effective date, and a current flag. Ingestion sets current to false on the old version when the new one lands. The retriever filters on current=true by default, and a separate query lets a person ask about history on purpose. That is the one line fix for this run.

Then make chunks carry their context: the document title and section heading go at the top of every chunk, so a piece of the 2023 policy says so in its first line. Use hybrid ranking, keywords and embeddings together, and rerank the top 20 with a cross-encoder when latency allows. Take fewer chunks into the prompt, three to five, and put them before the question (Liu et al. 2023 for why position matters).

Then measure retrieval on its own. Keep a set of 40 to 50 questions with the chunk that should win, labeled by hand, and track recall at 5 after every index change. The generation step gets a different check: does the answer use the cited chunk and only the cited chunk. When the two checks disagree you know which stage to open.

What to say in the interview

"Line 3. The index held two versions of the policy and ranked by similarity, so the superseded one won and the citation made it look safe. I would add an effective date and a current flag to every chunk, filter before ranking, and keep a labeled set to measure recall." Then name the three stages, chunking, ranking, citation, and say which one this bug lives in. Interviewers for RAG roles want to hear that a citation is not a correctness check.

The line

Help agent answering a policy question from an index
  1. 1userHow long do I have to return a laptop I bought online?
  2. 2llmsearch(q="laptop return window online purchase", k=3)
  3. 3tool[1] returns-policy-2023.pdf p2 "Laptops may be returned within 30 days of delivery" 0.81 [2] returns-policy-2025.pdf p1 "Laptops and tablets: 14 days from delivery" 0.79 [3] faq.md "Keep your receipt for any return" 0.62
  4. 4llmanswer: "You have 30 days from delivery to return a laptop [1]."
  5. 5toolsend_reply(body=answer) -> sent
  6. 6donestatus: success, citations: 1

Line 3. Both versions of the policy sat in the index with no date and no current flag, so the ranker scored them on words alone and the old page won by two hundredths. The model used the top chunk and cited it, which is what it was told to do. The citation looks like a safety check and is not one. The fix is upstream: a filter on current=true before ranking, and ingestion that retires the old version.

The pause

The answer at line 4 cited a real chunk. Why is that not enough, and what one field on each chunk would have prevented this run?

In the interview

“Your RAG system gave a confident, cited answer that was wrong. How do you find out which stage failed, and what do you change?”

Say your answer out loud, in under a minute. Then compare.

Notes