← All posts

Decoy passcodes: Qwen3.5-9B stays right at 454K tokens, Qwen3.5-4B mostly picks a decoy

I made the needle test harder. The haystack is now real math text instead of a repeated filler sentence, and besides the target passcode there are three decoy passcodes for other vault colors. The question asks for one color. The 9B answered correctly in all 4 runs, up to 454,278 tokens. The 4B was right in 1 of 4: at 704K and 512K it gave a decoy's passcode 3 times, even though it passed a single-needle test at 704K before.

ExperimentE21I
Date2026-10-29
BenchmarkRULER-style multikey needle: one target passcode sentence at 10%, 50% or 90% depth plus three decoy passcodes for other vault colors (near 25%, 60% and 80% depth), in shuffled paragraphs from the MATH training set. Greedy decoding, 512-token answer limit. A run passes only if the first code in the final answer, after any thinking block, is the target code.
ModelQwen3.5-9B and Qwen3.5-4B, Q4_K_M GGUF, flash attention on, q4_0 K and V cache, ubatch 64
HardwareOne of my dedicated test rigs: RTX 3080 10 GB
VerdictBASELINE

What I tested

My build of upstream llama.cpp PR 29827, "CUDA: cap FA convert buffer for quantized KV" (not my work, unmerged when tested). 9B at native 262,144 context (target at 50%) and 448K with YaRN x1.75 (10%, 50%, 90%). 4B at 704K with YaRN x2.75 (10%, 50%, 90%) and 512K with YaRN x2 (50%). Prompts were filled to the context size minus 1,500 tokens.

Pass bar, set before the run

None. Supporting measurement, plan written down before the run. A run passes if the target code is the answer; decoy picks are recorded.

Result

ModelContextDepthPrompt tokensAnswerPeak VRAMSharedPrefillTime
9B262K (native)50%255,660red code (pass)7,946 MiB116 MiB1,196 tok/s3.9 min
9B448K (YaRN x1.75)10%447,206blue code (pass)9,702 MiB140 MiB850 tok/s9.2 min
9B448K (YaRN x1.75)50%454,278green code (pass)9,702 MiB140 MiB845 tok/s9.4 min
9B448K (YaRN x1.75)90%449,169orange code (pass)9,704 MiB140 MiB852 tok/s9.2 min
4B704K (YaRN x2.75)10%709,568asked blue, gave the red decoy (fail)9,784 MiB170 MiB661 tok/s18.4 min
4B704K (YaRN x2.75)50%709,792asked green, gave the orange decoy (fail)9,786 MiB170 MiB661 tok/s18.4 min
4B704K (YaRN x2.75)90%709,515orange code (pass)9,784 MiB170 MiB661 tok/s18.4 min
4B512K (YaRN x2)50%514,510asked red, gave the orange decoy (fail)8,028 MiB146 MiB848 tok/s10.5 min

Fitting a long context in memory is not the same as using it. The 4B passed a single passcode at 704K in the previous round, but with three decoys around it, it gave the wrong vault's code in 3 of 4 runs.

In two of the three 4B failures it gave the orange decoy, which sits near 80% depth, the latest decoy in the prompt. Four runs are too few to call that a pattern.

After answering, the 9B kept writing extra question and answer pairs. It listed the decoy codes correctly and then made up codes for yellow and purple vaults that are not in the prompt. The 4B drifted into copying math text from the haystack.

The 704K prompts reuse the training paragraphs about 2 to 3 times (in a different order each pass), so the haystack has some repetition.

Shared GPU memory stayed between 116 and 170 MiB, under the 300 MiB line I use for counting a run as on the GPU. llama.cpp keeps the token embedding table and a small staging buffer in system memory.

Next round: the same test on the 4B at 128K to 512K to find where it starts to pick decoys, plus the 9B at 480K.

What happened

This round asked whether the models can pick the right fact out of a long prompt when similar facts compete with it. The 9B could: it found the asked-for passcode every time at 448K tokens, at the start, middle and end of the prompt. The 4B could not reliably: at 704K and 512K it mostly returned a passcode for a different vault. So for the 4B, the context that fits on the card is much longer than the context it can actually use. The memory saving that makes these runs fit is upstream PR 29827, so credit goes to its authors.

How to rerun

powershell -ExecutionPolicy Bypass -File e21i_chain.ps1

Code

All code for E21I: README.md, e21i_chain.ps1, results.jsonl.

Prior work

No novelty claim. This measures an existing upstream llama.cpp pull request with a standard RULER-style multikey needle test.

Written by Andrew Rose with help from AI tools. Every number comes from the run logs.

Questions or ideas? me@andrewroseit.com or @AndrewRoseIT.