Hallucination Triage for RAG: Wrong API Versus Wrong Advice Classes

Hallucination Triage for RAG: Wrong API Versus Wrong Advice Classes

“The bot hallucinated” is not a root cause. Senior RAG debugging separates wrong API (invented symbols/paths), wrong advice (real APIs, bad guidance), and wrong chunk (retrieval miss) because each class has a different fix. Blindly stuffing more context into the prompt wastes money and often makes overreach worse.

⚡ TL;DR: Tag every bad answer as missing_chunk | bad_rerank | stale_index | model_overreach | prompt_leak; map each to a concrete remediation; require citations so wrong-API cases fail closed. Use with Citation-Required RAG and RAG Evaluation.

The triage taxonomy

Class What you see Primary fix
missing_chunk Correct answer exists in repo; not in top-k Chunking, rewrite, filters, index coverage
bad_rerank Right chunk in top-20, not top-5 Reranker / hybrid weights
stale_index Answer matched deleted/renamed code Sync freshness, tombstones
model_overreach Citations OK but advice extrapolates Tighter prompts, refuse gaps, smaller temp
wrong_api Invented method/path Citation validator refuse + dictionary
prompt_leak Answer follows issue/tracker injection Sanitize inputs, guardrails
type HallucinationClass =
  | "missing_chunk"
  | "bad_rerank"
  | "stale_index"
  | "model_overreach"
  | "wrong_api"
  | "prompt_leak";

function classify(bug: BugReport, retrieved: Chunk[], answer: GroundedAnswer): HallucinationClass {
  const expect = bug.expect_paths;
  const inTopK = retrieved.some((r) => expect.includes(r.path));
  const inTop5 = retrieved.slice(0, 5).some((r) => expect.includes(r.path));
  if (answer.claims.some((c) => !retrieved.find((r) => r.path === c.path))) return "wrong_api";
  if (!inTopK && bug.still_in_git) return "missing_chunk";
  if (!inTopK && !bug.still_in_git) return "stale_index";
  if (inTopK && !inTop5) return "bad_rerank";
  if (bug.injection_markers) return "prompt_leak";
  return "model_overreach";
}

Wrong API vs wrong advice

Wrong API is a grounding failure: the model named PaymentClient.chargeAll that never existed. Fix with structured citations + validation (citation-required), not with a bigger context window.

Wrong advice cites real files but recommends async where the module is sync-only, or skips a mandatory auth check. Fix with:

# Separate eval slices
slices = {
  "wrong_api": golden_where(expect_reject_invented_symbols=True),
  "wrong_advice": golden_where(expect_policy_constraints=True),
  "retrieval": golden_where(expect_paths=True),
}

Playbook per class

missing_chunk  → rewrite + metadata filters + chunk boundaries; re-embed
bad_rerank     → cross-encoder / weight sweep; don't raise k blindly past 30
stale_index    → webhook sync SLA; show index git_sha in UI
model_overreach→ lower temperature; require open_questions; refuse
wrong_api      → JSON schema + citation ⊆ retrieved; hard refuse
prompt_leak    → sanitize Jira/Slack; Bedrock Guardrails

Avoid the “add top-20 chunks” reflex for every bug class — you increase overreach and cost for problems that are really sync or citation bugs.

Incident template

## RAG bad answer
- Question:
- Class: (taxonomy)
- Retrieved paths (k=10):
- Cited paths:
- Index git_sha / KB sync time:
- Fix PR / prompt version:
- Eval case ID added: yes/no

Every production complaint should graduate into a golden eval item—otherwise you only fix folklore.

Closing checklist

Dos
– Classify before changing prompts or k
– Split wrong-API vs wrong-advice eval slices
– Enforce citations to kill wrong-API classes
– Show index freshness in the UI for stale_index
– Add a golden case for every prod miss

Donts
– Do not treat all hallucinations as “model too small”
– Do not raise k as a universal remedy
– Do not skip triage in favor of anecdote-driven prompt edits
– Do not ignore prompt injection from trackers
– Do not close bugs without an eval fixture

Related reading

Last updated on September 11, 2026


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply