Domain 2 is where an enterprise architect earns their keep. Anyone can send a prompt to the most capable model and get a good answer; the architect's job is to design a system that gets good answers at a defensible cost, latency, and failure profile across millions of calls. That means treating the model tier, the prompt prefix, the context window, and the output contract as first-class architectural surfaces — each with its own knobs and its own failure modes.
This domain covers seven interlocking concerns: selecting and routing between the Opus, Sonnet, and Haiku tiers; engineering prompt caching so a large shared prefix is paid for once instead of on every request; keeping the context window healthy as conversations and agent loops grow; using extended (adaptive) thinking and the effort control deliberately; climbing the structured-output reliability ladder; choosing between few-shot examples and instructions; and applying compaction, scratchpads, and subagent isolation to long-horizon work.
Every recommendation here should be grounded in how current Claude models actually behave — verify specifics against docs.anthropic.com / docs.claude.com rather than from memory, because the model lineup and the API surface move quickly. This guide is an independent, unofficial study aid and is not affiliated with or endorsed by Anthropic. All examples are original.
Model selection and routing across tiers
The current lineup spans three practical tiers: an Opus tier (most capable, best for hard reasoning and long-horizon agentic work), a Sonnet tier (near-Opus quality on coding and agentic tasks at lower cost), and a Haiku tier (fastest and cheapest, for simple, latency-sensitive tasks). An architect's default should be the most capable tier the budget tolerates, then route down deliberately where a cheaper tier provably suffices — never the reverse, because silently downgrading to save cost is a decision the product owner should make, not a default.
| Tier | Best for | Trade-off to weigh |
|---|---|---|
| Opus | Hard reasoning, long-horizon agents, ambiguous tasks, high cost-of-error work | Highest per-token price and latency |
| Sonnet | High-volume coding/agentic pipelines, summarization, most production traffic | Slightly lower ceiling on the very hardest tasks |
| Haiku | Classification, routing, extraction, short deterministic replies | Smaller context window; weaker on multi-step reasoning |
A common enterprise pattern is a router: a cheap Haiku-tier classifier inspects each request and dispatches simple items to Haiku, everything else to Sonnet, and escalates only the flagged-hard cases to Opus. The router itself must be cheap and fast or it eats the savings. Measure the escalation rate — if 80% of traffic escalates to Opus, the router is theater.
Route by capability signal, not by request length. A short prompt can be a hard reasoning problem and a long prompt can be trivial extraction. Use a fast classifier, an explicit difficulty tag from the calling application, or a confidence threshold on a first cheap pass with escalation on low confidence.
Prompt caching: what is cacheable and why it matters
Prompt caching is a prefix match. The cache key is derived from the exact bytes of the rendered prompt up to each cache_control breakpoint, and the render order is fixed: tools, then system, then messages. Any byte change anywhere in the prefix invalidates the cache for everything after it. This single invariant drives every caching decision an architect makes.
Place stable content first (a frozen system prompt, a deterministically ordered tool list, retrieved reference documents) and volatile content last (timestamps, per-request IDs, the varying user question). Interpolating datetime.now() or a request UUID into the system prompt header silently makes everything after it uncacheable, no matter how many cache_control markers you add.
| Economics knob | Value / rule |
|---|---|
| Cache read cost | ~0.1x base input price |
| Cache write cost | 1.25x for 5-minute TTL, 2x for 1-hour TTL |
| Max breakpoints per request | 4 |
| Min cacheable prefix (Opus tier) | ~4096 tokens; shorter prefixes silently do not cache |
| Break-even (5m TTL) | ~2 requests (1.25x write + 0.1x read vs 2x uncached) |
# Cache a large shared prefix; keep the varying question after the breakpoint.
resp = client.messages.create(
model="claude-opus-4-8",
max_tokens=16000,
system=[{
"type": "text",
"text": LARGE_STABLE_POLICY_DOC, # frozen prefix, byte-identical every call
"cache_control": {"type": "ephemeral"} # breakpoint at end of the shared portion
}],
messages=[{"role": "user", "content": user_question}], # volatile, uncached
)
print(resp.usage.cache_read_input_tokens) # >0 on the second identical-prefix callOn the current Opus tier you can inject mid-conversation operator instructions as a role:"system" message appended to the messages array instead of editing the top-level system prompt. This preserves the cached history prefix and is the prompt-injection-safe operator channel; editing the top-level system prompt would re-process every cached turn uncached.
Context-window engineering and context rot
Current flagship models offer a 1M-token context window, but a large window is a budget, not a target. Two failure modes appear as context fills: lost-in-the-middle, where the model attends less reliably to information buried in the middle of a very long prompt than to content near the start or end; and context rot, where accumulated stale tool results, superseded plans, and completed thinking crowd out the signal the model actually needs.
- Put the most decision-relevant material near the start or the end of the prompt, not buried in the middle of a long block.
- Prune stale tool outputs as an agent loop grows rather than letting them accumulate indefinitely.
- Summarize or checkpoint completed sub-tasks so their conclusions survive but their verbose transcripts do not.
- Keep a large window in reserve as headroom for the model to think and act, rather than filling it to the brim with retrieved context.
| Technique | What it does | Use when |
|---|---|---|
| Context editing | Clears (removes) old tool results or thinking blocks | Old outputs are irrelevant; you want a lean transcript without a summary |
| Compaction | Summarizes earlier context into a compact block server-side | Conversation is approaching the window limit and history still matters |
| Memory (files) | Persists state to a file directory across sessions | State must survive beyond a single conversation |
When using compaction, the API returns a compaction block that must be passed back on subsequent requests — append the full response content, not just the extracted text, or the compaction state is silently lost and history balloons again.
Extended and adaptive thinking with effort
On current models the recommended pattern is adaptive thinking: the model decides when and how much to think per request, and interleaves thinking between tool calls automatically. The older fixed thinking-token-budget approach is deprecated on current models and is rejected outright on the newest ones — designing a new system around a hard budget_tokens value is building on a retired API surface.
Depth and overall token spend are controlled with the effort parameter (inside output_config), not a token budget. Effort levels run low, medium, high, xhigh, max. Higher effort buys more thorough reasoning and verification but costs more tokens and latency; on the newest models, higher effort up front can actually reduce total cost on agentic work by cutting the number of turns needed.
| Effort | Where it fits |
|---|---|
| low | Subagents, simple scoped tasks, latency-sensitive paths |
| medium | Balanced default for many applications |
| high | Most intelligence-sensitive work; a strong default on current Opus |
| xhigh | Hardest coding and agentic use cases |
| max | Correctness matters far more than cost; test for diminishing returns |
For long agentic loops, a task budget gives the model a token ceiling it is aware of, so it paces itself and finishes gracefully instead of being cut off. This is distinct from max_tokens, which is an enforced per-response ceiling the model cannot see.
The structured-output reliability ladder
When a downstream system needs machine-parseable output, reliability is a ladder — climb to the highest rung the task supports rather than defaulting to prompt-and-hope. The rungs, from most to least reliable, constrain the output at successively weaker layers.
- Top rung: strict tool use (strict: true on the tool with additionalProperties:false + required) or output_config.format with a JSON schema — the API enforces the shape, so the output validates exactly.
- Middle rung: a non-strict tool schema — the model is strongly steered toward the shape but the guarantee is softer.
- Bottom rung: asking for JSON in the prompt and parsing the text — works, but has no enforcement and drifts under load.
# Top-rung structured output: the API guarantees the response validates.
resp = client.messages.create(
model="claude-opus-4-8",
max_tokens=16000,
messages=[{"role": "user", "content": "Extract the vendor, amount, and due date."}],
output_config={
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {
"vendor": {"type": "string"},
"amount": {"type": "number"},
"due_date": {"type": "string", "format": "date"}
},
"required": ["vendor", "amount", "due_date"],
"additionalProperties": False
}
}
},
)Two operational notes: a brand-new schema incurs a one-time compilation cost on its first request, then caches; and structured-output format is incompatible with citations (returns a 400). Also always parse tool-call inputs with a real JSON parser rather than string-matching the serialized text — current models may escape Unicode or slashes differently than older ones.
Few-shot vs instructions, and long-context strategy at scale
Current models follow clear instructions closely and interpret them literally, which shifts the few-shot-vs-instructions balance. For well-specified, unambiguous tasks, precise instructions are often cheaper and more maintainable than a wall of examples. Reach for few-shot when the task is hard to describe but easy to demonstrate — an idiosyncratic format, a subtle tone, an edge-case taxonomy. When you do use examples, positive examples of the desired output tend to steer more effectively than negative do-not lists.
At scale, long-context work is managed with three structural patterns beyond raw window size. Compaction keeps a single long conversation under the limit. Scratchpads — a memory file the agent writes to and re-reads — let it externalize working state instead of holding everything in-context. Subagent isolation gives a sub-task its own fresh context window so its verbose exploration never pollutes the orchestrator's transcript, and the orchestrator receives only the distilled result.
- Compaction: summarize earlier turns server-side as the window fills; pass the compaction block back each turn.
- Scratchpads: give the agent a memory surface and tell it where to write and when to consult it.
- Subagent isolation: fan out independent sub-tasks to subagents with their own context; the parent keeps its prefix cached and its transcript clean.
- Tool search: discover tools on demand from a large library — schemas are appended, not swapped, so the prompt cache survives.
Key takeaways
- 01Default to the most capable tier the budget allows, then route down deliberately with a cheap fast classifier; never silently downgrade, and measure the escalation rate.
- 02Prompt caching is a prefix match over tools then system then messages — freeze the prefix, put volatile content last, and verify with usage.cache_read_input_tokens.
- 03A 1M-token window is a budget, not a target: mitigate lost-in-the-middle and context rot with placement, context editing, compaction, and memory.
- 04Use adaptive thinking plus the effort parameter (low through max); fixed budget_tokens is deprecated and rejected on the newest models.
- 05Climb the structured-output ladder: strict tool use / output_config.format over a plain tool schema over prompt-and-parse; assistant prefill now 400s.
- 06Prefer precise instructions for well-specified tasks and few-shot for hard-to-describe ones; dial back aggressive scaffolding that overtriggers on current models.
- 07Scale long-context work with compaction, scratchpads/memory, and subagent isolation — the last keeps the orchestrator's cache warm and transcript clean.
- 08Switching models mid-conversation invalidates the cache; use a subagent on the cheaper model instead of swapping the main loop's model.
Common mistakes
Interpolating a timestamp, UUID, or per-user ID into the system prompt for freshness or personalization.
Keep the system prefix byte-identical and move volatile values after the last cache_control breakpoint (or into a mid-conversation system message on supporting models).
Architecting a JSON pipeline around assistant prefill or a fixed thinking budget_tokens value.
Use output_config.format or strict tool use for structured output, and adaptive thinking with the effort parameter for reasoning depth — prefill and budget_tokens are rejected on current models.
Routing to a cheaper tier by request length, or defaulting the whole system to a cheap model to save cost.
Route on a capability signal (fast classifier, difficulty tag, confidence threshold) and default to the most capable tier the budget allows, escalating only what proves hard.
Filling the 1M window with retrieved context and letting stale tool results accumulate across an agent loop.
Reserve headroom, place key material at the start or end, and apply context editing/compaction so the signal is not buried in the middle or crowded out.
Carrying over CRITICAL/YOU MUST tool scaffolding tuned for older models.
Soften to plain when-to-use descriptions; current models follow instructions literally and overtrigger on aggressive language.
Frequently asked
How should I decide between routing to Sonnet versus escalating to Opus for a given request?
Route on a capability signal rather than a guess. Run a cheap fast classifier or a first low-effort pass, and escalate to Opus only when the task is flagged hard or the first pass returns low confidence. Default high-volume, well-specified traffic (summarization, extraction, most coding) to Sonnet, and reserve Opus for ambiguous, long-horizon, or high-cost-of-error work. Then instrument the escalation rate: if most traffic escalates, your router or your tier default is miscalibrated.
Why is my prompt cache never hitting even though I added cache_control?
Almost always a silent invalidator in the prefix. Caching is a prefix match over the exact bytes of tools, then system, then messages; a datetime.now() call, a request UUID, an unsorted JSON dump, or a per-user tool set anywhere in the prefix changes the bytes and invalidates everything after it. Also confirm the prefix clears the minimum cacheable length (about 4096 tokens on the Opus tier) — shorter prefixes silently do not cache. Diff the rendered prompt bytes between two requests and check usage.cache_read_input_tokens.
Do I still set a thinking budget to control reasoning cost?
No — on current models use adaptive thinking and control depth with the effort parameter (low, medium, high, xhigh, max) inside output_config. The fixed budget_tokens approach is deprecated on current models and rejected with a 400 on the newest ones. If you need a ceiling on a whole agentic loop, use a task budget, which the model is aware of and paces itself against, distinct from the enforced max_tokens per-response cap.
What is the single most reliable way to get machine-parseable JSON out of Claude?
Climb to the top of the reliability ladder: strict tool use (strict:true with additionalProperties:false and required) or output_config.format with a JSON schema, both of which the API enforces so the output validates exactly. A non-strict tool schema is the middle rung, and asking for JSON in the prompt and parsing the text is the least reliable. Do not rely on assistant prefill — it now returns a 400 on current models.
How do I keep a long-running agent from degrading as its context fills up?
Combine three patterns. Within a turn, use context editing to clear stale tool results and completed thinking. As the conversation nears the window limit, use compaction to summarize earlier history (and remember to pass the compaction block back each turn). For state that must outlive the session, write to a memory file. At the structural level, fan independent sub-tasks out to subagents with isolated context windows so their verbose work never pollutes the orchestrator's transcript or cold-invalidates its cache.
Independent, unofficial study material. Not affiliated with, endorsed by, or authorized by Anthropic. Every example is original and written to teach the public exam objectives — no real exam questions are reproduced. Technical details reflect Claude, the Anthropic API, Claude Code, and MCP as of July 25, 2026; always confirm specifics against current official documentation.
Test yourself
Turn what you just read into answers you can check.