How do I switch from LangSmith to Rius for tracing the OpenAI API?
Rius traces the OpenAI client once you install the openai extra and call rius.init(), so you drop wrap_openai and the LangSmith environment variables. Every OpenAI call in your process is traced, and each chat completion arrives as a span with the model, token counts and a cost. Your @traceable functions become @rius.observe, and LangSmith thread metadata becomes a Rius session. The LangSmith migration guide covers the other paths.
How it works
LangSmith traces OpenAI calls through a client wrapper, wrap_openai(OpenAI()). Rius has no wrapper. The OpenAI integration patches the client library for the whole process when you call rius.init(), so every client you create, anywhere in your code, is traced.
The extra installs the instrumentation, not the openai package itself. If the library is missing, init() logs a DependencyConflict and the integration stays off.
The rest of the mapping is one to one:
@traceablebecomes@rius.observe, and@traceable(name="Chat Pipeline")becomes@rius.observe(name="Chat Pipeline").run_type="tool"becomeskind=rius.SpanKind.TOOL, andrun_type="retriever"becomeskind=rius.SpanKind.RETRIEVER.- A thread set through
metadata={"thread_id": thread_id}becomeswith rius.session(thread_id):, which stamps the session on every span started inside it, child spans included. - Other metadata and tags become span attributes. Rius has no separate tag concept.
The integrations page lists every other library and framework that works the same way, in case you trace more than OpenAI.
Set it up
- Install the instrumentation for OpenAI next to the library you already use, and replace the LangSmith environment with a Rius key:
pip install "glassflow-rius[openai]" openai
# Before: LangSmith
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="lsv2_..."
export LANGSMITH_PROJECT="my-agent"
# After: Rius
export RIUS_API_KEY="ri_..."- Remove the wrapper and call
rius.init()before you create the client. Here is the code you have today:
# Before: LangSmith
from langsmith import traceable
from langsmith.wrappers import wrap_openai
from openai import OpenAI
client = wrap_openai(OpenAI())
@traceable(name="Chat Pipeline", metadata={"thread_id": thread_id})
def pipeline(question: str) -> str:
return client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": question}],
).choices[0].message.content
pipeline("What does Rius ingest?")- This is the same code on Rius. The client is a plain
OpenAI():
# After: Rius
import rius
from openai import OpenAI
rius.init(service_name="my-agent")
client = OpenAI() # no wrapper: init() instruments the library
@rius.observe(name="Chat Pipeline")
def pipeline(question: str) -> str:
return client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": question}],
).choices[0].message.content
with rius.session(thread_id):
pipeline("What does Rius ingest?")- If your app is in TypeScript, install
@arizeai/openinference-instrumentation-openai, callinit()before you create the client, andawait rius.readyto confirmopenaiis among the integrations that attached. - If you stream, pass
stream_options={"include_usage": True}to the call. Without it, streamed spans have no token counts, and no tokens means no cost. - Run one call and open the trace in the console. When Rius shows what you need, unset
LANGSMITH_TRACING, remove the wrapper and revoke the LangSmith keys. Until then, you can run both backends side by side. The migration overview describes the options.
What you get
- A span for each model call. Each chat completion carries the model, token usage and the input and output messages. The span shows the resolved model, for example
gpt-4o-mini-2024-07-18. - Cost per call. Rius computes it from the model and token counts. It is a list-price estimate in US dollars, and you never send a cost value.
- Nesting. Inside an
@rius.observefunction, the model call appears under your pipeline’s span instead of as a standalone trace. - Time to first token on Python streams. The Python integration records it without manual code. TypeScript streamed completions carry token usage but no time to first token.
- Errors that stand out. A rejected call, such as a 404 for an unknown model, a 429 or a timeout, is an ERROR span with
error.typenaming the error class, for exampleopenai.NotFoundError. - Sessions. Turns wrapped in
rius.session(thread_id)group together. - Content controls.
capture_content=Falseand masking apply to instrumented calls exactly as they do to manual ones.
Existing LangSmith traces stay in LangSmith. Rius starts from the first span you send.
When something else fits
- If you depend on datasets, experiments, evaluators, feedback queues or the Prompt Hub, keep LangSmith for those. Rius does not offer them, so run both backends instead of cutting over completely.
- If you cannot change code yet, LangSmith’s own OpenTelemetry export can point at Rius with environment variables. Model, tokens and cost arrive that way, but message content and session grouping do not, so treat it as a bridge and see the LangSmith migration guide for the gaps.