Skip to content

C3 · lesson 4 · 10 min read

Step-by-step reasoning and thinking

Let Claude reason before it answers with adaptive thinking and effort, know when manual chain-of-thought still applies, and when to split work into a chain of calls.

Ընտրեք տեքստը՝ հայերեն թարգմանությունը տեսնելու համար։Highlight text to see Armenian. Machine-assisted translation; English is the source of truth.

Official video by Anthropic on YouTube. Pressing play loads it from youtube-nocookie.com. ·open on YouTube

A model that answers in one pass has to be right on the first try. For a root-cause analysis, a tricky migration or a multi-step calculation, letting it reason first improves accuracy. There are two ways to get that: built-in thinking, and asking for chain-of-thought in the prompt. On current models the first is the default and the second is a fallback.

Adaptive thinking and effort

Current models use adaptive thinking: thinking: {"type": "adaptive"}. Claude decides per request whether and how much to think, based on the difficulty of the task and the effort level, which you set in output_config.effort (low, medium, high, xhigh, max). Lower effort means less work and lower cost and latency; higher effort means more thorough reasoning.

Model family (examples) Thinking when you omit thinking
Claude Opus 5.5, Sonnet 5.5, Haiku 5.5, Opus 5 On (adaptive)
Claude Opus 4.8, 4.7, 4.6, Sonnet 4.6 Off until you set type: "adaptive"

Some models let you switch it off ({"type": "disabled"}, for example Haiku 5.5 at high effort or below). Opus 5.5 never turns it off.

Thinking comes back as thinking blocks before the text. On the Claude 5 models, display defaults to "omitted": the block is there, with a signature, but its text is empty. Set display: "summarized" to read a summary. You never get the raw chain of thought.

import os
import sys

import anthropic

client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

response = client.messages.create(
    model="claude-haiku-5-5",
    max_tokens=16000,  # thinking counts toward max_tokens, so leave room
    thinking={"type": "adaptive", "display": "summarized"},
    output_config={"effort": os.environ.get("EFFORT", "medium")},
    system="You are an SRE doing root-cause analysis. Base every claim on the log.",
    messages=[
        {
            "role": "user",
            "content": f"<log>\n{sys.stdin.read()}\n</log>\n\n"
            "What is the most likely root cause? Give the cause, the evidence lines, "
            "and one check that would confirm it.",
        }
    ],
)
for block in response.content:
    if block.type == "thinking":
        print("--- thinking (summary) ---\n" + block.thinking)
    elif block.type == "text":
        print("--- answer ---\n" + block.text)
print(response.usage)

Prompting the reasoning

  • Prefer general instructions over a script. “Consider the failure modes carefully before answering” often beats a hand-written ten-step procedure. Claude’s own plan is frequently better than the one you’d prescribe.
  • Steer how often it thinks. If it thinks too much on easy inputs, say so (“think only when the problem needs several steps”), or lower effort.
  • Ask for a self-check. “Before you finish, verify the cause against the timestamps” catches errors. (Claude Opus 5 already verifies well, and extra instructions there can cause over-verification.)
  • Examples still work. Worked examples shape how Claude reasons in its thinking.

Legacy: budget_tokens

Older code uses manual extended thinking: thinking: {"type": "enabled", "budget_tokens": N}, with a minimum budget of 1,024 that must be below max_tokens. It is deprecated on Opus 4.6 and Sonnet 4.6 and returns a 400 error on Claude 4.7 and later. To migrate, switch to type: "adaptive" and move the depth control to effort. For a hard spending cap, rely on max_tokens. Effort is guidance, but max_tokens is a strict limit.

Two side effects to know for tool use. Manual extended thinking only allows tool_choice auto or none. And wherever forced tool use is accepted, a forced call skips thinking: the response starts with the tool_use block. If Claude needs to think before calling the tool, use auto and say in the prompt when to call it.

When to chain calls instead

Thinking handles most multi-step work inside one call. Split the task into a chain of separate API calls when you need to inspect, log or gate the intermediate results. The common pattern is draft, then review against criteria, then refine. Each step is a call you can evaluate, retry or stop. A typical DevOps chain is: summarise the alert storm, classify the summary, then draft the status-page update only if the class is page.

Recap

  • Adaptive thinking is the default on current models; control depth with output_config.effort.
  • Thinking blocks come first; on Claude 5 models their text is omitted unless you set display: "summarized".
  • Prefer general reasoning instructions and self-checks over long prescribed procedures.
  • Don’t ask current models to print their reasoning; it can trigger a reasoning_extraction refusal.
  • budget_tokens is legacy and rejected on 4.7 and later; forced tool calls skip thinking.
  • Use prompt chaining when you need to inspect or gate intermediate steps.

$ ./try-it.sh

Try it: root-cause analysis with adaptive thinking

  1. Save the script from this lesson as rca.py and run it on a log excerpt from a real or staged outage: python rca.py < outage.log.
  2. Run it again with EFFORT=low and with EFFORT=high. Compare the printed usage, the latency and the quality of the answer.
  3. Read the summarised thinking. Did it rule out the wrong hypotheses you would have checked first?
  4. Change the prompt to ask for the reasoning in <thinking> tags in the answer and observe what happens (on some models this is declined with stop_reason: refusal).

Check yourself

4 questions. Original practice questions, not taken from the real exam.

  1. A cost-analysis script written last year sends thinking: {"type": "enabled", "budget_tokens": 8000}. After switching the model to claude-opus-5-5, every request returns a 400 error.

    1. What is the correct migration?

  2. An incident classifier on claude-opus-5-5 uses a JSON schema with a field called step_by_step_reasoning, filled before the classification. Some responses come back with stop_reason "refusal" and the category reasoning_extraction.

    2. What should you change?

  3. A high-volume alert-summary job on claude-haiku-5-5 is too slow and too expensive. Most alerts are simple; Claude seems to think at length even on easy ones.

    3. Which two changes reduce cost and latency as intended? (Choose two.)

    Choose 2.

  4. On claude-haiku-5-5 you force a rollback_decision tool with tool_choice {"type": "tool"}. The decisions are poor, and you notice the responses never contain a thinking block.

    4. What explains this, and what is the fix?

Answer every question to check.