Introduction to Claude & the Anthropic Model Family
Every lab in this course targets Claude. Before you write more code against it, get the mental model straight: who the models are, how they differ, and how to pick the right one for a task — so your choices are deliberate, not cargo-culted.
Learning objectives
- Explain what an LLM is and how Claude is trained to be helpful/harmless/honest.
- Compare the model tiers (Opus/Sonnet/Haiku) and pick one deliberately.
- Reason about context windows, tokens, and cost.
- Choose the right model per task like a lead sizing a fleet.
code/cl1-intro/ in the course, with a README on how to run it. Read here, run there — no need to copy-paste.1 · What Claude is essential
Claude is a family of large language models from Anthropic: trained on vast text to predict the next token, then aligned to be helpful, harmless, and honest. You interact with it as a conversation — a list of user/assistant messages — and it responds. Everything in this course is built on that simple loop.
2 · The model family essential
Claude comes in tiers trading capability for speed/cost. Pick by the task, not by habit.
| Tier | Strength | Use for |
|---|---|---|
| Opus | most capable, deepest reasoning | hard reasoning, agents, complex code |
| Sonnet | balanced — smart + fast | most production work, RAG, tools |
| Haiku | fastest, cheapest | high-volume, simple classification, routing |
3 · Tokens & the context window essential
Models read/write in tokens (~¾ of a word). The context window is how many tokens the model can consider at once (prompt + response). You're billed per token, so tokens = cost.
tokens.pydef estimate(words, out_words, in_per_mtok, out_per_mtok):
# rough: 1 token ~= 0.75 words -> words / 0.75 tokens
in_tok = words / 0.75
out_tok = out_words / 0.75
cost = in_tok/1e6*in_per_mtok + out_tok/1e6*out_per_mtok
return round(in_tok), round(out_tok), round(cost, 4)
# a 2000-word RAG prompt, 300-word answer (illustrative prices)
print("Sonnet:", estimate(2000, 300, in_per_mtok=3, out_per_mtok=15))
print("Haiku: ", estimate(2000, 300, in_per_mtok=1, out_per_mtok=5))
Sonnet: (2667, 400, 0.014)
Haiku: (2667, 400, 0.0047)
This tiny program answers "about how many tokens will my request use, and what will it cost?" A token is a chunk of text (~¾ of a word), and you pay per token — so counting tokens is really counting money. The function does the arithmetic; the two print lines run it for two different models.
- The function takes four inputs: how many
wordsyou send in, how manyout_wordsyou expect back, and the two per-million-token prices (in_per_mtokfor input,out_per_mtokfor output). - It converts words to tokens by dividing by
0.75(since 1 token ≈ 0.75 words, a word is a bit more than one token). So 2000 words ≈ 2667 tokens. - The
costline multiplies each token count by its price. Prices are quoted per million tokens, so it divides by1e6(one million) first, then adds the input and output costs together. - It
returns three numbers — rounded input tokens, output tokens, and dollar cost — which theprintlines show for a Sonnet-priced and a Haiku-priced call.
What the output means: Each line is (input_tokens, output_tokens, cost). The same request costs $0.014 on Sonnet but only $0.0047 on Haiku — Haiku is roughly 3x cheaper here because its per-token prices are lower.
Try this: Change the answer length from 300 to 1500 words and re-run. Output tokens are billed at the higher rate, so long answers cost more — that's why trimming responses saves real money at scale.
4 · Intermediate — how the models differ in practice intermediate
Beyond marketing tiers: bigger models reason over more steps, follow complex instructions more reliably, and hallucinate less on hard tasks — but cost more and are slower. The gap shrinks on easy tasks, where a small model is often indistinguishable and far cheaper.
5 · Advanced — pick the right model per task advanced
A deliberate choice weighs capability need vs volume vs latency budget. Model the decision.
pick_model.pydef pick_model(task_hardness, volume_per_day, latency_sensitive):
"""hardness 1-5; returns the cheapest model that meets the need."""
if task_hardness >= 4:
return "opus" # hard reasoning worth the cost
if task_hardness >= 2 or latency_sensitive is False:
return "sonnet" # the workhorse default
return "haiku" # simple + high-volume + latency-sensitive
print("complex agent: ", pick_model(5, 1000, False))
print("prod RAG: ", pick_model(3, 50000, False))
print("high-volume routing:", pick_model(1, 1_000_000, True))
complex agent: opus
prod RAG: sonnet
high-volume routing: haiku
This function makes the model choice for you: given how hard a task is, how much volume you run, and whether speed matters, it returns the cheapest model that still meets the need. It reads top-to-bottom and returns at the first matching rule, so order matters.
task_hardnessis a 1–5 difficulty score. The first check — hardness>= 4— catches the hardest tasks and returns"opus", the most capable (and priciest) tier. Once it returns, the rest is skipped.- The second rule returns
"sonnet", the balanced "workhorse" default, for medium tasks (hardness>= 2) or anything not latency-sensitive. - If neither rule fired, the task is easy and speed-sensitive, so it falls through to
"haiku"— the fastest, cheapest tier. - The three
printcalls try it on a complex agent, a production RAG endpoint, and high-volume routing, so you can see each rule pick a different model.
What the output means: A complex agent → opus, prod RAG → sonnet, high-volume routing → haiku. The rules turn a fuzzy "which model?" into a repeatable decision.
Try this: Call pick_model(3, 50000, True) — hardness 3 still returns sonnet because the >= 2 rule fires before latency is even considered. Reordering the checks would change the answer, which is why rule order is a real design choice.
6 · Professional — cost at scale professional
At production volume, model choice is a budget line. A task that's fine on Haiku but running on Opus can cost 10-20x more for no quality gain. Route by difficulty: a cheap model handles the easy majority, escalating only hard cases to a bigger one.
routing_cost.pydef routed_cost(total, pct_hard, haiku_cost, opus_cost):
hard = total * pct_hard
easy = total - hard
routed = easy*haiku_cost + hard*opus_cost # route easy->haiku, hard->opus
all_opus = total*opus_cost
return round(routed,2), round(all_opus,2), round(100*(all_opus-routed)/all_opus)
routed, naive, saved = routed_cost(1_000_000, 0.1, 0.001, 0.02)
print(f"tiered routing: ${routed} | all-opus: ${naive} | saved {saved}%")
tiered routing: $2900.0 | all-opus: $20000.0 | saved 86%
This shows why routing saves money at scale. Instead of sending every request to the expensive model, you send the easy majority to a cheap model (Haiku) and only the hard minority to the pricey one (Opus). The function compares that bill against sending everything to Opus.
- Inputs:
totalrequests,pct_hard(the fraction that truly need the big model), and the per-request costshaiku_costandopus_cost. - It splits the traffic:
hardis the hard slice,easyis everything else. Here 10% (0.1) of a million requests is hard, so 900k are easy. routedis the smart bill — easy requests billed at the cheap Haiku price, hard ones at the Opus price.all_opusis the naive bill: every request at Opus price.- The last returned number is the percentage saved: how much smaller the routed bill is versus all-Opus, as a whole-number percent.
What the output means: Routing costs $2900 versus $20000 to send everything to Opus — a 86% saving, for the same work, because most requests didn't need the big model.
Try this: Bump pct_hard from 0.1 to 0.5 and re-run. As more traffic genuinely needs Opus, the saving shrinks — routing pays off most when the easy majority is large.
7 · Tech-lead — a model policy for the team tech-lead
A lead sets a model policy: default tier, when to escalate, cost guardrails, and a review of model choice in design. This keeps the team's spend sane and choices deliberate rather than everyone defaulting to the biggest model "to be safe."
Exercise C1.1 — Size the models for an app
Context: The chapter's habits — pick by task, estimate before you build, route at scale — only stick once you apply all three to one concrete app end to end.
Your task: For an app with three workloads (complex planning agent, medium RAG endpoint, high-volume classifier), pick a model for each with pick_model, estimate monthly cost with the token helper, and compute the savings of tiered routing versus all-Opus — then write a one-line model policy.
Requirements:
- Pick a model per workload using the selector
- Estimate each workload's monthly cost from its per-request cost and volume
- Compute tiered-routing savings against an all-Opus baseline
- Distill it into a single one-line model policy for the app
- Keep prices illustrative but the method live
💡 Hint: The one-line policy should read like the default-plus-escalation rule from the ladder, specialised to this app's three workloads.
🪜 Practice ladder beginner → industry
Six graded exercises, easy to real-world. Try each before opening its solution.
Context: Picking a Claude model is a leadership decision, not a habit: Opus, Sonnet and Haiku trade capability for speed and cost. Knowing which tier fits which job is the first thing a lead sizes.
Your task: Using the lesson's model-family table, match each tier — Opus, Sonnet, Haiku — to its strength and a typical use, and name the concrete current model ID for each family.
Requirements:
- Opus (
claude-opus-4-8): deepest reasoning — hard reasoning, agents, complex code - Sonnet (
claude-sonnet-4-5): balanced — most production work, RAG, tools; the sensible default - Haiku (
claude-haiku-4-5): fastest and cheapest — high-volume classification and routing - State the general rule: pick by task, not by habit
- Give the concrete model ID for each family
💡 Hint: Start from Sonnet as the default and justify any move up to Opus or down to Haiku — the burden of proof is on leaving the middle.
Show solution
| Tier | Strength | Use for | Current model ID |
|---|---|---|---|
| Opus | most capable, deepest reasoning | hard reasoning, agents, complex code | claude-opus-4-8 |
| Sonnet | balanced — smart + fast | most production work, RAG, tools | claude-sonnet-4-5 |
| Haiku | fastest, cheapest | high-volume, simple classification, routing | claude-haiku-4-5 |
Claude comes in tiers that trade capability for speed and cost. The lesson's guidance is to pick by the task, not by habit: reach for Opus (claude-opus-4-8) only when a task genuinely needs the deepest reasoning, use Sonnet (claude-sonnet-4-5) as the balanced default for most work, and drop to Haiku (claude-haiku-4-5) for high-volume, simple, latency-sensitive jobs.
Context: A request's cost is knowable before you send it. Estimating tokens and dollars for the same prompt on two tiers turns "which model?" into an arithmetic you can put in a budget.
Your task: Using the lesson's estimate helper, compute the input/output tokens and cost of a 2000-word prompt with a 300-word answer on both Sonnet (in $3 / out $15 per Mtok) and Haiku (in $1 / out $5 per Mtok).
Requirements:
- Convert words to tokens (roughly 1 token per 0.75 words)
- Cost = (tokens / 1e6) × per-million price, summed over input and output
- Report both tiers; Haiku lands roughly 3× cheaper for the same work
- Note that output tokens bill at the higher rate
- Prices are illustrative — swap in live published rates before real budgeting
💡 Hint: Because output bills several times higher than input, trimming the answer length moves the bill more than trimming the prompt.
Show solution
def estimate(words, out_words, in_per_mtok, out_per_mtok):
# rough: 1 token ~= 0.75 words -> words / 0.75 tokens
in_tok = words / 0.75
out_tok = out_words / 0.75
cost = in_tok/1e6*in_per_mtok + out_tok/1e6*out_per_mtok
return round(in_tok), round(out_tok), round(cost, 4)
print("Sonnet:", estimate(2000, 300, in_per_mtok=3, out_per_mtok=15))
print("Haiku: ", estimate(2000, 300, in_per_mtok=1, out_per_mtok=5))
Sonnet: (2667, 400, 0.014)
Haiku: (2667, 400, 0.0047)
Words become tokens by dividing by 0.75 (1 token ≈ 0.75 words), so 2000 words ≈ 2667 tokens. Cost multiplies each token count by its per-million price and sums input and output. The same request costs $0.014 on Sonnet but only $0.0047 on Haiku — roughly 3x cheaper here — because Haiku's per-token prices are lower. These are the lesson's illustrative prices, not a live price sheet.
Context: A model selector reads its rules top to bottom and returns at the first match, so rule order silently decides behaviour. Tracing one call by hand reveals what the ordering actually prioritises.
Your task: Using the lesson's pick_model, predict the return of pick_model(3, 50000, True), explain why latency is never considered, then state what a reordering would change.
Requirements:
- Predict the concrete return value for the given inputs
- Explain that the function returns at the first matching rule (short-circuit)
- Show that a middle-hardness case matches an earlier rule before the latency rule is ever reached
- Conclude that rule order is a deliberate design choice
- State which cases a reordering would change (e.g. latency-sensitive medium tasks)
💡 Hint: Follow the rules in the exact order written and stop at the first that fires — whatever sits below it simply never runs for that input.
Show solution
def pick_model(task_hardness, volume_per_day, latency_sensitive):
"""hardness 1-5; returns the cheapest model that meets the need."""
if task_hardness >= 4:
return "opus" # hard reasoning worth the cost
if task_hardness >= 2 or latency_sensitive is False:
return "sonnet" # the workhorse default
return "haiku" # simple + high-volume + latency-sensitive
print(pick_model(3, 50000, True)) # -> sonnet
pick_model(3, 50000, True) returns "sonnet". The function reads top-to-bottom and returns at the first matching rule. Hardness 3 fails the >= 4 Opus check, but satisfies task_hardness >= 2 in the second rule — which short-circuits before the latency_sensitive half of the or is ever evaluated. So latency is irrelevant here purely because of rule order.
If you reordered the checks — e.g. testing latency_sensitive is True before the hardness-2 rule — a latency-sensitive medium task could fall through to "haiku" instead. That's why rule order is a real design decision, not an incidental detail.
Context: Routing easy traffic to Haiku and hard traffic to Opus can cut a bill dramatically — but the saving depends entirely on how much of the traffic is actually hard.
Your task: Using the lesson's routed_cost helper, compute the routed cost, the all-Opus cost, and the percent saved for 1,000,000 requests where 10% are hard, then explain what happens as the hard fraction rises to 0.5.
Requirements:
- Split traffic: the easy majority priced at the Haiku rate, the hard minority at the Opus rate
- Compute the naive all-Opus bill for the same volume
- Report the percent saved (a large majority-easy split saves the most)
- Explain that as the hard fraction rises, routed cost climbs toward the all-Opus bill
- Conclude routing pays off most when the easy majority is large
💡 Hint: The saving is really just the price gap times the easy share — shrink the easy share and the gap has less to work on.
Show solution
def routed_cost(total, pct_hard, haiku_cost, opus_cost):
hard = total * pct_hard
easy = total - hard
routed = easy*haiku_cost + hard*opus_cost # route easy->haiku, hard->opus
all_opus = total*opus_cost
return round(routed,2), round(all_opus,2), round(100*(all_opus-routed)/all_opus)
print(routed_cost(1_000_000, 0.1, 0.001, 0.02)) # (2900.0, 20000.0, 86)
tiered routing: $2900.0 | all-opus: $20000.0 | saved 86%
With 10% hard, 900k easy requests bill at the cheap Haiku price and only 100k hard ones at the Opus price, so the routed bill is $2900 versus $20000 to send everything to Opus — an 86% saving for the same work, because most requests didn't need the big model.
Raising pct_hard to 0.5 sends half the traffic to Opus, so the routed bill climbs toward the all-Opus bill and the saving shrinks. As the knowledge check states: routing pays off most when the easy majority is large; the more traffic genuinely needs the big model, the less routing helps.
Context: A real app rarely has one workload. Sizing three at once — a planning agent, a RAG endpoint, a classifier — is the exercise that turns the selector and the cost estimator into a budget line.
Your task: For a complex planning agent, a medium RAG endpoint, and a high-volume classifier, pick a model for each with pick_model and compute per-request cost with estimate, then report the choices.
Requirements:
- Planning agent (high hardness) resolves to Opus
- RAG endpoint (medium hardness) resolves to Sonnet
- High-volume, latency-sensitive classifier resolves to Haiku
- Each pick follows the selector's rules exactly — don't override by taste
- Multiply per-request cost by daily volume for each workload's budget line
- Prices are illustrative; swap in live rates before committing
💡 Hint: Let the selector make the call for each workload, then let volume × per-request cost tell you which line item actually dominates the bill.
Show solution
def pick_model(task_hardness, volume_per_day, latency_sensitive):
if task_hardness >= 4:
return "opus"
if task_hardness >= 2 or latency_sensitive is False:
return "sonnet"
return "haiku"
def estimate(words, out_words, in_per_mtok, out_per_mtok):
in_tok = words / 0.75
out_tok = out_words / 0.75
cost = in_tok/1e6*in_per_mtok + out_tok/1e6*out_per_mtok
return round(in_tok), round(out_tok), round(cost, 6)
PRICES = {"opus": (15, 75), "sonnet": (3, 15), "haiku": (1, 5)} # illustrative per-Mtok
workloads = [
("planning agent", 5, 1_000, False, 3000, 800),
("RAG endpoint", 3, 50_000, False, 2000, 300),
("classifier", 1, 1_000_000, True, 200, 10),
]
for name, hard, vol, lat, win, wout in workloads:
m = pick_model(hard, vol, lat)
tok_in, tok_out, cost = estimate(win, wout, *PRICES[m])
print(f"{name:16} -> {m:6} ~${cost}/req x {vol}/day")
The choices follow the lesson's selector exactly: the planning agent (hardness 5) → opus, the RAG endpoint (hardness 3) → sonnet, the high-volume classifier (hardness 1, latency-sensitive) → haiku. Multiplying per-request cost by daily volume turns each choice into a budget line, which is the point of sizing deliberately. Sonnet/Haiku prices ($3/$15 and $1/$5 per Mtok) are the lesson's illustrative figures; the Opus figure here is illustrative too — swap in current published prices before real budgeting.
Context: Model choice at a company is architecture, not per-engineer whim. A one-page policy makes the default, the escalation rules and the cost guardrails explicit and reviewable.
Your task: As a tech lead, write a one-page model policy for the team: default tier, escalation and downgrade rules, cost guardrails, and how model choice is reviewed — grounded in the lesson's guidance.
Requirements:
- Default to
claude-sonnet-4-5for production, RAG and tool use - Escalate to Opus only on evidence (evals show Sonnet failing hard cases)
- Downgrade to Haiku only on evidence (evals show it good enough for volume)
- Route by difficulty at scale — the tier gap is 10–20× for no quality gain on easy work
- Declare tokens/volume/estimated cost at design time and alert on deviation
- Treat model choice as a reviewed, budgeted architecture decision
💡 Hint: "With evidence" is the whole policy — every move off the default should point at an eval result, not an opinion.
Show solution
Team Model Policy
- Default tier:
claude-sonnet-4-5(Sonnet) for all new work — the balanced workhorse for production, RAG, and tool use. - Escalate to Opus (
claude-opus-4-8) only with evidence: move to Opus when evals show Sonnet failing the hard cases — hard reasoning, complex agents, complex code. Not "to be safe." - Downgrade to Haiku (
claude-haiku-4-5) with evidence: drop to Haiku when evals show it's good enough for the volume — high-volume classification, routing, latency-sensitive simple tasks. - Route by difficulty at scale: send the easy majority to a cheap model and escalate only hard cases. A task fine on Haiku but run on Opus can cost 10–20x more for no quality gain; tiered routing can save ~86% when the easy majority is large.
- Cost guardrails: every workload declares expected tokens/volume and an estimated monthly cost (via the
estimatehelper) at design time; alert when actual spend deviates. Trim response length — output tokens bill at the higher rate. - Review: model choice is an architecture decision, reviewed in design like any capacity decision — measured, budgeted, and revisited — never a per-engineer whim. Let measurement, not vibes, size the fleet.
This operationalizes the lesson's core message: default to Sonnet, escalate or downgrade only on eval evidence, route by difficulty, and treat which-model-where as a deliberate, budgeted design choice.
✓ Checkpoint — you can move on when you can…
- Explain what Claude is and how it's aligned.
- Compare tiers and reason about tokens/context/cost.
- Pick a model per task deliberately.
- Set a team model policy and route by difficulty.
Knowledge check check yourself
The tiered-routing cost model sends ~90% easy traffic to Haiku and only the hard ~10% to Opus, saving ~86% versus all-Opus. Under what condition does that saving shrink, and why?
Show answer
The lesson advises defaulting to Sonnet and moving to Opus or Haiku only with evidence. Why should model choice be driven by evals rather than defaulting everyone to the biggest model 'to be safe'?