# How to Use the Tracing Module to Observe and Debug Agent Executions in AgentScope

> Debug agent executions in AgentScope with the tracing module. Easily observe agent interactions by enabling and applying tracing decorators for comprehensive debugging.

- Repository: [AgentScope-AI/agentscope](https://github.com/agentscope-ai/agentscope)
- Tags: how-to-guide
- Published: 2026-03-09

---

**Enable tracing by initializing AgentScope with a `tracing_url`, then apply decorators like `@trace_llm` or `@trace_reply` to capture OpenTelemetry spans for every agent interaction.**

AgentScope is an open-source multi-agent framework that provides built-in observability through its tracing module. By leveraging OpenTelemetry, you can use the tracing module to observe and debug agent executions in real-time, capturing the full lifecycle of LLM calls, tool invocations, and agent responses. This guide walks through enabling tracing, decorating your components, and interpreting the resulting telemetry data.

## How Tracing Works in AgentScope

The tracing system in AgentScope is built on OpenTelemetry and consists of several coordinated components. When `trace_enabled` is set to `True` (either via `agentscope.init` or manual configuration), the system activates span creation for decorated functions.

The core workflow involves:

1. **Setup**: The `setup_tracing` function in [`src/agentscope/tracing/_setup.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_setup.py) configures the OTLP exporter with your provided endpoint and registers a `BatchSpanProcessor` to batch and transmit spans efficiently.

2. **Tracer Retrieval**: The `_get_tracer()` function retrieves a tracer named `"agentscope"` (versioned with `__version__`) from the same setup module.

3. **Enablement Check**: Before creating any span, `_check_tracing_enabled()` in [`src/agentscope/tracing/_trace.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_trace.py) reads the global flag `_config.trace_enabled` to determine if tracing should proceed.

4. **Decoration**: Specialized decorators like `trace`, `trace_llm`, `trace_reply`, `trace_format`, `trace_toolkit`, and `trace_embedding` (all defined in [`src/agentscope/tracing/_trace.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_trace.py)) wrap target functions to start spans, capture request/response attributes, and set status codes.

5. **Attribute Extraction**: The `_get_*_attributes` utilities in [`src/agentscope/tracing/_extractor.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_extractor.py) convert internal AgentScope objects (messages, tool calls, embeddings) into OpenTelemetry-compatible attribute dictionaries.

6. **Attribute Definitions**: Constants for attribute keys are centralized in [`src/agentscope/tracing/_attributes.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_attributes.py) via `SpanAttributes` and `OperationNameValues` classes.

When a decorated function executes, the decorator creates a span with a generated operation name, records request attributes, executes the function, then records response attributes or exceptions, naturally forming a parent-child hierarchy that mirrors your call chain.

## Enabling Tracing in Your Application

Before you can observe agent executions, you must install the optional dependencies and initialize the tracing system.

### Installing OpenTelemetry Dependencies

Tracing requires the OpenTelemetry Python SDK. Install it via pip:

```bash
pip install opentelemetry-sdk opentelemetry-exporter-otlp

```

These packages are declared as optional extras in the AgentScope repository, so you may also install them as extras if supported by your distribution.

### Initializing with agentscope.init

The simplest way to enable tracing is to provide a `tracing_url` when initializing AgentScope:

```python
import agentscope

# Connect to Langfuse, Arize Phoenix, or any OTLP-compatible backend

agentscope.init(tracing_url="https://cloud.langfuse.com/api/public/otel/v1/traces")

```

This call internally executes `setup_tracing` from [`src/agentscope/tracing/_setup.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_setup.py), configures the OTLP exporter with your endpoint, registers a `BatchSpanProcessor`, and sets the global `_config.trace_enabled = True`.

### Manual Setup

If you need finer control, import and call `setup_tracing` directly:

```python
from agentscope.tracing import setup_tracing

setup_tracing(
    endpoint="http://localhost:4318/v1/traces",
    service_name="my-agent-service"
)

```

## Decorating Components for Observability

Once tracing is enabled, apply decorators to the functions and methods you want to observe. The [`src/agentscope/tracing/_trace.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_trace.py) file provides specialized decorators for different component types.

### General Function Tracing

Use the `@trace` decorator for arbitrary functions:

```python
from agentscope.tracing import trace

@trace(name="my_custom_func")
async def my_custom_func(x: int) -> int:
    return x * 2

```

This creates a span named **my_custom_func** and records the input `x` and the output value as attributes.

### LLM Calls

Decorate your model's `__call__` method with `@trace_llm` to capture full request and response payloads:

```python
from agentscope.tracing import trace_llm
from agentscope.model import ChatModelBase, ChatResponse

class MyLLM(ChatModelBase):
    @trace_llm
    async def __call__(self, messages: list[dict]) -> ChatResponse:
        # Simulated response

        return ChatResponse(id="msg", content=[])

```

Spans are labeled with the operation name `chat` and include the full request/response payloads. See the implementation in [`trace_llm`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_trace.py#L67-L79).

### Agent Reply

Track agent response generation with `@trace_reply`:

```python
from agentscope.tracing import trace_reply
from agentscope.agent import AgentBase
from agentscope.message import Msg, TextBlock

class EchoAgent(AgentBase):
    @trace_reply
    async def reply(self) -> Msg:
        return Msg("assistant", [TextBlock(type="text", text="Hello!")])

```

### Formatter

Capture formatting logic with `@trace_format`:

```python
from agentscope.tracing import trace_format
from agentscope.formatter import FormatterBase

class SimpleFormatter(FormatterBase):
    @trace_format
    async def format(self) -> list[dict]:
        return [{"role": "user", "content": "Hello"}]

```

### Toolkit (Tool Calls)

Trace tool invocations with `@trace_toolkit`:

```python
from agentscope.tracing import trace_toolkit
from agentscope.tool import Toolkit, ToolResponse
from agentscope.message import TextBlock

class MyToolkit(Toolkit):
    @trace_toolkit
    async def call_tool_function(self, tool_call):
        # Your tool logic here

        return ToolResponse(content=[TextBlock(type="text", text="Done")])

```

### Embedding Model

Monitor embedding generation with `@trace_embedding`:

```python
from agentscope.tracing import trace_embedding
from agentscope.embedding import EmbeddingModelBase

class MyEmbedding(EmbeddingModelBase):
    @trace_embedding
    async def __call__(self, texts: list[str]) -> list[list[float]]:
        return [[0.1, 0.2, 0.3] for _ in texts]

```

## Viewing and Interpreting Traces

Once your application runs with decorated components, the OpenTelemetry exporter sends span data to your configured backend. In tools like **Langfuse** or **Arize Phoenix**, you will see a hierarchical trace view:

```

Agent.reply
 ├─ LLM.chat (or LLM.embed)
 ├─ Toolkit.call_tool_function
 └─ Formatter.format

```

Each node displays **request attributes** (e.g., message content, tool input parameters) and **response attributes** (e.g., generated text, tool output). Errors appear with a red `ERROR` status and include the captured exception message and stack trace. This structure allows you to pinpoint latency bottlenecks, inspect payload contents, and debug failures across the entire agent execution chain.

## Complete End-to-End Example

Here is a runnable example that ties together initialization, decoration, and execution:

```python
import agentscope
from agentscope.tracing import trace_reply, trace_llm
from agentscope.agent import AgentBase
from agentscope.model import ChatModelBase, ChatResponse
from agentscope.message import Msg, TextBlock

# 1️⃣ Initialise tracing (replace with your backend URL)

agentscope.init(tracing_url="https://cloud.langfuse.com/api/public/otel/v1/traces")

# 2️⃣ Define a traced LLM

class EchoLLM(ChatModelBase):
    @trace_llm
    async def __call__(self, messages, **kwargs):
        # Echo the last user message

        user_msg = messages[-1]["content"]
        return ChatResponse(
            id="msg",
            content=[TextBlock(type="text", text=user_msg)]
        )

# 3️⃣ Define a traced agent that uses the LLM

class EchoAgent(AgentBase):
    def __init__(self):
        super().__init__(name="echo")
        self.llm = EchoLLM(stream=False)

    @trace_reply
    async def reply(self) -> Msg:
        # Simple single‑turn conversation

        user_msg = [{"role": "user", "content": "Hello"}]
        llm_res = await self.llm(user_msg)
        return Msg("assistant", llm_res.content, "assistant")

# 4️⃣ Run the agent

agent = EchoAgent()
response = await agent()
print(response.content)   # → [TextBlock(type='text', text='Hello')]

```

After executing this script, your tracing backend (e.g., Langfuse) displays:

- **`EchoAgent.reply`** as the parent span.  
- **`EchoLLM.__call__`** as a child span containing request attribute `"user_message": "Hello"` and response attribute `"generated_text": "Hello"`.

This visibility allows you to debug execution flows, inspect message payloads, and identify performance bottlenecks in real time.

## Key Source Files

The tracing implementation spans several files in the `src/agentscope/tracing/` directory:

| File | Role | Direct Link |
|------|------|-------------|
| [`_setup.py`](https://github.com/agentscope-ai/agentscope/blob/main/_setup.py) | Configures the OTLP exporter and registers the `BatchSpanProcessor`. | [[`_setup.py`](https://github.com/agentscope-ai/agentscope/blob/main/_setup.py)](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_setup.py) |
| [`_trace.py`](https://github.com/agentscope-ai/agentscope/blob/main/_trace.py) | Implements the `trace` decorator and specialized variants (`trace_llm`, `trace_reply`, etc.). | [[`_trace.py`](https://github.com/agentscope-ai/agentscope/blob/main/_trace.py)](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_trace.py) |
| [`_extractor.py`](https://github.com/agentscope-ai/agentscope/blob/main/_extractor.py) | Serializes AgentScope objects into OpenTelemetry-compatible attributes. | [[`_extractor.py`](https://github.com/agentscope-ai/agentscope/blob/main/_extractor.py)](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_extractor.py) |
| [`_attributes.py`](https://github.com/agentscope-ai/agentscope/blob/main/_attributes.py) | Defines attribute key constants (`SpanAttributes`, `OperationNameValues`). | [[`_attributes.py`](https://github.com/agentscope-ai/agentscope/blob/main/_attributes.py)](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_attributes.py) |
| [`__init__.py`](https://github.com/agentscope-ai/agentscope/blob/main/__init__.py) | Public API exports (`setup_tracing`, decorators). | [[`__init__.py`](https://github.com/agentscope-ai/agentscope/blob/main/__init__.py)](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/__init__.py) |
| [`tests/tracing_test.py`](https://github.com/agentscope-ai/agentscope/blob/main/tests/tracing_test.py) | Unit tests demonstrating usage patterns. | [[`tracing_test.py`](https://github.com/agentscope-ai/agentscope/blob/main/tracing_test.py)](https://github.com/agentscope-ai/agentscope/blob/main/tests/tracing_test.py) |

## Summary

- **Enable tracing** by passing `tracing_url` to `agentscope.init()` or calling `setup_tracing()` directly from [`src/agentscope/tracing/_setup.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_setup.py).
- **Decorate components** using specialized decorators (`@trace_llm`, `@trace_reply`, `@trace_toolkit`, etc.) from [`src/agentscope/tracing/_trace.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_trace.py) to capture request/response data.
- **Observe hierarchies** in OTLP-compatible backends like Langfuse or Arize Phoenix, where parent spans (agents) contain child spans (LLMs, tools, formatters).
- **Debug effectively** by inspecting span attributes for inputs, outputs, and exceptions without modifying your core business logic.

## Frequently Asked Questions

### Do I need to modify my existing agent code to enable tracing?

No. You only need to initialize tracing with `agentscope.init(tracing_url="...")` and add decorators to the methods you want to observe. The decorators in [`src/agentscope/tracing/_trace.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_trace.py) wrap your existing functions without changing their signatures or behavior, capturing inputs and outputs only when `trace_enabled` is `True`.

### What backends are compatible with AgentScope tracing?

AgentScope uses the OpenTelemetry Protocol (OTLP) to export spans. Any OTLP-compatible backend works, including **Langfuse**, **Arize Phoenix**, **Jaeger**, **Zipkin** (via OpenTelemetry Collector), and the standard **OpenTelemetry Collector** itself. You simply provide the OTLP endpoint URL when calling `setup_tracing()` or `agentscope.init()`.

### How do I trace synchronous functions?

The decorators in [`src/agentscope/tracing/_trace.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_trace.py) handle both synchronous and asynchronous functions automatically. When you apply `@trace`, `@trace_llm`, or any other specialized decorator to a sync function, the wrapper detects the function type and manages the span context appropriately. You do not need separate decorators for sync and async code.

### Can I disable tracing for specific components while keeping it enabled globally?

Yes. Tracing is controlled by the global `_config.trace_enabled` flag, but you decide which methods to decorate. Simply omit the `@trace_*` decorators on components you want to exclude from telemetry. Alternatively, conditionally apply decorators based on your own configuration logic. Since the decorators in [`src/agentscope/tracing/_trace.py`](https://github.com/agentscope-ai/agentscope/blob/main/src/agentscope/tracing/_trace.py) only create spans when the global flag is enabled, removing the decorator entirely is the most reliable way to exclude specific functions from tracing.