Insights

Your AI Agent Is Burning Tokens. Can You Prove Where They Went?

Explore the latest trends, insights, and stories from our team.

Engineering / AI observability

Token counters tell you what you spent. Distributed traces tell you why.

1User interaction
13LLM calls
16,060Tokens consumed
173Tracing spans
Observed in one production trace, approximately 13.8 seconds end to end.
System architecture

Tracing one request across AI operations

Diagram: One user request enters the AI application and orchestrator, fans out to classification, retrieval and embeddings, LLM gateway/model calls and optional validation, and returns one answer. Below, instrumented operations send traces through OpenTelemetry and the OTel Collector to ClickHouse. Observed production interaction: 13 LLM calls, 16,060 tokens, 173 spans, around 13.8 seconds.
One request can expand into multiple operations, with OpenTelemetry connecting model activity to the wider execution path.
Expanded AI request and OpenTelemetry pipeline diagram

One user interaction. Thirteen LLM calls. 16,060 tokens. 173 spans.

To the user, it looked like one request.

Behind the interface, however, that request expanded into multiple chat completions, embedding calls, retrieval operations, and downstream processing. The total model cost was only a few cents, but the dollar amount was not the interesting part. The interesting part was that a simple token counter could tell us how much the system consumed without explaining why it consumed it.

That distinction matters as enterprises move from simple prompt-response applications toward agentic AI systems.

An AI agent may classify a request, retrieve context, generate embeddings, invoke tools, route between models, call another model for validation, and perform additional processing before returning a single answer. The user sees one interaction. The infrastructure sees a distributed workflow.

In one production trace I examined, that workflow generated 13 separate LLM calls, 16,060 tokens and 173 spans in roughly 13.8 seconds. Another user action produced 681 spans across four services and ran for roughly 140 seconds end to end.

This is why the next challenge in AI cost management is not simply counting tokens.

It is explaining where they went.

01 One Prompt Is No Longer One Model Call

Traditional LLM monitoring often begins with three numbers: input tokens, output tokens and total cost.

Those numbers are useful, but they represent the end of the story rather than the beginning.

A modern AI application may sit behind an architecture that looks more like this:

Architecture / execution path
ONE REQUEST · MULTIPLE OPERATIONS

The work behind a single AI response

An orchestrator coordinates context retrieval, tool use, and model calls—while tracing connects the steps into one transaction.

Example AI request execution and telemetry pipeline User request flows to application and AI orchestrator. The orchestrator calls retrieval and tools as needed and invokes the LLM gateway, which communicates with the model provider. OpenTelemetry collects spans from instrumented application operations, and the Collector exports the traces to ClickHouse. 01 REQUEST & ORCHESTRATION illustrative execution path User Single request Starts the transaction Application Authentication & context Request boundary AI orchestrator Plans, routes & invokes Can fan out or call repeatedly USER SEES 1 answer can call directly 02 DOWNSTREAM OPERATIONS Retrieval / tools Embeddings, RAG, tool calls Invoked as needed LLM gateway Model routing & usage One or more LLM calls Model provider Runs model inference Returns model response 03 OBSERVABILITY LAYER OpenTelemetry spans + request context OTel Collector ClickHouse / analysis
01 · Request and orchestration
01UserSingle request
↓
02ApplicationAuthentication and request context
↓
03AI orchestratorPlans, routes and invokes; can fan out
↓
02 · Downstream operations
04Retrieval / toolsEmbeddings, RAG and tool calls when needed
↓
05LLM gatewayModel routing and token usage
↓
06Model providerRuns inference and returns the response
03 · Observability layer
OpenTelemetry → OTel Collector → ClickHouseCorrelated spans, context and analysis
The flow is illustrative: an agent can repeat, branch, or bypass operations. The tracing pipeline correlates instrumented steps without requiring every step to be a separate model call.
Figure 01 / Fan-out

One interaction. Thirteen model calls.

The answer is a single output; the work behind it is not.

SCHEMATIC FLOW
☻User request1 interaction
⌘OrchestratorRoute / retrieve / invoke
LLM gateway / model calls
01020304050607080910111213
✓Answer1 user-visible output
OpenTelemetry correlation
Application, tools and model activity in one trace
TRACE IDSPAN IDUSER CONTEXTMODELTOKEN USAGE
Measured observation: 13 model calls, 16,060 tokens and 173 spans. Their individual per-call token breakdown was not available in the source material.
One request, multiple LLM calls. The 13-call total is from the traced interaction; the intermediate workflow is illustrative.

At the same time, each of those components can emit telemetry into a shared observability pipeline.

OpenTelemetry makes it possible to correlate these pieces using traces, spans and attributes. Generative AI telemetry can include fields such as gen_ai.usage.prompt_tokens, gen_ai.usage.completion_tokens, gen_ai.usage.total_tokens and gen_ai.request.model, allowing model usage to become part of a broader execution trace rather than an isolated billing record.

That changes the questions engineering teams can ask.

Instead of only asking, “How many tokens did Model X use today?” teams can begin asking: Which user triggered those tokens? Which workflow caused them? How many separate model calls occurred? Which model consumed the most? Did embeddings contribute materially? Where was latency introduced? Was the expensive call necessary, or was it the result of hidden internal fan-out?

A provider dashboard can tell you consumption. A distributed trace can tell you causality.

Figure 02 / The visibility gap

Accounting vs. causality

Two very different ways to understand the same AI bill.

# Aggregate counters

“How much did we use?”

A total across all requests: valuable for billing, but often detached from the specific workflow.

total_tokens: 16,060
triggering_steps: unknown
root_cause: unknown
↗ Distributed traces

“What caused the usage?”

Correlate the initiating request, user context, tools, model calls and latency.

linked_llm_calls: 13
total_spans: 173
request_duration: ~13.8s
Aggregated usage quantifies consumption; correlated execution spans make it possible to investigate which operations produced that consumption.
Figure 06 / Workload comparison

Two requests, very different execution footprints

Separate observed interactions; each metric has its own scale.

REPORTED DATA

Tracing spans (count)

Request A173
Request B681
Request B recorded ~3.9× as many spans.

End-to-end duration (seconds)

Request A13.8s
Request B140s
A duration contrast, not a causal benchmark.
Spans tell you what ran. Trace relationships and timestamps help investigate why it ran and where time went.
Two observed user actions produced different tracing footprints: 173 versus 681 spans, and approximately 13.8 versus 140 seconds.

02 Token Attribution Is an Architecture Problem

Even complete token counts do not automatically tell you who caused the cost.

In the system I worked with, the LLM gateway operated at a broader application or team level. That was sufficient to identify which application was consuming AI resources, but not which individual user inside that application generated a particular request.

Getting user-level attribution onto LLM telemetry became a separate engineering problem.

The first solution was straightforward: pass user identity explicitly through function parameters until the value eventually reached the model call.

That approach became fragile as the system expanded.

Some internal components used shared wrappers. Others invoked model-related functionality through different routes. Over time, at least 10 separate call sites across two services required individual fixes because user identity was not being propagated consistently.

The more durable solution was architectural.

Instead of manually threading identity through every function signature, user context could be established once at the authenticated request boundary and stored in a request-scoped context available to downstream operations.

Figure 03 / Attribution

Stop hand-carrying identity across every function

ARCHITECTURAL COMPARISON
✕ Fragile pattern

Pass user ID at each call

request(user_id)
↓ function_a(user_id)
↓ helper_b(user_id)
↓ model_call(user_id?)

One forgotten parameter can disconnect usage from the person who triggered it.

✓ More durable pattern

Establish trusted request context

authenticated boundary
↓ set request context
↓ operations inherit context
↓ model span: user_key

Use stable, pseudonymous identifiers; avoid raw personal details on spans.

Request-scoped identity avoids relying on every function call to forward an identifier manually.

That design changes the problem from “Did every developer remember to forward the user ID?” to “Was the correct identity established when the request entered the system?”

For agentic systems, user, tenant and workflow context should behave like trace context: established at a trusted boundary and propagated systematically.

There is also an important privacy implication. Attribution does not mean telemetry should become a repository for raw personally identifiable information. A better design is often to use a stable pseudonymous identifier that remains useful for analysis without unnecessarily placing emails or other sensitive data directly onto spans. The system reviewed here demonstrated why that distinction deserves deliberate architectural attention.

03 Then We Learned the Telemetry Could Be Wrong

There is an even more uncomfortable problem.

What if the system responsible for measuring token consumption is itself losing data?

During one diagnostic investigation, token metrics in the observability layer were compared against usage recorded by the LLM gateway. The analysis documented an average match of approximately 91.5% during the measured window, with one day falling to 80.1%. That figure came from the engineering diagnostic, rather than an independently reproduced long-term benchmark, but the discrepancy was large enough to trigger a root-cause investigation.

Figure 04 / Reconciliation

How closely did telemetry match the gateway?

Reported diagnostic match rates from the measured window.

REPORTED DATA
Average reported match

Diagnostic average in the observed period

Lowest reported day

One observed day in the same investigation

Reported match Difference from 100%
Important: These circles visualize a diagnostic reconciliation metric, not a proven percentage of spans dropped. The article does not provide raw provider totals, a per-model breakdown, or a post-fix match rate.
Comparison of observability usage against LLM gateway usage: 91.5% average match in the measured window, with one day at 80.1%.

The primary problem was surprisingly simple.

The OpenTelemetry Collector contained a processor that discarded spans when end_time was zero.

That assumption seems reasonable for traditional synchronous telemetry: if a span has not ended, perhaps it is incomplete.

Streaming LLM responses break that assumption.

A streaming completion can emit telemetry before the stream has fully closed, meaning a zero end time may represent a legitimate intermediate state. The filter therefore discarded valid streaming LLM spans.

Worse, the pipeline was configured so the behavior happened silently.

Figure 05 / Root-cause sketch

The span-dropping filter, before and after

The record still represents an operation even if its telemetry is discarded.

SIMPLIFIED EXAMPLE

Before A valid record disappears

Incoming streaming-related recordend_time = 0
↓
Collector filterif end_time == 0: drop
↓
ClickHouseNo corresponding record arrives
✕ Usage can remain billed but unobserved

After Stop that unnecessary rejection

Incoming streaming-related recordend_time = 0
↓
Collector processingno blanket drop on end_time == 0
↓
Downstream handlingRecord can continue to export / analysis
✓ Removes this particular reason for loss
Technical nuance: normal OpenTelemetry SDK spans are generally exported after they end. A zero end timestamp is not a universal property of streaming; the exact source of zero-ended records should be confirmed in the instrumentation/export path.
The filter rejected records with a zero end timestamp. Removing that rejection prevented the specific loss path identified during the investigation.

The application continued working. The models continued returning answers. The provider continued recording usage. The observability system simply saw less activity than actually occurred.

That leads to a lesson I think every AI platform team should remember: A broken telemetry pipeline does not always look broken. Sometimes it simply makes your AI system look cheaper than it really is.

04 Your Observability Pipeline Is Also a Production System

The streaming issue was not the only failure mode.

The Collector also lacked sufficient memory backpressure. Under load, memory pressure could terminate the Collector and take unexported telemetry with it.

The export path also lacked adequate retry and buffering behavior, meaning a transient failure in the downstream analytics system could become permanent telemetry loss.

The remediation treated observability infrastructure the same way we would treat any other production service.

The problematic filtering rule was removed. A memory-limiting processor was introduced so ingestion could slow before resources were exhausted. Retry with exponential backoff and buffering was added to the exporter, and Collector resources were adjusted to better reflect observed traffic.

Figure 07 / Reliability pattern

Treat telemetry as a production data pipeline

A simplified set of protections across the collection path.

ARCHITECTURE
◎
Instrumented servicesEmit correlated traces and usage attributes
▥
Memory limiterApply protection and backpressure when stressed
↻
Buffer + retryAbsorb interruptions, retry transient export failures
▤
ClickHouseStore/query telemetry for investigations
Reliability means monitoring the monitoring system: queue depth, drops, memory, errors, and export success matter as much as application traces.
Instrumentation, memory protection, buffering and retries create a more resilient path from application telemetry to ClickHouse.

That is an important shift in mindset.

Teams often invest heavily in making AI applications resilient while treating telemetry as passive plumbing.

But the telemetry layer has processors, queues, memory limits, network dependencies, exporters and failure modes of its own.

If observability matters to your business, the observability system itself needs observability.

05 Five Practices I Would Carry Into Any Agentic AI Platform

01 / TRACE

Trace the business transaction, not only the model call.

Start with the user's action and connect everything it triggers downstream.

02 / ATTRIBUTE

Make attribution architectural.

Establish identity and tenant context at a trusted boundary rather than manually propagating it through dozens of call sites.

03 / STREAM

Design for streaming and asynchronous behavior.

Telemetry assumptions inherited from synchronous APIs can quietly fail when applied to LLM streaming and agent workflows.

04 / OPERATE

Treat the Collector as production infrastructure.

Backpressure, memory protection, buffering, retries and health monitoring should be first-class concerns.

05 / VERIFY

Reconcile telemetry against another source of truth.

Periodically compare observability data with gateway or provider usage. Otherwise, missing telemetry can look indistinguishable from lower consumption.

06 Token Counting Is Accounting. Tracing Is Causality.

AI interfaces are becoming simpler while the systems behind them are becoming more complex.

A user may see one chat box. Behind it may be dozens of model calls, embeddings, retrieval operations, agents, tools and hundreds of spans.

That makes aggregate token tracking necessary - but insufficient.

The operational questions enterprises increasingly need answered are not simply: How many tokens did we use?

They are: Who caused the usage? Which workflow produced it? Which models were invoked? What happened between the user's request and the final answer? And can we prove our telemetry captured the entire execution?

The central idea

Token counters tell you what you spent.
Distributed traces tell you why.

And when your AI agent starts burning tokens, “why” is the question that actually helps you fix it.