AI agents can handle complex tasks by delegating smaller jobs to other agents. A planning agent might ask one agent to search documentation, another to generate code, and a third to review the result. This approach can divide a large task into manageable pieces, but it also makes usage tracking more complicated.
The main challenge is that the parent agent may not account for every token consumed by its child agents. Each child can make multiple model calls, use a different model, repeat failed requests, or generate additional output while working with tools.
If an application records only the final response or the parent agent's usage, the reported cost may be incomplete.
A reliable solution requires a usage ledger that records model consumption at the individual request level, associates each request with the correct agent and workflow, and calculates costs using the applicable model pricing.
This article explains how to implement that approach in a C# application.
Why Delegated AI Work Needs Separate Cost Tracking
Consider a customer support application that uses an AI agent to investigate a complicated request. The main agent delegates work to three specialized agents:
- A retrieval agent searches internal documentation.
- An analysis agent examines the retrieved information.
- A response agent prepares the final answer.
Each agent may call a model several times. The retrieval agent might refine its search, while the analysis agent might request another explanation before returning its findings.
The total cost depends on all billable model calls, not just the final answer.
A basic accounting model is:
[
\text{Total Cost} = \sum_{i=1}^{n}\text{Cost of Model Call}_i
]
For a model with separate input and output token rates, the cost of a call can be calculated as:
[
\text{Cost} =
\frac{I \times R_i + O \times R_o}{1{,}000{,}000}
]
Here, (I) represents billable input tokens, (O) represents billable output tokens, and (R_i) and (R_o) represent the applicable rates per million tokens.
Some providers have separate rates for cached input, reasoning tokens, or other usage categories. Those categories must be handled according to the provider's billing rules rather than assumed to be included in the basic formula.
Design a Usage Ledger for Every Model Call
The most important design decision is to record usage at the model-call level instead of keeping only a running total in the parent agent.
Each usage record should contain enough information to explain where the cost originated.
| Field | Purpose |
|---|
| Workflow ID | Groups all work performed for one user request |
| Parent agent ID | Identifies the agent that delegated the task |
| Agent ID | Identifies the agent making the model call |
| Request ID | Identifies the individual model invocation |
| Model name | Determines the applicable pricing rules |
| Input tokens | Records input usage reported by the provider |
| Output tokens | Records output usage reported by the provider |
| Cached tokens | Tracks cached input when separately reported |
| Cost | Stores the calculated charge using the applicable pricing |
| Timestamp | Supports time-based reporting and investigation |
The request ID should be unique for each model invocation. If an agent retries a failed request, the retry should have its own request ID because it may generate additional billable usage.
The parent and child agent IDs provide the relationship needed to calculate costs across a delegated workflow.
Create a Token Usage Model in C#
Start with a record that represents the usage returned by a model provider.
public sealed record TokenUsage(
string WorkflowId,
string AgentId,
string? ParentAgentId,
string RequestId,
string Model,
long InputTokens,
long OutputTokens,
long CachedInputTokens,
DateTimeOffset RecordedAt);
This model provides the basic information required for cost attribution.
Cached input tokens are recorded separately because some providers report them as a subset of total input tokens. They should not automatically be added to input tokens or charged at the ordinary input rate.
The application should also validate incoming usage data. Token counts must not be negative, identifiers must be present, and cached token counts must follow the provider's reporting conventions.
For production use, persist usage records in a database or durable event store. An in-memory collection is suitable for a demonstration, but it will lose information when the application restarts.
Calculate Costs Using Configurable Model Rates
Avoid embedding model prices directly throughout the application. Model pricing can change, and different models may have different input, output, and cached-input rates.
A pricing configuration can represent the applicable rates per million tokens.
public sealed record ModelPricing(
decimal InputPerMillion,
decimal OutputPerMillion,
decimal CachedInputPerMillion);
The following calculator separates cached input from ordinary input, assuming the provider reports cached input as part of total input tokens.
public static class TokenCostCalculator
{
public static decimal Calculate(
TokenUsage usage,
ModelPricing pricing)
{
if (usage.InputTokens < 0 ||
usage.OutputTokens < 0 ||
usage.CachedInputTokens < 0)
{
throw new ArgumentOutOfRangeException(
nameof(usage),
"Token counts cannot be negative.");
}
if (usage.CachedInputTokens > usage.InputTokens)
{
throw new ArgumentException(
"Cached input cannot exceed total input.");
}
long uncachedInput =
usage.InputTokens - usage.CachedInputTokens;
decimal inputCost =
uncachedInput * pricing.InputPerMillion
/ 1_000_000m;
decimal cachedCost =
usage.CachedInputTokens
* pricing.CachedInputPerMillion
/ 1_000_000m;
decimal outputCost =
usage.OutputTokens * pricing.OutputPerMillion
/ 1_000_000m;
return inputCost + cachedCost + outputCost;
}
}
The decimal type is appropriate for financial calculations because it avoids the binary floating-point representation issues associated with double.
This example assumes that the provider's published rates use a per-million-token basis and that the listed token categories cover the request. If the provider bills reasoning tokens, image input, audio, or other usage separately, extend the pricing model accordingly.
Store the pricing version or effective date alongside calculated costs. Otherwise, a historical report may become difficult to reproduce after pricing changes.
Record Usage When Each Agent Calls a Model
The next step is to connect usage reporting to the model invocation layer.
The following example shows the general pattern using an application-defined interface. It is not a provider-specific SDK implementation; the adapter must be implemented for the model API or agent framework being used.
public sealed record ModelResult(
string Text,
long InputTokens,
long OutputTokens,
long CachedInputTokens);
public interface IModelClient
{
Task<ModelResult> GenerateAsync(
string prompt,
CancellationToken cancellationToken);
}
public interface IUsageLedger
{
Task RecordAsync(
TokenUsage usage,
CancellationToken cancellationToken);
}
A wrapper can record usage after a successful model response.
public sealed class TrackedModelClient
{
private readonly IModelClient _client;
private readonly IUsageLedger _ledger;
public TrackedModelClient(
IModelClient client,
IUsageLedger ledger)
{
_client = client;
_ledger = ledger;
}
public async Task<ModelResult> GenerateAsync(
string workflowId,
string agentId,
string? parentAgentId,
string requestId,
string model,
string prompt,
CancellationToken cancellationToken)
{
var result = await _client.GenerateAsync(
prompt,
cancellationToken);
var usage = new TokenUsage(
workflowId,
agentId,
parentAgentId,
requestId,
model,
result.InputTokens,
result.OutputTokens,
result.CachedInputTokens,
DateTimeOffset.UtcNow);
await _ledger.RecordAsync(
usage,
cancellationToken);
return result;
}
}
The adapter should populate token counts from the provider's actual usage metadata, not estimate them from the length of the returned text.
This implementation illustrates the tracking pattern, but it has an important limitation: if the model request succeeds and writing the usage record fails, the application could lose the accounting event. A production implementation should use durable event recording, retries, or another mechanism that preserves usage records even when downstream storage is temporarily unavailable.
Also, the example records usage after successful responses. If a provider charges for failed requests or partially completed operations, the integration must capture those cases wherever usage information is available.
Calculate the Total Cost Across Parent and Child Agents
A workflow should have one shared workflow ID. Every agent participating in that workflow should use the same ID while retaining its own agent ID and parent relationship.
For example:
| Agent | Parent agent | Input tokens | Output tokens |
|---|
| Planner | None | 1,200 | 300 |
| Retrieval | Planner | 2,000 | 400 |
| Analysis | Planner | 3,000 | 700 |
| Response | Planner | 1,500 | 500 |
These figures are illustrative and do not represent a real benchmark.
The ledger can aggregate all usage records associated with the workflow. If a child agent delegates work to another agent, that additional agent must also write usage records against the same workflow ID.
Do not add a parent's reported aggregate usage to the child records if that parent total already includes the children's consumption. Doing so would count the same tokens twice.
A simple database query can aggregate token usage by agent:
SELECT
WorkflowId,
AgentId,
Model,
SUM(InputTokens) AS TotalInputTokens,
SUM(OutputTokens) AS TotalOutputTokens,
SUM(Cost) AS TotalCost
FROM AgentUsage
GROUP BY
WorkflowId,
AgentId,
Model;
This query assumes the database stores a calculated Cost column and that each usage record represents one distinct model invocation. The final workflow cost can be calculated by grouping only by WorkflowId, while model-level grouping helps explain which models contribute most to the bill.
Compare Different Approaches to Cost Tracking
| Approach | Advantages | Limitations |
|---|
| Track only the parent agent | Easy to implement | May omit child usage or double-count aggregated usage |
| Track usage in each agent | Supports detailed attribution | Requires consistent instrumentation |
| Estimate tokens from text length | Useful for rough planning before a request | Does not provide authoritative billing data |
| Store provider usage in a durable ledger | Supports reconciliation, reporting, and audits | Requires storage, retry handling, and retention policies |
For a production application, a durable usage ledger is generally the most useful option. Token estimates can still help predict costs before a request, but they should be labeled as estimates and kept separate from actual reported usage.
Best Practices for Production Applications
Use Unique IDs and Idempotent Writes
Each model invocation should have a unique request ID. Add a database uniqueness constraint so that retrying a ledger write does not create duplicate charges in application reports.
Keep Usage and Billing Separate
Provider-reported token counts are usage data, while calculated cost depends on the applicable pricing rules. Preserve the original usage record so that costs can be recalculated when pricing changes or a calculation error is discovered.
Apply Per-Workflow Budgets
Set configurable limits for total workflow cost, individual agent cost, or model-call count. Check the budget before dispatching additional work and define what happens when a limit is reached.
Record Retries and Failed Calls
Track retries, timeouts, cancellations, and provider errors. Record usage whenever reliable usage information is available, and distinguish missing usage data from a confirmed zero-token request.
Avoid Logging Sensitive Prompts
Cost tracking generally needs token counts, identifiers, model names, and timestamps rather than complete prompts or responses. Avoid retaining sensitive content unless there is a specific, approved requirement.
Monitor More Than Token Counts
Track cost per workflow, cost per successful task, retries, latency, and failure rate. A workflow with fewer tokens can still be inefficient if it repeatedly fails or produces unusable results.
Common Mistakes and Troubleshooting
Reported Costs Are Lower Than the Provider Bill
Check whether every child agent uses the same tracking layer. Review failed calls, background tasks, tool-triggered model requests, and any agents that bypass the instrumented client.
Reported Costs Are Higher Than Expected
Check for duplicate ledger writes, parent-child usage being counted twice, incorrect cached-token handling, and stale pricing configuration.
Some Usage Records Have Zero Tokens
Confirm whether the provider actually reported zero usage or whether the adapter failed to parse the usage metadata. Represent unavailable usage as unknown rather than silently converting it to zero.
Costs Change Between Reports
Verify the pricing version, token categories, currency, and rounding rules. Preserve the underlying token counts and calculation metadata so historical reports can be reproduced.
Budget Limits Do Not Stop Delegation
Check that every agent dispatch passes through the budget controller. A limit checked only by the parent agent may not prevent an already-running child from making additional model calls.
Advantages and Disadvantages
Detailed token accounting makes it easier to understand which agents and workflows consume the most resources. It supports budget enforcement, model selection, cost allocation, and investigation of unexpected provider charges.
The trade-offs include additional instrumentation, storage requirements, pricing maintenance, and the need to handle missing or delayed usage information. Provider-reported token usage also does not necessarily explain every charge on an invoice, so financial reconciliation may still be necessary.
Summary
Tracking token costs in a multi-agent AI application requires more than recording the usage of the main agent. Every model invocation should produce an identifiable usage record associated with its workflow, agent, parent agent, and model.
A durable ledger, configurable pricing, idempotent writes, and workflow-level aggregation provide a foundation for accurate cost reporting. By combining usage tracking with budgets, retry monitoring, and provider reconciliation, developers can understand the real cost of delegated AI work and make better decisions about how their agents are designed and deployed.
Join the conversation! Your thoughts help the community grow.