Cost Attribution
Enforce budgets against real Databricks spend and attribute cost by agent, user, and tenant.
The SDK cost-budget tracks per-call USD from a static price table, good for immediate, synchronous
protection, but it doesn't know your real Databricks spend (model serving, SQL, AI Search, AI
Functions, Genie, Lakeflow, Feature Serving, all measured in DBUs in System Tables). Cost
reconciliation closes that gap. Enforce perScope budgets against actuals while keeping estimates
for perCall/perSession.
Hybrid enforcement
The key idea maps the existing limit tiers to what each can know:
perCall/perSessionstay estimate-based → immediate, synchronous soft caps. They catch a runaway agent now.perScope(tenant / agent / user) becomes the real-spend hard cap via an externalActualCostSource→ retroactive, cross-process. It catches sustained overspend on the next call.
System Tables lag 15–60 minutes, so actual enforcement is intentionally lagged, but the estimate tiers cover the window. A model call is never blocked on a warehouse query. Actuals are fetched asynchronously after the response, cached (default 60s), and a violation is enforced before the next call.
Databricks tenant limit
import { databricksTenantCostLimit } from '@fabric-harness/databricks';
const costLimit = databricksTenantCostLimit(client, warehouseId, tenantId, {
perDayUsd: 50,
cacheTtlMs: 60_000,
});
const fabric = await init({ costLimit /* …model, tools, policy */ });This returns a CostLimit with scopeSource: 'external' and a Databricks ActualCostSource that
queries system.billing.usage joined to system.billing.list_prices, filtered by fabric.* custom
tags, cached per scope key. Existing tenantCostLimit / postgresCostBudgetStore usage is
unchanged, scopeSource defaults to incremental.
Attribution dimensions
Spend is attributed across agent · user · tenant · model · provider · session · turn. Stamped
onto each ModelUsage and tool-call entry, these answer "which agent/user/tenant spent what".
const breakdown = await databricksActualCostSource(client, warehouseId).queryAttribution({
tenantId: 'acme',
startDate: '2026-06-01',
endDate: '2026-06-23',
groupBy: ['agentId', 'userId'],
});
// → [{ agentId, userId, tenantId, period, estimatedUsd, actualUsd, actualDbus, deltaUsd, calls }]queryAttribution is for offline/ops/dashboard use (it may scan large windows), not inline
enforcement. cost_limit events carry actualsFetchedAt / cacheTtlMs so consumers understand the
lag.
Attribution contract
Attributing spend to a specific agent/tenant requires Databricks resources to carry fabric.*
custom tags (which flow into system.billing.usage.custom_tags). The Databricks deploy targets can
tag the resources they create; for untagged / bring-your-own setups, scope coarsely by
warehouse/endpoint + time window.
See also
- Multi-tenancy · Databricks
- Example:
examples/with-databricks-cost-attribution(runs against a mocked warehouse).