Observability#

KodeAgent includes built-in support for observability through platforms such as Langfuse and LangSmith. Hierarchical tracing is integrated into both ReActAgent and CodeActAgent, providing complete observability into their decision-making and execution loops.

Key Features

Hierarchical Tracing: Traces, spans, and generations properly nested.
Backend Integrations: Direct support for Langfuse and LangSmith.
Graceful Degradation: No-op mode when tracing is disabled (default).
Zero Breaking Changes: Fully backward compatible.

Enabling Observability#

By default, both ReActAgent and CodeActAgent have observability disabled (using a no-op tracer). To enable observability, set the tracing_type parameter when initializing the agent.

ⓘ NOTE:

While langfuse is included with KodeAgent by default, langsmith is not and must be installed separately using pip install langsmith.

from kodeagent import ReActAgent, CodeActAgent
from kodeagent.tools import calculator

# Enable Langfuse tracing
agent = ReActAgent(
    name='Simple agent',
    model_name='gemini/gemini-2.5-flash-lite',
    tools=[calculator],
    tracing_type='langfuse',
)

# Enable LangSmith tracing
agent = CodeActAgent(
    name='Simple agent',
    model_name='gemini/gemini-2.5-flash-lite',
    tools=[calculator],
    tracing_type='langsmith',
)

Configuration#

Ensure the relevant environment variables are set for your chosen platform:

Langfuse:

export LANGFUSE_PUBLIC_KEY='your_public_key'
export LANGFUSE_SECRET_KEY='your_secret_key'
export LANGFUSE_HOST='https://api.langfuse.com'

LangSmith:

export LANGCHAIN_TRACING_V2='true'
export LANGCHAIN_API_KEY='your_api_key'
export LANGCHAIN_PROJECT='your_project_name'  # Optional

Viewing Traces#

Once observability is enabled, all agent interactions will be traced and sent to the configured backend (Langfuse or LangSmith). You can log in to your Langfuse dashboard (or LangSmith dashboard) to view detailed traces of each agent run, including:

  • Agent Decisions: See each thought, action, and observation made by the agent.

  • Tool Usage: Monitor which tools were invoked and their outputs (or what code was written).

  • Plan and Observations: Review the agent’s plan progress and observations made during the task.

  • Performance Metrics: Analyze response times and resource usage.

To view the traces:

  1. Go to https://cloud.langfuse.com (or https://smith.langchain.com)

  2. Find trace by agent class name

  3. Expand to see hierarchical trace tree

A screenshot of a sample trace in Langfuse:

KodeAgent trace on Langfuse dashboard

A screenshot of a sample trace in LangSmith:

KodeAgent trace on LangSmith dashboard

Trace Hierarchy#

The resulting trace hierarchy looks like this:

Agent.run() [root trace]
├── plan_creation [span]
│   └── (LLM call via ku.call_llm with component_name='Planner.create')
├── [iterations...]
│   ├── think [span] (for ReAct) or think_code [span] (for CodeAct)
│   ├── act [span]
│   ├── plan_update [span]
│   │   └── (LLM call via ku.call_llm with component_name='Planner.update')
│   └── observe [span]
│       └── (LLM call via ku.call_llm with component_name='Observer')
└── post_run [span] (if implemented)

Tracer Module#

Key Classes:

  • AbstractObservation - Universal observation interface

  • AbstractTracerManager - Universal manager interface

  • NoOpObservation - No-op observation implementation

  • NoOpTracerManager - No-op manager implementation

  • LangfuseTracerManager - Langfuse integration

  • LangSmithTracerManager - LangSmith integration

  • LangSmithObservation - LangSmith-specific observation wrapper

Architecture#

AbstractObservation (interface)
├── NoOpObservation (no-op impl)
├── Langfuse objects (referenced directly)
└── LangSmithObservation (wraps RunTree)

AbstractTracerManager (interface)
├── NoOpTracerManager (no-op impl)
├── LangfuseTracerManager (Langfuse impl)
└── LangSmithTracerManager (LangSmith impl)

Tracing Concepts Mapping#

The following table summarizes how OpenTelemetry (OTel) concepts map to the underlying SDK methods and KodeAgent’s internal tracer.

OTel Concept

Langfuse SDK

LangSmith SDK

KodeAgent Tracer (tracer.py)

Trace (Root)

langfuse.trace()

RunTree(run_type='chain')

start_trace()

Span (Sub-node)

parent.span()

parent.create_child(run_type='tool')

start_span()

Generation (LLM)

parent.generation()

parent.create_child(run_type='llm')

start_generation()

Event / Update

observation.update()

run_tree.error = ...

update()

End / Finalize

observation.end()

run_tree.end() + run_tree.patch()

end()

Flush / Sync

langfuse.flush()

client.flush()

flush()

LangSmith Implementation Details#

The LangSmithTracerManager requires a few extra steps to ensure traces are recorded reliably. Unlike the Langfuse SDK which often handles background syncing transparently, the LangSmith implementation explicitly calls RunTree.post() upon creation to initialize the run in the backend. During finalization in the end() method, it calls both RunTree.end() to record the outputs and RunTree.patch() to send the final state. Finally, the flush() method is used to ensure all buffered runs are transmitted before the process exits.