Reasoning Models
|
This content was generated with the assistance of AI and should be verified against the official documentation of each tool and framework before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
Examples on this page target the anthropic Python SDK 1.8.0 and claude-sonnet-5 (adaptive thinking, on by
default, high effort by default), the openai Python SDK 3.19.2 and a current GPT-6-family reasoning model
(gpt-6-sol, reasoning.effort), and Ollama 0.34.x with qwen3:8b, a thinking-capable local model alongside
DocsAssistant’s usual llama3.1:8b chat model
(The Model Landscape covers the model landscape more broadly). All parameter names
and model IDs below were re-verified against each vendor’s own documentation on 2026-09-28; where a name has
changed recently, this page says so explicitly rather than guessing.
Thinking: extended and adaptive reasoning
A model that answers in a single forward pass has to get everything right on the first try — no scratch work, no checking an intermediate result, no abandoning an approach that turns out to be wrong. Thinking (also called extended reasoning) removes that constraint: before producing its final answer, the model generates a separate stream of reasoning tokens in which it restates the problem, tries an approach, checks its own intermediate results, and backtracks when something doesn’t hold up. That reasoning is billed as output tokens and shows up in the response as one or more dedicated blocks, distinct from the final answer text.
Two designs for turning this on exist across vendors and even across a single vendor’s own model generations:
-
Manual, budget-driven thinking — the caller sets a fixed token budget for reasoning up front, and the model always spends against it. Anthropic calls this extended thinking (
thinking.type: "enabled"withbudget_tokens); it is the only mode some older reasoning-capable models support. -
Adaptive, effort-driven thinking — the model decides for itself whether to think at all and how deeply, steered by a separate, coarser effort knob rather than a token count. Anthropic’s current generation (
claude-sonnet-5and later) calls this adaptive thinking; OpenAI’sreasoning.effortparameter is the same idea under a different name.
The rest of this page covers both designs, because "reasoning model" in practice can mean either one depending on which model and vendor a request targets.
Anthropic: adaptive thinking, and printing thinking and text blocks separately
On claude-sonnet-5, thinking is on by default and needs no parameter to enable it, but the reasoning text is
hidden by default (the display field defaults to "omitted" on this model generation). Opting in with
display: "summarized" returns a human-readable summary of the model’s reasoning — never the raw internal
chain of thought — as separate thinking content blocks ahead of the final text block:
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=4096,
thinking={"type": "adaptive", "display": "summarized"},
messages=[
{
"role": "user",
"content": (
"DocsAssistant question: our HNSW index's recall dropped after we raised "
"ef_construction. Should ef_search also change, and why?"
),
}
],
)
for block in response.content:
if block.type == "thinking":
print("Thinking:\n", block.thinking)
elif block.type == "text":
print("\nAnswer:\n", block.text)
The response’s content array holds the two block types side by side: a thinking block (with an encrypted
signature field that must be passed back unchanged in any follow-up turn) and, after it, the ordinary text
block with the answer DocsAssistant would show the user. See the
Anthropic Thinking documentation, which this
example and the block shapes above derive from.
Extended thinking’s manual type: "enabled" plus budget_tokens form still exists, but its status is
model-dependent and changed recently enough to call out explicitly: it is the only thinking mode on Claude
Opus 4.5 and earlier reasoning-capable models, it is deprecated but still functional on the Claude 4.6
generation, and Claude 4.7 and later models — including claude-sonnet-5 — reject it with an HTTP 400
error. A request against an older, extended-thinking-only model looks like this instead:
response = client.messages.create(
model="claude-opus-4-5", # extended-thinking-only model
max_tokens=16000,
thinking={"type": "enabled", "budget_tokens": 10000}, # rejected on 4.7+ models
messages=[{"role": "user", "content": "..."}],
)
budget_tokens must be at least 1,024 and less than max_tokens (the one exception is interleaved thinking,
covered below, where the budget can span an entire turn’s tool calls). See the
Anthropic Extended Thinking
documentation for the full budget rules and the migration mapping from budget_tokens to adaptive thinking
plus effort.
Effort and budget parameters
"How hard should the model try" is governed by two different, vendor-specific knobs, and the exact parameter names are worth getting right because they move fast:
| Vendor | Parameter (verified 2026-09-28) | Notes |
|---|---|---|
Anthropic (extended thinking, older models) |
|
A hard token budget for reasoning; deprecated on the 4.6 generation, rejected on 4.7 and later. |
Anthropic (adaptive thinking, current models) |
|
A coarse effort level
( |
OpenAI |
|
Allowed values are model-dependent. The API defines |
An Anthropic request that lowers effort on the baseline model for the same kind of cheap classification task:
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
output_config={"effort": "low"}, # adaptive thinking stays on, but thinks less (or not at all)
messages=[
{
"role": "user",
"content": (
"Classify this DocsAssistant page as one of: foundations, similarity-search, rag, "
"agents, frameworks, operations. Page title: 'HNSW Indexes'."
),
}
],
)
for block in response.content:
if block.type == "text":
print(block.text)
See the Anthropic Effort documentation for
output_config.effort, its allowed levels and each model’s default.
An OpenAI reasoning request with an explicit effort level, run against DocsAssistant’s page-classification task:
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-sol", # current OpenAI reasoning model, verified 2026-09-28
reasoning={"effort": "low"}, # cheap, fast classification -- no need for deep reasoning here
input=[
{
"role": "user",
"content": (
"Classify this DocsAssistant page as one of: foundations, similarity-search, rag, "
"agents, frameworks, operations. Page title: 'HNSW Indexes'."
),
}
],
)
print(response.output_text)
See the OpenAI Reasoning models guide, which this
reasoning.effort shape and the current allowed levels derive from.
Because Anthropic’s effort and thinking are separate controls — thinking decides whether the model
reasons in dedicated blocks, effort decides how much work the whole response gets, thinking included — lowering effort is the first lever to pull for cost or latency, and raising it is the first lever to pull
when the model is thinking too little or too shallowly. Sampling & Decoding
covers which other sampling parameters a reasoning model ignores or restricts once thinking is active.
Interleaved thinking with tools
Interleaved thinking lets a reasoning model think again between tool calls in the same turn: it reasons about a tool’s result before deciding whether to call another tool or answer. Without it, a model that uses tools reasons once up front and then executes a fixed plan of tool calls; with it, each tool result can change what the model does next, which matters for a DocsAssistant agent that retrieves a document, notices the retrieved chunk doesn’t actually answer the question, and decides to retrieve again with a different query before answering.
On Anthropic’s current adaptive-thinking models, interleaving happens automatically, with no extra parameter.
Older models (Claude Opus 4.5, Claude Sonnet 4.5 and earlier Claude 4 models) need the
interleaved-thinking-2025-05-14 beta header on the request to get the same behaviour under manual extended
thinking. See the
Anthropic Thinking
documentation’s interleaved-thinking section for the turn structure and the per-model beta-header requirement.
Reasoning locally with Ollama
Ollama exposes thinking as a single request field, think, which accepts true, false, null (model
default) or a named level such as "low" / "medium" / "high" on models that support graded effort. As of
2026-09-28, Ollama’s own thinking documentation lists qwen3, gpt-oss and deepseek-r1 as thinking-capable
model families; this page uses qwen3:8b, a size that runs comfortably on a laptop, as DocsAssistant’s local
reasoning model, alongside the plain llama3.1:8b chat model this section uses elsewhere for fast, non-reasoning
requests:
from ollama import chat
response = chat(
model="qwen3:8b",
messages=[
{
"role": "user",
"content": "Why would raising ef_construction on an HNSW index also call for retuning ef_search?",
}
],
think=True,
)
print("Thinking:\n", response.message.thinking)
print("\nAnswer:\n", response.message.content)
The equivalent request against Ollama’s native /api/chat endpoint with curl:
curl http://localhost:11434/api/chat -d '{
"model": "qwen3:8b",
"messages": [{"role": "user", "content": "Why retune ef_search after raising ef_construction?"}],
"think": true,
"stream": false
}'
See the Ollama thinking documentation, which the think
parameter, its accepted values and the model list above derive from.
When reasoning helps — and when it only adds latency and cost
Thinking is not a free quality upgrade. It trades latency and token spend (reasoning tokens are billed as output tokens even when hidden from the response) for a chance at a better answer, and that trade only pays off on certain kinds of requests:
-
Reasoning tends to help on multi-step math and logic, non-trivial debugging, planning that requires weighing several options against constraints, and any DocsAssistant question whose answer depends on combining several retrieved facts rather than restating one of them (for example, "which of these three index types should we use given our recall and latency targets" rather than "what does HNSW stand for").
-
Reasoning tends to only add cost on lookup-style requests that a fast model already answers correctly: classification against a short fixed label set, extracting a field that is already present verbatim in the input, simple rephrasing or summarisation, and any request running at high volume and tight latency budgets where the fast model’s accuracy is already acceptable. Escalating from a fast model to a reasoning model only on low-confidence or failed responses — the cascade pattern Choosing a Model covers — gets most of the quality benefit without paying the reasoning cost on every request.
Prompting reasoning models: state goals and constraints, don’t script the steps
A reasoning model already plans its own intermediate steps; writing it a numbered chain-of-thought recipe — "first do X, then do Y, then check Z" — fights the thing the model is designed to do on its own and, in practice, tends to produce worse results than simply stating what a good answer looks like. The prompting shift this page’s techniques companion, Prompting Techniques, calls out for reasoning models specifically is: describe the goal, the constraints and any facts the model must ground its answer in, and let the model decide how to get there, rather than hand-authoring the chain of thought yourself the way a non-reasoning model often needs.
A DocsAssistant example of the shift:
-
Non-reasoning-style prompt (scripts the steps): "First list every index type mentioned in the retrieved chunks. Then, for each one, note its build time and query latency. Then compare them pairwise. Then pick the best one and explain why."
-
Reasoning-model prompt (states goals and constraints): "Given the retrieved chunks about HNSW, IVF and flat indexes, recommend one index type for a corpus of 2 million vectors with a 50ms p99 query latency budget. State the trade-off you’re accepting."
The second prompt gives the model the outcome and the constraints it must satisfy, and leaves the decomposition — which facts to compare, in what order — to the model’s own thinking.
Choosing between a reasoning model and a fast model
| Use a reasoning model when… | Use a fast (non-reasoning) model when… |
|---|---|
The task has several steps that depend on each other (planning, multi-hop retrieval, debugging) |
The task is a single lookup, extraction or classification against a short, well-defined answer |
Getting the answer wrong is costly, and a slower, more expensive answer is acceptable |
The request runs at high volume, or a user is waiting on a tight latency budget |
The input requires weighing trade-offs or constraints against each other |
The input already contains the answer verbatim, or the mapping from input to output is close to mechanical |
Early testing on your own evaluation set shows the fast model missing cases the reasoning model gets right |
Your evaluation set shows the fast model already at acceptable accuracy for the task |
The workload can tolerate escalation latency (a cascade’s second call) |
The workload is the first call in a cascade, deciding whether escalation is even needed |
Cost, Latency & Throughput covers the concrete latency and pricing impact of turning thinking on, and how a lower effort level or a smaller model trades against it.