gpt-oss ignores its reasoning_effort setting

dgx-spark gpt-oss-120bMuse-Glimmer-30B

Both models on this machine ship a reasoning-effort dial. gpt-oss-120b defaults to reasoning_effort: medium, Muse Glimmer to reasoning_strength: high. Both live in the chat template rather than in an API parameter, so nothing in the request names a level and you benchmark whatever the template happens to say.

I set out to publish both curves. One of them turned out to be flat, and proving that it was genuinely flat — rather than that I had broken the experiment — took more work than measuring it.

20,000 questions later: gpt-oss’s dial does nothing, Muse Glimmer’s does a great deal, and the difference between those two sentences is the post.

The two curves

Identical harness, identical questions, 2,800 per arm.

low medium high
gpt-oss-120b 74.89% 74.25% 74.86%
tokens per question 523 524 524
wall clock 3.82 h 3.87 h 3.84 h
Muse Glimmer 30B 77.79% 78.11% 74.93%
tokens per question 339 501 612
wall clock 2.68 h 3.72 h 4.50 h

Across its entire effort range gpt-oss moves 0.64 accuracy points — a quarter of the ±2.28 interval — and 0.3% in generation volume. Muse Glimmer moves 3.18 points and 80%.

That is the whole finding. A model asked to think harder that generates one extra token per question is not thinking harder.

Ruling out the boring explanations

A null result is only worth publishing if you have eliminated the ways you could have produced one by accident. There were four.

Did the instruction reach the model? The chat template patch could have silently failed. I asked the server what it actually renders, using its own /tokenize and /detokenize endpoints:

<|start|>system<|message|>You are ChatGPT, a large language model trained by OpenAI.
Knowledge cutoff: 2024-06
Current date: 2026-08-16

Reasoning: high

It arrives.

Did lm-eval send something the server re-templated? If the harness applied the chat template client-side and sent the result as a message, vLLM would wrap it again and the model would read an inner system block with the old setting. It does not: with tokenized_requests=False the harness sends structured messages and the server templates once.

Could the measurement detect an effect at all? Generation volume across the four models on this machine spans 4× — 226 to 2,207 tokens per question. The instrument is not blind.

Was it too early to tell? This is the one I got wrong in public. Three subjects in, I said the null looked real. Then I noticed those three were biology, business and chemistry — recall-heavy subjects where deliberation should help least — and that math, physics and engineering had not run. I flagged it and waited. They ran. Nothing changed.

The positive control I did not plan for

The strongest evidence came from the other model. Muse Glimmer was measured on the same harness, the same benchmark, the same greedy decoding, the same five-shot prompting, the same machine, the same week — and its dial works.

Whatever might have suppressed gpt-oss’s setting would have to leave Muse Glimmer’s alone. Few-shot anchoring and greedy decoding both fail that test.

Subject (accuracy %) lowmediumhigh (default) Spread
engineering 73.0 70.0 62.0 11.0
biology 83.0 91.0 89.0 8.0
computer science 83.5 84.5 78.0 6.5
law 55.5 51.0 49.0 6.5
physics 86.0 82.5 80.0 6.0
chemistry 83.5 81.5 78.0 5.5
business 88.0 87.0 83.0 5.0
health 76.0 79.5 75.0 4.5
philosophy 70.5 74.5 75.0 4.5
math 86.5 90.0 87.5 3.5
other 70.5 71.0 67.5 3.5
history 69.5 68.5 66.5 3.0
psychology 81.0 81.0 78.0 3.0
economics 82.5 81.5 80.5 2.0
Muse Glimmer 30B, MMLU-Pro accuracy by subject at three reasoning_strength levels. 200 questions per cell, rendered from data/subject-sweep/ at build time.

Its shipped high default is also the worst of its three settings on both axes at once — a finding with its own post.

For contrast, the same table for gpt-oss:

Subject (accuracy %) lowmedium (default)high Spread
law 51.0 52.5 56.5 5.5
engineering 66.0 63.5 62.0 4.0
history 59.0 60.0 63.0 4.0
physics 86.0 82.0 83.0 4.0
other 68.0 64.5 66.5 3.5
business 84.5 81.5 83.0 3.0
economics 82.5 83.5 85.0 2.5
math 87.0 89.5 88.0 2.5
psychology 77.5 77.5 75.0 2.5
biology 84.0 83.5 82.0 2.0
philosophy 69.0 67.0 67.5 2.0
chemistry 80.0 80.5 81.0 1.0
computer science 82.5 82.5 83.5 1.0
health 71.5 71.5 72.0 0.5
gpt-oss-120b, MMLU-Pro accuracy by subject at three reasoning_effort levels. Same harness, same questions, same week.

The experiment that closed it

Two explanations survived the sweeps, and both were plausible enough to need killing properly rather than arguing away.

Few-shot anchoring — five worked examples demonstrate a chain-of-thought length, and the model imitates them over a one-line system directive. Greedy decoding — a one-word prompt change perturbs logits, but argmax snaps back to the same trajectory.

So: effort × shots × decoding, 2×2×2, on math (reasoning-heavy) and psychology (fast recall control), 200 questions per cell. The primary readout is tokens per question, because generation length averages over hundreds of long samples and is far more sensitive than a proportion.

math medium high Δ tokens
5-shot greedy 589 616 +4.7%
0-shot greedy 657 649 −1.2%
5-shot sampled 623 610 −2.1%
0-shot sampled 658 648 −1.5%
psychology medium high Δ tokens
5-shot greedy 226 230 +1.5%
0-shot greedy 270 270 −0.1%
5-shot sampled 233 223 −4.5%
0-shot sampled 275 280 +1.9%

Nothing moves anywhere. Largest single deviation 4.7%, mean −0.19%, signs scattered in both directions — noise, not a suppressed effect.

The ablation script refuses to run against a server that does not render the effort level it was told to expect. That check is the one I wish I had written before the first sweep rather than after.

One thing that did move

Few-shot prompting genuinely does anchor generation length — it just is not what suppresses the effort setting. Independent of effort, five-shot answers are 7.7% shorter on math and 15.4% shorter on psychology than zero-shot.

So the mechanism I suspected is real. It is simply not the culprit, which is the difference between a hypothesis and a finding.

What this means if you run gpt-oss

On vLLM 0.19.0 on this hardware, setting reasoning_effort is not doing anything. If you have been running it at high expecting better answers, you have been paying nothing and receiving nothing — the setting is free because it is inert.

Two things I am not claiming. I have not shown the dial is broken in gpt-oss itself; this is one serving stack at one version, and the same weights under a different runtime may behave differently. And I have not shown effort dials are useless in general — the model in the next column proves the opposite.

The narrow, defensible claim: an effort setting that arrives at the model and changes nothing is indistinguishable from one you never set, and you should verify yours rather than assume it. The check costs one request:

POST /tokenize   {"model": ..., "messages": [{"role":"user","content":"hi"}]}
POST /detokenize {"model": ..., "tokens": [...]}

If the rendered prompt does not contain the level you set, stop there. If it does, measure generation volume at two settings before trusting accuracy numbers — length is where an effect shows first, and where its absence is unmistakable.

Total run time

Arm What ran Questions Tokens generated Machine time
gpt-oss-120b, effort low 14 subjects · 3,072-token cap 2,800 1,464,288 3.8 h
gpt-oss-120b, effort medium (default) 14 subjects · 3,072-token cap 2,800 1,466,513 3.9 h
gpt-oss-120b, effort high 14 subjects · 3,072-token cap 2,800 1,468,672 3.8 h
Muse Glimmer, strength low 14 subjects · 3,072-token cap 2,800 949,561 2.7 h
Muse Glimmer, strength medium 14 subjects · 3,072-token cap 2,800 1,403,712 3.7 h
Muse Glimmer, strength high (default) 14 subjects · 3,072-token cap 2,800 1,712,298 4.5 h
Total 16,800 8,465,044 22.4 h
Machine time for all six arms, summed from data/subject-sweep/. Scoring time only.

Six full fourteen-subject sweeps, 16,800 questions, about 22 hours.

The run time is itself a result here. gpt-oss-120b’s three arms took 3.8, 3.9 and 3.8 hours — indistinguishable, because the model generated within 0.3% of the same volume at every effort level. Muse Glimmer’s three took 2.7, 3.7 and 4.5 hours, rising with the setting, because that model actually does more work when asked to.

A model that honours a reasoning-effort setting gets measurably slower as you raise it. That is the cheapest available check, and it disagrees with gpt-oss’s own documentation before any accuracy number is computed.

What this does not settle

One serving stack, one version. vLLM 0.19.0 via nvcr.io/nvidia/vllm:26.04-py3. Worth re-testing on a newer build.

One benchmark shape. MMLU-Pro is multiple choice with a known answer. A model that would think longer on open-ended generation might have nowhere to put the extra effort here — though the ablation’s zero-shot arms argue against that, since removing the answer-format scaffolding changed nothing.

Extraction failures are measured but not compared. 4.5% of gpt-oss’s answers in the logged run failed the extraction regex against 1.2% for Muse Glimmer. The default runs predate per-question logging, so I cannot compare failure rates across effort levels — if high failed extraction more often, some of the flatness could be two effects cancelling. Unlikely at these magnitudes, but unmeasured.

Setup