n4nAI

Claude 3.7 Sonnet extended thinking: latency vs token budget

Analyzing Claude 3.7 Sonnet extended thinking latency versus token budget: how reasoning budgets affect TTFT, cost, and quality, with practical tuning advice.

n4n Team5 min read1,112 words

Audio narration

Coming soon — every post will get a voice note here.

Claude 3.7 Sonnet extended thinking latency is the single most important operational variable when you enable reasoning on this model. Turn on extended thinking and you trade time-to-first-token for answer quality, with a token budget that caps how long the model can reason before it responds. Engineers who treat the budget as a set-and-forget parameter ship apps with unpredictable tail latency and inflated bills.

What extended thinking actually does

Extended thinking makes the model emit a hidden chain of reasoning tokens before producing the visible answer. The API returns those tokens as a separate block (or streams them) but they are not shown to end users by default. The mechanism is explicit in the Anthropic SDK:

import anthropic

client = anthropic.Anthropic()
resp = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    max_tokens=20000,
    thinking={"type": "enabled", "budget_tokens": 10000},
    messages=[{"role": "user", "content": "Prove the greedy algorithm is optimal for interval scheduling."}]
)

The budget_tokens field sets the ceiling for hidden reasoning tokens. The model may use fewer, but never more. That ceiling is your primary lever on Claude 3.7 Sonnet extended thinking latency.

Latency is dominated by time-to-first-token

In a normal chat completion, the model starts emitting answer tokens within a second or two. With extended thinking, the first visible token cannot appear until the thinking phase completes. Your user-visible TTFT equals the thinking generation time plus the final answer generation time.

Thinking generation runs at the same throughput as normal decoding—there is no free speedup. So a 5,000-token reasoning trace adds roughly the same delay as generating 5,000 answer tokens. On a Sonnet-class model behind a shared gateway, that is tens of seconds to minutes of silence on the wire if you are not streaming.

start = time.time()
first_visible = None
with client.messages.stream(
    model="claude-3-7-sonnet-20250219",
    max_tokens=20000,
    thinking={"type": "enabled", "budget_tokens": 8000},
    messages=[{"role": "user", "content": "Design a rate limiter for 10k rps"}]
) as stream:
    for chunk in stream:
        if chunk.type == "content_block_delta" and chunk.content_block.type == "text":
            first_visible = time.time() - start
            break

If you do not measure first_visible separately from total completion, you will misunderstand where the time went.

Token budget is a cap, not a target

A common mistake is setting budget_tokens to the maximum allowed “just to be safe.” The model does not always fill the budget. For simple queries it may think for 800 tokens and stop. For hard queries it will burn the entire cap and then force itself to answer, sometimes truncating reasoning mid-step.

Weigh the tradeoff:

  • Low budget (1–2k): Fast, but complex multi-step tasks degrade sharply. The model cuts corners.
  • Medium budget (4–8k): Covers most coding and math reasoning. Latency is noticeable but acceptable for asynchronous workflows.
  • High budget (12k+): Needed for deep algorithmic or proof tasks. Claude 3.7 Sonnet extended thinking latency becomes the dominant cost; interactive UX needs a spinner or progressive disclosure.

Set the budget per request class, not globally. A SQL generation endpoint does not need the same headroom as a theorem prover.

Interaction with context window and max_tokens

The budget_tokens value is not independent of your output ceiling. In the Anthropic API, max_tokens bounds the total output, thinking inclusive. If you ask for budget_tokens: 16000 and max_tokens: 16000, the model has zero room for the visible answer and will error. You must size max_tokens as budget_tokens + expected_answer_tokens + slack.

# safe configuration for a 10k thinking cap and up to 4k answer
thinking_budget = 10000
max_tokens = thinking_budget + 4000 + 500

Claude 3.7 Sonnet supports a 200k token context window, but your input prompt also consumes space. A 30k-token codebase plus a 16k thinking budget plus answer leaves little headroom. Exceeding limits returns a hard error, not a graceful truncation. Validate budgets against your real input size distribution.

Measuring real-world latency distributions

Average latency lies. The thinking phase length varies with prompt complexity even for semantically similar inputs. Measure p50, p95, and p99 of TTFT with your actual traffic.

import statistics
samples = []  # collect first_visible times across requests
p50 = statistics.median(samples)
p95 = sorted(samples)[int(0.95 * len(samples))]

If p95 Claude 3.7 Sonnet extended thinking latency exceeds your SLA, lower the budget or disable thinking for that route. The model still answers; it just reasons less. Run this measurement per route, because a “explain this error” path and a “write a compiler” path have different reasoning depth.

Quality versus budget curves

Offline evals on reasoning benchmarks show a steep quality climb from 0 to ~4k thinking tokens, then diminishing returns. A coding task that scores 40% accuracy with no thinking might hit 70% at 4k and 73% at 12k. Those last 8k tokens cost latency and money for marginal gain.

Build a simple eval harness:

for budget in [0, 2000, 4000, 8000, 12000]:
    score = run_eval(budget)
    print(budget, score)

Plot the curve. Ship the budget at the knee, not the plateau. This is the only defensible way to tune Claude 3.7 Sonnet extended thinking latency against quality.

Streaming thinking to mask the delay

Anthropic streams thinking deltas. You can pipe them to a debug pane or a “reasoning” expandable UI. This does not reduce latency, but it converts dead air into perceived progress.

// browser-side: render thinking as it arrives
for await (const event of stream) {
  if (event.type === "thinking_delta") {
    reasoningEl.textContent += event.delta;
  }
}

If you hide thinking entirely, show a deterministic loading state timed to expected budget. Users tolerate a 30-second think if they see a progress bar; they abandon a blank screen.

Cache hits change the equation

Extended thinking prefixes are expensive to recompute. Anthropic supports prompt caching on the system and conversation prefix. If you cache the system prompt and prior turns, the model skips re-reading them before thinking.

When you run this through n4n.ai, the gateway honors your client routing directives and forwards provider cache-control hints, so a cached thinking prefix avoids recomputation across retries. That cuts TTFT on repeated calls (e.g., retry after timeout) without touching the token budget.

Set cache breakpoints at stable context boundaries:

resp = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    system=[{"type": "text", "text": "You are a senior engineer.", "cache_control": {"type": "ephemeral"}}],
    thinking={"type": "enabled", "budget_tokens": 6000},
    messages=[...]
)

Cost is token budget plus answer

Billing counts thinking tokens as output tokens. A 10k-token budget that gets fully used doubles your output cost versus a non-thinking call of equal answer length. The token budget is therefore a direct cost knob.

If your evaluation shows quality plateaus at 4k thinking tokens, shipping 10k is pure waste. Run offline evals with fixed budgets and plot quality vs cost per 1k requests.

Retries and idempotency

Thinking calls are long. A naive 30-second client timeout will abort mid-think and force a retry that pays the budget again. Set timeouts based on measured p99 plus buffer. If you must retry, use the same budget; do not escalate it, or you compound latency.

For background agents, make the call idempotent with a task ID and persist partial thinking streams so a crash resumes instead of restarting.

When to disable extended thinking

Not every request benefits. Use it when:

  • Task requires multi-step planning, code synthesis, or formal reasoning.
  • User is asynchronous (batch job, background agent).
  • Latency SLA > thinking time at chosen budget.

Skip it when:

  • Request is extractive (summarize, classify, rewrite).
  • Interactive latency < 2s required.
  • Budget would exceed remaining context window.

A hybrid router that decides per request based on a cheap classifier saves more money than any global tuning.

Decisive takeaway

Treat budget_tokens as a latency and cost SLA, not a model capability toggle. Measure Claude 3.7 Sonnet extended thinking latency at p95 for each task class, set the lowest budget that preserves eval quality, stream thinking to mask delay, and cache aggressively. If you cannot meet latency targets at the minimum viable budget, the model is the wrong tool for that path—route it elsewhere.

Tagsclaude-3-7-sonnetextended-thinkingreasoning-modellatency-benchmark

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All reasoning model latency overhead posts →