Skip to Content

How does Rius read OpenInference model name attributes?

Rius reads the model name from OpenInference’s llm.request.model_name, the model member of llm.invocation_parameters, or llm.model_name, and stores it as gen_ai.request.model at ingest. The provider-reported model is stored as gen_ai.response.model. With the model and token counts in place, OpenInference spans get model analytics and server-side cost like native spans.

How it works

OpenInference instrumentors emit standard OpenTelemetry spans. When Rius ingests them, it moves the values from the OpenInference attribute names onto the gen_ai.* keys and removes the source keys it mapped. This is called normalizing at ingest.

Request model. Rius takes the first of these that is set:

  1. llm.request.model_name
  2. the model member of llm.invocation_parameters
  3. llm.model_name

The result is stored as gen_ai.request.model. Inside llm.invocation_parameters, model_name is also accepted as a fallback for model.

Response model. Rius takes llm.response.model_name, else llm.model_name, and stores it as gen_ai.response.model. The llm.model_name fallback applies only when the span’s status is OK. On an ERROR or UNSET span, Rius does not use llm.model_name for the response model, because on those spans it may still hold the model you requested rather than the one the provider served.

Precedence. Native gen_ai.* keys always win. Normalization fills gaps and never overwrites a value the span already carries.

Tokens and cost. llm.token_count.prompt and llm.token_count.completion, with their cache and reasoning details, fill the token counts. Rius computes cost on the server from gen_ai.request.model and those counts. A span with no model, a model the price catalog does not know, or no counts gets no cost.

The Rius SDKs apply the same mapping in your process before export, with one difference: they skip the llm.model_name fallback, which only the platform applies.

Set it up

  1. Install the OpenInference instrumentor for your library and wire it to the Rius ingest endpoint with an OTLP exporter. This example uses the OpenAI instrumentor. The full setup, including the exporter details, is on the OpenInference page.
from opentelemetry.sdk.trace import SpanLimits, TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from openinference.instrumentation.openai import OpenAIInstrumentor # Raise the attribute limit: see "Raise the span attribute limit" below. provider = TracerProvider(span_limits=SpanLimits(max_span_attributes=4096)) provider.add_span_processor( BatchSpanProcessor( OTLPSpanExporter( endpoint="https://ingest.eu.console.rius-glassflow.com/v1/traces", headers={"Authorization": "Bearer <your API key>"}, ) ) ) OpenAIInstrumentor().instrument(tracer_provider=provider)
  1. Raise the span attribute limit. OpenInference writes one attribute per message field and per tool field, and OpenTelemetry keeps only 128 attributes per span by default. Past that, a span silently loses attributes, and the model can be one of them. The code above sets the limit in Python. For any language, set it through the environment:
export OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=4096
  1. Set the status on your spans as your instrumentor normally does. Rius uses an OK status to decide whether llm.model_name can fill the response model.

  2. Search and filter on the canonical keys, gen_ai.request.model and gen_ai.response.model. A filter on llm.model_name matches nothing, because that source key is removed once it is mapped.

For how this fits next to the other ways of sending traces, see Trace LLM calls with OpenTelemetry.

What you get

  • Your OpenInference spans carry gen_ai.request.model and, when the provider reports it, gen_ai.response.model, so model analytics work without changing your instrumentation.
  • Cost per call is computed by Rius from the model name and the token counts. Costs are list-price estimates in US dollars from LiteLLM’s public model-price catalog, and a model the catalog does not know gets an empty cost.
  • A span whose OpenInference kind is LLM, or that carries gen_ai.request.model and has no kind or operation, is counted as an LLM call in the console and in alerts.
  • Request parameters in llm.invocation_parameters, such as temperature and max_tokens, become gen_ai.request.* keys, and tool_choice becomes rius.request.tool_choice.
  • Values already set on gen_ai.* keys are kept as sent.

The span attribute reference has the full supported-conventions matrix, and the interoperability overview lists the other sender guides.

When something else fits

  • If you emit spans yourself, set gen_ai.request.model and the gen_ai.usage.* token counts directly. That skips the mapping and makes the model name explicit.
  • If you use Python or TypeScript and want the exporter, attribute limit and privacy controls wired for you, use the Rius SDK integrations instead of running OpenInference on its own.

Still stuck? Get help

Last updated on