Tuning the effort Parameter for Cost and Speed
The effort parameter sets how much reasoning depth Claude applies to a request, letting you trade quality for cost and speed on a per-call basis.
Search across all documentation pages
The effort parameter sets how much reasoning depth Claude applies to a request, letting you trade quality for cost and speed on a per-call basis.
Every request has an implicit cost and latency budget.
The effort parameter, passed under output_config, gives you a direct lever on that budget.
Lower effort favors speed and cost, higher effort favors thoroughness.
This is distinct from the thinking config, which controls whether reasoning is adaptive and visible at all.
The two settings compose, so a well-tuned production system usually sets both deliberately rather than leaving either at a default.
Quick-reference recipe card - copy-paste ready.
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
output_config={"effort": "medium"},
messages=[{"role": "user", "content": "Summarize this customer support thread."}],
)
print(response.content[-1].text)When to reach for this:
low effort keeps cost predictable.high or max effort is worth the cost.import anthropic
client = anthropic.Anthropic()
EFFORT_BY_TASK_TYPE = {
"classify": "low",
"summarize": "medium",
"code_review": "high",
"incident_root_cause": "max",
}
def run_task(task_type: str, prompt: str) -> str:
effort = EFFORT_BY_TASK_TYPE.get(task_type, "medium")
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1536,
thinking={"type": "adaptive"},
output_config={"effort": effort},
messages=[{"role": "user", "content": prompt}],
)
for block in response.content:
if block.type == "text":
return block.text
return ""
if __name__ == "__main__":
ticket = "User reports intermittent 502s on checkout, started after last night's deploy."
result = run_task("incident_root_cause", ticket)
print(result)What this demonstrates:
thinking={"type": "adaptive"} with an explicit effort ceiling, the two settings composing cleanly."medium" for unrecognized task types rather than failing.text block, ignoring any thinking block for this call site's purposes.max effort specifically to the highest-stakes task type, incident root cause analysis.output_config={"effort": "<level>"} sets a ceiling on how much reasoning computation Claude applies before answering.low, medium, high, max, from fastest and cheapest to most thorough and expensive.thinking block is visible, it governs the underlying reasoning budget, not just its display.thinking: adaptive thinking decides whether reasoning happens at all for a given prompt, effort caps how deep it goes when it does.| Level | Speed | Cost | Best fit |
|---|---|---|---|
low | Fastest | Lowest | Classification, extraction, short lookups |
medium | Balanced | Moderate | General assistant replies, summarization |
high | Slower | Higher | Code review, multi-step planning |
max | Slowest | Highest | Safety-critical analysis, deep debugging |
# Pattern: fail loudly on an invalid effort value instead of silently defaulting.
VALID_EFFORTS = {"low", "medium", "high", "max"}
def build_output_config(effort: str) -> dict:
if effort not in VALID_EFFORTS:
raise ValueError(f"Unknown effort level: {effort!r}")
return {"effort": effort}Validating the effort string before it reaches the API call catches typos ("med" instead of "medium") at the call site instead of as an opaque request error.
max effort everywhere "to be safe." This inflates cost and latency across your whole application, most requests do not need it. Fix: map effort to task type deliberately, reserve max for genuinely high-stakes calls.thinking config's job. Fix: set both thinking and output_config.effort explicitly when you need both self-calibration and a cost ceiling.high and max can meaningfully slow down a user-facing endpoint. Fix: benchmark p50 and p95 latency at each candidate effort level against your real traffic before choosing one."med" for "medium" surfaces as an API error deep in a request path. Fix: validate against the known set of levels before constructing the request.| Alternative | Use When | Don't Use When |
|---|---|---|
| Fixed single effort level for the whole app | The workload is uniform in difficulty | Requests vary widely in complexity or stakes |
| Per-request effort passed by the caller | Different product surfaces have different cost/quality needs | You cannot trust caller input or need centralized cost control |
| Effort routed by an upstream classifier | High request volume with mixed difficulty and a need for automatic tuning | Traffic is low enough that manual mapping is simpler and cheaper to maintain |
low, medium, high, and max, passed as a string under output_config={"effort": "<level>"}.
Not always. It increases the reasoning budget Claude is allowed to use, which tends to help on genuinely hard tasks but adds little value on simple ones while still costing more.
No. thinking controls whether and how adaptively reasoning happens and is shown; effort controls how deep that reasoning is allowed to go and its cost ceiling. They are independent and typically used together.
medium is a reasonable starting point for general-purpose assistant replies, then adjust up or down per task type based on measured quality and cost.
effort = EFFORT_BY_TASK_TYPE.get(task_type, "medium")
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
output_config={"effort": effort},
messages=[{"role": "user", "content": prompt}],
)Yes. Higher effort levels generally take longer to complete since Claude performs more reasoning work before producing the final answer.
Not necessarily. You can keep thinking={"type": "adaptive"} at low effort, Claude will still decide per-prompt whether any reasoning is warranted, just capped at a shallower depth.
Yes conceptually, since each model's baseline reasoning capability differs (Fable 5, Opus 4.8, Sonnet 5, Haiku 4.5), the same effort level does not produce identical depth or cost across models.
The request fails with an API error. Validate the value against the known set (low, medium, high, max) in your own code before sending it, so failures surface at the call site instead of deep in a request path.
Not necessarily. high effort is often sufficient for routine code review; reserve max for particularly high-stakes or complex diffs where the extra cost is justified by the risk of a missed issue.
In most applications, keep effort as a server-side decision tied to task type or internal routing logic, rather than exposing it directly to end users, to keep cost predictable.
Stack versions: Written against the Claude model lineup current as of ~June 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (the default), and Claude Haiku 4.5 - and the official
anthropicPython SDK (latest 0.x release). Model names, SDK versions, and pricing move quickly - verify current specifics at platform.claude.com/docs before relying on them.
Reviewed by Chris St. John·Last updated Jul 16, 2026