{"id":478,"date":"2026-07-19T05:05:03","date_gmt":"2026-07-19T05:05:03","guid":{"rendered":"https:\/\/abrarqasim.com\/blog\/llm-context-window-anti-hallucination-prompt-backfired\/"},"modified":"2026-07-19T05:05:03","modified_gmt":"2026-07-19T05:05:03","slug":"llm-context-window-anti-hallucination-prompt-backfired","status":"publish","type":"post","link":"https:\/\/abrarqasim.com\/blog\/llm-context-window-anti-hallucination-prompt-backfired\/","title":{"rendered":"LLM Context Windows: The Anti-Hallucination Prompt That Backfired"},"content":{"rendered":"<p>Short version for the impatient: the line I bolted onto my RAG prompt to stop hallucinations, &ldquo;If the answer isn&rsquo;t in the context, say you don&rsquo;t know,&rdquo; was quietly costing me correct answers. If you want to know why, read on.<\/p>\n<p>I found this out the annoying way. I had a support bot pulling from about 40 pages of product docs stuffed into a single long context window. It worked fine on my test questions. Then a teammate asked it something whose answer was plainly sitting in paragraph three of the docs, and the bot said &ldquo;I couldn&rsquo;t find that in the provided material.&rdquo; The fact was right there. I&rsquo;d read it myself thirty seconds earlier. I spent the next hour convinced my retrieval was broken. It wasn&rsquo;t. My prompt was.<\/p>\n<p>A paper that landed on arXiv this month put a name to what I&rsquo;d been fighting, so I stopped guessing and started measuring. Here&rsquo;s what I learned, and what I actually changed.<\/p>\n<h2 id=\"what-the-needle-test-actually-measures\">What the needle test actually measures<\/h2>\n<p>The classic way people check whether a model can use a big context is the needle-in-a-haystack test: bury one specific fact somewhere in a huge blob of text, then ask about it. If the model finds it, the context window &ldquo;works.&rdquo; Vendors love quoting near-perfect scores on this.<\/p>\n<p>The problem is that a single clean needle in an otherwise irrelevant haystack is not what your production data looks like. Real corpora have facts scattered across many documents, near-duplicates, half-relevant passages, and contradictions. The recent paper &ldquo;<a href=\"https:\/\/arxiv.org\/abs\/2601.02023\" rel=\"nofollow noopener\" target=\"_blank\">Not All Needles Are Found<\/a>&rdquo; builds an extended version of the test that varies where facts sit and how they&rsquo;re distributed, then runs it across Gemini 2.5 Flash, ChatGPT-5-mini, Claude 4.5 Haiku, and DeepSeek. Their headline finding is that reliability swings a lot depending on those conditions, even when the fact is definitely present.<\/p>\n<p>They separate three things most benchmarks smash together: pulling a fact out verbatim, reasoning over it, and the risk of making something up. Once you split those apart, the failure modes get much easier to see. And two of them are worth your attention.<\/p>\n<h2 id=\"the-safety-tax-nobody-warns-you-about\">The &ldquo;Safety Tax&rdquo; nobody warns you about<\/h2>\n<p>Here&rsquo;s the one that got me. The authors show that anti-hallucination prompts, the &ldquo;don&rsquo;t make it up, only answer from the provided text&rdquo; instructions we all paste in, can push a model into refusing to answer questions whose answers are actually present. They call it a Safety Tax. You told the model to be careful, so it got careful about everything, including the stuff it should have confidently returned.<\/p>\n<p>That matched my bug exactly. My prompt looked like this:<\/p>\n<pre><code class=\"language-text\">Answer ONLY using the context below. If the answer is not\nexplicitly stated in the context, respond with:\n&quot;I couldn't find that in the provided material.&quot;\n\nDo not use outside knowledge. Do not guess. Do not make\nanything up.\n<\/code><\/pre>\n<p>Read that as a nervous intern would. &ldquo;Explicitly stated&rdquo; is doing a lot of work. If the answer requires stitching two sentences together, or the phrasing in the docs doesn&rsquo;t match the phrasing in the question, a cautious model decides it wasn&rsquo;t &ldquo;explicit&rdquo; enough and bails. I&rsquo;d optimized for never being wrong and accidentally optimized for often being useless.<\/p>\n<p>The fix isn&rsquo;t to throw caution out. It&rsquo;s to stop conflating &ldquo;I&rsquo;m not certain this is stated word-for-word&rdquo; with &ldquo;this isn&rsquo;t here.&rdquo; Those are different claims, and the model will happily treat them as the same one if you let it.<\/p>\n<h2 id=\"distributional-collapse-or-why-dispersed-evidence-hurts\">Distributional collapse, or why dispersed evidence hurts<\/h2>\n<p>The second failure mode they document is what happens when the evidence you need is spread out instead of sitting in one tidy chunk. Performance drops when facts are dispersed across the context, even though nothing was removed. The model has all the pieces; it just struggles to pull them together and prioritize the relevant ones.<\/p>\n<p>If that sounds familiar, it should. Back in 2023 the &ldquo;<a href=\"https:\/\/arxiv.org\/abs\/2307.03172\" rel=\"nofollow noopener\" target=\"_blank\">Lost in the Middle<\/a>&rdquo; work showed models use information at the start and end of a long context far better than information buried in the middle. The new results say the position problem never fully went away, it just got more subtle. Bigger windows didn&rsquo;t make it disappear. They mostly made us stop checking.<\/p>\n<p>This is the part that changed how I think about retrieval. I used to treat a giant context window as a reason to be lazy: dump everything in, let the model sort it out. What the data says is that dumping everything in actively works against you when the answer depends on scattered evidence. Fewer, tighter, better-ordered chunks beat a wall of maybe-relevant text.<\/p>\n<h2 id=\"what-i-changed-in-my-prompts-and-my-retrieval\">What I changed in my prompts and my retrieval<\/h2>\n<p>Three concrete changes, in the order they helped most.<\/p>\n<p>First, I stopped forcing a binary. Instead of &ldquo;answer or refuse,&rdquo; I gave the model room to answer with a confidence signal. Something closer to:<\/p>\n<pre><code class=\"language-text\">Answer the question using the context below.\n\n- If the context directly supports an answer, give it.\n- If the context partially supports an answer, give your\n  best answer and note which part is uncertain.\n- Only say &quot;not covered&quot; if nothing in the context is\n  relevant at all.\n\nPrefer a useful, hedged answer over a refusal.\n<\/code><\/pre>\n<p>That last line matters more than it looks. It flips the default. The refusal is now the exceptional case, not the safe default the model reaches for under pressure.<\/p>\n<p>Second, I stopped stuffing the window. My retrieval used to return the top 20 chunks because I had the tokens to spare. I cut it to the top 6 and reranked them so the strongest evidence sits at the top, where the model actually reads carefully. My accuracy went up and my token bill went down, which is a rare combination. If you&rsquo;re doing retrieval at all, a reranking pass is the highest-leverage thing you can add, and I go deeper on the storage side of this in my <a href=\"https:\/\/abrarqasim.com\/blog\/pgvector-in-2026-why-i-deleted-pinecone-from-half-my-side-projects\" rel=\"noopener\">pgvector write-up<\/a>.<\/p>\n<p>Third, I started measuring refusals as their own metric. Not just &ldquo;was the answer right,&rdquo; but &ldquo;did the model refuse when it shouldn&rsquo;t have.&rdquo; That number was invisible to me before because a wrong refusal looks polite. It doesn&rsquo;t throw an error. It just quietly fails to help someone. If you only track accuracy on answered questions, the Safety Tax hides from you completely. I learned that lesson the hard way while building out evals, which I wrote about in <a href=\"https:\/\/abrarqasim.com\/blog\/llm-evaluation-metrics-what-i-trust-after-judges-failed-me\" rel=\"noopener\">what I trust after LLM judges failed me<\/a>.<\/p>\n<h2 id=\"when-a-strict-prompt-is-still-the-right-call\">When a strict prompt is still the right call<\/h2>\n<p>I don&rsquo;t want to oversell the fix. There are cases where you genuinely want the model to refuse rather than hedge. Anything touching medical dosing, legal citations, financial figures, or account actions should fail closed, not open. A hedged guess about someone&rsquo;s medication is worse than a refusal every time.<\/p>\n<p>So the real answer is that the &ldquo;don&rsquo;t make it up&rdquo; instruction isn&rsquo;t wrong, it&rsquo;s just unconditional in most people&rsquo;s prompts. You want it loud in the high-stakes paths and quiet in the low-stakes ones. Treating every question as if a wrong answer could get someone hurt is how you end up with a bot that refuses to tell you its own opening hours. The vendors&rsquo; own guidance on <a href=\"https:\/\/docs.claude.com\/en\/docs\/build-with-claude\/context-windows\" rel=\"nofollow noopener\" target=\"_blank\">context windows<\/a> is decent on the mechanics but light on this tradeoff, so you mostly have to tune it yourself.<\/p>\n<p>I spend a lot of my consulting time untangling exactly this kind of over-cautious pipeline, and it&rsquo;s usually one or two prompt lines doing the damage. If that&rsquo;s the sort of thing your team is stuck on, that&rsquo;s the <a href=\"https:\/\/abrarqasim.com\/work\" rel=\"noopener\">work I do<\/a>.<\/p>\n<h2 id=\"the-short-version-again\">The short version, again<\/h2>\n<p>If your long-context or RAG system is refusing questions whose answers are right there, look at your anti-hallucination instruction before you touch your retriever. Loosen the binary between &ldquo;answer&rdquo; and &ldquo;refuse,&rdquo; keep your strict mode for the paths that genuinely need it, and rerank so the good evidence sits where the model reads best. Then add one metric this week: count the questions your system refused that it should have answered. If you&rsquo;ve never measured that, I&rsquo;d bet money it&rsquo;s higher than you think.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>My long-context RAG bot kept refusing questions whose answers were right there. The fix was in my anti-hallucination prompt, not my retriever.<\/p>\n","protected":false},"author":2,"featured_media":477,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"","rank_math_description":"My long-context RAG bot kept refusing questions whose answers were right there. The fix was in my anti-hallucination prompt, not my retriever.","rank_math_focus_keyword":"llm context window","rank_math_canonical_url":"","rank_math_robots":"","footnotes":""},"categories":[4,520],"tags":[12,546,21,5,545,113,11,220],"class_list":["post-478","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai","category-llms","tag-ai-engineering","tag-context-window-2","tag-hallucination","tag-llm","tag-long-context","tag-prompt-engineering-2","tag-rag","tag-retrieval"],"_links":{"self":[{"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/posts\/478","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/comments?post=478"}],"version-history":[{"count":0,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/posts\/478\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/media\/477"}],"wp:attachment":[{"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/media?parent=478"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/categories?post=478"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/tags?post=478"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}