Product
Cutting Cloud Costs When Nothing Is Broken
Craig Conboy

What do you do when the only thing that is really wrong is the number on the cloud bill? I've been there! Somebody somewhere expected production to spend $25K a month on Anthropic inference, and we just spent $36,500 last month. Usage is up. Everyone in engineering is pretty sure things are working in the application as designed. But the budget is blown and nobody's happy.

Not every cloud cost problem is a bug.

Frugal Fixes are built to find and fix cloud waste that fits a common cost antipattern: a retry loop hammering an API, a Lambda sleeping on the clock, a per-order write to S3 that should have been a batch. Recognizable cost traps with recognizable fixes.

This post is about the other kind of cloud waste. There is no cost trap, no human error, no line of code that makes you wince. Its just software doing its thing. Software built on cloud services that bill for usage. Engineers and their coding agents can still bring those costs down, but the code on its own won't tell them what to change. They need production cost and usage data to do it.

To show what I mean, let's take a look at how a coding agent responds when we ask it to reduce costs. We will do every step twice: in the first case we will arm Claude Code with Frugal's cost and usage data, and in the second case we'll see what happens with Claude working with the code alone. We hit this same situation in Frugal's own production services, and a later post will cover how we used Frugal to bring those costs down.

The application that is spending 30% too much

Acme Expenses is an expense management backend: corporate cards, a receipt inbox, expense reports, a help center.

Acme Expenses, an expenses app for cards, receipts and reports, with eight AI features: Help Answers, Receipt Triage, Transaction Categorization, Monthly Summary, Report Titles, Violation Notes, Audit Narrative and Vendor Names.

It calls Anthropic from eight places, all through one client wrapped with the Frugal SDK:

from anthropic import Anthropic
from frugal_metrics import wrap_anthropic

client = wrap_anthropic(Anthropic())

That one line code change is what gives Frugal per-call-site token counts, latency, duplicate-request detection and prompt analysis for everything below.

From the code, we can get the list of all the call sites that contribute to our Anthropic bill:

Feature Call site Model What it does
Help Answers answer_help_question Sonnet 5 Answers help-center questions from the top five matching articles
Receipt Triage triage_inbound_email Haiku 4.5 Classifies email forwarded to the receipt inbox and pulls out merchant, total and date
Transaction Categorization categorize_transaction Haiku 4.5 Assigns an expense category to each card transaction as it posts
Monthly Summary summarize_monthly_spend Sonnet 5 Writes each account's monthly spend summary
Report Titles suggest_report_title Haiku 4.5 Suggests a title for an expense report
Violation Notes draft_violation_note Sonnet 5 Drafts the note sent when an expense breaks policy
Audit Narrative generate_audit_narrative Opus 5 Writes the narrative for an audit package, with adaptive thinking, high effort, 16K max tokens and a 30K-token prompt
Vendor Names normalize_vendor_name Haiku 4.5 Turns a card descriptor into a clean vendor name

If you were handed this list and the 30% cost reduction target, which call site would you look at first? If you said Audit Narrative, on Opus with a 30,000-token prompt and a thinking budget, you're in good company. Looks like trouble. But hold that thought.

The rest of this post walks through four decisions Claude made using data provided by Frugal: which call sites deserve an engineer's time, and then what to do about each of the three that do.

Spend time where the money is

The first question is the same one we always start with: where is the money going?

Finance says our Anthropic bill for acme-expenses is about $36.5k a month and needs to come down by at least 30%. Before anyone changes code, I want to know which AI call sites are worth an engineer's time and which we should leave alone. Use Frugal to work it out and give me a short, ranked recommendation.

Here's what Frugal returns:

AI call sites by cost, 2026-08-24 -> 2026-09-22 (30 days). Total $36,527.00.

 #  call site                                              model             calls/day   cost (30d)  share
 1  support/help_answers.py:26 answer_help_question        claude-sonnet-5      63,333   $13,870.00  38.0%
 2  inbox/email_triage.py:32 triage_inbound_email          claude-haiku-4-5     36,667   $11,440.00  31.3%
 3  ledger/categorize.py:47 categorize_transaction         claude-haiku-4-5    206,667    $7,626.00  20.9%
 4  insights/monthly_summary.py:24 summarize_monthly_spend claude-sonnet-5       1,400    $1,344.00   3.7%
 5  reports/titles.py:11 suggest_report_title              claude-haiku-4-5     80,000      $960.00   2.6%
 6  policy/violation_notes.py:41 draft_violation_note      claude-sonnet-5       3,167      $627.00   1.7%
 7  audit/narrative.py:20 generate_audit_narrative         claude-opus-5            37      $412.50   1.1%
 8  vendors/normalize.py:7 normalize_vendor_name           claude-haiku-4-5     30,000      $247.50   0.7%

Top 3 call sites: $32,936.00 (90.2% of spend).

Three call sites are 90% of the bill. Audit Narrative (generate_audit_narrative), the scary-looking Opus one, runs 37 times a day and costs $412 a month. You could delete it outright and not get 2% of the way to the target.

Anthropic spend by call site over 30 days. Help Answers $13,870, Receipt Triage $11,440 and Transaction Categorization $7,626 make up $32,936, 90% of the $36,527 total. Audit Narrative, on Opus with a 30K-token prompt, costs $412.

With Frugal's cost context in hand, Claude's recommendation was short: work on the top two first, since together they're 69% of the bill; treat the third as a design question for later; leave the bottom four ($2,247 a month between them) alone. That last part matters as much as the first. Four call sites that nobody needs to open, test, or argue about in code review.

For comparison, I asked the same question with Frugal disconnected. Working from the code alone, Claude put four other call sites ahead of Help Answers (answer_help_question), ranking it last of the five it thought were worth working on, with the note "only worth doing if Frugal shows real volume." Help Answers is the single most expensive call site, at 38% of the bill. The coding agent was doing the best it could with the insufficient information it had. The code shows what each call sends, not how often it runs, and it said so. But a team working from that ranking would have spent its first sprint on the wrong things.

Key insight from Frugal

Three of the eight call sites are 90% of the bill, and the one that looks most expensive in the code is 1.1%. Ranking by production cost first is what kept the work on the call sites that matter.

Caching repeated questions in Help Answers

Help Answers (answer_help_question) is the most expensive call site: $13,870 a month on Sonnet 5.

def answer_help_question(question: str, locale: str = "en-US") -> HelpAnswer:
    articles = search_help_articles(question, locale=locale, limit=5)
    context = "\n\n".join(f"[{a.id}] {a.title}\n{a.body}" for a in articles)

    response = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=1024,
        system=SYSTEM_PROMPT,
        messages=[{"role": "user", "content": f"Help articles:\n\n{context}\n\nQuestion: {question}"}],
    )

The code is fine. It looks up the five help articles that best match the user's question and asks Sonnet to answer from them. Frugal's detail for this call site shows what that costs:

Cost: $13,870.00 · rank 1 of 8 · 38.0% of Anthropic spend
  input         $9,120.00   65.8%      4.56B tokens
  output        $4,750.00   34.2%     475.0M tokens

Volume: 1,900,000 calls (63,333/day)

Frugal SDK metrics
  frugal.gen_ai.duplicate_requests      repeat_seen 1,216,000 of 1,900,000 (64%) · window 3600s
  frugal.gen_ai.noise_ratio             p50 0.03 · p95 0.06
  frugal.gen_ai.output_cap_utilization  p50 0.24 · p95 0.52
  frugal.gen_ai.cache_prefix_stable     system 100% · user 36%

frugal.gen_ai.duplicate_requests is measured on every call. The SDK hashes the whole request (model, system prompt, messages, parameters) and checks whether it has seen that exact request in the last hour. For this call site, 64% of requests are byte-for-byte repeats of one sent less than an hour earlier. The code takes free text, so there's no way to know that from reading it. Maybe the help widget suggests common questions, maybe everyone hits the same onboarding snag. The data doesn't tell us why but does tell us what we can do about it.

Claude went through the metrics one at a time and used each to rule something in or out:

Signal Value What it means
duplicate_requests 64% repeated within 1h Main lever. Identical request, identical answer.
cache_prefix_stable system 100%, user 36% Prompt caching barely helps: the system prompt is too short to cache, and the articles vary.
noise_ratio p50 0.03 Articles are already clean text. Nothing to strip.
output_cap_utilization p50 0.24 Lowering max_tokens wouldn't change spend.

The plan: a shared response cache in front of the call, keyed on a hash of the full request, with a one-hour TTL to match the window Frugal measured. Because the retrieved articles are part of the key, editing an article naturally invalidates the cached answer. A skipped call saves both its input and output tokens, so at a 64% hit rate that's about $8,900 a month. The repeat questions also get answered in milliseconds instead of three seconds.

Help Answers with a response cache: questions go through article search to a cache keyed on a hash of the full request with a one-hour TTL. 64% hit and return a cached answer in milliseconds with no tokens; 36% miss and go to Sonnet 5. Cost goes from $13,870 to about $5,000 a month.

Without Frugal, Claude's recommendation was to switch the model to Haiku. That's a reasonable instinct, but it's a quality trade you'd have to test, it saves less, and it applies the same fix to all the traffic when two-thirds of it doesn't need the model at all. It did mention a response cache, as something "only worth building if many questions repeat exactly." That's the right question. Frugal is where the answer lives.

Key insight from Frugal

64% of help questions are exact repeats of one asked in the last hour (frugal.gen_ai.duplicate_requests). Nothing in the code shows that, and it turns a response cache from a hunch into the obvious first move.

Stripping noise from Receipt Triage input

Receipt Triage (triage_inbound_email) is second: $11,440 a month on Haiku 4.5, which is already the cheapest model. Users forward receipts to an inbox address, and each email gets classified and its fields extracted.

def triage_inbound_email(message: EmailMessage) -> TriageResult:
    response = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=400,
        system=SYSTEM_PROMPT,
        messages=[{"role": "user", "content": f"{email_headers(message)}\n\n{email_body_text(message)}"}],
    )

The body comes from a helper that does the sensible thing:

def email_body_text(message: EmailMessage) -> str:
    """Body of the message, preferring the plain-text alternative."""
    part = message.get_body(preferencelist=("plain", "html"))
    return part.get_content() if part is not None else ""

Prefer plain text, fall back to HTML. Whether that fallback matters depends entirely on what people forward, and that isn't in the repo. Here's Frugal:

Cost: $11,440.00 · rank 2 of 8 · 31.3% of Anthropic spend
  input        $10,780.00   94.2%     10.78B tokens
  output          $660.00    5.8%    132.0M tokens

Per call: 9,800 input · 120 output tokens

Frugal SDK metrics
  frugal.gen_ai.duplicate_requests      repeat_seen 44,000 of 1,100,000 (4%) · window 3600s
  frugal.gen_ai.noise_ratio             p50 0.61 · p95 0.83

94% of the cost is input: 9,800 tokens in to get 120 tokens of JSON out. And frugal.gen_ai.noise_ratio, which measures how much of the input is HTML tags, base64 runs and long stretches of whitespace, sits at 0.61 for the median call and 0.83 at p95. Most of the receipts people forward are HTML-only emails from merchants, full of markup and inline images, so the fallback isn't the edge case. It's most of the traffic, and most of what this call site pays for is stuff the model can't use to find a merchant or a total.

With that, the plan came straight out of the data. Prompt caching is out: the only stable block is a 70-token system prompt. Changing the model is out, since it's already Haiku. Trimming output is out, at 5.8% of cost. Deduplication is real but small: 4% repeats, about $450 a month. Preprocessing is the lever. Convert HTML to text while keeping table rows together so totals stay next to their labels, drop base64 runs and data: URIs, collapse whitespace, cap the length. That's an estimated $5,000 to $7,000 a month. It also gave the change a way to check itself: after it ships, the median noise ratio should drop to near zero and input tokens per call should fall from 9,800 to somewhere around 3,000 to 4,000.

Receipt Triage input per call: 9,800 tokens today, about 39% text the model needs and 61% HTML tags, inline base64 images and whitespace. After cleanup (HTML to text, drop base64, collapse whitespace, cap length) about 3,000 to 4,000 tokens. Cost goes from $11,440 to about $4,500 to $6,500 a month.

Without Frugal, Claude followed the helper, noticed the HTML fallback and suggested the same kind of cleanup. But it could only offer it as a hypothesis: raw HTML is "typically 5–20× as many tokens as the visible text," and "this is based on reading the code, not on usage data." Step one of its plan was to go measure the call site in Frugal. That's the honest version of working without the data. You get a plausible idea and a to-do item to find out whether it's worth doing.

Key insight from Frugal

94% of this call site's cost is input, and 61% of that input is markup, base64 and whitespace (frugal.gen_ai.noise_ratio). That made preprocessing the lever and put a dollar figure on it before any code changed.

Moving Transaction Categorization to code first

Transaction Categorization (categorize_transaction) is third: $7,626 a month. It runs on every card transaction as it posts.

Cost: $7,626.00 · rank 3 of 8 · 20.9% of Anthropic spend
  input         $6,324.00   82.9%      6.32B tokens
  output        $1,302.00   17.1%    260.4M tokens

Volume: 6,200,000 calls (206,667/day)
Per call: 1,020 input · 42 output tokens · $0.00123/call

Frugal SDK metrics
  frugal.gen_ai.duplicate_requests      repeat_seen 124,000 of 6,200,000 (2%) · window 3600s
  frugal.gen_ai.noise_ratio             p50 0.01 · p95 0.02
  frugal.gen_ai.output_cap_utilization  p50 0.31 · p95 0.39
  frugal.gen_ai.cache_prefix_stable     system 100% · user 0%

Monthly cost: 2026-04 $6,268 · 2026-05 $6,519 · 2026-06 $6,779 · 2026-07 $7,051 · 2026-08 $7,333 · last 30d $7,626

This is the one where nothing is wrong. Only 2% of requests repeat, the input is clean, the output is a few dozen tokens, and it already runs on the cheapest model. The system prompt is identical on every call, but at about 1,000 tokens it's under Haiku's minimum cacheable length, so prompt caching would do nothing. Every quick fix is ruled out by the data, which is useful in itself, because it stops you from spending a week on one.

Claude's first idea was a good one that also came straight from the metrics: since roughly 940 of the 1,020 input tokens are that identical system prompt, send transactions in small groups per company so the prompt is paid once per group. That's about $5,000 a month, in exchange for a delay of up to half a minute before a category appears.

But look at it from a budget point of view. $7,600 a month, growing about 4% a month, is over $100,000 over the next year on one function that assigns expense categories. That's enough to justify a real piece of engineering. So I asked for one:

$7.6k a month, growing 4% a month, is over $90k a year on this one call site, with nothing wasteful to fix. That justifies a real engineering investment. I'd rather refactor categorization so deterministic code does most of the work and the model only handles what genuinely needs judgement. Use the fixture to work out how far that can go and what share of calls would still need the model.

The repo has an eval fixture of 4,000 categorized production transactions. Claude replayed it in date order, learning only from transactions that had already posted, and measured how much each deterministic layer could decide. The biggest layer uses the merchant category code (MCC), the four-digit code card networks attach to every merchant to say what kind of business it is, such as an airline, a hotel or a restaurant:

Transaction Categorization, code first and model last: the MCC table decides 61.9% of transactions, the memo table 25.1%, merchant history 0.9%, and Haiku 4.5 handles the remaining 12.1% that need judgement. Cost goes from $7,626 to about $920 a month in the central case, about $2,400 if conservative.

Each deterministic layer agreed with the final category at least 99.3% of the time.

The model keeps the cases that need judgement. Is dinner at a steakhouse a travel meal, a team dinner or client entertainment? That depends on the memo and the context, and that's exactly where a model earns its fee. A charge from a merchant coded as an airline is an airline ticket.

Using Frugal's per-call cost, Claude projected the call site going from $7,626 a month to about $920 in the central case, or about $2,400 if it turns out conservative, with most transactions categorized in milliseconds instead of most of a second. It was also candid about the weak spots in its own numbers: the fixture labels are mostly the model's own past answers, the memos in the fixture are tidier than real ones, and companies with custom rules weren't covered. So the plan starts with shadow mode, running the rules alongside the model and logging disagreements, and turns layers on one at a time while Frugal watches the call volume drop.

This is the kind of change no cost trap will ever flag, because there's nothing to flag. It takes an engineer deciding it's worth doing, and a number big enough to justify it.

Key insight from Frugal

Every waste signal is flat (2% repeats, 1% noise, 42 output tokens per call), but the call site costs $7,626 a month and grows 4% a month. The data rules out the quick fixes and makes the case for a real refactor.

What the data did

Put the four together and a pattern shows up. The code told Claude what each call site does. Frugal told it what that costs, how often it runs, and what the traffic looks like:

  • Where to look: three of eight call sites were 90% of the bill, and the scariest-looking one was nearly free.
  • What to do: a 64% repeat rate turned "maybe cache some answers?" into the obvious first move. A 0.61 noise ratio made preprocessing the lever, and sized it.
  • What not to do: prompt caching, model swaps and output trimming were ruled out call site by call site, before anyone wrote them.
  • Whether it's worth it: $7,600 a month with no waste is still a business case for a refactor.
  • How to tell if it worked: every plan ended with the Frugal metric that should move once the change ships.

Cost work competes for the same engineers

If the right changes are this clear, why wait for finance to ask? Mostly because each one takes engineering time, and while coding agents are making changes faster to write, they do the same for everything else competing for that week. Someone still has to judge whether a one-hour cache is acceptable for Help Answers, or when the categorization rules have run in shadow mode long enough to trust. Production cost data is what lets this work compete on its merits. It steers effort away from changes that were never going to move the bill, and it puts a number on the ones that will: about $9,000 a month for the cache, $6,000 for the email cleanup and $6,700 for the refactor.

Not every cost problem is a bug. Some are just software doing its job at a price nobody planned for. Engineers and their coding agents can still bring those costs down, as long as they have the cost and usage data to point them at the right problem.

Here I am talking about it and how the new and improved Frugal MCP brings the data to your ChatGPT, Copilot, Cursor or Claude: https://www.youtube.com/watch?v=IrRaJiZQM1I


Looking for help with cost optimizations like these? Book a Demo to see Frugal in action.

Back to Top
background Image
Robo Image

Take Frugal for a live test drive

Explore how Frugal scans your code and cloud services to find waste, recommend optimizations, and generate ready-to-use fixes in a secure, read-only environment.
background Image
robo image