n4nAI

Why deep research agents hallucinate citations

Engineering analysis of why deep research agents invent sources: architectural mismatches between generation and retrieval, and how to enforce verifiable citations.

n4n Team4 min read926 words

Audio narration

Coming soon — every post will get a voice note here.

A deep research agent hallucinated citations because its architecture asks a language model to write prose and attach references after the fact, not before. The failure is systemic, not a model quirk: when synthesis precedes verification, the generator optimizes for fluency and the citations become decorative. If you are building agentic search and shipping answers to users, you need to treat citation integrity as a data-integrity problem, not a prompt-tuning exercise.

The core mismatch: generation before verification

Standard RAG pipelines retrieve chunks, stuff them in context, and prompt the model to “answer with citations.” This looks correct but inverts the dependency graph. The model produces a token stream left to right. It decides what to say before it has committed to which retrieved span supports it. Even with retrieval context present, the decoder assigns highest probability to sequences that sound authoritative. A citation marker like [1] is just another token, and nothing in the loss function penalizes attaching [1] to a sentence that the referenced chunk does not entail.

In a deep research agent that issues multiple tool calls across turns, the problem compounds. The agent may read ten pages, summarize them in its own memory, and then draft a final report from the summary. By the time the report is written, the original URLs are two hops away from the generated claim. The model is now citing from memory, and memory is not a citation.

How agentic pipelines lose provenance

Consider a typical research loop:

docs = vector_search(query, top_k=8)
summary = llm.summarize(docs, instruction="Extract key facts")
report = llm.generate(f"Write a report using these facts: {summary}")

The summary step is where provenance dies. The summarizer condenses eight documents into free text. Unless you force it to emit structured triples with source IDs, the linkage is lost. The report generator never sees the original chunks; it sees a plausible summary that may already contain drift.

Tool loops that don’t bind sources

A more sophisticated agent uses tools:

for step in range(max_steps):
    action = llm.choose_tool(state)
    if action == "search":
        results = web_search(state.query)
        state.add(results)  # appends text, not attributed spans
    elif action == "answer":
        return llm.generate(state.history)

If state.add stores raw text without anchoring each fact to a result ID, the final generate call cannot ground its output. The model will still emit [1] because the prompt told it to, but the index maps to a vanished context window.

Why the model itself is biased toward plausible fiction

Transformers are trained on text where citations are sparse and often post-hoc. Academic writing attaches references at the end; web text rarely cites at all. The prior in the weights says “produce confident statements.” When the agent is under retrieval pressure—say a query with few real sources—the model fills gaps with learned patterns of authority. A deep research agent hallucinated citations in our internal eval when the retrieval set was deliberately thin: it invented DOIs that matched the format of real ones but failed resolution.

This is not stupidity. It is the path of least resistance given the objective. Without a hard constraint, the model trades citation accuracy for narrative coherence.

Concrete failure modes

We logged three recurring patterns:

  1. Format compliance without semantic binding. The model outputs [1] Source: example.com but the claim preceding it is absent from that page.
  2. Index drift. In multi-turn search, the agent re-indexes results per turn. Citation [3] in the final answer points to turn-2 result 3, but the numbering was reset in turn 3.
  3. Summarized sources. The agent cites a secondary summary it wrote, not the primary document.

A minimal repro of index drift:

{
  "turn_1_results": [{"id": 1, "url": "a.com"}, {"id": 2, "url": "b.com"}],
  "turn_2_results": [{"id": 1, "url": "c.com"}],
  "final_answer": "Finding X [2]."
}

Here [2] is ambiguous: turn-1 id 2 or turn-2 id 2? The agent didn’t namespace.

Engineering defenses that actually work

Constrained decoding and span attribution

Force the model to emit citations as structured objects, not inline markers. Use a schema:

{
  "claim": "GPT-4 was released in March 2023.",
  "source_id": "doc_7",
  "span": "OpenAI announced GPT-4 on March 21, 2023"
}

Then render the report by joining claims. If a claim lacks a source_id that maps to a retrieved document, drop it or flag it. This shifts the burden from “model remembers to cite” to “pipeline rejects uncited claims.”

Separate verification pass

Run a second model call with the generated claim and the cited source, asking a binary question: “Does the source text entail the claim? Answer yes/no with quote.” This is cheaper than generation and catches most hallucinations. Route the generator and verifier as independent calls; if the verifier model is rate-limited, you want fallback.

When running a citation validator alongside the generator, routing both through a single OpenAI-compatible endpoint that addresses 240+ models with automatic fallback keeps the pipeline resilient if a provider degrades. You avoid a hard dependency on one vendor’s uptime for your trust layer.

Make citations first-class in state

Redefine agent state as a list of attributed facts:

class Fact:
    text: str
    source_url: str
    retrieved_at: int

state.facts.append(Fact(text=snippet, source_url=url, retrieved_at=now))

The generator receives only state.facts and is instructed to reference source_url inline. No re-indexing, no drift.

Tradeoffs: latency, cost, refusal rates

Strict attribution increases latency. A verification pass doubles model calls. Structured extraction may require a more capable (and expensive) model to format output reliably. You will also see refusal rates climb: agents that cannot find a source for a salient point will either stay silent or explicitly say “no source found.” That is correct behavior, but product teams often interpret it as lower recall.

The alternative—fluent reports with decorative citations—erodes user trust faster than a missing answer. We measured qualitatively that a single fabricated DOI in a research summary destroys credibility more than three “unknown” hedges.

Takeaway

Stop treating citations as a formatting instruction. A deep research agent hallucinated citations because the system let it generate first and ground later. Bind every claim to a retrieved span at creation time, namespace sources across turns, and verify with a separate model pass. The deep research agent hallucinated citations only when we skipped these constraints; with structured facts and a validator, the same models produced auditable output. Ship the constraint, not the hope.

Tagshallucinationcitationsdeep-researchreliability

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All deep research & agentic search posts →