Skip to content
← All writing

Reasoning effort is a cost dial, not a quality setting

4 min read
.md
Cover illustration for Reasoning effort is a cost dial, not a quality setting

TL;DR

Reasoning modes are billed as output tokens, so a model left on its default thinking budget can cost several times more than needed on trivial calls. Each provider exposes the control differently, so normalise it behind one interface and set the level per agent role rather than globally.

Every message that arrives at my platform hits a classifier first, which picks the specialist agent to handle it. Small model, short prompt, four possible answers.

It was taking 4.6 seconds.

I checked the model. Fast. I checked the prompt. Short. Nothing about the job explained it, and since this call sits in front of every single message, 4.6 seconds was the floor for the whole product.

Then I read the response payload properly. The model was thinking. Hundreds of tokens of internal deliberation, on a multiple-choice question, because extended reasoning was on by default and I had never turned it off.

You are paying for the thinking

The thinking happens before the answer you see, and you are charged for it. Anthropic bills thinking tokens as output tokens. So does OpenAI with reasoning tokens. Output tokens are the expensive ones.

Which means leaving the default alone is a spending decision, taken once and then applied to every call you ever make, whether or not the work deserves it.

On my classifier it was about ten times the tokens needed to say one word.

Every provider spells it differently

This is the part that makes it easy to ignore. There is no shared parameter, so wiring it up means touching each provider adapter separately.

ProviderParameterValues
Anthropicthinking.budget_tokensAn integer budget
OpenAIreasoning_effortlow, medium, high
BytePlusextra_body.reasoning_effortminimal, low, medium, hi
DeepSeekNot configurableAlways on for reasoner models
OpenRouterPassed throughDepends on the underlying model

An integer budget and a three-value enum do not map onto each other cleanly, and pretending they do is how you end up with medium meaning something different on every path. I normalise to four internal levels and let each adapter translate, accepting that the translation is approximate.

type Effort = 'minimal' | 'low' | 'medium' | 'high'

const ANTHROPIC_BUDGET: Record<Effort, number | null> = {
  minimal: null,     // omit the thinking block entirely
  low: 5_000,
  medium: 10_000,
  high: 20_000,
}

export function applyEffort(provider: Provider, body: RequestBody, effort: Effort) {
  switch (provider) {
    case 'anthropic': {
      const budget = ANTHROPIC_BUDGET[effort]
      if (budget) body.thinking = { type: 'enabled', budget_tokens: budget }
      return body
    }
    case 'openai':
      body.reasoning_effort = effort === 'minimal' ? 'low' : effort
      return body
    case 'byteplus':
      body.extra_body = { ...body.extra_body, reasoning_effort: effort === 'high' ? 'hi' : effort }
      return body
    default:
      return body // provider ignores it; not an error
  }
}

The default branch returning the body untouched is deliberate. A provider that does not support the control should be a no-op, not a thrown error, or adding a provider breaks every call site.

Which calls actually need it?

The ones where the model has to work something out. Not the ones where it has to pick from a list.

I set effort per agent role rather than per request, because roles are stable and requests are not:

RoleEffortWhy
Routing and classificationminimalThe output space is a handful of tokens. Deliberation adds latency and changes the answer roughly never
Summarising and formattinglowStructure matters, invention does not
Planning and multi-step tool usemediumGetting the order wrong is expensive downstream
Debugging and analysishighThis is what the budget is for

Tie the level to the role in the same place you choose the model, and it stays consistent as prompts get edited by people who are not thinking about token budgets.

Measure it, because intuition is wrong here

I would not have found the classification problem by reading code. Aggregate token counts looked normal. Per-role counts, once I tagged usage by role, showed a step that produced four words consuming a large share of the bill.

Route everything through a gateway that records tokens per call with the role attached. Cloudflare AI Gateway does this in front of multiple providers, which is convenient if you are already routing across several.

The number to watch after you turn the dial down is not cost. It is your quality signal for that role: retry rate, escalation rate, validation failures.

After lowering effort on a roleReadingAction
Escalation and retry rates unchangedThe reasoning was not doing anythingKeep the lower setting
Escalations climbThe reasoning was load-bearing for that rolePut it back, and note what the role actually needs
Latency drops, quality signals flatThe deliberation was pure overheadCheck whether neighbouring roles have the same problem
Cost drops but validation failures riseYou moved the cost downstream into retriesNet saving is smaller than it looks; measure end to end

My classification path lost nothing measurable at minimal effort. The debugging path would be worse at anything below high, and I have not tried to save money there.

Sources

Common questions

Are reasoning or thinking tokens billed differently from normal output?

They are billed as output tokens, which are the expensive ones. Anthropic bills thinking tokens as output, and OpenAI does the same with reasoning tokens. Leaving the default alone is therefore a spending decision applied to every call you make, whether or not the work deserves it.

How much does extended reasoning cost on a trivial call?

On my classifier, a multiple-choice call with four possible answers, extended reasoning was running about ten times the tokens needed to say one word, and holding response time at 4.6 seconds. Because that call sat in front of every message, it set the latency floor for the whole product.

How do you set reasoning effort across different LLM providers?

There is no shared parameter, so normalise it behind one interface. Anthropic takes an integer thinking budget, OpenAI takes low, medium or high, and BytePlus takes minimal through hi. I map four internal levels onto each adapter and treat a provider that does not support the control as a no-op rather than an error.

Should reasoning effort be set per request or per agent role?

Per role. Roles are stable and requests are not, and tying effort to the role in the same place you choose the model keeps it consistent as prompts get edited by people who are not thinking about token budgets.

How do you tell whether lowering reasoning effort hurt quality?

Watch the quality signal for that role rather than the cost: retry rate, escalation rate, validation failures. If escalations climb after the change, the reasoning was doing real work. If nothing moves, it was not. My classification path lost nothing measurable at minimal effort.

Written by Elson Tan, Head of Technology and co-founder at Nedex Group, working on AI harness and agent infrastructure.

AboutRSS
  • 5 min read

    Metering tokens when the bill is the product

    Billing per message is easy and wrong: one user sends a sentence, another uploads a report. Metering the tokens you actually spend is harder, and the hard parts are idempotency, allowance checks and what to do mid-conversation.

  • 4 min read

    Route cheap models to orchestration, not to the work

    Most agent platforms pick one model and use it everywhere. Splitting model selection by role rather than by task is where the cost curve actually bends.

  • 6 min read

    Persist once, reference by id, hydrate on demand

    An agent that reads your uploaded file perfectly and then forgets it on the next turn is not a memory bug. It is a context design where file content was only ever turn-transient. The fix also cuts token cost.

Get in touch

Tell me who you are and what you are working on.

Your details are used only to reply to this message.