Library// diagnostic

Adding one new source made unrelated answers worse

In short

A fixed top-k makes every ingest a zero-sum contest: a new source that ranks moderately well across many queries takes slots that previously belonged to something better, on questions that have nothing to do with it. Prove it with a candidate-set diff over a fixed question set — record which chunk ids fell out of the top-k — before touching a model, a chunker or a prompt.

Key takeaways

  • No old chunk's score changed. Only the company above it did, and k stayed the same.
  • The evidence is a chunk-id diff of candidate sets before and after, on one frozen question set.
  • Compare each source's share of chunks against its share of top-k slots. 3 times its share is the evictor.
  • Short chunks and conversational transcripts evict hardest, because both are dense on-topic surface.
  • Answer-level evaluation cannot see this. A 10-point recall drop can leave answer quality flat for weeks.
  • The durable fix is per-source retrieval budgets, not deleting the source that was legitimately added.

Nothing regressed in the sense people mean when they say it. The passages that used to win still score exactly what they scored last month. What changed is who is standing above them, and because the shortlist is a fixed size, every slot the new source takes is a slot something else loses. That is why questions with no relationship to the new material get worse answers on the day it lands.

The reason this is hard to believe is that the two events look unconnected. Someone ingested a product manual set on Tuesday, and by Thursday the HR policy answers are vaguer. There is no code path linking those, and there does not need to be one: they are competing for the same 8 slots in the same ranked list.

The eviction diff, which is the only evidence worth having

Everything else in this investigation is opinion. The diff is a fact, and if you did not capture the before state you can usually reconstruct it, because most stores let you filter by source or ingest timestamp.

  1. Freeze a question set of 40 to 60 real queries taken from logs, deliberately weighted towards areas the new source has nothing to do with. Invented questions defeat the purpose here — they use the vocabulary of whatever you were thinking about.
  2. For each question, record the ordered chunk ids and scores of the top-k as the application actually runs it. This is the before state. If you never captured it, re-run the same queries with a filter that excludes the new ingest batch — a source column in Postgres with pgvector, a term filter in Elasticsearch, a namespace in a dedicated store — and that reconstruction is close enough to be conclusive.
  3. Run the same set against the live index twice and diff the two after-runs against each other first. Approximate indexes such as HNSW can return slightly different candidates between identical runs, and if they already disagree you are looking at instability rather than eviction.
  4. Diff by chunk id, not by text. For each question, list the ids that were in the before top-k and are absent from the after top-k, and note which source each replacement came from.
  5. Count the evictions and attribute them. A handful of changes on questions near the new material is normal. Evictions on questions unrelated to it, all replaced by chunks from one source, is the finding.
  6. Check what the replacements are. Read the text of 10 evicting chunks. In most cases they are not wrong, merely generic — which is exactly why they win everywhere and help nowhere.
Diff resultReadingNext move
Few evictions, mostly on related questionsNormal competition. The new source is winning where it should.Nothing. Re-run the diff after the next ingest
Many evictions, one source doing the replacingEviction confirmed, single culpritRun the share test below, then apply a retrieval budget
Evictions spread across several sourcesThe shortlist was already marginal and this ingest tipped itk is too small for the corpus; widen the candidate stage and rerank
Same ids present, order shuffled, answers still worseNot eviction. The margin at the top has collapsedSee the instability case rather than the ingest
No diff at all, answers still worseRetrieval is unchanged, so the fault is downstream of itLook at synthesis, context assembly or a prompt or model change on the same day
What the diff shows, and what it licenses you to do

That fourth row is worth separating carefully. If the winning ids are the same but the order moves between runs, the top of your list is separated by rounding rather than meaning, and the symptom belongs to the same question returning different passages every run. Ingesting anything makes that worse, but the ingest is not the cause and removing it will not fix it.

What makes a source an evictor

Sources do not evict in proportion to their size. Four characteristics do the damage, and all four describe text that is broadly plausible for many questions rather than strongly relevant to any.

CharacteristicWhy it wins slots it should notSignature
Verbose boilerplateConfidentiality notices, headers and standard preambles repeat across thousands of documents and are mildly on-topic for anything phrased formallyThe same paragraph appears as evicting text under many different chunk ids
Near-uniform marketing copyWritten to be broadly appealing, so it sits near the centre of the topic space and is a mediocre match for everythingEvictions spread evenly across unrelated question areas
Meeting and call transcriptsConversational language matches question-shaped queries structurally, without containing the answerEvicting chunks read as somebody discussing the topic rather than stating anything
Chunks much shorter than the restA 120-token chunk is topically concentrated where an 800-token chunk is diluted, so it beats the longer one on similarity while carrying less informationThe new source's share of top-k slots far exceeds its share of chunks
Four source characteristics, the mechanism, and how each one shows in the diff

The last one is the most common and the least suspected, because it looks like a settings detail rather than a ranking decision. Ingesting a source at a materially different chunk size than the rest of the corpus changes the competition for every query in the index, not just for queries about that source. If the existing corpus is chunked at 600 to 800 tokens and a new export arrives at 100 to 150, the new source is not merely present, it is structurally advantaged.

The repairs, in the order that keeps the diagnosis intact

  1. Re-chunk the new source to the corpus norm and re-run the diff. If the eviction count falls by most of its value, you are finished, and this is a one-line configuration change rather than an architecture project.
  2. Give retrieval a per-source budget. Fetch a wider candidate pool and cap how many slots any single source may occupy in the final list. This preserves the new material's ability to win where it is genuinely best and removes its ability to win everywhere.
  3. Filter instead of ranking, where the query implies a scope. If a question is about HR policy, product manuals should not be candidates at all — the distinction between filtering and ranking is set out in metadata filters in a retrieval query.
  4. Widen k and rerank the longer list, rather than widening k into the prompt. A second arm scored with BM25 helps here too, because a keyword list is ordered on different evidence and does not concede slots to a source that is merely on-topic. The trade is laid out in more candidates versus reranking.
  5. Strip boilerplate at index time. Confidentiality footers and repeated headers should never have become candidates; removing them is cheap and helps every query permanently.
  6. Only then reconsider the index shape. Whether the new material belongs in its own index at all is a structural question answered in one index versus per-source indexes, and it is a bigger change than the four above.

A fixed top-k is a room with a fixed number of chairs. Nobody took a chair away from the old passages; somebody else simply sat down first, on questions they had no business answering.

Three responses that make it worse

  • Rolling back the ingest. It restores yesterday's numbers and teaches you nothing, and the source will be added again next quarter by someone who was not in this conversation. The arithmetic is a property of a fixed k, not of that source.
  • Changing the embedding model. It re-scores everything, invalidates every threshold that depended on the old score distribution, and does not alter the fact that the shortlist has a fixed size. It is the most expensive move available and it is aimed at the wrong mechanism.
  • Deleting the offending chunks by hand. This works for a fortnight and hides the structural problem, which returns with the next source that happens to be short and generic.

Three adjacent symptoms are worth ruling out first. If the queries that got worse are identifier-shaped — part numbers, clause references, codes — the diff shows absence rather than eviction: see queries with a part number or a clause reference coming back empty. If they are questions about figures in tables, those chunks were weak candidates long before the ingest, which is the number in a table the assistant cannot find. And if the new source contradicts an existing one rather than outranking it, that is a duplicate-content problem in the data layer, not a ranking contest between legitimate documents.

Make the diff a gate on ingest, not an investigation

The reason this failure survives for weeks is that answer-level evaluation cannot see it. A recall drop of 10 points at the candidate stage frequently leaves answer quality apparently flat, because the second-best passage often supports a defensible answer — right up until the question where it does not. By the time the complaint arrives, 3 more ingests have happened and nobody can attribute anything.

So run the frozen question set automatically on every ingest and compare candidate sets, not outputs. Fail the ingest when evictions on unrelated questions exceed a stated count, or when any source's slot share exceeds its corpus share by more than the multiple you have chosen. That is a small harness — a question file, a diff and a threshold — and exactly the sort of narrowly scoped internal tooling and operations software that pays for itself the first time it blocks a bad ingest.

One last symptom to connect. Where retrieval sits inside an agent loop rather than a single call, eviction does not present as a worse answer at all — it presents as a run that keeps searching, rephrasing and searching again because no result ever satisfies the step, which is one of the causes behind an agent run that never reaches a final answer. The gradual version of the same arithmetic, arriving over months instead of overnight, is retrieval degrading as the corpus grows. Both sit alongside this page in retrieval and grounding, within the wider engineering library.

Frequently asked questions

Short answers to the follow-ups this page tends to raise.

Why did adding documents change answers on unrelated questions?

Because the candidate list has a fixed size and every document competes for the same slots. A new source that scores moderately well on many queries will displace passages that used to win them, even though the subjects are unrelated. No old chunk's score changed; only its rank did, and rank is what decides what reaches the prompt.

How do I prove a new source is displacing good results?

Diff the candidate sets by chunk id over a frozen question set, before and after the ingest, weighted towards questions the new source has nothing to do with. Then compute each source's share of top-k slots against its share of chunks. A source occupying several times its share is displacing others, and that single ratio is more convincing than any amount of reading answers.

Should we remove the new source?

Almost never. It was added because someone needs it, and removing it restores the old numbers without addressing why a fixed shortlist could not absorb it. Cap how many slots any one source may take in the final list, match its chunk size to the rest of the corpus, and it will win where it is genuinely best and stop winning everywhere else.

Does chunk size really affect results for other sources?

Yes, because similarity scoring compares whole chunks. A short chunk concentrated on one idea scores higher against a narrow question than a long chunk covering the same idea alongside four others, so a source chunked much smaller than the rest is structurally advantaged across the whole index. Keeping chunk sizes broadly comparable is less about ideal length and more about a fair contest.

  • retrieval
  • ingestion
  • ranking
  • regression
// shipped work

The work behind this page

Builds from our portfolio that this page draws on.

Working on something in this space?

Tell us where you are in a sentence or two. We'll tell you honestly whether we're the right team, and what a sensible first slice of the work looks like.

Start the conversation