enable_thinking. Qwen3.5-2B closed the reasoning slot before generation began. MiniCPM5 left the model a choice. Qwen3.5-4B, in the same family, opened the slot. You could call the same function on all three and end up giving them different starting conditions.
I built a template auditor that renders those cases rather than guessing from the template text. It confirmed the mismatch. I then made the mistake I was supposed to be investigating: I saw a plausible explanation and started expecting the result to support it.
What I actually ran
top_k and presence penalty to check whether the shared sampler was costing it points.
The run took place in September on one RTX 4060 with 8 GB of memory. There were 259 attempts across four configurations. The score is avg@n: calculate accuracy within each problem, then average across problems. That matters because I changed the attempt count during the first stage. Dividing all correct attempts by all attempts would give the early problems more weight.
| Configuration | Attempts | avg@n | 95% interval |
|---|---|---|---|
| Qwen3.5-2B, thinking off | 79 | 17.5% | 7.5–29.2% |
| Qwen3.5-2B, thinking on | 60 | 11.7% | 3.3–21.7% |
| MiniCPM5-2B, thinking on | 60 | 71.7% | 56.7–85.0% |
| Qwen3.5-2B, its recommended thinking sampler | 60 | 15.0% | 5.0–26.7% |
My explanation didn’t survive
The answer was there. The ending wasn’t.
The parts I would do differently
\boxed{} expression, so it had to be fixed and the saved outputs regraded. One grade changed from wrong to correct. Four outputs remain flagged as uncertain because I had saved only the last 400 characters, which was not enough to regrade everything properly. The repository preserves the original result file.
I should have saved complete answers from the start. I should also have checked the vendor settings before the first full run rather than learning about them from the looping results. Early stopping assumes that a detected reasoning loop would not eventually recover. That is plausible, but I have not measured its recovery rate by rerunning those attempts without the stop.
Power cuts made the persistence code matter more than I had expected. Initially I saved results after an entire batch completed. Later I saved and flushed each attempt as it finished. A subsequent interruption then cost the answer in flight instead of the whole batch. That was a small engineering change with a very obvious benefit.
I also learned not to add up per-answer latency in a batched run and call it GPU time. Several answers were running concurrently. The stage timing comes from the wall-clock log, excluding the periods when the machine was off. The stages used different concurrency because MiniCPM5’s full-length sequences occupied more memory, so even those timings are the cost of this experiment on this machine rather than a clean speed comparison.