Skip to Content
DocsTracingMulti-Agent Tracing

Multi-Agent Tracing

Multi-agent tracing captures how agents in a system interact — which agent ran, what it received and produced, and when control passed from one agent to another. Each agent becomes a distinct span in the trace, with handoffs recorded as first-class events.

There are two ways to instrument a multi-agent system: auto-instrumentation (zero-config for supported frameworks) and manual decoration (works with any framework or custom code).

Auto-Instrumentation

For supported frameworks, auto_instrument() handles all span creation automatically — no decorator changes required.

app.py
from rhesis.sdk import RhesisClient
from rhesis.sdk.telemetry import auto_instrument

client = RhesisClient(api_key="your-api-key", project_id="your-project-id")
auto_instrument("langgraph")

LangGraph

With LangGraph auto-instrumentation, every graph.invoke(), graph.ainvoke(), graph.stream(), and graph.astream() call is traced automatically. Nodes are classified as agents based on their name.

A node is treated as an agent if its name contains one of these keywords (case-insensitive):

KeywordExample node name
agentresearch_agent, agent_node
specialistbilling_specialist
orchestratormain_orchestrator
coordinatortask_coordinator
supervisorsupervisor

Nodes that don’t match are traced as regular spans. To explicitly mark a node, set agent_name or is_agent in the invocation metadata:

app.py
# Explicit agent name — overrides the node name in traces
graph.invoke(state, config={"metadata": {"agent_name": "researcher"}})

# Mark as agent without renaming
graph.invoke(state, config={"metadata": {"is_agent": True}})

Agent name resolution

The agent name on each ai.agent.invoke span is resolved with this priority order. The first source that produces a value wins:

  1. metadata.agent_name — explicit override passed in the invocation config.
  2. metadata.langgraph_node — set automatically by LangGraph for each node.
  3. serialized.name — provided by the framework when available.
  4. Last segment of serialized.id — falls back to the class path (for example ChatGoogleGenerativeAI).
  5. "unknown" — when none of the above is set.

Handoff detection

Handoffs are detected automatically in two ways:

  • transfer_to_* tools — any tool whose name starts with transfer_to_ creates an ai.agent.handoff span. Detection runs in the LangChain callback’s tool path, so it works for any LangChain-based system (including LangGraph and the LangGraph prebuilt agents that emit these tools), not just LangGraph specifically.
  • Sequential transitions — when one agent ends and a different agent starts, a handoff span is created between them.

More Frameworks

LangGraph is currently the only framework with native ai.agent.invoke and ai.agent.handoff span support out of the box (it benefits from the agent-name keywords, langgraph_node metadata, and transfer_to_* tool detection described above). LangChain itself is auto-instrumented for general tracing — LLM calls, tools, chains — but agent and handoff spans only appear when one of the agent signals above is present.

For every other framework (CrewAI, OpenAI Agents SDK, LlamaIndex, AutoGen, …), use manual decoration below: wrap the agent functions with @observe(span_name=AIOperationType.AGENT_INVOKE, ...) and they will produce the same span shape.

Manual Decoration

Use @observe with the ai.agent.invoke span name to instrument any agent function, regardless of how it’s built:

app.py
from rhesis.sdk import RhesisClient, observe
from rhesis.telemetry.schemas import AIOperationType
from rhesis.sdk.telemetry.attributes import AIAttributes

client = RhesisClient(api_key="your-api-key", project_id="your-project-id")

@observe(
    span_name=AIOperationType.AGENT_INVOKE,
    **{AIAttributes.AGENT_NAME: "research_agent"}
)
def research_agent(query: str) -> str:
    # Your agent logic here — LLM calls, tool use, etc.
    return run_research(query)

@observe(
    span_name=AIOperationType.AGENT_INVOKE,
    **{AIAttributes.AGENT_NAME: "analyst_agent"}
)
def analyst_agent(findings: str) -> str:
    return run_analysis(findings)

Recording Handoffs

To explicitly record when one agent hands off to another, create a handoff span around the transition:

app.py
from rhesis.telemetry.schemas import AIOperationType
from rhesis.sdk.telemetry.attributes import AIAttributes

@observe(
    span_name=AIOperationType.AGENT_HANDOFF,
    **{
        AIAttributes.AGENT_HANDOFF_FROM: "research_agent",
        AIAttributes.AGENT_HANDOFF_TO: "analyst_agent",
    }
)
def handoff_to_analyst(findings: str) -> str:
    return analyst_agent(findings)

Full Manual Example

multi_agent.py
from rhesis.sdk import RhesisClient, endpoint, observe
from rhesis.telemetry.schemas import AIOperationType
from rhesis.sdk.telemetry.attributes import AIAttributes

client = RhesisClient(api_key="your-api-key", project_id="your-project-id")

@observe(span_name=AIOperationType.AGENT_INVOKE,
         **{AIAttributes.AGENT_NAME: "research_agent"})
def research_agent(query: str) -> str:
    return call_llm(f"Research this topic: {query}")

@observe(span_name=AIOperationType.AGENT_HANDOFF,
         **{AIAttributes.AGENT_HANDOFF_FROM: "research_agent",
            AIAttributes.AGENT_HANDOFF_TO: "analyst_agent"})
def handoff(findings: str) -> str:
    return analyst_agent(findings)

@observe(span_name=AIOperationType.AGENT_INVOKE,
         **{AIAttributes.AGENT_NAME: "analyst_agent"})
def analyst_agent(findings: str) -> str:
    return call_llm(f"Analyze these findings: {findings}")

@endpoint()
def run_pipeline(input: str) -> dict:
    research = research_agent(input)
    result = handoff(research)
    return {"output": result}

Trace Visualization

The Graph View in Rhesis renders agents, tools, and handoffs as nodes and edges, with turn markers for multi-turn conversations:

Multi-agent trace graph view

Span Reference

ai.agent.invoke

AttributeKeyDescription
Operation typeai.operation.typeagent.invoke
Agent nameai.agent.nameAgent identifier
Event: inputai.agent.inputAgent input
Event: outputai.agent.outputAgent output

ai.agent.handoff

AttributeKeyDescription
Operation typeai.operation.typeagent.handoff
From agentai.agent.handoff.fromAgent initiating the handoff
To agentai.agent.handoff.toAgent receiving control

See Semantic Conventions for the full attribute reference.


Related: