# What reasoning_effort actually does on DeepSeek, OpenAI, Anthropic and Gemini: one name, five physics, and a five-line test

> Set one reasoning_effort for every provider and you get five different bills. Read against vendor docs, a Zenn effort ladder and a gateway vendor's probe, the same value is passed through on one surface, converted into a token budget by somebody else's table on another, honoured to the token here, accepted and ignored there, and rejected with a 400 elsewhere. DeepSeek's V4.1 Flash report publishes an effort-to-score-to-token curve; the Zenn ladder shows GPT-6 Astra's top gear scoring lower for 1.9× the cost. Check the reasoning-token count in usage with the five-line loop below.

- Published: Sep 11, 2026
- Updated: Oct 12, 2026
- Author: Leo Kaka, Engineering
- Tags: gateway, cost, providers
- Canonical: https://pirouter.ai/blog/reasoning-effort-one-name-five-physics

---
`reasoning_effort` does one of five things depending on where you send it, and the HTTP
status does not tell you which. On an OpenAI-compatible surface the string is forwarded as
sent. Through a translator it is converted into a thinking-token budget by a table you did
not write, so `medium` is 8,192 tokens on one path and 2,048 on another. On Qwen, GLM and
DeepSeek a numeric budget is honoured to the token. On Kimi K3 and MiniMax M3 the field is
accepted, ignored and billed. On GPT-5.6, on Claude 4.7 and later, and on Gemini Pro, the
wrong spelling is rejected with a 400. That is why the same value costs different amounts:
it is a name, not a unit. **A 200 tells you the JSON was accepted, not that the value reached
the model.** The reasoning-token count in `usage` is a practical check, and the last section
is a five-line loop that reads it.

Scope first. There are no measurements of mine in this post. What there is: DeepSeek's V4.1
Flash technical report; a Zenn effort ladder and a gateway vendor's thinking-control probe,
with their sample sizes in the sections below; a separate Zenn check of async tool calling;
and the four vendors' documentation read field by field. We build a gateway,
so we write both sides of this translation and know where each side is tempted to lie. The
previous post listed reasoning state as item 4 of the seven things a translator cannot hide
([One API for OpenAI, Anthropic and Google models](/blog/one-api-openai-anthropic-google)).
This is that item unfolded.

## What DeepSeek's V4.1 Flash report says effort buys, and what it costs

DeepSeek publishes an effort-to-score-to-token curve in §5.3.3 and Figure 9
([DeepSeek V4.1 Flash Technical Report](https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/resolve/main/DeepSeek_V41_Tech_Report.pdf)).
The dial is an integer from 1 to 100. DeepSeek reports that raising it from 25 to 100
moves the average Pass@1 over eight reasoning benchmarks from 67.1% to 76.3%, DeepSWE v1.1
from 66.0% to 74.2% and Terminal-Bench 2.1 from 82.4% to 90.6%, "at the cost of roughly
2.5× more output tokens."

![Three line charts from DeepSeek's V4.1 Flash technical report: Pass@1 (solid) and mean output tokens (dashed) against reasoning effort from 25 to 100, for eight reasoning benchmarks averaged, DeepSWE v1.1 and Terminal-Bench v2.1. Accuracy and token count rise together on all three; the output-token line steepens after 80.](/blog/images/reasoning-effort-one-name-five-physics-effort-curve.png "Fig. 1 — DeepSeek's own effort curve: Pass@1 (solid, left axis) and mean output tokens per response (dashed, right axis) as the effort value runs from 25 to 100. The public API exposes three points on it: 50, 75 and 100. Source: [DeepSeek V4.1 Flash Technical Report, Figure 9](https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/resolve/main/DeepSeek_V41_Tech_Report.pdf)")

Two details matter more than the headline. First, the gains are front-loaded: "the 60–80 range already recovers most of the accuracy of the maximum setting
at less than half of its token budget, whereas the final step to effort 100 lengthens agent
trajectories by 1.6–1.8× for only marginal improvements." Second, Appendix B.3 gives the
token side in absolute numbers. From 25 to 100 the mean response grows 2.0–3.1× on every
reasoning benchmark, "from 4.6k to 11.4k tokens per response on AIME 2026 and from 29.1k to
86.1k on MathArena Apex 2025," and accuracy never degrades as effort rises. MathArena Apex
gains 40.3 points, 25.3% to 65.6%. On a dataset where the answer takes 86k tokens, the dial
does what the name says.

How the dial works is in §5.1.4, and it decides what "effort" is. The value is text. The
training run prepends `Reasoning Effort: {effort} (range 1–100; higher values request more
thorough reasoning)` to the system prompt, then applies a length penalty whose coefficient
decays exponentially with the requested effort. Appendix C states the consequence: the
scalar is "a deployment-time control over the cost–quality trade-off without imposing a hard
token budget." DeepSeek's dial is a learned posture, not a cap, which is why the curve is
smooth and why, further down, a probe on a much smaller task sees almost nothing move.

The API exposes three points on the curve, not the curve: Table 2 maps `max`, `high` and
`low` to 100, 75 and 50, and the 25 setting in the figure is not a public tier. The docs
fold every other spelling onto those three: `minimal` becomes low, `medium`
becomes high, `xhigh` becomes high, `ultra` becomes max, with thinking on by default at
high ([Thinking Mode — DeepSeek API Docs](https://api-docs.deepseek.com/guides/thinking_mode)).
If your config says `medium` because that is what it says for OpenAI, DeepSeek runs it at
75, which is what it would have run without the parameter. The same page notes that in
thinking mode `temperature`, `presence_penalty` and `frequency_penalty` "will not trigger an
error but will also have no effect." The vendor that documents effort most transparently
ignores three other parameters on the same request, silently: one API, two of the five
physics at once.

Cost: the top tier against the 25 setting is about 2.5× the
output tokens, which is 2.5× the output bill. At the Flash off-peak output price of $0.60
per million tokens ([Models & Pricing — DeepSeek API Docs](https://api-docs.deepseek.com/quick_start/pricing)),
an 86k-token MathArena answer is about five cents and the 29k-token one at effort 25 is
under two. Cheap per call; a 2.5× multiplier on every step of an agent loop is not. The
report's own advice is that the maximum tier "is best reserved for the most challenging
tasks."

## A Zenn author's ladder on GPT-6 Astra: the top gear scored lower and cost 1.9× more

On 9 September a Zenn author published the effort ladder for GPT-6 Astra, in a benchmark
series that delegates a small Godot game implementation to a child model and grades the
result with 57 hidden tests
([Zenn — godot-llm-gamebench: how gpt-6-astra changes with effort (ja)](https://zenn.dev/oubakiou/articles/faa33490272980)).
Four effort levels, three runs each, twelve runs in all; the parent agent fixed at
claude-opus-5 at max effort, the child running on Codex CLI. Three runs per cell is an
indication, not a measurement. Costs are at the list
prices the author used, $10 per million input, $1 cached, $50 output.

| Effort | Mean score | Std. dev. | Median time | Child cost | Median output tokens |
|---|---|---|---|---|---|
| `low` | 90.88 | 7.08 | 6.5 min | $0.990 | 7.1k |
| `medium` | 91.76 | 5.77 | 7.6 min | $0.981 | 8.2k |
| `high` | 100.00 | 0.00 | 14.6 min | $1.597 | 15.1k |
| `xhigh` | 97.54 | 0.00 | 21.1 min | $2.969 | 29.9k |

Three readings. `high` scored 100 three times out of three, the first condition in the
series to do so, and the author calls it the series' best score. `xhigh` scored lower, and
not by noise: all three runs land on 97.54 with the same two hidden tests failing, standard
deviation zero, which the author describes as a reproducible regression specific to that
level. And `low` and `medium` are one gear with two labels: $0.990 against $0.981, 0.88
points apart, with `low` passing more hidden tests (55.0 of 57 against 53.0). On this task,
then, the dial has three useful positions, not four, and the ceiling is `high`. Code
quality, judged separately, went the other way, 4.42 against 4.25; if you want readable
code rather than passing code the top gear is arguable.

The bill tracks the tokens: child cost goes 3.0× from `low` to `xhigh` as median output
tokens go 7.1k to 29.9k. And the cross-model line from the same post: astra at `high` beats
gpt-5.6-luna at `high` by 1.23 points on the combined score at 35.5× the child cost, $1.597
against $0.045. Astra used fewer input tokens, 434k against 689k; a 50× input price does
not care. The author says this task is probably too easy to show what the expensive model
is for. It still shows what `xhigh` is for, which on this evidence is nothing.

OpenAI's guide is consistent with every line of that table. Effort values are
"model-dependent and can include none, minimal, low, medium, high, xhigh, and max"; GPT-6
Astra "does not support none reasoning effort" and returns HTTP 400 if you send it; GPT-5.5
defaults to medium; and the closing advice is to "Treat reasoning.effort as a tuning knob,
not the primary way to recover quality"
([Reasoning models — OpenAI API](https://developers.openai.com/api/docs/guides/reasoning)).
The same page says function calling with Astra is Responses-only, which a second Zenn author
confirmed the next day while measuring Astra's async tool calling, with `reasoning.effort`
set to `low` throughout
([Zenn — what GPT-6 Astra waits for: async tool calling and mid-turn steering, measured (ja)](https://zenn.dev/peoplex_blog/articles/65768c769de4b0)).
So on OpenAI the enum is a real gear, the set of gears is model-specific, and the top gear
is not the best one.

## Five physics: what happens to the value after the 200

Put the vendor pages, two gateway docs and one probe on one table and the parameter sorts
into five behaviours. ✓ means the meter moves as you asked, ⚠ that it moves by somebody
else's table, ✗ that the value never reached the model, whether the call was billed or
refused.

| # | Physics | Where it is written down | What the reasoning-token count does |
|---|---|---|---|
| a | ✓ Passed through as an enum | OpenAI-compatible surfaces; one gateway: "forwarded to the provider as sent," neither validated nor guaranteed | Moves, if the model has that tier |
| b | ⚠ Translated into a token budget | Google's OpenAI compatibility: `low` / `medium` / `high` → 1,024 / 8,192 / 24,576 on Gemini 2.5; one gateway on Anthropic: 2,048 / 8,192 / 16,384 / 32,768; LiteLLM on older Claude: 1,024 / 2,048 / 4,096 | Moves, in steps the translator chose |
| c | ✓ Honoured to the token | A 13-model probe, August 2026: `thinking_budget: 16` burned exactly 16 on Qwen 3.8 Max, GLM 5.2 and DeepSeek V4 | Equals what you sent |
| d | ✗ Accepted and ignored | Same probe: Kimi K3 burned 8 to 97 against a cap of 16, MiniMax M3 18 to 44; Anthropic's OpenAI-compatible layer lists `reasoning_effort` as Ignored; GLM ignores `reasoning_effort` per a client's provider notes | Flat, billed anyway |
| e | ✗ Rejected with 400 | GPT-5.6 rejects numeric budgets; Claude 4.7 and later reject `budget_tokens`; Gemini Pro rejects every off spelling; Astra rejects `none`; Qwen and DeepSeek reject a budget of 0 | Nothing to meter |

Each row with its source.

**(a) Passed through.** The plainest statement is in a gateway's own mapping doc: on
OpenAI-compatible upstreams the value is "Forwarded to the provider as sent - the gateway
neither validates the value nor guarantees the provider honours it"
([reasoning_effort on an AI Gateway: Per-Provider Behaviour](https://synthorai.io/docs/guides/reasoning-effort/)).
A second gateway states the same policy from the other end: "Effort tiers are never
downgraded by the gateway: providers that accept an effort parameter receive the value
unchanged (unsupported values result in a provider error)"
([Reasoning — LLM Gateway Docs](https://docs.llmgateway.io/features/reasoning)). Pass-through
is the honest default. It also means `xhigh` in an OpenAI-shaped config is DeepSeek's
`high`, OpenAI's `xhigh`, and a provider error anywhere the word does not exist.

**(b) Translated.** Google publishes its table. Through the OpenAI-compatible endpoint,
`minimal` and `low` both become `thinking_budget: 1024` on Gemini 2.5, `medium` becomes
8,192 and `high` 24,576; on the Gemini 3 line the same words become `thinking_level` values
([Gemini API — OpenAI compatibility, Thinking](https://ai.google.dev/gemini-api/docs/openai?hl=en)).
One gateway's Anthropic mapping is `low` / `medium` / `high` / `xhigh` / `max` → 2,048 /
8,192 / 16,384 / 32,768 tokens, clamped to stay under `max_tokens` and "skipped entirely
when max_tokens cannot fit Anthropic's 1,024-token minimum"
([reasoning_effort on an AI Gateway: Per-Provider Behaviour](https://synthorai.io/docs/guides/reasoning-effort/)).
LiteLLM's table for older Claude models, which the previous post read, is 1,024 / 2,048 /
4,096 ([LiteLLM — Anthropic, Usage - Thinking](https://docs.litellm.ai/docs/providers/anthropic#usage---thinking--reasoning_content)).
So `medium` is 8,192 thinking tokens on Google's path and on one gateway's Anthropic path,
and 2,048 on LiteLLM's: same string, four-fold difference, all documented, none wrong. The second gateway clamps whatever it derives to
1,024–128,000 on Anthropic and lets an explicit `reasoning.max_tokens` override the word
([Reasoning — LLM Gateway Docs](https://docs.llmgateway.io/features/reasoning)).

A note on a claim you may have read: that LangChain's Anthropic integration turns
`reasoning_effort` into a budget as a ratio of `max_tokens`, 0.1 for minimal up to 0.8 for
high. I read langchain-anthropic at 1.5.0, 1.5.3 and 1.6.0. `reasoning_effort` is typed as
`max | xhigh | high | medium | low` and written straight into `output_config["effort"]`; if
you did not set `thinking` yourself, the integration adds
`{"type": "adaptive", "display": "summarized"}` on models whose profile lists `xhigh`
([langchain-anthropic — chat_models.py](https://github.com/langchain-ai/langchain/blob/master/libs/partners/anthropic/langchain_anthropic/chat_models.py)).
No ratio, no clamp. It is physics (a), and Anthropic's enum is not a budget of anything,
which is the next section.

**(c) Honoured.** In August one gateway vendor's engineering team probed 13 models from
nine vendors with every thinking-control spelling the OpenAI-compatible surface accepts,
three runs per cell, measured on 11 and 12 August 2026
([LLM Thinking Controls: What 13 Models Accept, Ignore, or Enforce](https://synthorai.io/blog/llm-thinking-controls/)).
Their data, not mine, read through their own gateway, and their DeepSeek builds were V4
(the 0731 Flash and Pro), not V4.1. With `thinking_budget: 16`, Qwen 3.8 Max, GLM 5.2 and
both DeepSeek V4 builds burned exactly 16 reasoning tokens. Gemini Flash treated caps of 0
through 64 as off and let 1,024 through; Gemini Pro cut its burn under a cap but floored
around 200 against a requested 64. A budget enforced to the token is the only one of the
five physics where "budget" means what it means in accounting.

**(d) Accepted and ignored.** Same probe, and here it reports four runs rather than its
usual three: Kimi K3 burned 8, 19, 79 and 97 reasoning tokens against the same cap of 16,
never 16; MiniMax M3 burned 18 to 44, "billed as usual, with
nothing in the response hinting the cap had been dropped." Anthropic's own
OpenAI-compatibility page lists `reasoning_effort` under Ignored
([OpenAI SDK compatibility — Claude Platform Docs](https://platform.claude.com/docs/en/cli-sdks-libraries/libraries/openai-sdk)).
A third-party client's provider notes say GLM's endpoint "silently ignores" the field and
drives thinking only through `thinking.type`
([Reasoning controls by provider — DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix/blob/ee2ace1dbd3967d387ff50247e15e7fb53feaa0f/docs/REASONING_PROVIDERS.md)).
The probe's effort ladders show the same shape from the other side. On a five-step
arithmetic task, DeepSeek V4 read 78 reasoning tokens at `low` and 54 at `max`, Kimi 94 at
`minimal` and 67 at `max`, MiniMax between 61 and 93 in no order; GLM's `high` burned less
than its `low`. Flat lines and a zigzag. Only the two Geminis climbed, 137 to 390 on Flash
and 180 to 387 on Pro.

Mind the scale before you read that against DeepSeek's curve. A task that takes 50 to 100
reasoning tokens is not where the report says the dial operates; its curves start at 4.6k
tokens per answer, and the mechanism is a soft posture, not a cap. A flat probe on a trivial
task and a monotone vendor curve on hard benchmarks are both true. What the probe
establishes is narrower: at small task sizes several dials do nothing, and the bill does not
tell you.

**(e) Rejected.** Same probe: GPT-5.6 returned 400 for `thinking_budget` and for
`thinking: {"type": "disabled"}`; Claude Sonnet 5 and Opus 5 returned 400 for
`budget_tokens`; Gemini 3.1 Pro returned 400 for every off spelling; Qwen and DeepSeek
rejected a budget of 0. Google's page says why for Pro: "Reasoning cannot be turned off for
Gemini 2.5 Pro or 3 models." Anthropic's says why for `budget_tokens`: deprecated on the 4.6
models, and "Claude 4.7 and later models do not support it and reject requests that use it,
returning a 400 error"
([Extended thinking — Claude Platform Docs](https://platform.claude.com/docs/en/build-with-claude/extended-thinking)).
OpenAI's says why for Astra and `none`. Rejection is the cheapest of the five: one failed
call, no reasoning bill, and you know.

## Anthropic and Gemini: on two of the four, "medium" is a posture, not a quantity

The table treats Anthropic's and Gemini's levels as enums, which is what the wire carries.
What the words mean differs from OpenAI and DeepSeek, and the difference is billable.

Anthropic's `output_config.effort` takes `low`, `medium`, `high`, `xhigh` and `max`, with
the caveat that not every model with `max` has `xhigh`. The doc: "By default, Claude uses
high effort"; "Setting effort to high produces exactly the same behavior as omitting the
effort parameter entirely"; and the sentence that decides how to read the whole dial,
"Effort is a behavioral signal, not a strict token budget"
([Effort — Claude Platform Docs](https://platform.claude.com/docs/en/build-with-claude/effort)).
It applies to every output token, tool calls included: "Lower effort also means fewer and
terser tool calls." So on Claude, `medium` does not buy a quantity of
thinking. It buys a shorter agent. The steering page adds the cost most configs miss: "The
resolved effort value is rendered into the prompt, so changing it between requests
invalidates cache breakpoints," and their worked example shows the third request re-creating
3,546 cached tokens because effort went from high to medium
([Steering thinking — Claude Platform Docs](https://platform.claude.com/docs/en/build-with-claude/adaptive-thinking)).
Flip effort per call on Claude and you pay a cache write per flip.

The legacy dial, `thinking.budget_tokens`, was a quantity, or nearly one: minimum 1,024, must
be less than `max_tokens`, and "a target rather than a strict cap"
([Extended thinking — Claude Platform Docs](https://platform.claude.com/docs/en/build-with-claude/extended-thinking)).
It is deprecated on 4.6 and a 400 on 4.7 and later. Every translation table in row (b) that
still converts your word into `budget_tokens` is, on a current Claude model, converting into
an error. DeepSeek's Anthropic-format endpoint, incidentally, takes the
opposite line: `thinking` is "Supported (budget_tokens is ignored)" and `output_config` is
"Only effort is supported"
([Using the Anthropic API — DeepSeek API Docs](https://api-docs.deepseek.com/guides/anthropic_api)),
so the same Anthropic-shaped request carries a budget that one backend rejects and another
discards.

Gemini has two fields and a model table. `thinkingLevel` is an enum, `MINIMAL` / `LOW` /
`MEDIUM` / `HIGH`, "Recommended for Gemini 3 or later models. Use with earlier models results
in an error"; `thinkingBudget` is an integer for the 2.5 line
([Gemini API reference — ThinkingConfig](https://ai.google.dev/api/generate-content?hl=en#ThinkingConfig)).
Which levels exist depends on the model: gemini-3.8-flash defaults to medium and offers low,
medium and high; gemini-3.1-pro-preview defaults to high with the same three; gemini-3.6-flash
adds minimal; gemini-2.5-flash-lite is off by default
([Gemini thinking — Gemini API](https://ai.google.dev/gemini-api/docs/thinking?hl=en)). Pro
and the 3 series cannot be switched off. And one line on that page costs real money:
`max_output_tokens` "acts as a hard cutoff enforced by the infrastructure without changing
how the model allocates its thinking budget," so a model that hits it while thinking returns
`incomplete` with truncated or empty output "while still billing for any thinking tokens
generated." Google's own advice is to lower `thinking_level` rather than set a small output
cap. A cap is not a dial.

So on two of the four providers, `medium` is a posture the model interprets per request. On
OpenAI it is a gear with model-specific teeth. On DeepSeek it is a point on a published
curve. None of those is a token count, and only physics (c) ever was.

## The response side: reasoning_content is a DeepSeek convention, not an OpenAI field

The request is half the translation. On the way back, the field where the reasoning lands
is not standard either. An llm-rosetta issue from May lays it out: `reasoning_content`
"was introduced by DeepSeek and adopted by several Chinese providers, but it is not part of
the OpenAI standard"
([llm-rosetta #185 — Normalize reasoning/thinking fields across OpenAI Chat-compatible providers](https://github.com/Oaklight/llm-rosetta/issues/185)).
Its table: DeepSeek, Volcengine, Qwen, Zhipu and Moonshot return `message.reasoning_content`
as a string, Volcengine with an `encrypted_content` alongside; OpenRouter returns
`message.reasoning` plus a `reasoning_details` array carrying format metadata; MiniMax
embeds `<think>…</think>` inside `content` unless you opt into `reasoning_split`. Seven
providers, four shapes, and a converter that had hard-coded the first.

DeepSeek's own rule makes the shape load-bearing. With `tools` in the request, "the
reasoning_content must be fully passed back to the API in all subsequent requests — even for
turns where the model did not perform a tool call. If your code does not correctly pass back
reasoning_content, the API will return a 400 error." Without `tools`, the same field is
ignored if you send it
([Thinking Mode — DeepSeek API Docs](https://api-docs.deepseek.com/guides/thinking_mode)).
OpenAI returns no reasoning text on Chat Completions; on Responses the state is an
`encrypted_content` blob or lives server-side behind `previous_response_id`. Anthropic
returns `thinking` blocks with a `signature`; Gemini attaches thought signatures to parts.
The previous post covered those three state models. The point here is narrower: a gateway
that translates `reasoning_effort` on the way in also picks one of four field shapes on the
way out, and on one of the four a wrong pick is a 400 on the next turn.

## Check the reasoning-token count, then run the ladder

Every vendor bills reasoning as output and reports it separately. The field names differ.
The meaning does not.

| Surface | Where the count is | Documented in |
|---|---|---|
| OpenAI Responses | `usage.output_tokens_details.reasoning_tokens` | [Reasoning models — OpenAI API](https://developers.openai.com/api/docs/guides/reasoning) |
| OpenAI-compatible Chat Completions (DeepSeek and others) | `usage.completion_tokens_details.reasoning_tokens` | [Create Chat Completion — DeepSeek API Docs](https://api-docs.deepseek.com/api/create-chat-completion) |
| Anthropic Messages | `usage.output_tokens_details.thinking_tokens` | [Extended thinking — Claude Platform Docs](https://platform.claude.com/docs/en/build-with-claude/extended-thinking) |
| Gemini generateContent | `usageMetadata.thoughtsTokenCount` | [Gemini API reference — UsageMetadata](https://ai.google.dev/api/generate-content?hl=en#UsageMetadata) |
| Gemini Interactions | `usage.total_thought_tokens` | [Gemini thinking — Gemini API](https://ai.google.dev/gemini-api/docs/thinking?hl=en) |

The ladder is the same prompt at every effort spelling, reading that field each time. Over
an OpenAI-compatible surface, five lines:

```bash
for e in none minimal low medium high xhigh max; do
  jq -n --arg m "$MODEL" --arg e "$e" --arg p "$PROMPT" \
     '{model:$m, reasoning_effort:$e, messages:[{role:"user", content:$p}]}' |
  curl -s "$BASE_URL/chat/completions" -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d @- |
    jq -r --arg e "$e" '[$e, (.usage.completion_tokens_details.reasoning_tokens // "-"), (.error.message // "ok")] | @tsv'
done
```

Read the three columns as clues, not a verdict. If counts rise across repeated runs, compare
the pattern with the translation tables in row (b); the counts alone cannot distinguish
pass-through (a) from translation (b). A flat ladder may suggest (d), but first check whether
the provider supports the parameter, whether the gateway forwarded it, and whether the task
was sensitive enough to effort to show a difference. A dash with an error message points to
(e). To test for (c), send a numeric budget instead of the word and check across repeated
runs whether the count equals it. Use a prompt that needs a few hundred reasoning tokens at
the bottom rung, because trivial prompts can look flat even on real dials; run each rung three
times, as both measurements above did. Cost: seven rungs, three runs, twenty-one calls; well
under a cent at a Flash-class output price, a few dollars at Astra's. Either way it is cheaper
than one day of a wrong global default.

For native Anthropic and Gemini surfaces the same loop works with the field names from the
table; the endpoint and the parameter name change, the idea does not.

## What a gateway can honestly translate, and what it has to refuse to fake

A gateway can honestly translate four things. Field names and positions: `reasoning_effort`
to `reasoning.effort` to `output_config.effort` to `thinking_level` is a rename, and a rename
is safe. Response shape: the four response shapes can be normalised into one field as long
as the raw blob is kept alongside, the way `reasoning_details` keeps the
original format tag. The meter: five field names into one number, no arithmetic. And
rejection: a 400 from upstream should arrive as a 400, with the upstream's message, because
the client that sent `none` to Astra needs to learn that from the response, not from the
invoice.

It cannot honestly do four others. A word into a number, because there is no unit; every
table in row (b) is somebody's opinion, and the honest version of (b) is to publish the
table and let you override it with an explicit budget. An off switch on a model that cannot
be switched off. A parameter confirmed to be ignored upstream presented as one that worked;
if the meter stays flat, investigate before claiming the parameter was ignored. And a `budget_tokens` on a
Claude model that returns 400 for it.

If you set one effort value for the whole application, three rules, each with its price.
Set it per model, not per app; the cost is one line of config per model in your routing
table. Hold it constant within a cached conversation on Claude, or use the per-message
effort form where the model supports it; the cost of not doing so is one cache write per
change, 3,546 tokens in Anthropic's own example. And read the reasoning-token count on
every response; if repeated counts stay flat across effort levels on a sufficiently demanding
task, flag possible non-effect and inspect parameter support and pass-through before calling
it (d). The cost is one field in your logging; a flat count is a prompt to investigate, not
proof of an ignored setting.

The gateway we are building is designed to do the first list and refuse the second: pass the
value through unchanged, surface the upstream's own reasoning-token count on every response,
and return the upstream's 400 rather than invent a mapping it cannot verify. That describes
what we are building, not a shipped capability.

Run the ladder tonight on each model in your routing table. Paste the three columns into a
comment next to the effort line in your config. The next person to touch that line will see
which of the five physics it is, before the bill does.

No single number works across providers — that is the argument. A starting position does:
do not open at the top gear. The Zenn ladder's top gear scored 2.46 points below the one
beneath it for $1.37 and 6.5 minutes more per run, and DeepSeek's curve buys its last eight
points at roughly 2.5× the output tokens. Start one rung down, and let a failing task, not
a hunch, move the dial up.

---

## Sources

### huggingface.co

- [DeepSeek V4.1 Flash Technical Report](https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/resolve/main/DeepSeek_V41_Tech_Report.pdf)

### api-docs.deepseek.com

- [Thinking Mode — DeepSeek API Docs](https://api-docs.deepseek.com/guides/thinking_mode)
- [Models & Pricing — DeepSeek API Docs](https://api-docs.deepseek.com/quick_start/pricing)
- [Using the Anthropic API — DeepSeek API Docs](https://api-docs.deepseek.com/guides/anthropic_api)
- [Create Chat Completion — DeepSeek API Docs](https://api-docs.deepseek.com/api/create-chat-completion)

### zenn.dev

- [Zenn — godot-llm-gamebench: how gpt-6-astra changes with effort (ja)](https://zenn.dev/oubakiou/articles/faa33490272980)
- [Zenn — what GPT-6 Astra waits for: async tool calling and mid-turn steering,…](https://zenn.dev/peoplex_blog/articles/65768c769de4b0)

### developers.openai.com

- [Reasoning models — OpenAI API](https://developers.openai.com/api/docs/guides/reasoning)

### synthorai.io

- [reasoning_effort on an AI Gateway: Per-Provider Behaviour](https://synthorai.io/docs/guides/reasoning-effort/)
- [LLM Thinking Controls: What 13 Models Accept, Ignore, or Enforce](https://synthorai.io/blog/llm-thinking-controls/)

### docs.llmgateway.io

- [Reasoning — LLM Gateway Docs](https://docs.llmgateway.io/features/reasoning)

### ai.google.dev

- [Gemini API — OpenAI compatibility, Thinking](https://ai.google.dev/gemini-api/docs/openai?hl=en)
- [Gemini API reference — ThinkingConfig](https://ai.google.dev/api/generate-content?hl=en#ThinkingConfig)
- [Gemini thinking — Gemini API](https://ai.google.dev/gemini-api/docs/thinking?hl=en)
- [Gemini API reference — UsageMetadata](https://ai.google.dev/api/generate-content?hl=en#UsageMetadata)

### docs.litellm.ai

- [LiteLLM — Anthropic, Usage - Thinking](https://docs.litellm.ai/docs/providers/anthropic#usage---thinking--reasoning_content)

### github.com

- [langchain-anthropic — chat_models.py](https://github.com/langchain-ai/langchain/blob/master/libs/partners/anthropic/langchain_anthropic/chat_models.py)
- [Reasoning controls by provider — DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix/blob/ee2ace1dbd3967d387ff50247e15e7fb53feaa0f/docs/REASONING_PROVIDERS.md)
- [llm-rosetta #185 — Normalize reasoning/thinking fields across OpenAI…](https://github.com/Oaklight/llm-rosetta/issues/185)

### platform.claude.com

- [OpenAI SDK compatibility — Claude Platform Docs](https://platform.claude.com/docs/en/cli-sdks-libraries/libraries/openai-sdk)
- [Extended thinking — Claude Platform Docs](https://platform.claude.com/docs/en/build-with-claude/extended-thinking)
- [Effort — Claude Platform Docs](https://platform.claude.com/docs/en/build-with-claude/effort)
- [Steering thinking — Claude Platform Docs](https://platform.claude.com/docs/en/build-with-claude/adaptive-thinking)
