DocumentationAPI ReferenceRelease Notes
DocumentationLog In
Documentation

Upload Hiererchical Data via SDK

This page outlines the process for logging hierarchical data to Deepchecks.

Logging Hierarchical Data to Deepchecks

Deepchecks supports use cases that involve hierarchical relationships between spans, such as agentic systems, multi-step pipelines, and orchestrated workflows. In these cases, spans may have parent–child relationships, sibling order, and nested execution paths.

This hierarchy is critical both for observability and for evaluations that depend on lineage and ordering (for example, identifying all tool calls that are descendants of an agent).

Many frameworks (such as CrewAI or LangGraph) provide this structure automatically. For users running custom or internal frameworks, Deepchecks allows you to manually define and upload this hierarchical structure using spans. For an up-to-date list of supported frameworks and setup instructions, see the Frameworks page.

Example

This example demonstrates how to log a simple hierarchical trace with a Root span, an Agent span, and a Tool span using the Deepchecks SDK:

import time
from deepchecks_llm_client.client import DeepchecksLLMClient
from deepchecks_llm_client.data_types import EnvType, Span, SpanKind

# Initialize the Deepchecks client
client = DeepchecksLLMClient(
    host="https://app.llm.deepchecks.com/",
    api_token="x"  # Replace "x" with your actual API key
)

# Example trace
trace_id = "trace_001"
session_id = "session_alpha"
base_time = time.time()

# Root span
root_span = Span(
    span_id="span_1",
    span_name="customer_support_chain",
    trace_id=trace_id,
    span_kind=SpanKind.CHAIN,
    parent_id=None, #This is the root span since span_kind=SpanKind.CHAIN and parent_id=None
    started_at=base_time,
    finished_at=base_time + 5.0,
    input="Customer asks: How do I reset my password?",
    output="Password reset instructions provided",
    status_code='OK',
    session_id=session_id
)

# Agent span (child of Root)
agent_span = Span(
    span_id="span_2",
    span_name="routing_agent",
    trace_id=trace_id,
    span_kind=SpanKind.AGENT,
    parent_id="span_1",
    started_at=base_time + 0.1,
    finished_at=base_time + 1.0,
    input="Analyze query and route to handler",
    output="Route to: password_reset_handler",
    status_code='OK',
    graph_parent_name="customer_support_chain",
    session_id=session_id
)

# Tool span (child of Agent)
tool_span = Span(
    span_id="span_3",
    span_name="account_verification_tool",
    trace_id=trace_id,
    span_kind=SpanKind.TOOL,
    parent_id="span_2",
    started_at=base_time + 1.1,
    finished_at=base_time + 1.5,
    input="check_account_status(user_id='12345')",
    output="{'status': 'active', 'can_reset': true}",
    graph_parent_name="routing_agent",
    session_id=session_id
)

# Collect spans
spans = [root_span, agent_span, tool_span]

# Log spans to Deepchecks
result = client.log_spans(
		app_name="my_app", #Insert your Deepchecks app name here
    version_name="v1", #Insert your Deepchecks version name here
    env_type=EnvType.EVAL, #Insert the environment here
    spans=spans
)

Core Classes and Functions

The Span class

The Span dataclass represents a single unit of work in your system. You define the hierarchy of your trace by creating multiple Span objects and linking them via trace_id and parent_id.

Required fields

span_id – Unique identifier for the span

span_name – Descriptive name of the operation

trace_id – Identifier grouping spans into a single trace

span_kind – Type of span (CHAIN, AGENT, TOOL, LLM, RETRIEVAL)

parent_idspan_id of the parent (None for Root span)

started_at – Start timestamp (float)

finished_at – End timestamp (float)

Recommended / optional fields

input / output – Data passed into or out of the operation

full_prompt – Complete LLM prompt

expected_output – Expected result for evaluations

information_retrieval – Retrieved documents or data

tokens – Number of tokens processed

status_code / status_description – Execution status and context

graph_parent_name – Logical parent span name

session_id – Grouping identifier for related traces

metadata – Custom key–value properties

🚧

Root Span Notice

Important: There must be exactly one Root span per trace, defined as span_kind=CHAIN and parent_id=None.

Logging Spans

To send your spans to Deepchecks, use the log_spans function of the DeepchecksLLMClient class:

client = DeepchecksLLMClient()

client.log_spans(
    app_name="my_app",
    version_name="v1",
    env_type=EnvType.EVAL,
    spans=[...list of Span objects...]
)

Parameters

app_name – Name of your Deepchecks application

version_name – Deepchecks Version identifier

env_type – Environment type (EVAL or PROD)

spans – List of Span objects representing the trace

🚧

Hierarchical data evaluation timing

All spans in a trace should ideally be uploaded together, including the Root span, though this is not mandatory. Evaluations begin only once the Root span is ingested. Child spans uploaded before the Root will be stored until the Root arrives.

Key Considerations

Timestamps are critical

started_at and finished_at define both latency for observability and span order within the trace. Accurate timestamps ensure correct evaluation and visualization of the workflow.

Tokens are optional but recommended

Used for observability, cost tracking, and token-based evaluation metrics. If not provided, Deepchecks does not infer tokens.