How does Rius read OpenTelemetry GenAI model name attributes?
Rius reads the requested model from gen_ai.request.model and the served model from gen_ai.response.model, then uses them for model analytics and cost. Set gen_ai.request.model together with token counts and Rius computes cost for the call. If your spans use OpenInference names such as llm.model_name, Rius moves them onto the GenAI keys when it ingests them.
How it works
The OpenTelemetry GenAI convention uses three attributes for the model:
gen_ai.request.modelis the model you asked for. It drives model analytics and cost.gen_ai.response.modelis the model the provider reports it served.gen_ai.provider.nameis the provider, for exampleopenaioranthropic.
Rius keeps these keys as you send them. It treats a span as an LLM call when its kind is LLM, set directly or derived from the chat, text_completion or generate_content operation. A span with neither a kind nor an operation counts as an LLM call when it carries gen_ai.request.model. Agent, tool, retrieval and embedding spans are not LLM calls even when they carry a model, but their cost still appears in the per-model breakdown and the cost totals.
If a sender uses other names, Rius normalizes them at ingest. Normalization moves values onto the canonical keys and removes the source keys it mapped. Native gen_ai.* keys always win, and normalization only fills gaps. For OpenInference:
- The request model comes from
llm.request.model_name, else themodelmember ofllm.invocation_parameters, elsellm.model_name. - The response model comes from
llm.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 served one. - The Rius SDKs apply the same mapping in your process before export, except the
llm.model_namefallback, which only the platform applies.
Rius also moves the deprecated gen_ai.system to gen_ai.provider.name, and it normalizes ai.model.* from the Vercel AI SDK (v5, v6). Keys such as gen_ai.request.temperature carry the request parameters that the GenAI conventions define.
Set it up
- Set
gen_ai.request.modelon the span for each model call, with at least onegen_ai.usage.*token count. Cost needs the model and at least one count, and a count you leave out is read as 0. - Add
gen_ai.response.modelandgen_ai.provider.namewhen your client reports them. - Name the span the way the GenAI conventions ask, the operation followed by the model, such as
chat gpt-4o. Rius does not require it, but the SDKs emit it, so mixed fleets read alike. - Never send a cost attribute. Send tokens and the model name, and Rius computes cost.
This is the shape of a model call span (the token counts are examples):
{
"gen_ai.operation.name": "chat",
"gen_ai.provider.name": "openai",
"gen_ai.request.model": "gpt-4o",
"gen_ai.response.model": "gpt-4o",
"gen_ai.usage.input_tokens": 120,
"gen_ai.usage.output_tokens": 45
}- When you search or filter in trace inspection, use the canonical key. A filter on
gen_ai.request.modelmatches the stored model, while a filter on a source key such asllm.token_count.promptmatches nothing, because Rius removed it after mapping.
The span attribute reference lists every key and what Rius does with it. The Interoperability page links to the setup guide for each sender. Trace LLM calls with OpenTelemetry compares the sender paths.
What you get
- Model on every call. The span for each model call carries the requested model, and the served model when the provider reports it.
- Cost per call. Rius prices the model and token counts, with cache reads and writes at their own rates. Costs are list-price estimates in US dollars from LiteLLM’s public model-price catalog, not billed amounts.
- Per-model cost. Cost by model on the usage view and the per-model breakdown use the model name from these attributes.
- An empty cost, not zero, when Rius cannot price a call. A span with no model, a model the price catalog does not know, or none of the token counts gets no cost.
- One set of names. OpenInference, OpenLLMetry and Vercel AI SDK spans land on the same
gen_ai.*keys as native GenAI spans, so one filter covers all of them. - Reranking spans. A reranking span from the SDKs shows as
LLMwhen it carriesgen_ai.request.model, and as Other when it does not.
When something else fits
- If your spans carry no
gen_ai.request.modeland no model from a mapped convention, Rius shows no model and no cost for them, so add the attribute at the source. - If you want a model priced at a custom or negotiated rate, Rius does not support it, because costs always come from the public catalog’s list prices.
- If you only need span structure and timing, you can skip token and model attributes, but the call then has no cost.