Skip to Content

How do I see one whole conversation in an agent built with CrewAI?

Rius shows one whole CrewAI conversation as a session: wrap each kickoff in rius.session() with your own conversation id, and every trace from that conversation shares it. The integration records the model calls on its own, and you add observe wrappers for the run and its tools. You then open the conversation from the session link in a trace header, or by pasting the id into the search box on the Spans tab.

How it works

Each crew.kickoff() produces one trace. With no session id, every trace is its own session, so a multi-turn conversation appears as separate, unrelated traces. A session id on each kickoff ties them together.

What Rius records on its own

  • Every model call CrewAI makes arrives as an LLM generation with model, tokens, cost and time to first token. CrewAI drives the OpenAI client, so the openai integration captures these calls. If LiteLLM is installed, CrewAI uses it instead, and the litellm integration captures them.
  • Prompts and replies are captured by default, so the conversation text is on each generation.

What needs something of your own

  • The run itself: wrap your entrypoint around crew.kickoff() with observe and kind=SpanKind.AGENT. That becomes the root span of the trace.
  • Each tool: put observe with kind=SpanKind.TOOL on the tool body, under @tool. These show up as TOOL spans.
  • The session: scope each kickoff with rius.session(), reusing your own conversation id.
  • Crews and tasks produce no spans of their own, so which task a generation belongs to is not visible. Wrap per-task entrypoints with observe if you need that.

Generation spans are all named ChatCompletion, so tell them apart by position and content, not by name.

Set it up

  1. Install the SDK with the openai extra next to CrewAI. The full setup is on the CrewAI integration page, and the Integrations overview covers the other frameworks.
pip install "glassflow-rius[openai]" crewai
  1. Initialise Rius, trace your tools with the TOOL kind, and wrap the entrypoint as an AGENT span. @tool stays outermost and observe goes on 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())
  1. Call handle_ticket inside rius.session() for every turn of the same conversation, using the same id each time. That id is what groups the traces.
  2. Set CREWAI_TRACING_ENABLED=false where no terminal is attached, such as CI or containers, because CrewAI asks about its own tracing on first run.
  3. If you stream calls, enable usage on the underlying client, or the generations carry no token counts.

What you get

Run a few turns of one conversation, then open the console and read it in these places. The Exploring traces page covers each view in full.

  • Session link. Each trace header shows its session. The link opens the Spans tab filtered to that session, so you see every span from every turn.
  • Search by id. Paste the conversation id into the search box on the Spans tab to list every span in that session.
  • Waterfall. Each turn is a tree: your AGENT root, LLM generations with tokens inline, and your named TOOL spans. A run that calls a tool reads as an LLM call, the tool, then a second LLM call that answers.
  • Input / Output tab. Prompt and completion for each generation. Since previous llm call shows what each step added to the prompt, so a dropped turn or a rewritten system prompt stands out.
  • Cost and tokens. Each generation has its tokens and a list-price cost estimate in US dollars, and the trace header sums them.

To watch conversations across your whole agent fleet, see Monitor AI agents in production.

When something else fits

  • If you need to know which crew task a model call belongs to, add an observe wrapper per task, because the framework’s crews and tasks produce no spans.
  • If a turn is a single run with no follow-ups, you do not need a session id, since one trace already shows the whole run.

Still stuck? Get help

Last updated on