Site

Models — Choosing the Right Model

Tutorial 8.0  •  AI / Learn

8.0 What This Teaches

The Anthropic API offers several Claude models at different capability and cost levels. Picking the right one for each task saves money and improves response speed without sacrificing quality. This tutorial covers:

8.1 The Claude Model Family

Claude models come in three tiers. Each tier has a distinct speed/cost/capability trade-off:
TierModel IDBest For
Haiku claude-haiku-4-5-20251001 Fast, cheap, simple tasks: classification, short summaries, simple Q&A
Sonnet claude-sonnet-4-6 Balanced performance: most code tasks, moderate reasoning, everyday use
Opus claude-opus-4-7 Complex reasoning, architecture design, hard debugging, nuanced writing
Haiku is the fastest and least expensive. Opus is the most capable but slowest and most expensive. Sonnet sits in the middle and handles the majority of real-world tasks.

8.2 Choosing by Task

Use this table as a starting point. When in doubt, try Sonnet first and move up to Opus only if quality is insufficient.
TaskRecommended ModelReason
Simple Q&AHaikuShort prompt, short answer - no heavy reasoning needed
Code generationSonnetGood code quality at reasonable cost
Complex architecture designOpusRequires deep multi-step reasoning
Batch classificationHaikuHigh volume, low complexity - cost matters
Debugging hard bugsOpusNeeds careful multi-file reasoning
Unit test generationSonnetRepetitive structured output - Sonnet handles it well

8.3 The model Parameter

Switching models requires changing only one string. The following script sends the same prompt to all three models and prints each response along with token usage:
# compare_models.py - send one prompt to all three Claude tiers.
import anthropic

client = anthropic.Anthropic()

MODELS = [
    "claude-haiku-4-5-20251001",
    "claude-sonnet-4-6",
    "claude-opus-4-7",
]

PROMPT = "Explain what a Python decorator is in two sentences."

for model_id in MODELS:
    response = client.messages.create(
        model=model_id,
        max_tokens=256,
        messages=[{"role": "user", "content": PROMPT}]
    )
    usage = response.usage
    print(f"--- {model_id} ---")
    print(response.content[0].text)
    print(f"Input tokens: {usage.input_tokens}  Output tokens: {usage.output_tokens}")
    print()
Run this and compare the three responses side by side. You will often find Haiku gives a usable answer in a fraction of the time.

8.4 The max_tokens Parameter

max_tokens caps how many tokens the model may generate in one response. Each model has its own maximum output limit - Haiku's ceiling is lower than Opus's. Always set max_tokens explicitly so the API does not use an unpredictable default. A good rule of thumb:
# Always set max_tokens - never rely on the default.
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=512,          # explicit limit
    messages=[{"role": "user", "content": "Write a Python sort function."}]
)
If the response is cut off, check response.stop_reason. A value of "max_tokens" means the output was truncated - raise the limit and retry.

8.5 The temperature Parameter

temperature controls how random the model's output is. It ranges from 0.0 to 1.0: For code generation, use temperature=0. Random variation in code causes inconsistent output and makes automated testing unreliable. For creative writing or brainstorming, a higher temperature produces more varied results.
# code_gen.py - temperature=0 for deterministic code output.
import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=512,
    temperature=0,           # deterministic output for code tasks
    messages=[
        {"role": "user", "content": "Write a Python function that reverses a string."}
    ]
)

print(response.content[0].text)

8.6 Switching Models in Code

Hardcoding model strings at every call site makes them hard to update when a new version ships. Wrap the call in a function with a default model parameter instead:
# call_model.py - encapsulate model choice so callers stay clean.
import anthropic

client = anthropic.Anthropic()

def call_model(prompt, model="claude-sonnet-4-6", max_tokens=512, temperature=0):
    """Send a single-turn prompt and return the response text."""
    response = client.messages.create(
        model=model,
        max_tokens=max_tokens,
        temperature=temperature,
        messages=[{"role": "user", "content": prompt}]
    )
    return response.content[0].text

# Normal use - Sonnet with defaults
answer = call_model("What is a Python list comprehension?")
print(answer)

# Escalate to Opus for a harder question
design = call_model(
    "Design a thread-safe task queue in Python.",
    model="claude-opus-4-7",
    max_tokens=1024
)
print(design)
Callers never see a model string. To upgrade the default across the whole app, change one line in call_model.

8.7 Exercise

Exercise Write a script that sends the prompt "Write a Python function to check if a number is prime" to both claude-haiku-4-5-20251001 and claude-sonnet-4-6. For each model, print the full response and then print the input token count, the output token count, and the total tokens used. Compare the two responses: does Haiku's answer look correct? Is there a quality difference worth the cost difference?

8.8 Common Mistakes

Always using Opus when Haiku or Sonnet would do

Opus costs significantly more and responds more slowly than the other tiers. Using it for simple Q&A or classification wastes money and adds latency. Start with Haiku or Sonnet and move up only when output quality is insufficient.

Not setting temperature=0 for code tasks

# Bad - default temperature introduces randomness in code output.
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=512,
    messages=[{"role": "user", "content": "Write a sort function."}]
)

# Good - pin temperature for reproducible code.
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=512,
    temperature=0,
    messages=[{"role": "user", "content": "Write a sort function."}]
)
Random variation in code output causes different runs to produce structurally different functions, making automated testing unreliable.

Hardcoding model strings throughout your app

# Bad - model string scattered at every call site.
client.messages.create(model="claude-sonnet-4-6", ...)
client.messages.create(model="claude-sonnet-4-6", ...)

# Good - one constant or function, updated in one place.
DEFAULT_MODEL = "claude-sonnet-4-6"
client.messages.create(model=DEFAULT_MODEL, ...)
When a model version is deprecated, you will need to update every scattered reference. Use a constant or wrapper function.

8.9 Key Terms

TermMeaning
model familyThe set of related Claude models sharing an architecture generation
HaikuThe fast, low-cost Claude tier for simple tasks
SonnetThe balanced Claude tier suited to most everyday and code tasks
OpusThe most capable Claude tier for complex reasoning and architecture
temperatureA 0.0-1.0 parameter controlling output randomness; 0 = most deterministic
deterministicProducing the same output for the same input; temperature=0 approaches this
max output tokensThe per-model ceiling on how many tokens one response may contain
model IDThe exact string passed to the model parameter, e.g. claude-sonnet-4-6