Claude Models, Prompting & Context Engineering
This domain is where candidates who write good prompts fail and architects who understand economics pass. The exam does not ask you to write the cleverest prompt. It asks which model a stage should run on, why a guardrail in the system prompt does not actually enforce anything, and what happens to the bill when you put the varying content before the stable content. Every item here has a defensible number behind it: a token price, a cache multiplier, a context ceiling. Know the numbers.
- Select appropriate Claude models based on trade-offs
- Design system prompts, templates, and guardrails
- Apply prompt engineering techniques (zero-shot, few-shot, chain-of-thought)
- Optimize context windows and manage token usage
- Implement prompt reuse strategies (caching, modular prompts, Skills)
usage.input_tokens is the uncached remainder only, the tokens processed at full price. The cached portion is reported separately in usage.cache_read_input_tokens. If you multiply input_tokens by the input price to estimate cost, you undercount every request that hit the cache, and you will conclude caching "didn't help" when it saved you 90%. Total prompt size is the sum of all three usage fields, never the one.
1. Model Selection Is a Trade-Off Table, Not a Preference
An architect does not have a favorite model. They have a routing policy: a mapping from task shape to the cheapest model that clears the quality bar for that task. The exam tests whether you can read that mapping off a table of real specifications rather than reaching for the biggest name.
| Model | Model ID | Context | Input $/1M | Output $/1M |
|---|---|---|---|---|
| Claude Opus 4.8 | claude-opus-4-8 | 1M | $5.00 | $25.00 |
| Claude Sonnet 5 | claude-sonnet-5 | 1M | $3.00 | $15.00 |
| Claude Haiku 4.5 | claude-haiku-4-5 | 200K | $1.00 | $5.00 |
| Claude Fable 5 | claude-fable-5 | 1M | $10.00 | $50.00 |
Read the table before you read the question. Three facts jump out and each is an exam item:
- Haiku's context is the odd one out. Every other model here carries a 1M window; Haiku 4.5 caps at 200K. If a scenario feeds a stage 400K tokens of retrieved context and offers Haiku as the "cost-optimized" answer, Haiku is disqualified by the context limit, not merely a weaker choice. The request would fail.
- Output is five times the input price on every model. A model that "thinks out loud" or emits a verbose rationale costs far more per token on the way out than in. Output-token discipline is a cost lever, not a style preference.
- Fable 5 is the most expensive tier, above Opus. It is not the default upgrade. Reach for it only when a task genuinely needs the most capable widely released model; otherwise Opus 4.8 is the top of the routing ladder.
The routing discipline
Route on task fit, not on a blanket cost rule. Cheap, high-volume, well-specified work (classification, extraction, routing, short summaries) goes to Haiku. Hard synthesis, long-horizon reasoning, and anything where a wrong answer is expensive goes to Opus. The middle (production workloads that need near-Opus quality at lower cost) is Sonnet's territory.
| Task shape | Route to | Why not the cheaper tier |
|---|---|---|
| Binary / enum classification, PII detection, intent routing | Haiku 4.5 | Nothing cheaper exists, and the task is fully specified |
| High-volume summarization, structured extraction | Sonnet 5 | Haiku may drop nuance; Sonnet is the volume sweet spot |
| Multi-step synthesis, ambiguous judgment, code generation | Opus 4.8 | A wrong answer here costs more than the token delta |
| Frontier reasoning, longest-horizon autonomous work | Fable 5 | Only when Opus is demonstrably insufficient |
2. Effort and Adaptive Thinking: The Architectural Dial
Beyond model choice, two request-level controls trade tokens and latency for answer quality. Together they are the finest-grained cost/quality dial you have, and the exam expects you to know they exist and default correctly.
- Adaptive thinking —
thinking={"type": "adaptive"}lets Claude decide when and how deeply to reason. On the Opus tier, omitting thethinkingparameter means the model runs with no thinking at all. If you want reasoning, you must ask for it explicitly. - Effort —
output_config={"effort": ...}sets how much the model deliberates and spends overall. The default ishigh. Lower effort means fewer tokens and lower latency at some cost to depth; raise it when correctness matters more than the bill.
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=8000,
# On Opus-tier, omitting this means NO thinking. Ask for it explicitly.
thinking={"type": "adaptive"},
# effort is NESTED inside output_config, not a top-level parameter.
output_config={"effort": "high"}, # low | medium | high | xhigh | max
messages=[{"role": "user", "content": task}],
)
The nesting is a real exam trap. effort lives inside output_config. A top-level effort= or a top-level output_format= is the wrong shape; structured output is likewise output_config={"format": {...}}. And note what is absent: there is no temperature, no top_p, no top_k. Those sampling parameters have been removed from the current models and now return HTTP 400.
# Every line below is now REJECTED on Opus 4.8 / Sonnet 5 / Fable 5:
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=8000,
thinking={"type": "enabled", "budget_tokens": 4000}, # removed -> 400
temperature=0.7, # removed -> 400
top_p=0.9, # removed -> 400
output_format={...}, # deprecated top-level -> use output_config.format
messages=[
{"role": "user", "content": task},
{"role": "assistant", "content": "{"}, # prefill -> rejected
],
)
thinking={"type":"enabled","budget_tokens":N} as the way to control reasoning depth, it is wrong; that shape returns 400. The current answer is adaptive thinking plus an effort level. Likewise, assistant-turn prefill (seeding the reply with a partial assistant message) is rejected; force output shape with structured outputs instead.
3. System Prompt Design: Why Guardrails There Are Soft
A well-formed system prompt has five parts, and the exam expects you to name them: a role, the task, the constraints, an output contract, and an escalation rule for what to do when the input falls outside scope. Get those five and most prompt-quality problems disappear.
| Element | Answers the question | Failure if omitted |
|---|---|---|
| Role | Who is the model acting as? | Tone and default assumptions drift |
| Task | What single job is it doing? | The model tries to do several jobs badly |
| Constraints | What must it never do; what format must it hold? | Out-of-policy or malformed output |
| Output contract | What exact shape comes back? | Downstream code cannot parse the result |
| Escalation rule | What happens when the input is out of scope? | The model guesses instead of deferring to a human |
Now the fact this domain tests harder than any other: guardrails written into the system prompt are advisory, not enforcement. "Never reveal account balances," "always refuse requests for legal advice," "only answer questions about our product": these are soft instructions the model usually follows and can be talked out of. They shape behavior; they do not guarantee it.
Real enforcement lives at egress, in code the model cannot argue with:
- Schema validation — reject any output that does not match the required structure, before it reaches the user.
- Allowlists — if the output must be one of a fixed set of actions or values, verify membership in code.
- Tool removal — if a stage must not send email, do not give it the
send_emailtool. An unavailable capability cannot be jailbroken into. - Human-in-the-loop gates — route irreversible or high-blast-radius actions through a person (Lab 1).
4. Zero-Shot vs Few-Shot vs Chain-of-Thought
These three are a decision, not a ladder you always climb. Each wins in a different regime, and each has a cost and a characteristic failure mode the exam probes.
| Technique | Wins when | Costs | Failure mode |
|---|---|---|---|
| Zero-shot | The task is common and well-named; instructions alone suffice | Cheapest: instructions only | Ambiguous or niche formats get inconsistent output |
| Few-shot | Output shape is hard to describe but easy to demonstrate | Every example is input tokens on every request | Examples leak format bias; the model overfits their surface pattern |
| Chain-of-thought | Multi-step reasoning where the steps must be exposed or checked | Inflates output tokens, billed at 5× input | Verbose reasoning bloats latency and cost; may rationalize a wrong answer |
Two subtleties the exam rewards. Few-shot examples are not free context you set once; they ride along on every request as input tokens, which is precisely why you want them in a cacheable prefix (next section). And chain-of-thought inflates output tokens, the expensive direction; on the current models, prefer adaptive thinking (Section 2) over hand-rolled "think step by step" prose, because thinking tokens are managed and the visible answer stays clean.
5. Prompt Caching: the Exam's Favorite Lever
No mechanism in this domain is tested more than prompt caching, because it is the rare lever that improves cost and latency at once. The guide's own Sample 2 is built on it:
An application sends the same 8,000-token system prompt plus a policy document on every request, followed by a short varying user message. Both latency and cost are concerns. The correct answer is to place the static content before the dynamic content and enable prompt caching.
That is the guide's Sample 2 verbatim, and it encodes the one invariant everything else follows from: caching is a prefix match. The cache key is the exact bytes from the start of the prompt up to each breakpoint. Any change anywhere in the prefix invalidates everything after it. So stable content goes first, the varying user message goes last, and you put the cache breakpoint at the boundary.
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
system=[
{
"type": "text",
"text": POLICY_DOCUMENT, # ~8,000 stable tokens
"cache_control": {"type": "ephemeral"}, # breakpoint HERE
},
],
messages=[
# The varying part comes AFTER the cached prefix.
{"role": "user", "content": customer_question},
],
)
# Verify the cache actually hit:
print(response.usage.cache_read_input_tokens) # ~8000 on a hit
print(response.usage.input_tokens) # only the uncached remainder
Now the mistake the exam builds a distractor from, putting the varying content first, so the prefix changes every request and the cache never hits:
# WRONG: the question changes every request, so it invalidates the
# entire prefix that follows it. cache_read_input_tokens stays 0 forever.
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
system=[
{"type": "text", "text": customer_question}, # varies -> poisons prefix
{"type": "text", "text": POLICY_DOCUMENT,
"cache_control": {"type": "ephemeral"}}, # never reused
],
messages=[{"role": "user", "content": "Answer using the policy above."}],
)
The rules the exam quizzes on caching
| Rule | Value |
|---|---|
| Match type | Prefix only — any byte change in the prefix invalidates all breakpoints after it |
| Render order | tools → system → messages. Stable content first, in that order |
| Max breakpoints | 4 per request |
| Cache read price | ≈ 0.1× the input price |
| Cache write price | 1.25× input (5-minute TTL) or 2× (1-hour TTL) |
| Minimum cacheable prefix (Opus 4.8) | 4096 tokens — shorter prefixes silently do not cache |
| Verify with | usage.cache_read_input_tokens — zero across identical prefixes means a silent invalidator |
The economics follow from the multipliers. A 5-minute write costs 1.25×; a read costs 0.1×. So two requests that share a prefix already win: 1.25 + 0.1 = 1.35× versus 2× uncached. The 1-hour TTL doubles the write to 2× but keeps the entry alive across gaps, worth it only when traffic is bursty enough that a 5-minute entry would expire between requests.
cache_creation_input_tokens comes back zero and you keep paying full price wondering why the "cache" saved nothing. The minimum cacheable prefix is model-dependent, and Opus 4.8's is 4096. A 3,000-token shared prompt that caches fine on a lower-minimum model will not cache on Opus. If an item says "caching was enabled but reads are zero," the shortlist is: prefix under the minimum, a silent invalidator (a timestamp or UUID in the prefix), or dynamic-before-static ordering.
6. Context Window Optimization
The 1M-token window is a budget, not a target. Cost is linear in tokens, so filling the window because it is available is the same mistake as buying the biggest model because it exists. The architect's job is to put the fewest tokens in front of the model that let it succeed.
| Technique | What it does |
|---|---|
| Retrieval, not stuffing | Fetch the few relevant passages instead of pasting the whole corpus (Lab 4) |
| Progressive disclosure | Load detail only when the task reaches for it, the model of Skills |
| Tool-output pruning | Clear stale tool results from the transcript once they are no longer needed |
| Compaction | Summarize earlier turns server-side as a long conversation approaches the limit |
| Subagent isolation | A subagent reads 40 files and returns a 200-token finding; the parent never carries the corpus (Lab 2) |
One token-counting rule the exam states plainly: count with the API, never with a foreign tokenizer.
# Token counts are model-specific. Pass the model you will actually call.
count = client.messages.count_tokens(
model="claude-opus-4-8",
system=[{"type": "text", "text": POLICY_DOCUMENT}],
messages=[{"role": "user", "content": customer_question}],
)
print(count.input_tokens)
# NEVER use tiktoken here: it is OpenAI's tokenizer and UNDERCOUNTS for
# Claude (worse on code and non-English), so any budget built on it is wrong.
tiktoken is the wrong tokenizer and undercounts for Claude. It is OpenAI's, and it under-reports Claude token counts by roughly 15–20% on ordinary text and far more on code. Any context budget, cost estimate, or "will this fit" check built on tiktoken is optimistic in a way that bites you in production when the real prompt overflows the window. Use client.messages.count_tokens() with the model you will call.
7. Prompt Reuse: Caching, Modular Prompts, and Skills
Reuse is one objective with three mechanisms, and they compose. Caching (Section 5) reuses rendered bytes. Modular prompts and Skills reuse authored content in a way that keeps those bytes cacheable.
- Modular prompts — compose the prompt from stable blocks (role, policy, format contract) plus a small volatile tail. Because the stable blocks render identically every time, they form a cacheable prefix. Modularity is what makes caching survive as the prompt evolves.
- Skills — versioned, reusable capability folders (instructions plus resources) that Claude progressively discloses: the short description sits in context by default, and the full instructions load only when the task calls for them. That is context-window optimization and reuse in one primitive.
There is a single architecture rule that ties reuse to caching, and it is worth memorizing as one sentence: anything that varies goes last.
# Stable, reusable blocks render byte-identical every request -> cacheable.
system_blocks = [
{"type": "text", "text": ROLE_AND_TASK}, # module 1 (stable)
{"type": "text", "text": OUTPUT_CONTRACT}, # module 2 (stable)
{
"type": "text",
"text": POLICY_DOCUMENT, # module 3 (stable, large)
"cache_control": {"type": "ephemeral"}, # breakpoint after the last stable block
},
]
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
system=system_blocks,
# Everything that varies is here, AFTER the cached prefix.
messages=[{"role": "user", "content": customer_question}],
)
cache_read_input_tokens reads zero. Inject anything volatile after the last breakpoint, in a message. "Anything that varies goes last" is not a style tip; it is the difference between a 90% cost cut and paying full price on every call.
8. Design Exercise: A Support System at 40k/Day
Self-driven lab Lab3_Self_Driven_Lab.ipynbScenario. A support platform sends the same 8,000-token policy prefix on every request, followed by a short varying customer question. Volume is 40,000 requests per day. Leadership wants both lower cost per ticket and faster first response. Work the numbers and the routing.
- Confirm the shape matches Sample 2. Large stable prefix, short varying suffix, both cost and latency in play. This is the caching case. Place the 8k policy in the
systemarray before the question, with acache_controlbreakpoint on the policy block. - Check the minimum. 8,000 tokens clears Opus 4.8's 4096-token minimum cacheable prefix comfortably, so the breakpoint will actually take.
- Compute the cache economics. Without caching, each request pays for 8,000 prefix tokens at input price. With caching, the first request of each 5-minute window writes at 1.25× and every subsequent request reads at 0.1×. At 40k/day the prefix is re-read constantly, so almost every request pays 0.1× instead of 1× on the prefix, roughly a 90% reduction on the 8k prefix cost, plus lower time-to-first-token because the prefix is not reprocessed.
- Choose models per stage. Route a cheap first stage (classify the ticket's intent and detect whether it is even in scope) to Haiku 4.5 ($1/$5). Send only the tickets that need genuine policy synthesis to Opus 4.8. Do not route the whole volume to Opus, and do not route the hard synthesis to Haiku to "save money"; that is the always-wrong smallest-model answer.
- Watch the context ceiling. If any stage must load a much larger policy corpus (say 300K tokens of retrieved regulation), Haiku's 200K window disqualifies it for that stage regardless of price. Sonnet or Opus, both 1M, carry it.
- Write the escalation rule into the system prompt. The five-part prompt needs its escalation clause: e.g. "If the question is not answerable from the policy above, or asks for a refund over $500, do not answer; return
{"escalate": true, "reason": ...}so a human agent takes it." Then enforce that at egress with schema validation (Section 3): the prompt asks, the validator guarantees.
Step 3 is the number you put in front of a CFO. Step 4 is the routing that keeps the bill honest. Step 6 is the one the exam tests hardest, because the escalation clause lives in a soft prompt, and the guarantee lives in the hard validator.
Check Yourself
Exam-style items. Commit to an answer before expanding.
An app sends the same 8,000-token policy document with every request, then a short varying customer question. The team reports that caching is enabled but cache_read_input_tokens is zero on every request. The prefix is well above the minimum. What is the most likely cause?
Correct: B. Caching is a prefix match. If the varying content renders before the stable content, every request has a different prefix and there is nothing to reuse; reads stay zero. The fix is dynamic-content-last: policy first with the breakpoint, question after.
A is unlikely at any real request rate; 40k/day keeps a 5-minute entry perpetually warm, and expiry would still show occasional non-zero reads. C is false; all current models cache. D inverts the actual rule: input_tokens is the uncached remainder only, so it excludes cached tokens rather than including them; the read counter is exactly how you detect a hit.
A compliance requirement states that a support agent must never reveal a customer's account balance. An architect proposes adding "You must never reveal account balances under any circumstances" to the system prompt. Which two changes actually enforce the requirement? (Choose two.)
Correct: B and C. Enforcement lives at egress and in capability, not in prose. A schema/pattern validator rejects any response that leaks a balance before it reaches the user (B), and removing the lookup tool means the customer-facing stage cannot obtain a balance to leak in the first place (C). Together they guarantee what the prompt only requests.
A is the trap: prompt instructions are advisory and can be talked out of, no matter how emphatic. D changes verbosity, not what information is disclosed. E is doubly wrong; temperature is removed from current models and returns 400, and randomness has nothing to do with a disclosure guarantee.
A pipeline has three stages: (1) classify each incoming ticket into one of six intents, (2) detect PII, and (3) synthesize a nuanced, policy-grounded resolution for the hard cases. To minimize cost per correct output, how should the stages be routed?
Correct: C. Classification and PII detection are cheap, well-specified tasks Haiku handles at $1/$5. The nuanced synthesis is where a wrong answer is expensive, so it earns Opus. Routing by task fit (cheap model for the easy stages, capable model for the hard one) minimizes cost per correct output.
A is the always-wrong "smallest model regardless of fit" answer: Haiku on stage 3 produces weak resolutions that get retried or escalated, so its cost per correct output is worse, not better. B overpays on two stages that Haiku clears easily. D reaches for the most expensive tier ($10/$50) with no evidence Opus is insufficient; Fable is not the default upgrade.
An engineer wants Claude to reason step-by-step before answering on the current Opus model and sets thinking={"type":"enabled","budget_tokens":4000} with temperature=0.3. The request fails with HTTP 400. What is the correct configuration?
Correct: B. On the current models the fixed thinking-budget shape is removed and returns 400; adaptive thinking replaces it, with depth controlled by the nested output_config.effort. Sampling parameters like temperature are also removed, so the request must drop it entirely.
A still sends the deprecated budget_tokens, which is itself the 400. C keeps both a removed parameter and puts effort at the wrong level; effort must be nested inside output_config. D relies on assistant-turn prefill, which is rejected on current models; force structure with structured outputs, and get reasoning from adaptive thinking, not a prefilled preamble.
Key Takeaways
usage.input_tokensis the uncached remainder only. Total prompt size is the sum ofinput_tokens+cache_creation_input_tokens+cache_read_input_tokens. Cost math on the single field undercounts every cache hit.- Route by task fit: Haiku 4.5 for cheap well-specified work, Opus 4.8 for hard synthesis, Sonnet 5 for the volume middle, Fable 5 only when Opus is demonstrably insufficient. "Smallest model regardless of fit" is always wrong.
- Haiku's 200K context is the odd one out; a stage that needs more than 200K tokens disqualifies Haiku on capacity, not price.
- On Opus-tier, omitting
thinkingmeans no thinking. Usethinking={"type":"adaptive"}and the nestedoutput_config={"effort":...}dial.budget_tokens,temperature, top-leveloutput_format, and assistant prefill all return 400. - System-prompt guardrails are soft. Real enforcement is at egress: schema validation, allowlists, tool removal, human gates. When an item asks how to guarantee behavior, the answer is a code-level control, not a stronger instruction.
- Caching is a prefix match: stable content first, breakpoint on the last stable block, varying content last. Order is
tools→system→messages; max 4 breakpoints; reads ≈ 0.1×, writes 1.25× (5m) or 2× (1h). The guide's Sample 2 is exactly this. - On Opus 4.8 the minimum cacheable prefix is 4096 tokens; below it, the breakpoint silently does nothing. Verify hits with
cache_read_input_tokens. - The 1M window is a budget, not a target. Retrieve instead of stuffing; prune tool output; compact; isolate corpora in subagents. Count tokens with
client.messages.count_tokens(), nevertiktoken. - Reuse composes: modular prompts keep a cacheable prefix, Skills progressively disclose. The one rule that ties it together: anything that varies goes last.