Once you start using an LLM for real database work — parsing alert logs, interpreting AWR reports, generating shell scripts, drafting runbooks — the bill stops being a rounding error. A workflow that costs a few cents in testing can cost hundreds of dollars a month once it runs against a production fleet every day.
The good news is that most of that cost is avoidable, and the techniques are mechanical rather than clever. This post covers what actually moves the number, in the order I would implement them.
1. Understand what you are paying for
Every API call bills on two things: the tokens you send (input) and the tokens the model generates (output). A rough rule is that one token is about four characters, or three-quarters of an English word.
The asymmetry matters:
| Model | Input / MTok | Output / MTok |
|---|---|---|
| Haiku 4.5 | $1 | $5 |
| Sonnet 5 | $2 | $10 |
| Opus 5 | $5 | $25 |
Output costs five times input on every tier. A verbose response is far more expensive than a verbose prompt. That single fact drives several of the decisions below.
2. Measure before you optimise
You cannot tune what you have not measured. This is the same discipline as looking at an AWR report before changing an init parameter.
Give each workload its own API key
The usage dashboard breaks spend down by key. One key for log analysis, one for script generation, one for ad-hoc work. Without this you know your total bill but not which job caused it.
Log the usage block from every response
Every API response returns token counts:
{
"usage": {
"input_tokens": 105,
"output_tokens": 239,
"cache_read_input_tokens": 7123,
"cache_creation_input_tokens": 7345
}
}
Capture that into a table alongside the job name and timestamp. After a week you will know exactly where the tokens go.
Count tokens before you send
count_tokens endpoint against the model you are actually calling.3. Right-size the model — the single biggest lever
Most teams pick one model and run everything through it. That is the equivalent of running every query on your largest database server.
Haiku costs one fifth of Opus on both input and output. For DBA workloads the split is usually clear:
| Task type | Model | Why |
|---|---|---|
| Log line classification, error extraction, alert routing, output formatting | Haiku | Structured input, short output, no deep reasoning needed |
| Script generation, AWR interpretation, documentation, routine analysis | Sonnet | Most day-to-day work sits here |
| Complex root cause analysis, architecture decisions, difficult migrations | Opus | Worth the price when the reasoning is genuinely hard |
A practical pattern is two-stage: use Haiku to filter and classify a large volume of input, then send only the interesting cases to Sonnet or Opus. Ninety percent of alert log lines are noise. There is no reason to pay premium rates to have them identified as noise.
4. Prompt caching — 90% off repeated context
This is the feature most people never configure, and it is usually the second biggest saving.
You mark a section of your prompt as cacheable. The first call writes it to cache; subsequent calls read it at a tenth of the standard input price.
| Operation | Cost vs base input | Cache duration |
|---|---|---|
| 5-minute cache write | 1.25x | 5 minutes |
| 1-hour cache write | 2x | 1 hour |
| Cache read (hit) | 0.1x | Same as the write |
The break-even is quick: the 5-minute cache pays for itself after a single read, the 1-hour cache after two.
The structural requirement
Static content first, dynamic content last. Caching matches on a prefix, so anything that changes between calls must come after everything that does not. If you shuffle the order, the prefix stops matching and you pay full price without noticing.
For database work, the cacheable prefix is usually substantial:
- The system prompt and role instructions
- Your environment's naming conventions and standards
- A schema definition or data dictionary extract
- A runbook or troubleshooting playbook
- Few-shot examples of good output
That block might be several thousand tokens, and it is identical on every call. Paying full price for it a thousand times a day is pure waste.
Example
import anthropic
client = anthropic.Anthropic()
RUNBOOK = open("oracle_alert_runbook.txt").read() # static, large
response = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=500,
system=[
{
"type": "text",
"text": "You analyse Oracle alert log entries. "
"Classify severity and identify the ORA error.",
},
{
"type": "text",
"text": RUNBOOK,
"cache_control": {"type": "ephemeral"},
},
],
messages=[
{"role": "user", "content": log_excerpt} # dynamic, small, LAST
],
)
Confirm it is working by checking cache_read_input_tokens in the response. If it stays at zero across repeated calls, your prefix is not matching — something dynamic has crept in ahead of the breakpoint.
5. Batch API — 50% off anything not interactive
The Batch API processes requests asynchronously at half price on both input and output. A large share of DBA automation does not need an answer in two seconds:
- Overnight alert log analysis across a fleet
- Bulk documentation or runbook generation
- Classifying a backlog of tickets or incidents
- Scanning a month of logs for a pattern
- Reviewing scripts in a repository
Batch and caching discounts stack, which is where the numbers get interesting.
custom_id, never on position. And because a batch can take longer than five minutes, use the 1-hour cache duration or your cache expires mid-run.6. Trim the payload
Because output costs five times input, response discipline matters most.
- Cap max_tokens at what the task actually needs. If you want a severity classification, you need twenty tokens, not two thousand.
- Ask for structured output. JSON or a table instead of prose. "Return only the ORA error code and a one-line cause" beats an open request every time.
- Strip boilerplate before sending. Repeated headers, banner text and duplicate stack traces are pure cost. A short pre-processing step in shell or Python pays for itself immediately.
- Summarise conversation history rather than resending every turn in a long-running session.
7. Watch the server-side tool costs
If your workflow uses built-in tools, they bill separately from tokens:
- Web search is charged per search on top of token cost, and the results count as input tokens in that turn and every following turn of the conversation.
- Web fetch has no surcharge, but the fetched content becomes input tokens. A large PDF can run to six figures of tokens. Cap it with
max_content_tokens. - Tool definitions themselves add a few hundred input tokens per request. If you are passing twenty tools and using three, trim the list.
8. Worked example
An illustrative daily workload: 500 alert log excerpts analysed per day, each roughly 2,000 tokens of log text, sharing a 3,000-token runbook prefix, producing about 300 tokens of output each.
| Configuration | Approx. daily cost | Reduction |
|---|---|---|
| Everything on Opus, no caching, real time | $16.25 | baseline |
| Routed to Haiku | $3.25 | 80% |
| Haiku + prompt caching on the runbook | $1.93 | 88% |
| Haiku + caching + Batch API | $0.98 | 94% |
Note where the saving actually comes from. Model routing does most of the work; caching and batching compound on top. If you only do one thing, make it the routing.
Your own numbers will differ — the ratio of shared prefix to unique input is what determines how much caching helps. Measure your workload first (section 2) rather than assuming these ratios transfer.
9. Implementation order
- Measure. Separate API keys, log the usage block, establish a baseline.
- Route by task. Highest impact. Move classification and extraction work down to the cheapest model that does the job well.
- Add caching. Low effort — restructure the prompt so static content comes first, add one field. Verify with
cache_read_input_tokens. - Migrate to batch. Highest effort because it changes your workflow, but a flat 50% on everything eligible.
- Trim payloads. Ongoing refinement once the structural work is done.
- Re-measure. Compare against the baseline from step 1 and validate output quality, not just cost.
References
- Pricing reference — authoritative rates and how discounts stack
- Prompt caching — breakpoints, durations, implementation
- Batch processing — submit and poll patterns
Conclusion
Token cost optimisation is closer to database tuning than to software development. You measure first, find the expensive operation, and fix that rather than micro-optimising everywhere. The same instinct that stops you adding indexes before reading an execution plan applies here.
The order that matters: route work to the right model, cache what repeats, batch what can wait. Everything else is refinement.
