The Research Agent That Cited the Wrong Page

Every source was real and had been read. Two citations still pointed at the wrong page — one at a source that disagreed. Attribution is a lookup, and generation isn't a lookup.

A research agent produced a well-structured brief with eleven citations. Nine were correct. One pointed at a page that discussed the topic but didn't contain the claim. One pointed at a page that contradicted it.

The agent hadn't invented the sources — every URL was real and had genuinely been fetched during the run. The failure happened at a specific, identifiable point, and it's the characteristic failure of retrieval-plus-synthesis agents: attribution drift.

Where the drift happens

Reconstruct the run. The agent searched, fetched eight pages, and accumulated their content in context. It then wrote a synthesis drawing on all of them.

At synthesis time, the model holds eight documents and produces a claim. The claim is a blend — informed by several sources, phrased in the model's own words. Then it must attach a citation. Nothing in the context marks which document produced which idea, because that association was never recorded anywhere; it existed only implicitly in how the model composed the sentence.

So the citation is chosen the same way everything else is: by plausibility. The model picks the source that most resembles the claim's topic. Usually that's the right source. Sometimes it's the neighbouring one that discussed the same topic differently — including one that disagreed.

The insight worth carrying: citation is a retrieval task being performed by a generation process. It goes wrong exactly where you'd expect a fuzzy match to go wrong.

Why it's hard to notice

Wrong citations survive review better than wrong claims. The claim is usually true — it came from somewhere real — so a reader checking accuracy finds nothing wrong. Checking attribution means opening every link and searching for the specific claim, which nobody does at eleven citations per brief.

The contradicting-source case is the dangerous one. A reader who follows that link sees a page arguing the opposite and concludes the whole brief is unreliable, which is a harsher verdict than the work deserves and hard to recover from.

Bind the claim to the source at extraction time

The fix is structural: stop asking the model to remember provenance and make it record provenance as it goes.

Extract before you synthesize. After each fetch, run a small extraction step that produces atomic, attributed claims:

{ claim: "The service tier limits requests to 60 per minute",
  source_url: "…/pricing",
  quote: "Standard tier: 60 requests/minute",
  fetched_at: "2026-08-25T14:02Z" }

Now the association is data, not memory. Synthesis consumes these records, and each carries its own attribution.

Require the quote, and verify it mechanically. The extraction must include a verbatim span from the source. Then check it in code: if the quote isn't a literal substring of the fetched document, discard the record. This catches paraphrase-drift at the point it happens, cheaply, without a model in the loop.

Cite the record, not the URL. Have the synthesis reference claim IDs — [c17] — which the loop expands into a citation. The model is choosing among a small set of structured records rather than free-associating a URL, and any claim with no ID attached is visibly uncited.

Keep an explicit contradiction step. Before synthesis, scan the extracted claims for pairs that conflict on the same subject. Surface them rather than blending them. A brief that says "sources disagree on the rate limit: A says 60/min, B says 100/min" is more valuable than one that silently picks a side — and blending is precisely how the contradicting-citation case arises.

🔍 Auditing an existing research agent

Take twenty citations from recent output and check each one for the specific claim — not the topic, the claim. Sort the failures:

  • Right source, claim slightly reshaped → your synthesis is drifting from the extract. Tighten to quote-backed claims.
  • Adjacent source on the same topic → provenance was lost before synthesis. Extract-then-synthesize fixes it.
  • Source doesn't support it at all → the claim came from parametric knowledge, not the documents. This one needs a hard rule: every claim must map to an extracted record or be marked unsourced.

What it costs

An extra model call per fetched document, and a synthesis step reading structured records instead of raw pages — often cheaper, since extracts are far smaller than full documents. For a research agent, this usually reduces total tokens while improving attribution, which makes it one of the rare changes with no real trade-off.

The takeaway

An agent that fetches real sources and produces true claims can still attribute them wrongly, because attribution is a lookup and generation isn't a lookup. Record the claim-to-source binding at extraction time, require a verifiable quote, cite record IDs rather than URLs, and surface disagreement instead of averaging it. Then a citation means what a reader assumes it means.

Keep reading

Similar posts

Matched on shared tags and category — the more bars, the stronger the overlap with what you just read.