I trace CrewAI with LangSmith. How do I switch to Rius?
Rius traces CrewAI through its OpenAI integration: install glassflow-rius[openai], call rius.init(), and wrap your entrypoint and tools with observe. Model calls arrive as generations with model, tokens and cost, and your wrappers give the run and its tools their shape. You can keep LangSmith running while you compare, then remove its setup. Rius has no evals, datasets or prompt management, so keep those in LangSmith if you depend on them.
How it works
CrewAI 1.x drives the OpenAI client natively, so the Rius openai integration captures its model calls. If LiteLLM is installed, CrewAI uses it as a fallback, and you rely on the LiteLLM integration instead. The CrewAI integration page covers this in full.
The crew structure runs inside the framework, where auto-instrumentation cannot see it. You wrap the entrypoint and the tool bodies with observe, which replaces the LangSmith run types you used before:
- Your entrypoint around
crew.kickoff()becomes the rootAGENTspan. - Each model call becomes an
LLMgeneration with model, tokens, cost and time to first token. - Each tool becomes a
TOOLspan from yourobservewrapper on the function body. - A LangSmith thread becomes a session, set with
rius.session().
Crews and tasks produce no spans of their own, and generation spans carry the generic name ChatCompletion. To see which task a call belongs to, wrap per-task entrypoints with observe.
The LangSmith migration guide maps @traceable to @rius.observe and run_type="tool" to kind=rius.SpanKind.TOOL. It also describes pointing LangSmith’s own OpenTelemetry export at Rius as a bridge, which leaves out content and thread grouping. For CrewAI, the integration route above is the one that gives you content and sessions.
Set it up
-
Install the Rius SDK with the OpenAI extra next to CrewAI:
pip install "glassflow-rius[openai]" crewai -
Add the Rius setup. Call
rius.init()once at startup, and swap any@traceabledecorators around your crew forobserve. TheLANGSMITH_*variables can stay until you cut over in step 5. Put@tooloutermost on each tool andobserveon the function body:import rius from crewai import Agent, Crew, Task from crewai.tools import tool from rius import SpanKind rius.init(api_key="ri_...", service_name="my-agent") @tool("account_status") @rius.observe(kind=SpanKind.TOOL) def account_status(email: str) -> str: """Fetch a customer's account standing by email.""" return lookup(email) support_agent = Agent( role="Support specialist", goal="Answer support tickets accurately and concisely.", backstory="You resolve product and account questions.", tools=[account_status], llm="gpt-5-mini", ) @rius.observe(name="handle-ticket", kind=SpanKind.AGENT) def handle_ticket(ticket: str) -> str: task = Task( description=f"Resolve this support ticket: {ticket}", expected_output="A short, direct answer.", agent=support_agent, ) return str(Crew(agents=[support_agent], tasks=[task]).kickoff()) -
Map threads to sessions. Where you put a thread id in LangSmith metadata, scope each kickoff with
with rius.session(thread_id):and reuse your own id. -
Keep CrewAI’s own tracing prompt quiet. CrewAI asks about its own tracing product on first run. Set
CREWAI_TRACING_ENABLED=falsewhere no terminal is attached, such as CI or containers. -
Run both backends for a while. Leave LangSmith in place while you compare trace counts, token totals and cost on real traffic. Once nothing needs it, unset
LANGSMITH_TRACING, remove the LangSmith decorators and revoke its keys. The migration overview covers the general cutover. -
Verify one run that calls a tool. In the console you should see the root
AGENTspan, theLLMgenerations with model, tokens and cost, and your namedTOOLspans:handle-ticket AGENT 8.4s ├─ ChatCompletion LLM 3.9s agent decides to call the tool ├─ execute_tool account_status TOOL 0ms └─ ChatCompletion LLM 4.3s agent answers
What you get
- A trace per run with an
AGENTroot,LLMgenerations andTOOLspans, each generation carrying model, tokens, cost and time to first token. - Cost computed by Rius from the model and token counts. These are list-price estimates in US dollars, so you never send a cost value.
- Sessions that group the turns of one conversation or job, from
rius.session(). - Streamed calls carry token counts only when usage is enabled on the underlying OpenAI client. See the OpenAI integration note on
include_usage. - Everything else Rius does on top of traces, such as alerts, users and the Agents page.
When something else fits
- If evaluation datasets, feedback scores, annotation queues or a prompt registry are central to your workflow, keep LangSmith for those pieces and run Rius beside it for tracing.
- Rius starts from the first span you send. It does not import existing LangSmith traces, so keep LangSmith available for history.