# トレースの実装

> トレースの実装 - OpenTelemetryのトレースとカスタムスパン計装をエージェントツールに追加して、監視、デバッグ、オブザーバビリティを実現する方法を説明します。

This Markdown file sits beside the HTML page at the same path (with a `.md` suffix). It summarizes the topic and lists links for tools and LLM context.

Companion generated at `2026-07-15T05:55:44.567811+00:00` (UTC).

## Primary page

- [トレースの実装](https://docs.datarobot.com/ja/docs/agentic-ai/agentic-develop/agentic-tracing-code.html.md): Full documentation for this topic (Markdown sidecar).

## Sections on this page

- [ツールにカスタムトレースを追加する](https://docs.datarobot.com/ja/docs/agentic-ai/agentic-develop/agentic-tracing-code.html.md#add-custom-tracing-to-tools): In-page section heading.
- [ツール例](https://docs.datarobot.com/ja/docs/agentic-ai/agentic-develop/agentic-tracing-code.html.md#tool-examples): In-page section heading.
- [ネストされたスパンの作成](https://docs.datarobot.com/ja/docs/agentic-ai/agentic-develop/agentic-tracing-code.html.md#create-nested-spans): In-page section heading.
- [スパンにイベントを追加する](https://docs.datarobot.com/ja/docs/agentic-ai/agentic-develop/agentic-tracing-code.html.md#add-events-to-spans): In-page section heading.
- [エージェントにカスタムトレースを追加する](https://docs.datarobot.com/ja/docs/agentic-ai/agentic-develop/agentic-tracing-code.html.md#trace-agent-configuration): In-page section heading.
- [スパンと属性をトレーステーブルにマッピングする](https://docs.datarobot.com/ja/docs/agentic-ai/agentic-develop/agentic-tracing-code.html.md#map-spans-and-attributes-to-the-tracing-table): In-page section heading.
- [トレーステーブルにツール名を表示する](https://docs.datarobot.com/ja/docs/agentic-ai/agentic-develop/agentic-tracing-code.html.md#surface-tool-names-in-the-tracing-table): In-page section heading.
- [ベストプラクティス](https://docs.datarobot.com/ja/docs/agentic-ai/agentic-develop/agentic-tracing-code.html.md#best-practices): In-page section heading.

## Documentation content

OpenTelemetry（OTel）は、エージェントに包括的なオブザーバビリティを提供し、エージェントの実行をリアルタイムで監視、トレース、デバッグできます。 このガイドでは、エージェントツールにカスタムトレースを追加して、詳細な実行情報を取得する方法を説明します。

OpenTelemetryによるトレースは、以下のことに役立ちます。

- エージェントのパフォーマンスと実行フローを監視する。
- 詳細な実行トレースを追跡することで、問題をデバッグする。
- ツールの実行パターンとタイミングを把握する。
- ツールのカスタム属性とメタデータを確認する。

エージェントテンプレートには、CrewAI、LangGraph、Llama-Indexなどのフレームワーク向けのOpenTelemetry計装がすでに含まれています。 この計装により、以下のスパンが自動的に取得されます。

- エージェントの実行
- ツールの起動
- LLM APIの呼び出し
- HTTPリクエスト

ツールにカスタムスパンやカスタム属性を追加することで、このデフォルトトレースを強化することができます。

## ツールにカスタムトレースを追加する

OpenTelemetryのカスタムトレースをツールに追加して、ツールの実行に関する追加情報を取得します。 これにより、ユースケースに固有のカスタム属性、中間出力、実行の詳細を追跡できます。

ツールにカスタムトレースを追加する基本的なパターンは以下のとおりです。

```
from opentelemetry import trace

tracer = trace.get_tracer(__name__)

# Within your tool's execution
with tracer.start_as_current_span("my_custom_span_name"):
    current_span = trace.get_current_span()
    current_span.set_attribute("tool_name", "my_tool_name")
    current_span.set_attribute("gen_ai.prompt", "input passed to this step")
    current_span.set_attribute("datarobot.moderation.cost", 0.0)

    # Your tool logic here
    result = perform_tool_action()

    current_span.set_attribute("gen_ai.completion", str(result))
    # Optionally add more attributes about the result
    current_span.set_attribute("result.status", "success")
    current_span.set_attribute("result.size", len(result))

    return result 
```

### ツール例

OpenTelemetryのカスタムトレースをエージェントツールに追加する方法については、以下のコード例を参照してください。

**CrewAI:**
```
import requests
from crewai.tools import BaseTool
from opentelemetry import trace

tracer = trace.get_tracer(__name__)

class WeatherTool(BaseTool):
    name: str = "weather_tool"
    description: str = (
        "Fetches the current weather for a specified city. "
        "Requires an API key from OpenWeatherMap."
    )

    def _run(self, city: str) -> str:
        with tracer.start_as_current_span("weather_tool_fetch"):
            current_span = trace.get_current_span()
            current_span.set_attribute("tool_name", "weather_tool")
            current_span.set_attribute("gen_ai.prompt", f"weather lookup for {city}")
            current_span.set_attribute("datarobot.moderation.cost", 0.0)

            # Set custom attributes
            current_span.set_attribute("weather.city", city)
            current_span.set_attribute("weather.api", "openweathermap")

            api_key = "YOUR_API_KEY"  # Replace with your API key
            base_url = "http://api.openweathermap.org/data/2.5/weather"
            params = {"q": city, "appid": api_key, "units": "metric"}

            try:
                response = requests.get(base_url, params=params, timeout=10)
                response.raise_for_status()

                data = response.json()
                weather = data['weather'][0]
                main = data['main']

                # Add result attributes
                current_span.set_attribute("weather.temperature", main['temp'])
                current_span.set_attribute("weather.condition", weather['main'])

                result = (
                    f"Current weather in {data['name']}, {data['sys']['country']}:\n"
                    f"Temperature: {main['temp']}°C (feels like {main['feels_like']}°C)\n"
                    f"Condition: {weather['main']} - {weather['description']}\n"
                    f"Humidity: {main['humidity']}%\n"
                    f"Pressure: {main['pressure']} hPa"
                )
                current_span.set_attribute("gen_ai.completion", result)

                return result

            except requests.exceptions.RequestException as e:
                current_span.set_attribute("weather.error", str(e))
                err = f"Error fetching weather data: {str(e)}"
                current_span.set_attribute("gen_ai.completion", err)
                return err 
```

**LangGraph:**
```
import requests
from langchain.tools import BaseTool
from opentelemetry import trace

tracer = trace.get_tracer(__name__)

class WeatherTool(BaseTool):
    name: str = "weather_tool"
    description: str = (
        "Fetches the current weather for a specified city. "
        "Requires an API key from OpenWeatherMap."
    )

    def _run(self, city: str) -> str:
        with tracer.start_as_current_span("weather_tool_fetch"):
            current_span = trace.get_current_span()
            current_span.set_attribute("tool_name", "weather_tool")
            current_span.set_attribute("gen_ai.prompt", f"weather lookup for {city}")
            current_span.set_attribute("datarobot.moderation.cost", 0.0)

            # Set custom attributes
            current_span.set_attribute("weather.city", city)

            api_key = "YOUR_API_KEY"  # Replace with your API key
            base_url = "http://api.openweathermap.org/data/2.5/weather"
            params = {"q": city, "appid": api_key, "units": "metric"}

            try:
                response = requests.get(base_url, params=params, timeout=10)
                response.raise_for_status()

                data = response.json()

                # Add result attributes
                current_span.set_attribute("weather.temperature", data['main']['temp'])

                result = f"Temperature in {city}: {data['main']['temp']}°C"
                current_span.set_attribute("gen_ai.completion", result)
                return result

            except requests.exceptions.RequestException as e:
                current_span.set_attribute("weather.error", str(e))
                err = f"Error: {str(e)}"
                current_span.set_attribute("gen_ai.completion", err)
                return err 
```

**Llama-Index:**
```
import requests
from llama_index.core.tools import FunctionTool
from opentelemetry import trace

tracer = trace.get_tracer(__name__)

def _weather_run(city: str) -> str:
    """Fetches the current weather for a specified city. Requires an API key from OpenWeatherMap."""
    with tracer.start_as_current_span("weather_tool_fetch"):
        current_span = trace.get_current_span()
        current_span.set_attribute("tool_name", "weather_tool")
        current_span.set_attribute("gen_ai.prompt", f"weather lookup for {city}")
        current_span.set_attribute("datarobot.moderation.cost", 0.0)

        # Set custom attributes
        current_span.set_attribute("weather.city", city)

        api_key = "YOUR_API_KEY"  # Replace with your API key
        base_url = "http://api.openweathermap.org/data/2.5/weather"
        params = {"q": city, "appid": api_key, "units": "metric"}

        try:
            response = requests.get(base_url, params=params, timeout=10)
            response.raise_for_status()

            data = response.json()

            # Add result attributes
            current_span.set_attribute("weather.temperature", data['main']['temp'])

            result = f"Temperature in {city}: {data['main']['temp']}°C"
            current_span.set_attribute("gen_ai.completion", result)
            return result

        except requests.exceptions.RequestException as e:
            current_span.set_attribute("weather.error", str(e))
            err = f"Error: {str(e)}"
            current_span.set_attribute("gen_ai.completion", err)
            return err

def WeatherTool() -> FunctionTool:
    return FunctionTool.from_defaults(
        fn=_weather_run,
        name="weather_tool",
        description=(
            "Fetches the current weather for a specified city. "
            "Requires an API key from OpenWeatherMap."
        ),
    ) 
```


## ネストされたスパンの作成

ネストされたスパンを作成して、複数のステップからなる複雑なツールの実行を表します。

```
from opentelemetry import trace

tracer = trace.get_tracer(__name__)

def complex_tool_workflow(input_data):
    with tracer.start_as_current_span("complex_tool_main"):
        current_span = trace.get_current_span()
        current_span.set_attribute("input.size", len(input_data))

        # First step in the workflow
        with tracer.start_as_current_span("data_processing"):
            processed_data = process_data(input_data)
            trace.get_current_span().set_attribute("processed_items", len(processed_data))

        # Second step in the workflow
        with tracer.start_as_current_span("data_validation"):
            validated_data = validate_data(processed_data)
            trace.get_current_span().set_attribute("validated_items", len(validated_data))

        # Third step in the workflow
        with tracer.start_as_current_span("result_generation"):
            result = generate_result(validated_data)
            current_span.set_attribute("result.size", len(result))

        return result 
```

### スパンにイベントを追加する

スパンにイベントを追加して、ツール実行の重要なタイミングをマークします。

```
from opentelemetry import trace
from datetime import datetime

tracer = trace.get_tracer(__name__)

def tool_with_events():
    with tracer.start_as_current_span("tool_execution"):
        current_span = trace.get_current_span()

        # Add an event for when processing starts
        current_span.add_event(
            "Processing started",
            {"timestamp": datetime.utcnow().isoformat()}
        )

        # Your tool logic
        intermediate_result = perform_action()

        # Add an event for mid-execution
        current_span.add_event(
            "Intermediate result ready",
            {"result_count": len(intermediate_result)}
        )

        # More processing
        final_result = complete_processing(intermediate_result)

        # Add final event
        current_span.add_event(
            "Processing completed",
            {"output_size": len(final_result)}
        )

        return final_result 
```

## エージェントにカスタムトレースを追加する

カスタムトレースを設定して、構成や環境の詳細を含むエージェントの起動方法を取り込むことができます。 ランタイムパラメーター（環境変数など）をスパンに表示するには、以下の手順に従います。

1. .envファイルを更新して、以下の環境変数を含め、ローカル開発時およびモデルをパッケージ化する際に使用できるようにします。 EXAMPLE_ENV_VAR=my_example_value
2. agent/model-metadata.yamlにパラメーターを追加して、エージェントの実行時に挿入できるようにします。 runtimeParameterDefinitions:-fieldName:EXAMPLE_ENV_VARtype:stringdefaultValue:SET_VIA_PULUMI_OR_MANUALLY
3. agent/agent/config.pyのConfigクラスにパラメーター（例：example_env_var: str = ""）を追加して、エージェントコードで値をconfig.example_env_varとして使用できるようにします。
4. infra/infra/llm.pyを更新して、ランタイムパラメーターをカスタムモデル環境に転送します。 custom_model_runtime_parameters=[# ...existing parameters...datarobot.CustomModelRuntimeParameterValueArgs(key="EXAMPLE_ENV_VAR",type="string",value=os.environ.get("EXAMPLE_ENV_VAR"),),]
5. 設定読み込みコードをスパンでラップし、set_attributeとadd_eventを使用して値を添付します。 プロパティ名はテンプレートによって異なります（例：CrewAIテンプレートではagent_planner）。 @propertydefagent_planner(self)->Any:withtracer.start_as_current_span("config_variables"):current_span=trace.get_current_span()current_span.set_attribute("config.example_env_var",config.example_env_var)current_span.add_event("config attribute set on span")# ...agent code continued...

開発中にエージェントをローカルで実行すると、トレースビジュアライザーには、 `config.example_env_var=my_example_value` などの属性を持つ `config_variables` スパンが表示されます。 これにより、ランタイムパラメーターやその他の環境値が正しく読み込まれたことを簡単に確認できます。

エージェントをカスタムアプリケーションとしてデプロイすると、そのアプリケーションに対して [オーナーまたはエディター](https://docs.datarobot.com/ja/docs/wb-apps/custom-apps/manage-custom-app.html.md#share-applications) の権限を持つユーザーは、DataRobot UIの トレース タブでこれらのスパンを確認できます。 [カスタムアプリケーションのトレース](https://docs.datarobot.com/ja/docs/wb-apps/custom-apps/monitor-app.html.md#tracing) を参照してください。

## スパンと属性をトレーステーブルにマッピングする

デプロイでは、トレーステーブルにOpenTelemetryのスパン属性から派生したいくつかの列が表示されます。 トレース全体に以下の命名規則が適用されます。

| トレーステーブルの列 | 属性 | 派生方法 |
| --- | --- | --- |
| コスト | datarobot.moderation.cost | トレース内のすべてのスパンにおける合計。 |
| プロンプト | gen_ai.prompt | 複数のスパンがこの属性を設定している場合、トレース順で最初の値が使用されます。 |
| 補完 | gen_ai.completion | 複数のスパンがこの属性を設定している場合、トレース順で最後の値が使用されます。 |
| ツール | tool_name | トレース内のいずれかのスパンで見つかった一意のtool_nameがすべてリストされます。 |

### トレーステーブルにツール名を表示する

ツール 列には、スパン属性 `tool_name` の値が入力されます。 一部のフレームワークではこれがツールスパンに自動的に設定されますが、設定されないものもあります。 トレースのスパンタイムラインにツールの実行が表示されているのに ツール が空の場合は、ツール本体を囲むスパンを作成（またはアクティブなスパンを使用）し、 `tool_name` を明示的に設定します。

**withスパン内:**
```
from opentelemetry import trace

tracer = trace.get_tracer(__name__)

def my_tool_impl(query: str) -> str:
    with tracer.start_as_current_span("my_tool"):
        span = trace.get_current_span()
        # Attributes that map to deployment Tracing table columns (see above)
        span.set_attribute("tool_name", "my_tool_name")
        span.set_attribute("gen_ai.prompt", query)
        span.set_attribute("datarobot.moderation.cost", 0.0)  # numeric; summed per trace
        # ... tool logic ...
        result = "result"
        span.set_attribute("gen_ai.completion", result)
        return result 
```

**現在のスパンのみ:**
スパンがすでにアクティブである場合（例：アップストリームの計装によるもの）、そのスパンに属性を設定できます。

```
from opentelemetry import trace

span = trace.get_current_span()
span.set_attribute("tool_name", "my_tool_name")
span.set_attribute("gen_ai.prompt", "user input or request text")
span.set_attribute("gen_ai.completion", "model or tool output text")
span.set_attribute("datarobot.moderation.cost", 0.0) 
```


LangGraphや同様のフレームワークでは、ツール呼び出しは、スパンに `tool_name` を追加しない方法でコールバックを介して接続されることがあります。手動で計装を行うことで、 ツール 列に名前を表示させることができます。

## ベストプラクティス

わかりやすいスパン名を使用する：

- スパンには明確でわかりやすい名前を使います（たとえば、 "span1" ではなく "weather_fetch" ）。
- 必要に応じて、スパン名にツール名を含めます。

意味のある属性を設定する：

- 実行に関するコンテキストを提供する属性を追加します。
- 一貫性のある属性命名規則を使用します（例： tool.input 、 tool.output 、 tool.error ）。
- サイズ、カウント、ステータスなどの関連するメタデータを含めます。
- デプロイの トレース テーブル内の コスト 、 プロンプト 、 補完 、および ツール に値を入力するには、関連するスパンに datarobot.moderation.cost 、 gen_ai.prompt 、 gen_ai.completion 、および tool_name を設定します。

スパンを適切に使用する：

- すべてのコード行ではなく、重要な操作のためにスパンを作成します。
- 各スパンは、意味のある作業単位を表す必要があります。
- サブ操作を表すには、ネストされたスパンを使用します。
