Repository navigation
fix(rag): count identical chunks once in a search and cite every copy - #7131
Conversation
A document indexed twice under different names filled the model's top-k with copies of itself, and the agent cited whichever copy was indexed first. The SDK search fetches more candidates until it has k distinct chunks and records every file holding each one (chunk_metadata source_files and source_paths). query_documents names the other files in also_in, and query_specific_file resolves a chunk inside the requested file, so a twin elsewhere cannot supply its page. Closes amd#4740
|
Verdict: Request changes This stops a document indexed twice under different names from filling the model's context with copies of itself: identical chunks now count once, the search fetches more until it has k different ones, and the agent cites every file holding the text. The approach is sound and well tested, but it opens one gap.
Real-world evidenceN/A: no evidence bundle was produced for this run. The verdict rests on static review and the author's test output: 7 new tests that fail on 🔍 Technical details🟡
For the test, mark one of the two policy files as left out (for example by patching Checked, no issue
Strengths
|
Identical chunks now collapse to one in a search, so when the copy the search kept belonged to a file left out of the search, the text vanished even though another file still being served holds it. A chunk now stays when any copy of its text sits in a served file.
Summary
A document indexed twice under different names no longer fills the model's context with copies of itself. Identical chunks now count once in a search, so the model gets k different chunks. Each collapsed chunk lists every file that holds it, and the agent cites all of them instead of whichever copy was indexed first.
Why
The
exact_duplicatehard case in #4733 found duplicates taking 40% of the top 5 chunks given to the model. As the bot noted on the issue, collapsing after FAISS's top-k cut would only trade crowding for a short context, so the search fetches more candidates until it has k distinct ones.Linked issue
Closes #4740
Changes
chunk_metadatagainssource_files/source_paths(every file holding the text), andquery_metadata["source_files"]includes them.source_file/source_pathstay as they were.query_documentscites every file holding the text:source_fileis the first, andalso_inlists the rest. It resolves positions in one pass instead ofrag.chunks.index()per chunk.query_specific_filelooks a chunk up only in the requested file, so a twin in another document can't supply the page number.meta['source'], a key that doesn't exist.Test plan
Run in a
python:3.12container:pytest tests/unit/rag/test_duplicate_chunks.py: 7 passed. All 7 fail onmain(a copy takes a place, a missing source, a citation from the wrong file).pytest tests/unit/rag tests/test_rag.py tests/unit/test_chat_rag_budget.py tests/unit/chat/ui/test_sse_handler.py: 1,341 passed, 35 skipped.pytest tests/unit: 38,405 passed, 584 skipped, 15 failed, of 38,908 collected, with no crashed workers. The 15 fail the same way onmainin this container: 14 shell-guardrail and skill-grant tests refuseghandnpmbecause neither is installed there, and one expects a folder it can't create, but the container runs as root. 44 tests have::inside their parameters, so they were rerun by file to account for them.python util/lint.py --all: passes. Pylint crashed in its parallel workers, so it was rerun alone with--jobs 1, which exits 0.The tool result the agent reads gains
also_in, sorag_qualityis the eval category to watch on the next RC.Evidence
The new tests index one policy under
policy.txtandpolicy (copy).txtbeside three other documents, in a real FAISS index:Checklist
Closes #N/Fixes #N/Refs #N).python util/lint.py --all,pytest tests/unit/).