Cost Management › Cost Allocation

Michael BrenndoerferFebruary 14, 20267 min read
Language AI HandbookAll chapters
Part 65 of 67Production Systems
Chapter 499Cost Management › Cost Allocation
Reading section 4 of 8 · Cost Allocation · 7 minSection 4 of 8 · 7 min

Book contents

Section 4 of 8 · 7 min read

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.

In[11]:
Code
# 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)
Out[12]:
Console
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:

In[13]:
Code
# 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()
Out[14]:
Console
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)
Out[15]:
Visualization
Histogram of simulated daily cost for tracked users, with most users clustered near zero and a long right tail; dashed lines mark the median and 95th percentile.
Distribution of daily cost per user for the simulated 500-request workload. The long right tail shows that a small fraction of tracked users account for a disproportionate share of total cost, a common pattern that motivates per-user limits and tiered pricing.

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.