Adaptive Thinking in Claude: What It Actually Means (And How to Use It)
๐Ÿ’ป code

Adaptive Thinking in Claude: What It Actually Means (And How to Use It)

Claude Foundations & Model Family

Part 4 of 6

Claude Foundations & Model Family

View all chapters โ†’
Devesh Korde

Devesh Korde

November 6, 2026

๐Ÿ“– 11 min read
#claude#adaptive-thinking#effort#api
โšก TL;DR
  • Adaptive thinking means Claude decides, per request, whether to think and how much. On Opus 5.5, Sonnet 5.5, Haiku 5.5, Fable 5.1 and Mythos 5.1, it is already on if you send no thinking field.
  • There is no deep-think switch. Two dials matter: the thinking mode (whether) and the effort level (how much). Effort is the one you tune.
  • You are billed for the full thinking tokens as output tokens, even when the thinking text is hidden. Changing effort between requests also invalidates your prompt cache.
  • Adaptive thinking decides how hard one model thinks. It does not decide which model to use. That still needs your own escalation signals.

Here is something that surprised me while reading the docs for this post.

If you call Claude Opus 5.5, Sonnet 5.5, or Haiku 5.5 and never mention thinking, thinking is already on. You didn't enable anything. The model is deciding, request by request, whether to reason before it answers.

That is adaptive thinking. This post explains what it actually does, what it costs, and when to turn the dials.

Scope, upfront: I did not benchmark any of this. Everything below comes from Anthropic's documentation as of 2026-11-06, and I flag where something is my own reasoning rather than a documented fact. Where the docs say "measure on your own workload," I mean it too.

What adaptive thinking actually means

In the old model, you gave Claude a thinking token budget and it reasoned up to that limit. Adaptive thinking drops the budget. Claude evaluates each request and decides whether to think and how deeply. A simple factual question may get a direct answer with no thinking at all. A multistep math problem or a tricky debugging task triggers deeper reasoning.

Three consequences follow, all from the docs:

  1. The decision is per request. The same conversation can contain turns with thinking and turns without it. Don't write code that assumes every assistant turn starts with a thinking block.
  2. Thinking interleaves with tools automatically. Claude can think between tool calls and evaluate each result before acting. No beta header is needed.
  3. In tool loops, most reasoning happens early. The first request after new user input typically carries most of the thinking. Follow-up requests that only process tool results can skip it, even at the highest effort levels.

A note on terminology. You may see "deep think mode" in articles. That is not an API setting. The closest real thing is raising the effort level, which I cover below.

A request goes in and Claude decides whether to think
A request goes in and Claude decides whether to think

Two dials, not one

This is where most confusion starts. There are two separate controls:

  • thinking is the mode. It controls whether thinking blocks exist at all.
  • effort (set at output_config.effort) controls how much work Claude puts into the whole response. In adaptive mode, that includes how often and how deeply it thinks. It also affects text and tool calls, so it works even with thinking off.

Don't pass "adaptive" as an effort value. It's a thinking mode, not an effort level.

EffortThinking behavior (per the docs)
maxThinks most readily, at the greatest depth, with no length constraint
xhighMore readily and deeper than high, suited to extended exploration
highThinks on most requests that benefit from it
mediumModerate thinking; may skip it for simple queries
lowMinimizes thinking; skips it for simple, speed-sensitive tasks

Effort is a soft signal, not a token budget. Even at low, Claude still thinks on sufficiently hard problems. It just thinks less.

Here is the minimal call:

response = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=16000,
    thinking={"type": "adaptive", "display": "summarized"},
    output_config={"effort": "medium"},
    messages=[{"role": "user", "content": "Why does this retry loop never refresh the token?"}],
)

What your model does by default

Defaults differ by model, and this is where I'd tell you to check your own setup. From the docs' configuration table:

ModelNo thinking fieldTurn it off?Default effort
Opus 5.5AdaptiveNo (400 error)medium
Sonnet 5.5Adaptivedisabled returns 400; between_tools works at high or belowhigh
Haiku 5.5Adaptivedisabled works at high or belowmedium
Fable 5.1, Mythos 5.1AdaptiveNohigh
Opus 4.8, 4.7Thinking off until you send adaptiveYeshigh

Two things stand out.

The defaults aren't aligned across models. Opus 5.5 and Haiku 5.5 default to medium, while Sonnet 5.5 defaults to high. If you compare models, set effort explicitly on all of them. Otherwise you are comparing different effort levels and calling it a model difference.

The thinking text is hidden by default. On these models, display defaults to "omitted", so thinking blocks arrive empty. You still pay for them. To see summaries, opt in with display: "summarized". And remember: that text is a summary, not the raw chain of thought. Useful for debugging, not an audit trail.

Two dials labeled thinking and effort
Two dials labeled thinking and effort

What it costs

Thinking is not free, and the billing has a few surprises.

  • You pay for the full thinking, not the summary. Thinking tokens are billed as output tokens, and the billed count does not match the visible count. Summary generation itself has no charge.
  • Hiding thinking doesn't save money. display: "omitted" reduces latency (faster time to first text token when streaming), not cost.
  • You can measure it. The response reports usage.output_tokens_details.thinking_tokens, the raw reasoning tokens, always less than or equal to output_tokens.
  • Prior thinking can cost you again as input. On models that keep all prior turns, which includes Haiku 5.5 and the Opus 4.5-and-later, Sonnet 4.6-and-later, Fable and Mythos lines, earlier thinking blocks stay in context and are billed as input. Long agent sessions accumulate this. The docs point to thinking block clearing if you need to reclaim space.

Two separate limits

max_tokens and effort do different jobs:

  • max_tokens is a hard cap on thinking plus response text combined.
  • effort is soft guidance on how much of that Claude spends thinking.

If you see stop_reason: "max_tokens", you have two fixes: raise the cap if those requests needed the reasoning, or lower effort if they were over-thought. A max_tokens sized for a no-thinking response is often too small once Claude starts reasoning on hard requests.

Also note: the SDK requires streaming when max_tokens exceeds 21,333, and the docs suggest batch processing for workloads pushing thinking beyond roughly 32k tokens per request, to avoid timeouts.

When to turn it up, down, or off

The docs' guidance is consistent: lower effort before you reach for prompt tricks, and measure before you ship.

Here are the documented starting points for the 5.5 family and Fable 5.1:

ModelDocumented starting point
Haiku 5.5Start at medium. Use low for chat, short tool tasks, and simple high-volume requests. Use high for knowledge work, longer agent tasks, and strict instruction following.
Sonnet 5.5Start at high unless the workload is agentic or latency-sensitive. For agentic coding, medium for well-specified tasks and high for harder ones. For chat, medium or low.
Opus 5.5Default is medium. Docs say to run a fresh effort sweep on your evals rather than carrying settings over.
Fable 5.1Start at high. Go to xhigh or max for the most capability-sensitive work; step down for routine work once evals show quality holds.

A few cautions the docs raise that are easy to miss:

  • Low effort has a failure mode on Haiku 5.5. In long agent prompts, the model is more likely to skip a search, stop early, or skip a check at low.
  • max isn't automatically better. For Opus 4.7 specifically, the docs say it adds significant cost for small gains on most workloads and can lead to overthinking on some structured-output tasks.
  • Telling the model to think less doesn't reliably work on every model. On Sonnet 5.5 and Haiku 5.5, prompt instructions to reduce thinking aren't dependable. Lower the effort instead.
  • You can't always turn thinking off. Opus 5.5, Fable 5.1, and Mythos 5.1 reject disabled. Sonnet 5.5's lowest setting is between_tools, which turns off up-front thinking.

The gotcha that breaks your cache

This one is the most practical thing I found.

The thinking configuration and the resolved effort level are rendered into the prompt itself. So changing effort between requests invalidates your prompt cache. The docs include a worked example: a conversation on Opus 5.5 that moved from the default medium to low produced a full cache miss on the third request, where the second had been a full cache read.

Setting effort explicitly to the model's default is the same as omitting it, so that doesn't break anything. But varying it per request does.

Your options:

  1. Pick one level per conversation and keep it.
  2. Use per-message effort (beta) on supported models. It uses a system message carrying only output_config.effort and the beta header mid-conversation-output-config-2026-07-01, and it preserves the cache. The docs list it for Fable 5.1, Mythos 5.1, Opus 5.5, Opus 5, Sonnet 5.5, and Haiku 5.5, with some platform differences.
  3. Mind the exceptions. With Sonnet 5.5 on between_tools or Haiku 5.5 with thinking disabled, effort can't change mid-conversation at all.

Related: if you pass thinking blocks back, pass them unmodified and keep your message history append-only. On Claude 5.1 and later models, the API checks that earlier thinking blocks still match everything before them. Edit the history and those blocks can be dropped.

A prompt cache stack breaking when the effort dial changes
A prompt cache stack breaking when the effort dial changes

Adaptive thinking is not a router

Here is the part where I want to push back on how this feature gets pitched.

Adaptive thinking decides how hard one model thinks about one request. It does not decide which model should handle the work. Those are different problems, and the Day 2 comments made me see it.

A tech lead pointed out that upfront routing is itself a cost, and that a better pattern is to run the cheaper model by default and escalate on signals. The signals they named were low self-consistency, a failed cheap verifier, and known-hard categories. That is a design pattern from a reader plus my own reasoning, not an Anthropic feature, and I haven't benchmarked it. But it fits well with adaptive thinking:

  • Inside a model, let adaptive thinking and effort handle the easy-versus-hard split.
  • Across models, escalate only when something tells you the cheap answer isn't good enough. Run the request twice and compare. Check the output with a cheap verifier such as a schema, a test, or a rule. Maintain a short list of categories you already know are hard.

One more honest limit. Thinking can help within a step, but it doesn't remove error compounding across steps. If a chain of 10 steps each succeeds 80% of the time, the end-to-end rate is about 11%, because 0.8 to the power of 10 is roughly 0.107. Verify between steps. Don't assume more thinking fixes a long chain.

How to find your own setting

The docs' advice is to run a representative sample of your traffic and compare, so here is a small sweep you can adapt:

for effort in ["low", "medium", "high"]:
    r = client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=16000,
        thinking={"type": "adaptive"},
        output_config={"effort": effort},
        messages=SAMPLE_PROMPT,
    )
    usage = r.usage
    thinking = getattr(getattr(usage, "output_tokens_details", None), "thinking_tokens", None)
    print(effort, usage.output_tokens, thinking)
    # Also record latency and score the answer against your own checks.

Track four things per level: how often thinking triggers, output tokens, latency, and answer quality on the cases that matter to you. The thinking token field is documented in the API response; check that your SDK version exposes it.

Migration gotchas worth a minute

If you are moving from an older model, the docs flag several changes that bite:

  • thinking: {type: "enabled"} with budget_tokens returns a 400 error on the 5.5 family. Move to adaptive plus effort.
  • Forced tool use (tool_choice of any or a named tool) is rejected on Opus 5.5, Sonnet 5.5, Fable 5.1, and Mythos 5.1. Use auto with strict tool use or structured outputs.
  • Non-default temperature, top_p, or top_k values return a 400 on these models. From API version 2026-10-21, including any of them returns a 400 on every model.

What I haven't tested

  • No benchmarks. I didn't measure token usage, latency, or quality at any effort level. Every number here is what the docs say or simple arithmetic.
  • Docs move. This reflects documentation read on 2026-11-06. Several features, including per-message effort and display: "updates", are beta.
  • Defaults vary by platform and API version. Check the model's capabilities through the Models API before relying on a table, including mine.
  • The routing pattern is untested. It is a reasonable design, not a measured result.

The short version

Thinking is on by default for most current models. Effort is the dial you actually tune. You pay for all the thinking even when you can't see it. And changing effort mid-conversation quietly resets your cache.

Pick an effort level on purpose, measure it on your own traffic, and write down why you chose it. Don't leave it to the default.


Sources

Claude Haiku 5.5 Is Underrated (Here's Why Everyone's Using It Wrong)

Claude Haiku 5.5 Is Underrated (Here's Why Everyone's Using It Wrong)

XML Tags Changed How I Prompt Claude (A Complete Guide)

XML Tags Changed How I Prompt Claude (A Complete Guide)

โ† Back to all articles

Related Articles