Claude Agent SDKclaude-agent-sdk 0.2.157 · Python 3.10+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
46 small wins to finish your pathNext lesson →

Model, thinking and effort

effort is the option that says how much reasoning Claude puts into a turn, and model, fallback_model, thinking and betas choose and tune the model doing it.

Last updated: 20 Oct, 2026 · Claude Agent SDK

A schema decides the shape of the answer. These options decide who writes it and how hard they work on it. All of them reach Claude Code as flags, so the command line is the place to check what you asked for.

Choosing a model and a backup

python
from claude_agent_sdk import ClaudeAgentOptions
from flags import flags

# the backup takes over while the first is overloaded, and is dropped when it recovers
print(flags(ClaudeAgentOptions(model="claude-sonnet-5", fallback_model="claude-opus-5")))
print(flags(ClaudeAgentOptions(effort="low")))

model takes an alias or a full model name, and with neither it, your settings nor your environment choosing one, the session starts on Claude Code's default. fallback_model also accepts a comma separated list, and the first model is retried at the start of each user turn: configuration.

Watch out. No model is reached in this course. The desk answers from a script, its total_cost_usd is a literal zero and its token counts are word counts, so a model name in these options changes the command line and no more than that.

Turning extended thinking on and off

thinking takes one of three shapes. adaptive lets Claude decide when to think, enabled sets a token budget, and disabled turns it off. The optional display field asks for the thinking text to come back summarised rather than left out.

Example
print(flags(ClaudeAgentOptions(thinking={"type": "adaptive", "display": "summarized"})))
print(flags(ClaudeAgentOptions(thinking={"type": "enabled", "budget_tokens": 8000})))
print(flags(ClaudeAgentOptions(thinking={"type": "disabled"})))
  • adaptive becomes --thinking adaptive, and the display choice rides beside it.
  • enabled becomes --max-thinking-tokens with the budget. There is no --thinking enabled.
  • disabled becomes --thinking disabled and carries no budget.

max_thinking_tokens is the older option and the Python reference marks it deprecated. Passing both is worth doing once, to see which one the SDK keeps.

Example
print(flags(ClaudeAgentOptions(max_thinking_tokens=4000)))
print(flags(ClaudeAgentOptions(thinking={"type": "adaptive"}, max_thinking_tokens=4000)))

On its own the old option still works. Beside thinking it is dropped without a warning, which is the behaviour to know about before you set both in the same place.

Asking for more reasoning with effort

LevelWhat it doesSuits
"low"Least reasoning, fastest answersLookups, listing a directory
"medium"Balanced reasoningRoutine edits
"high"Thorough analysisRefactors, debugging
"xhigh"Deeper again, where the model supports itAgentic coding
"max"The most reasoningMulti-step problems

Leaving it unset lets Claude Code resolve the level itself. Not every model supports the parameter, and xhigh falls back to high on a model that does not take it: agent-loop.

shop_desk.py replaces ShopModel.reply with a version that reads the level, and shop_tools.py adds a second order, B22, to ORDERS. The desk turns effort into how many of the orders named in a question it bothers to check, which stands in for a model reasoning further before it answers.

Exampleshop_desk.py, the new lines inside ShopModel.reply
    def reply(self, said, results, tools=(), rules="", skills=(), agents=(), effort=None):
        ...
        # low effort reads the newest id only; from high up it checks every id it was given
        orders = ORDER.findall(said[-1]) or ORDER.findall(" ".join(said))[-1:]
        if effort in (None, "low", "medium"):
            orders = orders[:1]
Exampleshop_desk.py, think now
    def think(self, results):
        """One step from the stand-in model, with what this session gives it."""
        return self.model.reply(self.said, results, self.offered(), self.rules(),
                                self.permitted(), self.setup.get("agents") or {},
                                self.options.effort)
Exampleshop_tools.py, ORDERS now
ORDERS = {"A17": "Order A17 shipped on 3 March.",
          "B22": "Order B22 is being packed today."}

Two runs, one level apart

python
from claude_agent_sdk import ClaudeAgentOptions
from shop_tools import shop
from watch import watch


def desk(effort):
    # one option apart, and two orders named in the question
    return ClaudeAgentOptions(mcp_servers={"shop": shop}, setting_sources=["project"],
                              allowed_tools=["mcp__shop__lookup_order"], effort=effort)
Example
await watch("Where are A17 and B22?", desk("low"))
Example
await watch("Where are A17 and B22?", desk("high"))
  • At low one tool call goes out and the second order is never looked at.
  • At high both are looked up and both appear in the answer.
  • The question was the same. The level decided how much of it was answered.

Turning on a beta

betas takes the beta features the SDK knows about, and the type lists one: context-1m-2025-08-07, the million token context window.

Example
print(flags(ClaudeAgentOptions(betas=["context-1m-2025-08-07"])))

The Python reference warns that this beta is retired for Claude Sonnet 4.5 and Sonnet 4 on the Claude API, where passing it now fails any request over the standard window. A model that runs with the larger window by default is the route to take instead: the Python reference.

Where these options change a bill

  • An agent that only reads files: a smaller model and effort="low".
  • A debugging run on a hard failure: effort="high" for that run alone, set per subagent when only one part needs it.
  • A service that must answer during an outage: a fallback_model, so an overloaded first choice does not end the session.
Watch out. Effort and extended thinking are separate settings. Effort changes how much reasoning goes into a response; thinking decides whether thinking blocks are produced at all, and whether you receive their text. Low effort with thinking on is a real combination, and so is maximum effort with it off.
Try it yourself
  • Set effort="max" and compare the run with "high".
  • Pass thinking={"type": "enabled", "budget_tokens": 1} and read the flag.
  • Add a third order to the question and run both levels again.

You understood something today that you didn't yesterday.