AI and LLM Cost Audit
Worked example on synthetic data
Worked example on synthetic data — the workload, invoices and logs in this document are synthetic; the patterns and mechanisms are drawn from real audits.
| Client | Client A |
| Sector | B2B SaaS |
| Engineers | 40 |
| Geography | United States |
| Scope | Four providers, nine billed services, one 30-day invoice window. |
| Currency | USD as billed |
| Measurement window | 20 July 2026 to 18 August 2026 (30 days) |
| Invoice | INV-2026-08-0417 |
| Verification window | 1 September 2026 to 30 September 2026 (30 days) |
| Invoice | INV-2026-09-0431 |
| Report date | 2026-10-06 |
| Price table captured | 2 October 2026 |
Identified is not the same as realized. One of those numbers lives on a slide; the other has to survive the next invoice.
Structural. Structural diagnosis covering all four providers: every invoice line was attributed to a service, a feature and a provider, and reconciled back to the invoice total.
Behavioural. Behavioural diagnosis on two features only — the support assistant and the agent orchestrator — where request-level gateway logs covered the full window.
Not covered. Prompt-content analysis, per-end-customer attribution, training and fine-tuning spend, and any workload that does not appear on an invoice are out of scope for this document.
Client A spent $10,920 on AI and LLM services in the 30 days ending 18 August 2026, across 4 providers and 9 billed services. We attributed all of it, found $2,180 of avoidable spend in two mechanisms, and watched part of it come off the next invoice.
Read the two numbers separately. $2,180 was identified. $1,340 of it was implemented inside the engagement and then confirmed on the invoice from the verification window. The remaining $840 is still identified and still on the bill; it is never added to the verified figure anywhere in this document, and it is never described as a saving.
| 1 | Spend mapEvery invoice line attributed to a feature, a provider and a service. | Pages 3–4 |
| 2 | Unit economicsThree unit costs, each derived from one invoice line and one metered volume. | Page 5 |
| 3 | Waste listSeven findings: phenomenon, evidence, amount and confidence. | Pages 6–8 |
| 4 | Optimization roadmapOrdered by implementation cost, with what was actually verified. | Page 9 |
| 5 | What we do not recommendFive things we looked at and declined, with the arithmetic. | Pages 10–11 |
| 6 | Method appendixSources, sampling, assumptions, limits and the reconciliation tables. | Pages 12–14 |
Client A runs four production workloads on someone else's GPUs. The map below starts from the invoice, because the invoice is the only list of AI spend that is guaranteed to be complete: it contains every line somebody is paying for, including the ones nobody remembers building.
| Feature | Provider(s) | Monthly | Share |
|---|---|---|---|
| Support chatbotCustomer-facing assistant answering product questions inside the application. | Provider 1 | $4,180 | 38.3% |
| Batch summarisationNightly summarisation of support tickets and release notes. | Provider 1, Provider 4 | $2,640 | 24.2% |
| Retrieval and embeddingsEmbedding of customer documentation plus query-time retrieval and reranking. | Provider 2 | $1,920 | 17.6% |
| Agent retries (avoidable)Spend generated by repeat attempts rather than by new work. | Provider 3 | $980 | 9.0% |
| Dead model routesRoutes and endpoints that are billed but no longer serve a user-visible feature. | Provider 2, Provider 3, Provider 4 | $1,200 | 11.0% |
| Total | 4 providers | $10,920 | 100.0% |
Bars are drawn to the share of monthly spend. The two amber bars are the mechanisms described in section 3; they are the only part of this chart that is not doing work for a customer.
| Provider | Account | Feature(s) served | Monthly | Share |
|---|---|---|---|---|
| Provider 1Frontier model API (redacted) | acct_••••7f2 | Support chatbot / Batch summarisation | $4,820 | 44.1% |
| Provider 2Hyperscaler AI services (redacted) | acct_••••c19 | Retrieval and embeddings / Dead model routes | $2,440 | 22.3% |
| Provider 3Inference platform (redacted) | acct_••••a04 | Agent retries (avoidable) / Dead model routes | $1,420 | 13.0% |
| Provider 4Managed document AI (redacted) | acct_••••3b8 | Batch summarisation / Dead model routes | $2,240 | 20.5% |
| Total | 9 services | $10,920 | 100.0% |
| Service | Endpoint | Provider / feature | Monthly | Share |
|---|---|---|---|---|
| Chat completion, productionStreaming chat with tool calls. 20,900 sessions in the window. This is the only line the customer would notice if it changed. | prod-chat-v3 (redacted) | Provider 1Support chatbot | $4,180 | 38.3% |
| Summarisation, on-demand batchOverflow jobs sent to the frontier API whenever the nightly window overruns. | batch-sum-a (redacted) | Provider 1Batch summarisation | $640 | 5.9% |
| Embeddings, index buildRe-embedding of changed documents. A full index rebuild also ran twice inside the window. | embed-index (redacted) | Provider 2Retrieval and embeddings | $980 | 9.0% |
| Vector search, query timePer-query charges, including the reads consumed by the reranker. | vector-query (redacted) | Provider 2Retrieval and embeddings | $940 | 8.6% |
| Legacy completion routesTwo deprecated entries were still present in the gateway route table and still receiving traffic. | legacy-completion-v1 and v2 (redacted) | Provider 2Dead model routes | $520 | 4.8% |
| Agent orchestratorPlanner and executor loop for internal automations. All repeat attempts on this service are counted here. | agent-orchestrator (redacted) | Provider 3Agent retries (avoidable) | $980 | 9.0% |
| Provisioned throughput endpointBilled on a monthly minimum. No feature has routed to it since the route table was rebuilt. | pt-endpoint-eu (redacted) | Provider 3Dead model routes | $440 | 4.0% |
| Managed document pipelinePer-page pricing covering the same corpus as the batch service above. | doc-pipeline-b (redacted) | Provider 4Batch summarisation | $2,000 | 18.3% |
| Idle cloned deploymentCloned for a project that was cancelled. Still reserved, still billed, never called. | deploy-clone-07 (redacted) | Provider 4Dead model routes | $240 | 2.2% |
| Total | $10,920 | 100.0% |
Identifiers are redacted; in a live engagement this column carries the client's own account and endpoint names. Each of the 9 services was attributed to exactly one feature and one provider, so no share of any line had to be apportioned by estimate.
Three unit costs, each derived by dividing one invoice line by a volume that the provider itself meters. Nothing here is modelled from product analytics, so the arithmetic can be repeated from the invoice and the usage export alone.
| Unit | Feature | Feature spend | Volume | Derived price | Tokens / unit | Per million tokens |
|---|---|---|---|---|---|---|
| Cost per chatbot sessionFeature spend divided by metered sessions. | Support chatbot | $4,180 | 20,900 | $0.20 | 10,000 | $20.00 |
| Cost per 1,000 documents summarisedFeature spend divided by documents processed, then expressed per thousand. | Batch summarisation | $2,640 | 1,760,000 | $1.50 | 800 | $1.88 |
| Cost per 1,000 retrievalsFeature spend divided by metered retrieval calls, then expressed per thousand. | Retrieval and embeddings | $1,920 | 3,200,000 | $0.60 | 48 | $12.50 |
Seven findings, grouped into two mechanisms. Each finding carries the evidence that produced it, the amount it represents, and a confidence level with the reason for that level. Amounts are monthly and are stated at the unit prices captured on the date in the appendix.
Two mechanisms carry the whole of it: Agent retries, where work was repeated that could not have succeeded, and Dead model routes, where capacity is billed with nothing routed to it. Each finding below states the phenomenon, the evidence that produced it, the amount, and a confidence level with its reason.
A retry that eventually succeeds is cheaper than a failed customer request, so retries are not waste by definition. We counted only attempts that could not have succeeded, and attempts that repeated work the system had already completed.
$580 implemented and verified · $400 identified, not yet implemented · 45.0% of all identified waste
Routes and endpoints that are billed on schedule but no longer serve a user-visible feature. This category is the cheapest to recover and the easiest to reintroduce, which is why the roadmap ends with a control rather than with a cleanup.
$760 implemented and verified · $440 identified, not yet implemented · 55.0% of all identified waste
| Mechanism | Findings | Identified | Verified | Still open | Share of spend |
|---|---|---|---|---|---|
| Agent retries (avoidable) | 3 | $980 | $580 | $400 | 9.0% |
| Dead model routes | 4 | $1,200 | $760 | $440 | 11.0% |
| Identified waste | 7 | $2,180 | $1,340 | $840 | 20.0% |
$1,340 of the $2,180 identified waste was implemented and confirmed on the following invoice; $840 is still identified and still on the bill. Section 6 reconciles the 7 findings against the 5 invoice lines, and section 4 shows what happened when each one was acted on. Two things are deliberately not claimed as waste anywhere in this document: the difference between the two services that summarise the same corpus, and any vendor price movement inside the period.
Seven items, ordered by what it costs to implement. Configuration-only items sit above anything that needs a code change, and both sit above anything that needs a contract. Each item names the findings it closes and the spend at stake.
Move the retry decision below the response-class check so that anything which is not a transport failure or a rate limit fails immediately and surfaces the error to the calling feature.
Verification: Attempt counters for the orchestrator, plus the corresponding invoice line on the following invoice. · Configuration-only · About 1 hour of engineering time · findings F2 · Implemented and verified on the following invoice
Remove both entries from the gateway route table and rewrite the fallback rule in the same change, so that the entries cannot be reintroduced by a rule nobody is looking at.
Verification: Route table snapshot after the change, plus the disappearance of the endpoint's invoice line. · Configuration-only · About 1 hour of engineering time · findings F4, F5 · Implemented and verified on the following invoice
Exponential backoff with jitter, a hard cap of two attempts per logical task, and a per-session retry budget. The budget is what stops a degraded downstream service from being answered with more load.
Verification: Mean attempts per logical task, compared against the same statistic in the baseline window. · Configuration-only · About 2 hours of engineering time · findings F1 · Implemented and verified on the following invoice
Delete the deployment outright. The diff is the part that lasts: a monthly comparison of reserved capacity against traffic history, reviewed by a named person.
Verification: Reserved-capacity invoice line, plus the first inventory diff run. · Configuration-only · About 2 hours of engineering time · findings F7 · Implemented and verified on the following invoice
Attach an idempotency key to every tool call and resume an interrupted turn from its last checkpoint instead of replaying it. The replay is what turns one customer answer into three billed executions.
Verification: Duplicate tool-call rate per completed turn, measured over a full week after release. · Small project · 1 to 2 weeks · findings F3 · Identified, not yet implemented
Ask the provider to re-scope the reservation to the workload that actually exists, or let it lapse at the end of term. Until either happens, route the overflow batch job onto it so that the reservation carries real work.
Verification: Contract amendment or lapse date, plus the metered-request counter on the endpoint. · Commercial and configuration · 2 to 4 weeks, mostly waiting · findings F6 · Identified, not yet implemented
Flag any route with no traffic for 14 days, and any reserved capacity with no traffic for 30 days, into the same review that already looks at cost. Canary every route change so that a fallback rule cannot silently keep an old entry alive.
Verification: The control's own output, reviewed monthly. · Project, ongoing · A few days to set up, then minutes a month · findings none · Preventive control. No incremental dollars at stake
What came off the bill. 4 items worth $1,340 were implemented inside the engagement and confirmed on the following invoice. 2 items worth $840 remain identified and are not counted anywhere as a saving. Total at stake: $2,180, 20.0% of the $10,920 spent in the window.
Sequencing. Items 1 to 4 are configuration and recover $1,340 a month for hours of engineering time rather than weeks, which is why they come before anything that needs a sprint. Item 5 is the only finding that needs code, and its fix also removes a class of user-visible double answers. Item 6 unlocks a $440 finding but is gated by a contract, so it is scheduled as a commercial conversation with a technical half that can ship immediately. Item 7 carries no dollars; it is the reason items 2 and 4 will still be true in a year.
Items 1 to 4 are verified: they were implemented inside the engagement and the reduction appears on the invoice from the verification window, normalised for the 2.4% volume drift. Items 5 and 6 are carried as identified spend at $840. We are not counting them as savings, and we are not counting any provider price movement in the period as a result of our work.
This is the part of the audit that saves the most money, and it is the part nobody puts in a proposal. Each item below was looked at properly and then declined, with the arithmetic that produced the decision.
Verdict. Declined. The largest line is the largest because it is the only line a customer can see.
Verdict. Declined. Your portable spend is below the break-even point, and the comparison is already generous to self-hosting.
Inputs used: nodes for availability 2 · node price per hour 2.75 · hours per month 730 · engineer time, in FTE 0.25 · fully loaded engineer cost 12000 · platform overhead 450 · workloads treated as portable batch-summarisation, retrieval-embeddings · utilisation of one node 9
Declined on purpose. We are reporting zero waste from a difference that looks like a finding.
Verdict. Declined. The ceiling is a tenth of the vendor fee, and the ceiling is optimistic.
Inputs used: vendor fee 900 · reusable share measured 3.6 · feature batch-summarisation
Verdict. Declined. We measured the hourly distribution first, and it does not support the recommendation.
Inputs used: discount offered 50 · share already inside the window 18.1 · workloads treated as portable batch-summarisation · maximum delay introduced 12
Verdict. Declined. The tier is smaller than the redundancy it would cost.
Inputs used: tier discount 6 · services that would move s6, s7, s8, s9 · provider degradations, minutes 41, 96
What was read, how it was sampled, what was assumed, and what this document can and cannot support. The reconciliation tables at the end of this section are generated from the same data file as every number above.
| Source | What was read |
|---|---|
| Invoice, measurement window | Line-level invoice export from four providers, covering the 30 days ending 18 August 2026. |
| Invoice, verification window | The following month's export for the same four providers, used only to verify items that were implemented. |
| Provider usage reports | Metered volumes per endpoint: sessions, documents, retrieval calls and reserved-capacity availability. |
| Gateway and application logs | Request-level logs with attempt counters, response classes and tool-call fingerprints, for the chatbot and the orchestrator. |
| Read-only configuration and inventory | Gateway route table, orchestrator retry configuration, and the reserved-capacity and deployment inventory. Read as text; nothing was changed. |
| Not collected | Prompt bodies, customer content, source code and any production access. None of it was requested or received. |
Captured 2 October 2026. Unit prices were captured on the date above and archived with the working papers. Providers change prices; a report without a capture date is not checkable six months later.
| Assumption | Value used | Why it matters |
|---|---|---|
| Retry attribution | One hundred percent to the owning feature | A repeat attempt is charged to the feature that owns the request identifier and is never split across features. |
| Volume drift | 2.4% between windows | Verified reductions are normalised to baseline volume. Without this, volume growth would silently cancel part of a real reduction. |
| Document volume | Seven days extrapolated by 30 divided by 7 | The largest single uncertainty in this document, and the reason the batch unit cost is stated with more caution than the other two. |
| Currency | USD as billed | No currency conversion was applied and no list prices were reconstructed. |
| Discounts | Net amounts as invoiced | The enterprise discount was already applied upstream, so this document cannot be used to reason about list price. |
| One-off events | Included, not stripped out | Two full index rebuilds sit inside the retrieval line. They recur, so treating them as accidents would flatter the baseline. |
| Level | Meaning |
|---|---|
| High | The amount is visible on the invoice and corroborated by a second independent source, such as a log or an inventory read. Two sources, consistent, no sampling. |
| Medium | The billing is unambiguous but either the attribution is inferential or a term we cannot see affects how much is recoverable. |
| Low | Evidence exists but depends on an assumption we could not test. Nothing in this document is rated Low; anything that would have been was left out instead. |
Each table below is arithmetic rather than narrative. The middle column is generated from the same data file that produced every other number in this document, so it can be recomputed independently.
| Line item | Services | Amount | Reconciles to |
|---|---|---|---|
| Support chatbot | 1 | $4,180 | s1 |
| Batch summarisation | 2 | $2,640 | s2, s8 |
| Retrieval and embeddings | 2 | $1,920 | s3, s4 |
| Agent retries (avoidable) | 1 | $980 | s6 |
| Dead model routes | 3 | $1,200 | s5, s7, s9 |
| Sum of 5 line items | $10,920 | $10,920 |
| Finding | Amount | Verified | Pending |
|---|---|---|---|
| F1 Retry storm with no backoff and no cap Agent retries (avoidable) | $320 | $320 | — |
| F2 Retries issued on responses that could never succeed Agent retries (avoidable) | $260 | $260 | — |
| F3 Duplicate tool execution, including replay after a broken stream Agent retries (avoidable) | $400 | — | $400 |
| F4 Deprecated route still receiving live traffic Dead model routes | $300 | $300 | — |
| F5 Superseded batch route left in the table Dead model routes | $220 | $220 | — |
| F6 Reserved endpoint with no routed traffic Dead model routes | $440 | — | $440 |
| F7 Cloned deployment from a cancelled project Dead model routes | $240 | $240 | — |
| Subtotal: Agent retries (avoidable), 3 findings | $980 | $580 | $400 |
| Subtotal: Dead model routes, 4 findings | $1,200 | $760 | $440 |
| Identified waste, 7 findings in 2 mechanisms | $2,180 | $1,340 | $840 |
$1,340 realized and verified plus $840 still identified equals the $2,180 identified waste, which is 20.0% of the $10,920 spent in the window: $1,340, 12.3% of spend, and $840, 7.7% of spend. Rounding is applied for display only. Reconciliation uses unrounded values, which is why a column of displayed figures can appear to be off by a tenth of a percent.
On redaction. In a real engagement this appendix carries the client's own account identifiers, endpoint names and route table keys. In this worked example every identifier has been redacted to a form such as acct_••••7f2 or prod-chat-v3 (redacted). The redaction is cosmetic: it removes names, not amounts, and the arithmetic is unaffected.
The two mechanisms that mattered here were a retry policy that never read the response class, and a route table that outlived the models in it. Neither needed a rewrite, and neither would have been found by a tool that only reads the invoice. That is the difference between a spend report and an audit.