Cost Attribution in GaaS: How to Charge the Right Customer for Shared Agent Infrastructure
Agentic AI-as-a-Service runs on shared infrastructure, pooled model quotas, a common vector store, a cache every tenant warms, sub-agents that don't carry a customer ID. The hard part isn't paying the bill; it's knowing whose task ran up which line item. This guide explains why cost attribution breaks in agent systems, the four cost layers you actually have to split, the trace-based tagging approach that works, and the political fights (caching, idle capacity, shared retries) that turn a metering problem into a margin problem. If you can't attribute cost to a customer, you can't price, forecast, or defend your gross margin, and in GaaS you will find out the hard way.
Table of Contents
- Why Attribution Is Harder for Agents Than for SaaS
- The Four Layers You Have to Split
- Direct Costs: The Easy 60%
- Shared Costs: Where the Money Hides
- The Trace Is the Ledger
- Allocation Methods and When Each One Lies
- The Caching Paradox
- Idle Capacity and the Reserved-Compute Problem
- What to Actually Build First
- Insights Most People Overlook
- References
Why Attribution Is Harder for Agents Than for SaaS
In classic SaaS, cost attribution barely exists as a discipline. You pay for servers and a database, you divide by the number of seats, and your gross margin is whatever's left after a rounding error. The marginal cost of one more user logging in is close to zero, so nobody loses sleep over which customer is "expensive."
Agentic AI breaks that comfortable arithmetic. The marginal cost of one more task is not zero, it's a stack of inference calls, tool invocations, retries, and sometimes a small crowd of sub-agents that each burn tokens. Two customers paying you the same monthly amount can differ in actual cost of service by 10x or more, depending on how messy their tasks are, how often the agent retries, and how deep the reasoning goes. The averaging trick that saved SaaS finance teams becomes a slow-motion margin leak in GaaS.
Now layer on the architecture. To keep unit costs sane, almost every serious GaaS vendor shares infrastructure across tenants: a pooled set of model-provider rate limits, a shared vector database, a prompt cache that any customer's traffic can warm, a fleet of long-running agent workers that sit idle between jobs. Sharing is exactly what makes the economics work, and exactly what destroys clean attribution. The moment a cost is shared, you have to allocate it, and allocation is where vendors quietly lose track of who owes what.
There's a structural reason this matters more than it first appears. GaaS pricing is converging on per-task and per-outcome models, which means your revenue is denominated in the same unit as your cost. If you don't know the true cost of a task for a specific customer, you are pricing blind. As a16z has argued about the shift to outcome-based AI pricing, the vendors who win will be the ones who understand their cost-to-serve at the level of an individual unit of work, not a monthly average.
The Four Layers You Have to Split
Before you can attribute anything, you have to name the costs. In a typical agent platform, spend falls into four layers, roughly in descending order of how easy they are to assign:
- Inference cost, tokens consumed by the LLM(s) the agent calls. Usually the biggest single line, often 50-70% of cost-to-serve.
- Tool and external-API cost, the search APIs, code-execution sandboxes, third-party data, and downstream model vendors the agent invokes. This is the layer that compounds in deep workflows.
- Platform compute, the orchestration layer, agent runtime, queues, and the always-on workers that wait for jobs.
- Shared services, the vector store, the cache, observability, logging, and the human reviewers who handle escalations.
The first two are mostly direct, you can trace them to a task if you instrument well. The last two are mostly shared, they exist whether or not a given customer runs anything this hour. The entire discipline of agent cost attribution is really about minimizing how much of your total cost lands in layers 3 and 4, and being honest about how you split what remains.
Direct Costs: The Easy 60%
Start with the win you can actually get. Every model-provider API returns token usage on the response, input tokens, output tokens, and increasingly a separate count for cached and reasoning tokens. If your agent passes a customer ID (and ideally a task ID) through every call, you can sum those tokens per task and multiply by the per-token rate. That's your inference attribution, and for most vendors it covers the majority of variable cost.
Tool calls work the same way in principle: wrap every external invocation so it emits a usage event tagged with the task. A web-search call costs a known amount; a code-sandbox second costs a known amount; a downstream vendor model returns its own token count. The mechanism is identical, you're just attaching a price to an event and stamping it with whose task triggered it.
The trap here is reasoning tokens and retries. A task that looks cheap on the surface can quietly triple its inference bill because the model "thought" for thousands of hidden tokens, or because the agent failed a step and silently retried four times. If your attribution only counts the visible request, you'll under-attribute the expensive customers and over-attribute the cheap ones, the exact opposite of what you want. Capture every call in the task's trace, including the ones that failed and got retried. (The compounding here is severe enough that it deserves its own treatment; the retry-cost problem is a beat unto itself.)
A practical discipline: never attribute cost from your application's view of a task. Attribute it from the provider's billed usage. The two diverge constantly, cached input is cheaper, failed calls still cost money, batched calls get discounts, and only the billed number defends your margin.
Shared Costs: Where the Money Hides
Here's the uncomfortable part. Even with perfect token tracking, you'll typically find that 25-40% of your real spend can't be tied to any single task. It's the vector database that's provisioned for peak load. It's the agent workers you keep warm so latency stays low. It's the cache. It's the on-call human reviewer. It's the observability bill, which for a heavily instrumented agent platform is not a rounding error.
These costs share two nasty properties: they're largely fixed in the short run (you pay for the provisioned vector store whether traffic is high or low), and they're jointly caused (no single customer "owns" the cache's existence). Classic cost accounting calls these joint and common costs, and it has known the dirty secret for a century: there is no objectively correct way to split them. Every allocation method is a defensible fiction. Your job is to pick the fiction that least distorts your decisions.
The mistake nearly every early GaaS team makes is to ignore these costs during pricing, attribute only the direct token spend, declare a healthy "gross margin," and then wonder why the P&L doesn't match. The shared layer is precisely where the classic activity-based costing literature warns that conventional allocation hides the true cost-to-serve of your most demanding customers behind an average. In GaaS, your most demanding customers are usually your power users, the ones running thousands of long, retry-heavy tasks, and they are the ones the average flatters most.
The Trace Is the Ledger
If you take one architectural idea from this piece, take this: the distributed trace of an agent run is your billing ledger. Not a separate metering system bolted on afterward, the trace itself.
An agent task is already a tree of spans: the top-level request, each model call, each tool invocation, each sub-agent it spawns, each retry. If every span carries the customer ID and task ID as attributes, and every span that costs money also carries its cost (tokens × rate, API units × rate), then summing the tree gives you exact per-task attribution for everything in the direct layers, including the fan-out into sub-agents that otherwise vanishes from naive accounting.
This is where the OpenTelemetry GenAI semantic conventions have quietly become load-bearing for GaaS economics. They standardize how token usage, model identity, and operation type appear on a span. Adopt them and your tracing system doubles as your cost-attribution system, because the same span that tells you why a task was slow also tells you what it cost and whom to bill. Vendors who treat observability and cost accounting as one problem instead of two end up with dramatically cleaner books, and the ability to answer "why did this customer's bill spike?" in minutes instead of a forensic afternoon.
The non-obvious requirement: propagate the customer ID into sub-agents. When an agent spawns a sub-agent, the child often starts a fresh context and loses the parent's tags. If you don't explicitly pass identity down the tree, fan-out cost lands in an "unattributed" bucket and your heaviest workflows look cheaper than they are. Treat customer ID like a security credential, it must travel with every hop.
Allocation Methods and When Each One Lies
For the shared layer that genuinely can't be traced, you have to choose an allocation key. The main options, and where each one quietly misleads:
- Equal split (per tenant). Divide shared cost by number of customers. Simple, and wrong the instant your customers differ in size, which is always. A startup running 50 tasks a month subsidizes nothing and gets charged the same shared overhead as an enterprise running 50,000.
- Usage-proportional (by task or token volume). Allocate shared cost in proportion to each customer's direct usage. This is the default that works for most GaaS vendors: heavy users carry more of the cache and vector-store cost because they drive more of the need for it. The lie is that some shared costs (a minimum vector-store footprint, a baseline reviewer on call) exist even for tiny customers, so pure proportionality under-charges the long tail.
- Driver-based (activity-based costing). Pick a real cost driver for each shared resource, vector-store cost allocated by stored-vector count, reviewer cost by escalation count, idle-worker cost by reserved concurrency. More work, far more accurate, and the only method that surfaces a customer who is cheap on tokens but expensive on, say, human escalations.
A pragmatic stance: use driver-based allocation for the two or three shared costs that are large enough to matter, and usage-proportional for the rest. Don't gold-plate the allocation of a $40/month logging bill. Do get serious about the vector store and the human-in-the-loop layer, because those are where customers diverge most.
The Caching Paradox
Prompt caching is the single most counterintuitive line in agent cost attribution, and it's worth slowing down for.
Caching lowers your total inference cost, cached input tokens are billed at a fraction of full price by every major provider. Wonderful for margin. The problem is attribution: who gets the savings? Customer A's traffic warms a shared cache. Customer B's task then hits that warm cache and pays the cheap rate. Did Customer A do Customer B a favor? Should A's bill reflect the cost of warming it? Should B's bill reflect the full price or the cached price?
There's no clean answer, but there's a clean principle: attribute cost based on what the provider actually billed for that specific call, not on some imputed "fair share." If B's call hit the cache and got billed at the cached rate, B pays the cached rate. The warming cost A incurred was a real cost A paid on its own calls; you don't claw it back. This keeps attribution honest and matches the provider's invoice, which is the only number that survives an audit.
The trap is the opposite move, pricing every customer as if the cache doesn't exist, pocketing the cache savings as house margin, and then getting blindsided when a customer's traffic pattern stops hitting the cache and their real cost jumps. If your margin secretly depends on cross-tenant cache hits, you have a hidden dependency that one churned customer can expose. Caching is a quiet lever on gross margin, and treating it as a guaranteed discount rather than a probabilistic one is how vendors get surprised.
Idle Capacity and the Reserved-Compute Problem
Long-running and low-latency agents create a cost that has no natural owner: the idle worker. To serve a task in 200ms instead of cold-starting for 8 seconds, you keep capacity warm. That capacity costs money every minute, including the minutes nobody is using it.
Whom do you charge for idle? The customer who would have used it? Everyone, proportionally? The answer depends on why the capacity exists. If you keep a warm pool because one enterprise customer demands low latency in their SLA, that's a direct cost of serving that customer, and it should land on their bill, even though no single task "used" it. If the warm pool serves everyone's burst traffic, it's a shared cost, and reserved-concurrency-based allocation is the honest split.
This connects directly to the reserved-versus-on-demand compute tradeoff that cloud-native businesses have wrestled with for years. The cloud world learned to separate committed capacity (reserved instances you pay for regardless) from consumed capacity, and to attribute the gap deliberately rather than letting it disappear into overhead. GaaS should steal that discipline wholesale. The danger sign is a vendor whose "cost per task" looks great in a spreadsheet but whose actual infrastructure bill is dominated by idle warm capacity that the per-task math conveniently ignores. That gap is where stated margins and real margins diverge, and it's exactly the kind of thing that gets hidden until a board meeting forces it into the light.
What to Actually Build First
You don't need a perfect cost-accounting system on day one. You need, in order:
- Per-task token and tool attribution via the trace, with customer ID propagated through every span including sub-agents. This alone gives you 60-75% of cost attributed accurately and is the foundation for everything else.
- A named "shared/unattributed" bucket that you report honestly rather than pretending into zero. Watching this bucket grow as a percentage of revenue is one of the earliest warning signs of a margin problem.
- Driver-based allocation for your two largest shared costs, usually the vector store and human-in-the-loop. Leave the small stuff on usage-proportional.
- A per-customer cost-to-serve report you can actually read, ideally next to that customer's revenue, so you can see which accounts are underwater before renewal, not after.
Do those four and you'll know, for the first time, which of your customers you actually make money on. Most GaaS vendors operating today cannot answer that question with confidence, which is its own kind of competitive opportunity.
Insights Most People Overlook
Your cheapest-looking customer on tokens can be your most expensive on humans. Cost-to-serve hides in the layers nobody meters. A customer whose tasks rarely escalate but burn tokens is better than a low-token customer who triggers a human review on a third of their runs, yet token-only attribution flips that ranking. The escalation rate, not the token count, is often the real margin signal, which is why human-intervention rate is becoming a load-bearing economic metric and not just a quality one.
The "unattributed" bucket is a leading indicator, not an accounting nuisance. Most teams treat unallocated cost as a rounding error to be smoothed away. Watch its trend instead. A rising unattributed percentage usually means fan-out is increasing (sub-agents losing their tags), retries are climbing, or shared infrastructure is growing faster than billable usage. Each of those is a margin story you want to read early, and the bucket is the only place it shows up before the P&L does.
Cross-tenant cache hits are unpriced risk, not free margin. If your gross margin quietly depends on Customer A warming a cache that Customer B exploits, you have a correlated dependency hiding in your unit economics. Lose A, or watch A change its traffic pattern, and B's true cost jumps without B doing anything different. Stress-test your margin against the assumption that cache hit rates fall, because the day a big tenant churns, they sometimes do.
Attributing from the provider's invoice instead of your app's task model is the single highest-leverage discipline. Billed usage and application-level usage diverge constantly: cached input, failed-but-charged calls, batch discounts, reasoning tokens you can't see. Teams that attribute from their own task abstraction build a tidy system that's wrong by 15-30%. Teams that attribute from billed usage build an ugly system that's right. In a business priced per task, right beats tidy every time.
The trace and the invoice should reconcile, and the day they stop is the day to investigate. Treat your summed per-task attribution as a number that must tie out to the provider's monthly bill within a small tolerance. When the trace says you spent X and the invoice says X plus 20%, that gap is real money you're not charging anyone, usually idle capacity, untracked retries, or a sub-agent path that lost its tags. Reconciliation isn't bureaucracy here; it's the smoke detector for margin leaks.
References
More in Economics
- Fan-Out Economics: How to Model Cost When Agents Spawn Sub-Agents
- The "Idle Agent" Cost Problem: What Your GaaS Vendor Isn't Putting on the Invoice
- Why Falling Token Prices Didn't Lower Your Agent Bills
- Benchmarking Inference Spend Across the Top 10 Agent Platforms (And Why the Numbers Lie)
- The Token-Volatility Problem: Budgeting When Inference Costs Swing Week to Week