Key takeaways
- The GenAI semantic conventions define three span types for agents:
invoke_agentat the top,chatfor each model call andexecute_toolfor each tool invocation. - Token usage rides on the span itself, as
gen_ai.usage.input_tokensandgen_ai.usage.output_tokens, alongside the metricgen_ai.client.token.usage. - As of v1.41 the spec covers 4 span kinds (agent, workflow, tool, model) plus 2 required metrics for latency and token usage.
- A 10-step agent run emits 20 or more spans, one per model call and one per tool call. That is the resolution at which cost becomes attributable.
- The conventions are CNCF-backed and adopted by at least 4 major platforms including Google Cloud, AWS, Azure and Datadog, so instrumenting once does not lock you to one tracing vendor.
Does ChatGPT recommend your competitor instead of you?
Check how AI assistants describe your company, and whose name they give when someone asks for a recommendation in your category. Run an audit today, from $19.
The OpenTelemetry GenAI semantic conventions now put gen_ai.usage.input_tokens and gen_ai.usage.output_tokens on every model span, under a schema that reached v1.41 and is adopted across the major clouds.
That sounds like a housekeeping detail. It is the difference between knowing what your agents cost and knowing which step spent it.
What does an instrumented agent run actually look like?
A tree, not a log stream. Three span types carry it.
| Span | Covers | Attributes that matter operationally |
|---|---|---|
invoke_agent | The whole run, top of the tree | Parent for all 20 or more child spans |
chat | One model call | gen_ai.request.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, gen_ai.response.finish_reasons |
execute_tool | One tool invocation | Duration, outcome, position in the chain |
Two metrics sit alongside: gen_ai.client.operation.duration and gen_ai.client.token.usage. Between the spans and those two metrics you have latency and spend for every unit of work an agent performs.
What a single run emits
| Emitted | Count per run | Carries |
|---|---|---|
invoke_agent span | 1 | Total duration, parent of all others |
chat spans | 10 | Input and output tokens, model name |
execute_tool spans | 8 to 12 | Tool name, duration, outcome |
| Total spans | 19 to 23 | The full reasoning chain |
| Metric data points | 2 per model call, 20 total | Duration and token usage |
Why is the tree shape the important part?
Because agent failures are structural, and a flat log cannot show structure.
A log line tells you a call happened. A span tells you what it cost and what it was a child of. When a task consumes four times its usual budget, the flat view shows you forty calls that each look normal. The tree shows you one execute_tool span that failed and a subtree of retries underneath it.
That is the same information. Only one arrangement of it lets you answer the question in under a minute.
The finish reason is the cheapest signal you are ignoring
gen_ai.response.finish_reasons records why generation stopped. Aggregate it across a week and truncation shows up as a distinct population rather than as scattered odd outputs. Teams routinely discover that a measurable share of their runs were being cut off by a length limit nobody had revisited since the prototype.
What can you answer once the spans exist?
Questions that currently require someone to spend an afternoon in a billing console.
| Question | How you answer it from spans |
|---|---|
| Which step costs the most per completed task? | Sum token attributes by span name, divide by successful invoke_agent spans |
| What share of spend went to retried work? | Sum tokens on spans whose parent produced a later sibling at the same step |
| Which tool is slowest at the ninety-fifth percentile? | Duration on execute_tool, grouped by tool name |
| Did last week's prompt change cost or save money? | Token usage per completed task, split by deploy |
| Which model version is actually serving traffic? | gen_ai.request.model, grouped over time |
| What share of runs hit a length limit? | gen_ai.response.finish_reasons, counted over 7 days |
The last one catches more people than it should. Frameworks that resolve an alias to a concrete version do not always tell you which version they resolved to, and the span is often the only place the answer is written down.
What does it cost to adopt?
Less than building your own, and the reason is the schema rather than the code.
Most agent frameworks now emit these spans with a configuration flag, so the instrumentation itself is often an afternoon. The saving is that a trace written to a public convention stays readable when you change tracing vendor, change agent framework, or hand the system to another team. Bespoke telemetry has to be re-learned every time any of those happens.
There is one real cost to weigh. Attributes such as gen_ai.input.messages and gen_ai.output.messages capture content, which means prompts and outputs land in your tracing backend. That is a retention and access decision, not a default to accept without thinking.
The question for your next observability review
Not “are we tracing our agents”. Ask: can I get cost per completed task, split by step, without opening a billing console? If the answer is no, the spans are not carrying the token attributes, and everything above is unavailable to you.
Frequently asked questions
What are the OpenTelemetry GenAI semantic conventions?
A standard schema for describing model and agent telemetry, developed by the OpenTelemetry GenAI Special Interest Group formed in April 2024 and backed by the CNCF. They define span names, attributes and metrics so traces from different frameworks describe the same things the same way.
Which spans does an agent run produce?
A top-level invoke_agent span, a child chat span for each model call, and an execute_tool span for each tool invocation. The result is a tree that shows the reasoning chain rather than a flat log stream.
How do you attribute AI cost to a specific step?
Read gen_ai.usage.input_tokens and gen_ai.usage.output_tokens off each span, multiply by the rate for the model in gen_ai.request.model, and aggregate by the parent span. Because the numbers are attributes rather than log text, this is a query rather than a parsing exercise.
Does adopting OpenTelemetry for agents lock you into a vendor?
No, and that is the point of a semantic convention. The schema is CNCF-backed and adopted across major clouds and observability platforms, so instrumentation written once is readable by whichever backend you move to.
Method and sources
- OpenTelemetry, Inside the LLM Call: GenAI Observability with OpenTelemetry, opentelemetry.io blog, 2026. Primary source for the invoke_agent, chat and execute_tool span names and for the gen_ai attribute and metric names quoted in this article.
- OpenTelemetry Semantic Conventions for Generative AI, specification v1.41, cited for coverage of agent, workflow, tool and model spans and required latency and token-usage metrics.
- 2026 write-ups on the GenAI Special Interest Group, formed April 2024, and its expansion to cover agent orchestration, MCP tool calling, content capture and quality evaluation.
- Adoption across Google Cloud, AWS, Azure and Datadog, as stated in OpenTelemetry documentation and vendor materials.
- No figures in this article are our own measurements. Attribute and metric names are quoted from the specification and its documentation.