Cost Management › Cost Allocation
Language AI HandbookAll chapters Cost Management › Cost AllocationOne section · Sections in this chapter4 / 8 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Cost allocation answers the question: who spent what? This question matters for several reasons. In multi-tenant platforms, allocation enables chargeback to business units or customers. In product development, it reveals which features or use cases are expensive relative to their value. In budget planning, it provides the data needed to forecast future spending.
Allocation Architectures
Cost allocation in LLM systems requires instrumentation at the request level. Each request must be tagged with enough metadata to attribute its cost to the appropriate owner. The specific attributes depend on the organizational context:
- User or customer ID: For consumer-facing applications, associate each request with the user who initiated it.
- Feature or product area: Tag requests by the product feature that triggered them (e.g., "autocomplete", "summarization", "chat").
- Tenant or team: In internal platforms, associate requests with the team or cost center responsible.
- Request class: Distinguish between interactive (latency-sensitive) and batch (throughput-optimized) workloads, which may be priced differently.
The cost of each request is computed from its token counts and the current cost per token for the serving tier used. Token counts can be obtained either from the tokenizer at request time or from the inference framework's output, which typically reports prompt and completion token counts.
# Cost allocation system implementation
import time
from collections import defaultdict
from dataclasses import dataclass
@dataclass
class RequestRecord:
"""A single request record for cost attribution."""
request_id: str
user_id: str
feature: str
team: str
timestamp: float
prompt_tokens: int
completion_tokens: int
model_tier: str # "small", "medium", "large"
# Cost rates by model tier (USD per 1K tokens)
TIER_COSTS = {
"small": {"input": 0.0002, "output": 0.0005}, # 7B model
"medium": {"input": 0.0010, "output": 0.0020}, # 13B model
"large": {"input": 0.0015, "output": 0.0050}, # 70B model
}
def compute_request_cost(record: RequestRecord) -> float:
"""Compute the dollar cost of a single request."""
rates = TIER_COSTS[record.model_tier]
input_cost = (record.prompt_tokens / 1000) * rates["input"]
output_cost = (record.completion_tokens / 1000) * rates["output"]
return input_cost + output_cost
def aggregate_costs(records: list) -> dict:
"""Aggregate costs by user, feature, and team."""
by_user = defaultdict(float)
by_feature = defaultdict(float)
by_team = defaultdict(float)
by_tier = defaultdict(float)
for record in records:
cost = compute_request_cost(record)
by_user[record.user_id] += cost
by_feature[record.feature] += cost
by_team[record.team] += cost
by_tier[record.model_tier] += cost
return {
"by_user": dict(by_user),
"by_feature": dict(by_feature),
"by_team": dict(by_team),
"by_tier": dict(by_tier),
"total": sum(by_user.values()),
}
# Simulate request records
import random
random.seed(42)
users = [f"user_{i:04d}" for i in range(200)]
features = ["autocomplete", "summarization", "chat", "search", "translation"]
teams = ["product_a", "product_b", "infra", "research"]
tiers = ["small", "medium", "large"]
tier_weights = [0.6, 0.3, 0.1] # Most requests use smaller, cheaper models
simulated_records = []
for i in range(5000):
prompt_len = max(50, int(random.lognormvariate(6, 0.8)))
completion_len = max(20, int(random.lognormvariate(5, 0.7)))
tier = random.choices(tiers, weights=tier_weights)[0]
simulated_records.append(
RequestRecord(
request_id=f"req_{i:06d}",
user_id=random.choice(users),
feature=random.choice(features),
team=random.choice(teams),
timestamp=time.time() - random.uniform(0, 86400),
prompt_tokens=min(prompt_len, 4096),
completion_tokens=min(completion_len, 1024),
model_tier=tier,
)
)
allocation = aggregate_costs(simulated_records)Cost Allocation Report (5,000 requests) Total cost: $2.99 By Feature: chat $0.621 (20.7%) autocomplete $0.618 (20.6%) summarization $0.610 (20.4%) search $0.606 (20.2%) translation $0.540 (18.0%) By Team: research $0.806 (26.9%) product_a $0.762 (25.4%) infra $0.714 (23.9%) product_b $0.711 (23.8%) By Model Tier: medium $1.471 (49.1%) large $0.914 (30.5%) small $0.609 (20.3%)
Showback vs. Chargeback
There are two philosophies for how to use allocation data: showback and chargeback.
With showback, cost reports are informational. Teams can see what they are spending but costs are not transferred from a central budget. Showback is simpler to implement and avoids the organizational friction of reallocating money between teams. It works well for driving awareness and encouraging efficiency without creating financial incentives that might cause teams to under-invest in AI capabilities.
With chargeback, actual costs are transferred to consuming teams' budgets. This creates direct economic incentives for efficiency: teams that over-provision or use expensive models when cheaper ones would suffice bear the cost directly. Chargeback is better at aligning incentives but requires mature internal billing infrastructure and can create perverse incentives where teams avoid beneficial AI use to minimize their chargeback.
A common approach is to start with showback to build awareness and then introduce chargeback once teams understand the cost structure and have had time to optimize.
Per-User Cost Limits and Quotas
For consumer-facing applications, per-user cost controls prevent individual users from consuming disproportionate resources. This is particularly important for applications with open-ended generation where a single user can trigger very expensive requests.
The implementation involves maintaining a running cost counter per user and enforcing limits before processing requests:
# Per-user cost limiting with token budgets
class UserCostTracker:
"""Track and enforce per-user cost limits."""
def __init__(self, daily_limit_usd: float):
self.daily_limit_usd = daily_limit_usd
self.user_costs = defaultdict(float) # user_id -> daily cost so far
self.user_request_counts = defaultdict(int)
def check_and_deduct(self, user_id: str, estimated_cost: float) -> tuple:
"""
Check if user is within budget and deduct the estimated cost.
Returns (allowed: bool, remaining_budget: float).
"""
current_spend = self.user_costs[user_id]
remaining = self.daily_limit_usd - current_spend
if estimated_cost > remaining:
return False, remaining
self.user_costs[user_id] += estimated_cost
self.user_request_counts[user_id] += 1
return True, remaining - estimated_cost
def get_usage_report(self) -> dict:
"""Return usage stats for all users who made requests."""
return {
user_id: {
"total_cost": self.user_costs[user_id],
"requests": self.user_request_counts[user_id],
"utilization_pct": self.user_costs[user_id]
/ self.daily_limit_usd
* 100,
}
for user_id in self.user_costs
}
# Simulate per-user tracking with $0.50 daily limit
tracker = UserCostTracker(daily_limit_usd=0.50)
blocked_count = 0
processed_count = 0
for record in simulated_records[:500]:
cost = compute_request_cost(record)
allowed, remaining = tracker.check_and_deduct(record.user_id, cost)
if allowed:
processed_count += 1
else:
blocked_count += 1
usage = tracker.get_usage_report()Per-User Cost Limiting Results (500 requests, $0.50 daily limit): Requests processed: 500 Requests blocked: 0 (0.0%) Unique users tracked: 181 Top 5 spenders: user_0197: $0.0090 (6 requests, 1.8% of limit) user_0173: $0.0084 (5 requests, 1.7% of limit) user_0138: $0.0076 (6 requests, 1.5% of limit) user_0086: $0.0066 (8 requests, 1.3% of limit) user_0079: $0.0066 (4 requests, 1.3% of limit)

Cost Attribution in Multi-Tenant Systems
In platforms that serve multiple organizations (multi-tenant SaaS), cost attribution requires additional infrastructure:
Request tagging: Each API request must carry a tenant identifier, which is propagated through the inference pipeline and logged alongside resource usage metrics.
Tenant-level aggregation: Usage data must be aggregated per tenant at regular intervals (hourly or daily) for billing and reporting.
Overhead allocation: Infrastructure costs that cannot be directly attributed to individual requests (load balancers, monitoring, storage) must be allocated using a reasonable model, typically proportional to request volume or token consumption.
Cost vs. price: The cost incurred (what you pay for infrastructure) and the price charged (what you bill the tenant) are separate concerns. Pricing decisions involve margins, competitive positioning, and commitment discounts; cost tracking is a prerequisite for pricing, not a substitute.