Which OpenTelemetry attribute should my spans use for model name?
Rius reads the model name from the GenAI convention key gen_ai.request.model, so set that on every span for a model call. Rius also reads gen_ai.response.model for the model the provider reports, and it accepts OpenInference’s llm.* model attributes by moving them onto the GenAI keys at ingest. Cost is computed from gen_ai.request.model plus the token counts, so this one attribute decides whether a call gets a cost.
How it works
- Request model.
gen_ai.request.modelis the model you asked for. Rius uses it for model analytics, for the per-model cost breakdown and, with the token counts, for the cost of the call. - Response model.
gen_ai.response.modelis the model the provider reports. Send it when you have it. It is separate from the request model and does not replace it. - Counting LLM calls. A span with neither a span kind nor an operation name still counts as an LLM call when it carries
gen_ai.request.model. - OpenInference attributes. For spans from OpenInference, Rius fills the request model from
llm.request.model_name, else themodelmember ofllm.invocation_parameters, elsellm.model_name. The response model comes fromllm.response.model_name, elsellm.model_name, but only when the span’s status is OK. On an ERROR or UNSET span,llm.model_namemay still hold the requested model, so Rius does not read it as the response model. - Vercel AI SDK. For versions 5 and 6, the
ai.model.*attributes are normalized at ingest, along with tokens and messages. - Which key wins. If a span carries both a native
gen_ai.*key and an OpenInference name, the native key wins. Normalization fills gaps and never overwrites. Rius removes the source keys it mapped and stores the value under the GenAI key. - Where to search. Search and filter on
gen_ai.request.model, not onllm.model_name.
The Rius SDKs apply the same OpenInference mapping in your process before export, except for the llm.model_name fallback, which only the platform applies. The full list of attributes is in the span attribute reference.
Set it up
- Set
gen_ai.request.modelon the span for each model call, with the token counts beside it. A span named the way the GenAI conventions ask, such aschat gpt-4o, reads the same as spans from the Rius SDKs. Here is an example span, shown as its attributes:
{
"gen_ai.operation.name": "chat",
"gen_ai.provider.name": "openai",
"gen_ai.request.model": "gpt-4o",
"gen_ai.response.model": "gpt-4o-2024-08-06",
"gen_ai.usage.input_tokens": 812,
"gen_ai.usage.output_tokens": 164
}- Set
gen_ai.operation.nametochat,text_completionorgenerate_content, or setopeninference.span.kindtoLLM. Setting either one makes Rius derive the other. - Send token counts as
gen_ai.usage.input_tokensandgen_ai.usage.output_tokens. Never send a cost attribute. Rius computes cost from the model and the counts, and a span with no model, a model the price catalog does not know, or no counts gets no cost. - If you export without the Rius SDKs, raise OpenTelemetry’s attribute limit. OpenTelemetry SDKs keep at most 128 attributes per span and drop the rest without an error, and a span that loses its model attribute gets no model analytics or cost:
export OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=4096- Point your exporter at Rius. Trace LLM calls with OpenTelemetry covers the endpoint, headers and each kind of sender.
What you get
- Model analytics and a per-model cost breakdown, grouped by
gen_ai.request.model. - A cost for each call, from the request model and the token counts, each count priced at its own rate.
- Spans that follow the GenAI conventions are counted as LLM calls in the console and in alerts.
- Spans from OpenInference land on the same model key as spans that already use the GenAI convention, so one filter finds both.
- The requested and the served model side by side when you send
gen_ai.response.model.
When something else fits
- If your spans come from OpenInference or the Vercel AI SDK 5 or 6, you can leave their model attributes as they are, because Rius maps them to
gen_ai.request.modelat ingest. - If you write the instrumentation yourself, set
gen_ai.request.modeldirectly rather than an OpenInference name, so the span needs no mapping.
Related
Last updated on