Cost Attribution & Team Chargeback

8 min read Module 8 of 10 Topic 24 of 30

What you'll learn

  • Tag every LLM API call with team, workflow, and environment metadata at the instrumentation layer
  • Build a PostgreSQL cost table that aggregates token usage into dollar amounts for showback reporting
  • Create Grafana cost dashboards with per-team breakdowns and month-to-date burn trajectories
  • Enforce per-team monthly budgets with soft warning thresholds and hard caps that block further API calls
Building this at your company? For enterprise and company teams taking this to production: book a 30-minute session with our AI engineers for architecture guidance, code review, and a rollout plan for your use case.
Book a Team Session

A single shared LLM API key used by twelve teams without cost attribution is an accounting bomb. The bill arrives at the end of the month as a single line item, and the conversation that follows: who ran what, which workflow was expensive, and who should be accountable, is painful and inconclusive without data. Enterprise agent platforms need cost attribution built in from the start, not retrofitted after the first surprise invoice. This lesson covers the full stack from per-call metadata tagging through budget enforcement.

Why Cost Visibility Changes Agent Development Behavior

When engineers cannot see the cost of their workflows, they optimize for capability and ignore efficiency. A workflow that issues 15 LLM calls with 4,000-token system prompts per call feels fast and correct in development, where it processes a handful of test documents. In production, processing 10,000 documents per day, the same workflow generates $2,400 in daily LLM spend, a number that surprises everyone when it surfaces on the monthly bill.

Cost visibility changes the feedback loop. When engineers can see a dashboard showing their team’s daily spend against their monthly budget, they make different design decisions: they choose smaller models for classification tasks, cache embeddings rather than recomputing them, and trim system prompts to the minimum effective size.

Tagging Every LLM Call with Metadata

Cost attribution is only as good as the metadata you capture at call time. Retrospective attribution, trying to figure out which team ran which workflow from log timestamps, is unreliable and does not scale. The correct approach is to inject metadata before every API call and persist it alongside the token counts.

import anthropic
from dataclasses import dataclass
from datetime import datetime, UTC
import asyncpg

@dataclass
class CostContext:
    team_id: str
    workflow_id: str
    workflow_type: str
    environment: str  # "production", "staging", "development"
    user_id: str | None = None

# Cost per million tokens (update when pricing changes)
MODEL_COSTS = {
    "claude-opus-4-8":   {"input": 15.0,  "output": 75.0},
    "claude-sonnet-5": {"input": 3.0,   "output": 15.0},
    "claude-haiku-4-5":  {"input": 0.8,   "output": 4.0},
}

class InstrumentedAnthropicClient:
    def __init__(self, db_pool: asyncpg.Pool, cost_ctx: CostContext):
        self._client = anthropic.AsyncAnthropic()
        self._db = db_pool
        self._ctx = cost_ctx

    async def create_message(self, model: str, messages: list, **kwargs) -> anthropic.Message:
        response = await self._client.messages.create(
            model=model, messages=messages, **kwargs
        )

        # WHY compute cost here rather than in a batch job: immediate persistence
        # means budget enforcement can query the cost table in real time without
        # waiting for a nightly aggregation to catch overruns.
        input_cost = (response.usage.input_tokens / 1_000_000) * MODEL_COSTS[model]["input"]
        output_cost = (response.usage.output_tokens / 1_000_000) * MODEL_COSTS[model]["output"]
        total_cost = input_cost + output_cost

        await self._db.execute("""
            INSERT INTO llm_cost_events (
                recorded_at, team_id, workflow_id, workflow_type,
                environment, user_id, model,
                input_tokens, output_tokens, cost_usd
            ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
        """,
            datetime.now(UTC),
            self._ctx.team_id, self._ctx.workflow_id,
            self._ctx.workflow_type, self._ctx.environment,
            self._ctx.user_id, model,
            response.usage.input_tokens, response.usage.output_tokens,
            total_cost
        )

        return response

The schema for llm_cost_events should include an index on (team_id, recorded_at) for fast monthly roll-ups and a partial index on environment = 'production' for the dashboards that exclude development noise.

PostgreSQL Cost Aggregation and Budget Enforcement

With events persisted per-call, aggregation becomes straightforward SQL. The budget enforcement query runs before each LLM call and returns the current month’s spend for the requesting team:

async def check_and_enforce_budget(
    db: asyncpg.Pool,
    team_id: str,
    budget_usd: float,
    estimated_call_cost: float,
) -> None:
    """Raise BudgetExceededError before an API call if it would breach the monthly cap."""
    row = await db.fetchrow("""
        SELECT COALESCE(SUM(cost_usd), 0) as month_spend
        FROM llm_cost_events
        WHERE team_id = $1
          AND environment = 'production'
          AND date_trunc('month', recorded_at) = date_trunc('month', NOW())
    """, team_id)

    month_spend = float(row["month_spend"])
    soft_warning_threshold = budget_usd * 0.80
    hard_cap = budget_usd

    if month_spend >= hard_cap:
        # WHY raise before the call: the cost is still zero at this point.
        # After a 1,200-token response, the overrun is baked in and cannot be undone.
        raise BudgetExceededError(
            f"Team {team_id} has exhausted monthly budget of ${budget_usd:.2f}. "
            f"Current spend: ${month_spend:.2f}. Request manager approval to continue."
        )

    if month_spend >= soft_warning_threshold:
        # Non-blocking warning: emit a metric that triggers a Grafana alert
        # without interrupting the workflow. Engineers see the warning in Slack,
        # not a production error page.
        budget_warning_gauge.labels(team_id=team_id).set(month_spend / budget_usd)

Grafana Cost Dashboards

flowchart TD
    DB["PostgreSQL\nllm_cost_events"] --> DS["Grafana PostgreSQL\ndata source"]
    DS --> MTD["Month-to-date spend\nper team (bar chart)"]
    DS --> TRAJ["Spend trajectory\n(actual vs. linear budget)"]
    DS --> WF["Cost by workflow type\n(top 10 pie chart)"]
    DS --> MDL["Cost by model\n(stacked area chart)"]
    MTD --> ALERT["Budget threshold\nannotation lines"]
    TRAJ --> ALERT
    style DB fill:#EEF0F7,stroke:#6366F1,color:#0F172A
    style DS fill:#EEF0F7,stroke:#6366F1,color:#0F172A
    style MTD fill:#f0fdf9,stroke:#0D9488,color:#0F172A
    style TRAJ fill:#f0fdf9,stroke:#0D9488,color:#0F172A
    style WF fill:#f0fdf9,stroke:#0D9488,color:#0F172A
    style MDL fill:#f0fdf9,stroke:#0D9488,color:#0F172A
    style ALERT fill:#fff7ed,stroke:#f59e0b,color:#0F172A

The spend trajectory panel is the most actionable for budget management. It plots actual cumulative spend alongside a linear projection line (daily budget × days elapsed). When the actual spend line rises faster than the projection, the team is on track to exceed their budget before month end, visible 10 days before the overrun occurs, when there is still time to act.

Showback vs. Chargeback Models

flowchart TD
    COSTS["Monthly LLM Spend\nAttributed by Team"] --> SB["Showback Model\nReporting only, no money moves"]
    COSTS --> CB["Chargeback Model\nCosts billed to team cost centers"]
    SB --> AWARE["Teams see costs,\nbehavior changes gradually"]
    CB --> ACCT["Teams directly accountable,\nfaster optimization incentive"]
    SB --> RISK["Risk: teams may ignore\nif there is no financial consequence"]
    CB --> RISK2["Risk: teams optimize\nfor cost over quality if caps are too tight"]
    style COSTS fill:#EEF0F7,stroke:#6366F1,color:#0F172A
    style SB fill:#EEF0F7,stroke:#6366F1,color:#0F172A
    style CB fill:#EEF0F7,stroke:#6366F1,color:#0F172A
    style AWARE fill:#f0fdf9,stroke:#0D9488,color:#0F172A
    style ACCT fill:#f0fdf9,stroke:#0D9488,color:#0F172A
    style RISK fill:#fff7ed,stroke:#f59e0b,color:#0F172A
    style RISK2 fill:#fff7ed,stroke:#f59e0b,color:#0F172A

Start with showback: give teams read access to their cost dashboards for one quarter before activating chargeback. This lets them understand their baseline, optimize obvious inefficiencies, and set realistic budget expectations. Teams that discover they are consuming $8,000/month when they expected $2,000 need time to investigate and restructure workflows, not an immediate invoice.

The cost optimization feedback loop that emerges from this visibility is where most enterprise teams find 40-60% savings: identifying that a routing classifier using claude-opus-4-8 for a task that claude-haiku-4-5 handles equally well, discovering a system prompt that grew to 3,000 tokens through accumulated iteration, or noticing that a workflow re-fetches the same reference documents on every call instead of caching them.

The next lesson shifts from cost observability to deployment infrastructure, covering Kubernetes-native patterns for running enterprise agent systems with proper resource limits, health probes, and graceful shutdown handling.

Knowledge Check

3 questions to test your understanding

1 Your enterprise agent platform is shared across 12 teams. At the end of the month, finance receives a single $180,000 LLM bill with no breakdown. Two teams deny they ran expensive workflows. What is the minimum instrumentation change that resolves this immediately?

2 A team's monthly LLM budget is $5,000. They have consumed $4,800 by the 22nd of the month. Which enforcement approach minimizes business disruption while preventing budget overrun?

3 You want to identify which specific agent prompts are responsible for the highest token consumption across your fleet. Which data combination enables this analysis?

Discussion

Questions and notes from learners on this topic

Loading discussion…

Go further with expert guidance

Ready to build production AI?
Talk to our R&D team.

These courses give you the foundation. Our embedded AI teams take you from prototype to production in 30–90 days, with your team, your codebase, your goals. Book a free strategy call to see how we can accelerate your AI initiative.

30 minutes · No obligation · Expert AI engineers, not sales reps

AI Architecture Review

Audit your current stack and identify high-impact improvements

Project Review

Get expert feedback on your AI implementation and codebase

Team Mentoring

Upskill your engineers with hands-on AI coaching sessions

AI Strategy

Define your AI roadmap, prioritization, and implementation plan