How do I move my instrumentation code from LangSmith to Rius?
Rius replaces LangSmith instrumentation with one rius.init() call for LangChain and LangGraph apps, and with @rius.observe plus the Rius integrations for @traceable and the client wrappers. Your chains, agents and graphs stay as they are. LangSmith threads become Rius sessions, and metadata becomes span attributes. Feedback, datasets, evaluators and prompt management have no counterpart in Rius. The full walkthrough is in Migrate from LangSmith to Rius.
How it works
Rius takes OpenTelemetry traces, so most of the move is a dependency change and a few lines of setup. It is part of the wider Migrate to Rius approach: keep what already emits OpenTelemetry, and swap what is tied to another tool’s SDK.
Here is how each LangSmith concept maps:
- Project becomes an agent, named by
service.name(service_nameinrius.init()). Give each environment, such as production and staging, its own workspace and API key. - Trace stays a trace, and each run is a span.
- Run types (
llm,chain,tool,retriever,embedding) become span kinds (LLM,CHAIN,TOOL,RETRIEVER,EMBEDDING,AGENT). You set one withkind=on@rius.observe, and integrations set it for you. - LLM runs become generations, which carry the model, tokens and cost. Rius computes cost on its side from the model and token counts.
- Threads become sessions. A thread is metadata you repeat on every run. A session is a scope:
with rius.session(thread_id):stampssession.idon every span started inside it, including spans from auto-instrumentation. - Metadata and tags become span attributes. There is no separate tag concept.
- Client wrappers (
wrap_openai,wrap_anthropic) become nothing.rius.init()instruments the OpenAI and Anthropic libraries process-wide, so every client you create is traced.
For LangChain and LangGraph, the Rius langchain integration hooks the same callback system LangSmith uses, so LCEL chains, agents and graph nodes are traced without code changes.
Set it up
- LangChain or LangGraph app. Install the extra, then replace the LangSmith environment variables with your Rius key and one
init()call at startup.
pip install "glassflow-rius[langchain]"
# Before: LangSmith
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="lsv2_..."
export LANGSMITH_PROJECT="my-agent"
# After: Rius
export RIUS_API_KEY="ri_..."import rius
client = rius.init(service_name="my-agent")In a short-lived script, call client.flush() before it exits. Unset LANGSMITH_TRACING once you no longer want LangSmith’s callback tracer running alongside.
@traceablecode. Installpip install "glassflow-rius[openai,anthropic]", then swap the decorators.@traceablebecomes@rius.observe, a custom name goes inname=,run_type="retriever"becomeskind=rius.SpanKind.RETRIEVERandrun_type="tool"becomeskind=rius.SpanKind.TOOL. Dropwrap_openaiandwrap_anthropic.
import rius
from openai import OpenAI
rius.init(service_name="my-agent")
client = OpenAI() # no wrapper: init() instruments the library
@rius.observe(kind=rius.SpanKind.RETRIEVER)
def retrieve(question: str) -> str:
return search(question)
@rius.observe(name="Chat Pipeline")
def pipeline(question: str) -> str:
context = retrieve(question)
return client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "system", "content": f"Context: {context}"},
{"role": "user", "content": question}],
).choices[0].message.content
with rius.session(thread_id):
pipeline("What does Rius ingest?")-
Hand-traced model calls. If you trace calls by hand with
run_type="llm", check the integrations list first. You can often delete that code, because an integration already records the call. -
Metadata and tags. Call
span.set_attribute(key, value)insiderius.start_as_current_span(...). Inside an@rius.observefunction, useopentelemetry.trace.get_current_span().set_attribute(key, value). -
No code change yet? LangSmith’s own OpenTelemetry export can send to Rius as a bridge. It needs
langsmith0.4.25 or newer and no LangSmith API key. Content and threads do not arrive this way, so move to steps 1 and 2 for those.
pip install "langsmith[otel]"
export LANGSMITH_TRACING=true
export LANGSMITH_OTEL_ENABLED=true
export LANGSMITH_OTEL_ONLY=true # send only to the OTLP endpoint below
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.eu.console.rius-glassflow.com"
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer <your API key>"
export OTEL_SERVICE_NAME="my-agent" # LangSmith defaults it to "langsmith"- Run both, then cut over. Leaving
LANGSMITH_TRACING=trueset keeps LangSmith receiving traces next to Rius. Compare trace counts, token totals and cost on real traffic. Then remove@traceableand the wrappers and revoke the LangSmith keys.
What you get
- The same nested trace tree you see in LangSmith: the agent run, each model step and each tool step.
- Model calls as generations with model, token counts and a list-price cost estimate in US dollars.
- Conversation turns grouped into sessions, set once per request with
rius.session. - Alerts, users, and a view of which agent processes are alive when you use the Rius SDK.
What has no counterpart in Rius:
- Datasets, experiments, evaluators and LLM-as-judge.
- Feedback scores and annotation queues.
- Prompt Hub and Playground. Prompt content on spans is captured and inspectable, but there is no registry.
- Hosting or running agents, as LangSmith Deployment and Studio do. Rius observes agents wherever they run.
- Self-hosting. Rius is a managed service only.
- Importing old traces. Existing runs stay in LangSmith, and Rius starts from the first span you send.
When something else fits
If evaluations, datasets or annotation queues are central to your workflow, keep LangSmith for those pieces and run both backends rather than cutting over completely. If your code already emits OpenTelemetry through OpenInference or OpenLLMetry, keep it and re-point the exporter instead of rewriting anything.