Subchapter 5.40
shared/cost-optimization.mdMarkdown44 KBView on GitHub
If you arrived via
/claude-api cost-optimize: this is the right file. Execute the steps below in order rather than summarizing the guide back to the user - presenting the profile, the ranked plan, and the findings IS part of the execution. Start with Step 0 (establish scope, quality bar, and baseline), and finish with Step 4’s two deliverables: the cost profile and the changes.
API spend is optimized in units of cost per completed task, not cost per token. A model with a higher sticker price can be the cheaper option if it finishes the job in fewer turns, and a cheaper model that fails still bills its tokens, then the retry, then whatever the failure costs downstream. Every judgment below reads cost and quality together.
The levers divide into two kinds, and the order of the steps is load-bearing:
Where this workflow sits: the prompt-audit subcommand (shared/prompt-audit.md) audits the prompt surface (prompts, skills, tool descriptions) alone; this workflow is the holistic cost pass - request shape, caching, loop structure, output, batching, effort, model - and runs that audit as one sub-lever of input hygiene (§ 2.2) rather than restating its patterns; and once the project has an eval, the levers become a hillclimb - one change at a time against the eval, keep or revert (Step 3).
Measured expectations quoted below are snapshots of Anthropic’s published runs (sources at the end). They are directional, not guarantees - the validation loop in Step 3 is what makes a number true for this project - and both sources are fetched live - the platform guide through shared/live-sources.md, the cookbook at its URL in the Sources section below: wherever a fetched page differs from this snapshot, the page wins.
First, establish three things - from the request and the repository where they answer it, and from the user where they don’t. Unlike the prompt audit, this workflow is interactive by design: when context for a lever is missing, or a step would spend real money, work through it with the user rather than assuming. It is not expected to one-shot the audit. State all three at the top of the report (the baseline value itself may read “pending Step 1” at first).
Scope. If the request names files or directories, that is the scope. Otherwise it is every place the project calls the Claude API - request builders, agent loops, batch jobs. Note distinct traffic classes (an interactive path and a nightly job are different workloads even on one key): the profile, the ranking, and every validation later run per class, and “cost per task” means nothing blended across classes. Also establish which platform the code targets (first-party Anthropic API, Claude Platform on AWS, Bedrock, Vertex, or Foundry) - feature availability varies, and it filters which levers are even on the table.
Quality bar. Find the project’s eval, test suite, or outcome checks for its LLM calls. If none exists, say so prominently in the report: without one, savings cannot be told apart from regressions. Do not stop - free wins are safe to propose regardless - but mark every tradeoff lever “needs an eval before applying”, and ask the user what outcome check they can provide. An eval only validates the traffic class it covers: mark levers on uncovered paths the same way. If the only check is the user’s own manual review, it gates free wins - it never clears a tradeoff. The full no-eval endgame - including a minimal eval recipe that unblocks tradeoffs - is in Step 3.
Baseline cost per task. The baseline is whatever honest number is cheapest to obtain, in this order:
usage objects per task, not per request - four token counts, each at its own rate: regular input, cache writes (1.25x input for the 5-minute duration, 2x for 1-hour), cache reads (0.1x input), and output - multiplier structure as published on the pricing page; confirm it when you fetch the rates.For current per-model rates, WebFetch the Pricing URL from shared/live-sources.md - prices change; do not quote remembered ones (if the pricing fetch fails, effective realized rates come from dividing cost-report amounts by the usage report’s matching token counts - same model, same token type). For counting tokens in prompts and files, see shared/token-counting.md (count_tokens returns the count without running inference). Sanity-check an estimated baseline against any known monthly bill: divergence usually means multi-turn history growth the single-turn estimate missed.
The profile can be measured or estimated. Measure when the organization’s access allows it; fall back to reading the code. Either way, the levers that pay are decided by the workload’s shape, not by the list of what exists.
If the user has an Admin API key (sk-ant-admin01-... - a different key type from the standard API key; not available for individual accounts - creation and scopes are covered in the Admin API docs, reachable from the Usage and Cost Admin API URL in shared/live-sources.md), pull the real numbers instead of estimating. These are report reads, not model calls - they consume no tokens. Full parameters and response schemas: the Usage and Cost Admin API URL in shared/live-sources.md.
GET /v1/organizations/usage_report/messages with group_by[]=model and bucket_width=1d (the default page is 7 daily buckets - raise limit, up to 31; the group_by dimensions also include api_key_id, workspace_id, service_tier, and context_window, among others). Each result splits into exactly the quantities the levers below act on: uncached_input_tokens, cache_read_input_tokens, cache_creation.ephemeral_5m_input_tokens / ephemeral_1h_input_tokens, and output_tokens.GET /v1/organizations/cost_report (daily granularity, USD as decimal strings in cents) with group_by[]=description; description-grouped results carry structured model, cost_type, token_type, and service_tier fields - token_type makes the cache split readable directly in dollars. Code execution appears under a Code Execution Usage description; Priority Tier costs are not included in this endpoint - track those through the usage endpoint’s service_tier dimension.The measured profile answers directly: the real cache hit rate (cache_read_input_tokens against uncached input), how much traffic already rides the batch tier, the input/output balance, and where spend concentrates by model, key, and workspace. Check that the measured footprint plausibly matches the audited code (same models, a believable order of magnitude): the report covers the whole organization, and a key shared across projects blends their traffic - making per-project reads, including Step 3’s post-cutover confirmation, unattributable. On a mismatch, reconcile against the code estimate, scope usage-report queries by api_key_ids[] / workspace_ids[] where the separation exists (the cost report takes neither filter - it segments only by workspace, via group_by), and recommend per-project keys or workspaces as a measurement prerequisite where it doesn’t. Optimization effort follows the audited scope’s spend, not the org blend.
Without Admin API access (no Admin key, a Claude Enterprise organization, or Claude Platform on AWS - whose feature availability shared/claude-platform-on-aws.md covers) - and even with it, for the structural facts no usage report can show - read the request-building code:
Per-model defaults, parameter support, and per-platform feature availability change across releases. For any “what happens when
thinking/effortis omitted”, “does this model accepteffort“, “what levels does it support”, or “is this feature available on Bedrock/Vertex/Foundry” question, read the answer from SKILL.md -> Thinking & Effort,shared/models.md, orshared/platform-availability.md(or the live Models API) - never assume, and never encode the answer in this guide.
max_tokens set to?cache_control breakpoints already, and what do cache_read_input_tokens / cache_creation_input_tokens show in practice?Before ranking on estimates, ask the user whether the application already logs response.usage per request - and if so, to paste a representative day’s worth. That turns cache hit rate, the input/output split, and thinking-token spend from guesses into measurements at zero API cost, and it decides which tier of the ranking table below applies. If the app doesn’t log usage yet, note that adding it is itself a free-win diff (Step 3) and proceed on the code estimate.
Estimating cache hit rate without usage data. If the app logs request timestamps, simulate the TTL walk: sort timestamps, count a hit whenever the gap to the previous request is <= TTL (reads refresh the entry), and run it for each cache TTL the platform offers (see shared/prompt-caching.md) - the difference between durations is the longer-TTL lever’s ceiling on the user’s real traffic. If only aggregate volume is known, approximate with Poisson arrivals: hit rate ~ 1 - e^(-lambda·TTL) where lambda is requests per second. Either beats comparing average gap to TTL, which ignores burstiness.
Before touching code, size each lever the profile makes applicable so the shortlist can be ordered. How you quote the size depends on what data you have - an estimate and a measurement must not look the same in the report:
| Data available | Quote each ceiling as |
|---|---|
| Admin API usage/cost report | Dollar range, labeled measured |
App-side usage logs, or a user-reported bill total only | % of current bill, with dollars only as a parenthetical “(~ $Y at your reported $X/mo)” - the % is the claim; the $ is the user’s own arithmetic |
| Neither (pure code read) | Relative buckets - “largest / medium / small”, or an order-of-magnitude band - no specific figures |
Before sizing, drop any lever the target platform doesn’t support (shared/platform-availability.md is the single source of truth - do not assume 1P availability carries to Bedrock, Vertex, Foundry, or Claude Platform on AWS). A lever that can’t ship on the user’s platform isn’t worth ranking; list it under “skipped” with the availability reason instead.
Within whichever unit applies, size each lever from the measured (or estimated) spend components and the measured expectations quoted in Step 2 - for example:
uncached_input_tokens with the code profile here: unique per-request payload can never cache, so on a workload that is mostly payload (or already well cached) this ceiling is honestly small. Sanity-bound the result against the published agent-loop range (a factor of 2.5 to 3.7 off at 81% to 90% hit rates).service_tier to find what already batches, use a finer bucket_width to spot scheduled spikes, and ask the user which traffic can wait.Ceilings that claim the same tokens (caching an inlined document versus deleting it) are mutually exclusive: compute each ceiling unconditionally, rank, then deflate each for its overlap with the levers above it, so the shortlist can never sum past the bill.
Present the ranked shortlist with the profile evidence behind each number - labeled as ranked by savings ceiling, not application order (Step 2’s § 2.x numbering decides the sequence) - and say where the list stops: a lever whose ceiling is a small fraction of the bill - or would not repay the approved runs and effort needed to validate it - does not earn an eval cycle, and most levers will not earn a place on any given workload (the “Workload shape -> lever” table near the end of this file is the map for matching profile to levers). On a small bill the honest shortlist may be empty: “nothing here is worth changing” is a successful finding, not a failure - report it plainly. Expected savings are planning numbers, not results - Step 3’s measurements are the results.
Free wins may be applied directly when the request asked for edits (a bare subcommand invocation has not asked - propose). Tradeoff levers (2.6 onward) are always presented with their measured quality cost and applied only on the user’s explicit acceptance - never trade accuracy for cost silently. And every run that exercises the model - the baseline, each lever’s validation pass - spends real API money: get explicit approval before each one, with the expected cost, or once as a Step 3 measurement budget that covers them.
Pricing multipliers quoted below (cache read/write rates, batch discount) are current as of writing - confirm against the Pricing URL in shared/live-sources.md before computing any ceiling.
Every turn of an agentic task resends the entire growing conversation - system prompt, tool definitions, every prior turn - so a 40-turn task sends its first turn 40 times and task cost grows with roughly the square of turn count. Caching does not stop the resending; it reprices it to 0.1x for everything already cached.
For design and placement - the prefix-match invariant, classifying inputs by stability, breakpoint patterns, the anti-pattern table - read shared/prompt-caching.md and follow its workflow; do not improvise cache_control markers. Points that matter specifically for cost:
shared/prompt-caching.md § Automatic vs explicit breakpoints.shared/prompt-caching.md § Choosing the TTL.thinking or effort between requests (always invalidates the messages cache, and on some models the tools+system cache too - shared/prompt-caching.md § Invalidation hierarchy); changing a task budget mid-task; every context-editing pass; switching models mid-conversation (caches are per-model).cache_read_input_tokens should dominate regular input_tokens, and cache_creation_input_tokens should be roughly one turn’s worth, not the whole conversation. If it isn’t, hunt for a cache-breaker with the healthy-loop signature and payload-diff method in shared/prompt-caching.md § Verifying cache hits - unless the workload’s input is mostly unique per-request payload (which can never cache), or the misses are concurrent-batch artifacts (§ 2.5); neither is a breaker, and neither has a fix.input_tokens, cache_creation_input_tokens, cache_read_input_tokens, output_tokens) for both; and exits non-zero if the second request’s cache_read_input_tokens is zero. Ship it alongside the caching diff so the user can run the before/after themselves. It spends real tokens and may execute the project’s tools - run it only under the standing approval rule, and point it at a scratch environment if the request’s tools mutate state.Send the model what the task needs, let it fetch the rest. Each sub-lever has a skip-when; the caveat at the end of this section governs all of them.
defer_loading on rarely-used tools, so definitions load only when needed. Pays once schemas run past roughly 10K tokens (MCP servers reach that fast); below that the search step is overhead. Measurement gotcha: the token-counting endpoint rejects server tools - read billed input off a max_tokens: 1 request instead (a paid, if tiny, model call: it sits under the standing approval rule).shared/live-sources.md).get_policy(claim_id) over get_all_policies()), and give list tools limit/fields/date_range parameters.shared/token-counting.md): count first, then truncate, summarize, or route oversize payloads to the Files API.prompt-audit subcommand (shared/prompt-audit.md) as part of this step; its pattern tables are the reference for dated prompt text (this guide deliberately does not restate them), and its report and proposed diff fold into this workflow’s deliverables. Skip when the prompt surface is small and recently audited. Prompts written for an older model make the current one over-work: on a support-desk evaluation, prompts written for Claude Opus 4.8 cost 36% more per ticket on Claude Opus 5 for no change in accuracy; audited, the same prompts were 14% cheaper than unaudited and more accurate (97% of tickets, up from 92%). On the Claude Sonnet 4.6 to Claude Sonnet 5 migration the audit took 14% off at the same accuracy.Caveat for the whole section: a smaller prefix is not automatically a cheaper task. Deferring context means the model may spend discovery turns fetching what it previously read inline. Validate against the eval - on the cookbook’s workload, wrapping the manual in a tool matched the explicit-breakpoint config on cost and gave back accuracy.
Only relevant when the profile shows deep loops with bulky accumulating results; short loops never trigger these and the added machinery is pure overhead.
instructions string so task-critical state survives the summary.max_tokens is a backstop, not a tuning knob. The model never sees it; hitting it cuts the response off mid-thought with stop_reason: "max_tokens". In Anthropic’s coding runs a 16,384-token cap ended 15% of Claude Opus 5’s attempts and a third of Claude Fable 5’s, none of them solved - capped runs spent less per attempt and bought proportionally fewer solves, so cost per solved task didn’t improve. Set it to 64,000 for agentic work (128,000 at xhigh or max effort), stream responses that large, and treat stop_reason: max_tokens as a failed attempt rather than retrying at the same cap.max_tokens.<CANNOT_REVIEW>), so it stops instead of spending tokens explaining.50% off every token in the request, including cache reads and writes - the discounts stack. The second-largest free lever after caching for unattended agent work - evaluation runs, backfills, scheduled jobs.
shared/live-sources.md).From here down, every lever trades capability for cost. Sweep on the eval, one change at a time.
Sweep effort before touching the model (on models that expose an effort parameter - check shared/models.md or the Effort Parameter URL in shared/live-sources.md). Effort scales thinking and tool-call depth without changing the model. Test each level in a separate session - changing effort mid-session invalidates the cache and distorts the comparison. Sweep mechanics that keep the comparison honest:
output_config.effort; same model throughout. Complete every sample request at one setting before starting the next, in a stable order, so cache reads are comparable across settings - and if the cache meters still differ materially between settings, say so and weight the read toward output-side cost.What to expect by workload shape:
low gave up 1 to 3 points for a third to a half off cost per task; medium matched the default’s accuracy at 70% to 85% of its cost; the default bought nothing measurable over medium on any of the four benchmarks measured. Lower effort is also faster (4.5 versus 7.9 minutes per problem on one research benchmark).medium for half the cost, and about 8 points at low for a quarter of it.Re-run failures at higher effort - when the workload has a usable failure signal (tests, a checker, a validator). Run everything at low and re-run failures at the default: in Anthropic’s coding runs, about 93% passed for about $0.70 per task, against 91.7% for $1.39 running everything at the default - the same pass rate for half the cost, counting the failed cheap attempts. Starting at medium solved about 94% for about $0.95. Use this for the saving, not the lift, and price in the checker and the doubled wall-clock on failures.
Task budgets (the model sees the budget and paces itself - this is the budget control that saves money): set from the loop’s 90th-percentile token usage, then tighten. The budget is advisory - it steers the model rather than stopping it - so verify adherence on the workload. Measured on coding: a generous budget gave up about 2.7 points of pass rate for an 18% saving; the tightest allowed budget gave up 4.4 points for 47%. Budgets below the 20,000-token floor are rejected; very tight budgets can produce refusal-like behavior; set the budget once on the first request - a mid-task change invalidates the cache. Check model availability before wiring it in (beta, and not available on every current model) - parameter shape, the streaming requirement, and supported models are in this skill’s SKILL.md -> Task Budgets (Quick Reference) and shared/model-migration.md -> Task Budgets.
Backstops that don’t save per-task money but cap the damage: a Managed Agents session budget is a hard dollar stop; a workspace spend limit is the final backstop on the whole workspace.
Model choice constrains the intelligence ceiling, which is why it comes after every lever that doesn’t.
low effort beat Claude Sonnet 5 on a deep-research benchmark while costing about 10% less per task; on a coding subset both models largely saturate, Claude Opus 5 matched Claude Fable 5 (91.7% versus 91.3%) at about 60% of its cost. For most agent workloads, start with Claude Opus 5. At the other end, Claude Haiku 4.5 answered knowledge questions at about a tenth of Claude Opus 5’s cost per question at 63% accuracy versus 92% - it fits high-volume work with checkable outputs, not long agentic loops.low passes the eval, drop one model tier, confirm which parameters and effort levels the target tier supports (SKILL.md -> Thinking & Effort), reset effort to that tier’s default - not a hardcoded level; the default and the supported range vary by model - and re-sweep down from there (on a tier without effort support, evaluate at its single default only). One notch at a time, against the eval - and when there is no cheaper tier, the lever is exhausted; say so rather than inventing a step. Current model lineup and discovery: shared/models.md; for model-swap mechanics and per-target breaking changes, the migrate subcommand (shared/model-migration.md).medium effort, at about the same cost - sweep effort and price the stronger model alone before adding the advisor.response.usage logging is itself a free-win diff, and it is the measurement channel for everything after it when there is no Admin API key.response.usage, and reports pass rate and cost per task. Each config is one invocation; the sweep is a loop over configs.Adapted from the cookbook’s takeaways table, for mapping a profile to levers (row 1’s watch-out is extended):
| Where the cost is | Reach for | Skip it or watch out when |
|---|---|---|
| Same system prompt and tools re-billed on every call | Prompt caching with auto first, then an explicit breakpoint on the static prefix when many independent conversations share it or prefix layers change at different rates, and 1-hour TTL if calls are more than five minutes apart | Anything dynamic sits above the breakpoint - move that content into the user turn. And a cache that already reads well needs nothing: concurrent-batch misses (§ 2.5) aren’t breakers, and a 1-hour TTL doesn’t reach calls that are hours apart |
| Large reference document in every prompt | Move it behind a tool or skill | Each call needs most of the document rather than a section, or the eval shows misses on cases that hinge on rules the model has to go looking for |
| Many or heavy tool schemas | Tool search with defer_loading | Under roughly 10K schema tokens, where the search step is overhead |
| Images, PDFs, or large files in context | Downscale images to what the task needs, and use the Files API plus code execution for tables and PDFs | There is nothing to extract or compute so the sandbox only adds tokens |
| Unbounded user-supplied input | Token counting as an ingestion gate | |
| Bulky results piling up across a long loop | Context editing or compaction server-side, or a client-side prune at natural boundaries | Loops are short or the cleared content is still needed, and note that every edit breaks the cache from that point |
| One self-contained step with bulky intermediates | Subagent, optionally on a cheaper model | The deciding model needs that intermediate context to judge well |
| Long visible responses | Specify the output shape with an example, with max_tokens as a backstop and a stop-sequence sentinel for early exits | |
| Thinking and tool calls dominate, and the eval has headroom | Lower effort first, then drop a model tier and re-sweep effort | Always a direct capability trade, so step down one notch at a time against the eval |
| Mostly routine cases with a few hard ones | Advisor tool on a cheaper driver | There is no cheap signal to gate the consult, leaving the driver to spot hard cases itself |
| No one is waiting on the response | Batch API, flattening a tool loop into one request by pre-fetching its inputs if you have to | A user is waiting, or when flattening changes how the model reasons |
Report skeleton (section order and required columns - keep the rest flexible):
Lever | Type (free win / tradeoff) | Savings ceiling | Data source (measured / usage logs / code estimate). Ceiling is in the unit tier the data supports (Step 1 -> Rank the levers). Caption the table “ranked by savings ceiling, not application order.”The measured results above come from two published Anthropic sources (and the Admin API facts in Step 1 from a third); fetch them when the user needs the full write-ups, charts, or current numbers:
shared/live-sources.md.https://platform.claude.com/cookbook/cost-optimization-cost-optimization) - a runnable end-to-end worked example of this workflow.shared/live-sources.md; the endpoint reference pages linked from that page carry the full parameter and response schemas.shared/live-sources.md, never remembered rates.