OpenTelemetry 入門:AI アプリケーションと AI Agent 開発者のためのわかりやすいガイド

はじめに

AI アプリケーションの開発を始めたばかりの頃は、「モデルが回答できるか」だけに目が向きがちである。しかし、システムを実環境に投入すると、問題はすぐに次のようなものへ変わる。

  • このリクエストはなぜ失敗したのか。
  • 問題は検索、モデル、Tool、データベースのどこにあったのか。
  • Agent はなぜ同じ Tool を繰り返し呼び出したのか。
  • どのステップが最も遅く、最も高コストだったのか。
  • 1つのユーザータスクが API、Queue、Worker をまたぐとき、実行全体をどのようにつなげればよいのか。

OpenTelemetry は、こうした問いに答えるための共通の可観測性基盤を提供する、オープンな標準とツール群である。


1. OpenTelemetry を一文で理解する

OpenTelemetry(略称 OTel)は、テレメトリデータを生成、関連付け、処理、エクスポートするためのオープン標準とツールチェーンである。

テレメトリとは、システムの状態を理解するためにプログラムの実行中に生成されるデータである。OpenTelemetry の成熟度が高い中核シグナルは Trace、Metric、Log である。Baggage はサービス間でコンテキスト情報を伝播するために使われ、Profile は現時点で Alpha 段階にある。

  • Trace:1回のリクエストで何が起きたか。
  • Metric:一定期間にシステム全体がどのように動作したか。
  • Log:特定の時点でどのようなイベントが発生したか。
  • Baggage:呼び出しチェーンとともに、どのコンテキスト情報を伝播するか。
  • Profile:CPU やメモリなどのリソースをプログラムのどこで消費したか。現在も発展途上のシグナルである。

OpenTelemetry 自体は通常、データの長期保存、検索、可視化を担わない。統一された収集仕様、SDK、転送機構の集合と考えると理解しやすい。Langfuse、LangSmith、Phoenix、Grafana Tempo、Prometheus、Loki、Datadog などが、データを受信、保存、分析、表示するバックエンドとなる。


2. 「配送システム」で OpenTelemetry を理解する

1回の AI Agent リクエストが生成する観測データを、配送ネットワークを流れる荷物にたとえてみよう。

OpenTelemetry の概念配送システムでのたとえ実際の役割
Instrumentation(計装)商品を梱包して伝票を貼るプログラムに収集ロジックを追加する
Trace / Metric / Log種類の異なる荷物異なる種類のテレメトリシグナル
API標準の発送窓口アプリケーションコードがテレメトリを作成する方法を定める
SDK配送会社の実行システムサンプリング、処理、集約、エクスポートを行う
Exporter配送車両データを外部へ送信する
OTLP輸送プロトコルテレメトリのエンコードと転送方法を定める
Collector仕分けセンター受信、秘匿化、フィルタリング、サンプリング、バッチ処理、転送を行う
Backend倉庫と管理コンソール保存、検索、可視化、分析を行う
Trace Context荷物の追跡番号サービスをまたいで同じ呼び出しチェーンを維持する
Resource発送元情報データを生成したサービス、バージョン、環境を識別する
Semantic Conventions共通のフィールド辞書属性名と操作名を統一する

最も重要な点は次のとおりである。

OpenTelemetry は監視画面ではなく、Langfuse と競合する製品でもない。アプリケーションと各種可観測性バックエンドを接続する、標準化された中間層である。


3. AI Agent アーキテクチャにおける OpenTelemetry の位置

一般的な構成は次のようになる。

ユーザーリクエスト
FastAPI / Web サービス
AI Agent / RAG Pipeline
├── クエリ書き換え
├── Retriever
├── Reranker
├── LLM
├── Tool Call
└── データベース / 外部 API

アプリケーション内部:
├── 自動計装:HTTP、FastAPI、データベース、Redis など
├── 手動計装:Agent、RAG、LLM、Tool などの業務ステップ
├── Metrics:リクエスト数、レイテンシ、エラー率、Token など
└── Structured Logs:構造化ログ
          ↓ OTLP
OpenTelemetry Collector
├── 秘匿化
├── フィルタリング
├── サンプリング
├── バッチ処理とリトライ
└── 複数バックエンドへの配信
       ├── Langfuse / LangSmith / Phoenix:AI Trace と評価
       ├── Tempo / Datadog:汎用分散トレーシング
       ├── Prometheus / Grafana:メトリクスとアラート
       └── Loki / ログ基盤:ログ検索

この構成は2つの平面に分けられる。

  1. Instrumentation Plane:アプリケーション内部にあり、データを生成する。
  2. Pipeline Plane:通常は Collector が担い、データの転送と処理を行う。

4. 混同しやすい中核コンポーネント

4.1 Specification:仕様

Specification は OpenTelemetry の「ルールブック」である。Trace、Metric、Log、Context、OTLP などの概念がどのように動作すべきかを定義する。コードそのものではなく、各言語の SDK とツールが実装時に従う共通契約である。

4.2 API:アプリケーションコードが使うインターフェース

API はテレメトリの作成方法を定義する。たとえば次のように使う。

tracer.start_as_current_span("rag.retrieve")

API は安定性と軽量性を重視している。ライブラリは API のみに依存し、データの最終的な送信先を決めずに済む。

4.3 SDK:収集とエクスポートを実際に行う実装

SDK は API で生成されたデータを実際のテレメトリとして処理する。主な役割は次のとおりである。

  • Provider の作成。
  • サンプリング。
  • Metric の集約。
  • バッチ処理。
  • Exporter の呼び出し。
  • Resource の設定。
  • データをエクスポートするか、どのようにエクスポートするかの制御。

要約すると、次の関係になる。

API:「このデータを記録したい」と表現するためのメソッド
SDK:そのデータを実際に処理し、送信する仕組み

4.4 Instrumentation と Instrument は別の概念

この2つは特に混同しやすい。

Instrumentation(計装) は、コードに可観測性を追加するプロセス全体を指す。

with tracer.start_as_current_span("tool.weather"):
    result = call_weather_tool()

Instrument は Metrics に固有のオブジェクトであり、Counter、Histogram、ObservableGauge などが該当する。

request_counter = meter.create_counter("agent.requests")

したがって、次のように区別できる。

Instrumentation = プログラムに観測ロジックを追加すること
Instrument = 特定種類の Metric を記録するためのオブジェクト

4.5 Provider、Tracer、Meter

TracerProvider は Tracer の中央エントリーポイント兼設定オブジェクトであり、Tracer は Span を作成する。

TracerProvider → Tracer → Span

MeterProvider は Meter の中央エントリーポイント兼設定オブジェクトであり、Meter は Metric Instrument を作成する。

MeterProvider → Meter → Counter / Histogram / Gauge

Provider は通常、リクエストごとではなく、アプリケーション起動時に1回だけ初期化する。

4.6 Exporter

Exporter はテレメトリを外部へ送信する。

OTLP Exporter → Collector
Console Exporter → ターミナル
Prometheus Exporter → Prometheus 互換エンドポイント

Exporter はアプリケーションまたは Collector 内の出力アダプターであり、ストレージシステムではない。

4.7 OTLP

OTLP は OpenTelemetry Protocol の略であり、Trace、Metric、Log などの対応シグナルを、アプリケーション、Collector、バックエンド間で転送する方法を定める。

アプリケーション --OTLP--> Collector --OTLP/その他のプロトコル--> バックエンド

OTLP はプロトコルであり、サービスやデータベースではない。

4.8 Collector

OpenTelemetry Collector は独立して動作するテレメトリサービスである。典型的な Pipeline は次の形を取る。

Receiver → Processor → Exporter
  • Receiver:データを受信する。
  • Processor:バッチ処理、フィルタリング、サンプリング、秘匿化、属性付与を行う。
  • Exporter:1つまたは複数のバックエンドへデータを送信する。

Collector は、Pipeline 同士を接続する Connector や、ヘルスチェック、認証などの補助機能を提供する Extension も利用できる。

4.9 Backend

Backend は、データを最終的に保存、検索、表示、分析する基盤である。例として次が挙げられる。

  • Langfuse:AI、LLM、Agent の Trace、コスト、評価、データセット。
  • LangSmith:Agent Tracing と Evaluation。
  • Phoenix:AI Observability と Evaluation。
  • Tempo:Trace の保存と検索。
  • Prometheus:Metric の保存と検索。
  • Loki:ログの保存と検索。

OpenTelemetry との関係は、通常次のように整理できる。

OpenTelemetry はデータの生成と転送を担う
Backend はデータの保存と利用を担う

5. OpenTelemetry の主な可観測性シグナル

5.1 Trace:1回のリクエストの完全な実行経路

Trace は次の問いに答える。

「この特定のリクエストは、どのステップをどの順序で通過したのか」

1回の AI Agent タスクは次のように表現できる。

Trace: agent.run
├── Span: auth.check
├── Span: session.load
├── Span: rag.retrieve
│   ├── Span: embedding.create
│   └── Span: vector_db.search
├── Span: reranker.rank
├── Span: llm.plan
├── Span: tool.weather
├── Span: llm.answer
└── Span: result.persist

Span

Span は Trace 内の1つの作業単位であり、データベースクエリ、モデル呼び出し、Tool 実行などを表す。

Span は通常、次の情報を持つ。

  • name:ステップ名。
  • start/end time:開始時刻と終了時刻。
  • parent:親 Span。
  • attributes:構造化属性。
  • events:ステップ内の重要な時点。
  • status:成功またはエラーの状態。
  • links:別の Trace または Span との関連。
  • trace_id / span_id:呼び出しチェーンの識別子。

Attribute

Attribute は Span に付与する Key-Value 情報である。

gen_ai.agent.name = "support-agent"
gen_ai.request.model = "example-model"
gen_ai.tool.name = "search_orders"
app.tool.success = true

最初の3つは、現在も発展中の GenAI セマンティック規約に由来する。app.tool.success は、業務フィールドを説明するために本文で用いるカスタム属性である。本番システムでは、カスタムフィールドに安定した明示的な名前空間を使い、OpenTelemetry の公式フィールドに見えないようにする。

Span Event

Event は Span の存続期間中に発生した重要な瞬間を表す。

retry_started
rate_limit_received
fallback_model_selected

親子関係は、1つの実行チェーンが直接継続していることを表す。Queue や非同期タスクでも、Producer の Context を Consumer が抽出できれば、Consumer Span は同じ Trace を継続できる。複数の上流処理が1つのタスクを起動する場合、Batch が複数メッセージを統合する場合、または単一の親子関係では因果関係を正しく表せない場合に Link を使う。

Trace が適する場面

  • 1回の失敗リクエストを調査する。
  • Agent のループを分析する。
  • Tool の選択と引数を確認する。
  • RAG の検索と Reranking の経路を確認する。
  • 最も遅いステップを特定する。
  • API、Worker、データベース、外部サービスを接続して見る。

5.2 Metrics:多数のリクエストを集約した数値傾向

Metric は次の問いに答える。

「システム全体は最近どのように動作しているか」

例として次がある。

1分あたりのリクエスト数
タスク成功率
エラー率
P95 レイテンシ
LLM Token 総数
成功タスク1件あたりのコスト
現在の Queue 長
Tool 呼び出し失敗回数

中核オブジェクトの関係は次のとおりである。

MeterProvider
Meter
Instrument
Measurement
集約された Metric

Measurement

Measurement は1回の具体的な測定値である。

request_counter.add(1)
latency_histogram.record(850)

ここでは 1850 がそれぞれ Measurement になる。

主な Instrument

Instrument特徴AI アプリケーションでの例
Counter増加のみリクエスト総数、エラー総数、Token 総数
UpDownCounter増減可能現在実行中の Agent 数
Histogram数値分布を記録レイテンシ、Token 数、ドキュメントサイズ
ObservableGauge現在値を定期的に取得Queue 長、現在のメモリ使用量、アクティブタスク数

Observation

Observation は非同期 Instrument のコールバックが返す1回の観測値であり、Python の async/await とは無関係である。

たとえば OpenTelemetry が定期的にコールバックを呼び出し、現在の Queue 長を取得できる。

def observe_queue_size(options):
    yield Observation(queue.qsize(), {"queue": "rag-ingestion"})

Metric が適する場面

  • Dashboard。
  • 傾向分析。
  • SLO とアラート。
  • キャパシティプランニング。
  • リリース前後の比較。
  • コストとスループットの監視。

Cardinality:必ず理解すべき Metric のリスク

Cardinality は、Attribute 値の組み合わせの種類数を指す。

次のようなフィールドを Metric Attribute に直接入れてはならない。Prometheus などのバックエンドでは、通常 Label として表現される。

user_id
session_id
trace_id
完全な URL
生の Prompt
注文番号

ほぼすべての値が異なるため、膨大な時系列が生成され、保存と検索のコストが制御不能になる。高 Cardinality のフィールドは Metric Attribute ではなく Trace または Log に置く。


5.3 Logs:特定の時点で発生した具体的なイベント

Log はタイムスタンプ付きのイベント記録である。構造化ログの利用を推奨する。

{
  "timestamp": "2026-07-16T12:00:00Z",
  "level": "ERROR",
  "event": "tool_call_failed",
  "tool_name": "search_orders",
  "error_type": "timeout",
  "trace_id": "...",
  "span_id": "..."
}

構造化ログで重要なのは、単に JSON の見た目をしていることではない。機械が安定して検索できるよう、フィールド名と型を長期的に統一する必要がある。

Log は次の用途に適している。

  • 例外のスタックトレース。
  • Tool が返したエラーの詳細。
  • 業務監査イベント。
  • 状態変化。
  • Collector または Worker の実行情報。

Trace と Log は trace_idspan_id で関連付けることが望ましい。Metric で異常を検出し、Trace を開いて問題のステップを特定し、対応する Log で詳細なエラーを確認する。


5.4 Profiles:CPU とメモリをコードのどこで消費したか

Profile は次の問いに答える。

「プログラムの実行中、CPU 時間、メモリ割り当て、呼び出しスタックを主にどこで消費したか」

Profile はパフォーマンスエンジニアリング寄りのシグナルである。OpenTelemetry Profiles 仕様は現在 Alpha であり、AI Agent プロジェクトの最初の優先事項ではない。まず Trace、Metrics、Logs を整備すればよい。


6. 4種類のシグナルをどのように連携させるか

実用的には次のように理解できる。

Metrics:システム全体に問題があることを検出する
Trace:特定リクエストのどのステップに問題があるかを特定する
Logs:そのステップの具体的なエラー詳細を確認する
Profiles:コードレベルの性能ボトルネックをさらに分析する

たとえば次のようになる。

Metrics:P95 が3秒から12秒へ上昇した
Trace:遅いリクエストはすべて reranker.rank で停滞している
Logs:Reranker API が何度もタイムアウトし、リトライしている
Profile:ローカル前処理にも CPU ホットスポットがある

これらは互いを置き換えるものではなく、同じシステムを異なる角度から観測する。


7. Context Propagation:サービスをまたぐ呼び出しを1本の Trace にする

AI システムは次のような境界をまたぐことが多い。

FastAPI → Queue → Worker → LLM → Tool Service → Database

各サービスが無関係な Trace を作成すると、互いにつながらない断片しか見えない。

Context Propagation は、trace_id と現在の span_id をプロセス境界を越えて伝播する。HTTP では通常、traceparent Header を含む W3C Trace Context を使う。Message Queue では、Context をメッセージ属性へ注入し、Consumer 側で抽出する必要がある。

Service A が Trace を作成
   ↓ traceparent を注入
Service B が Context を抽出
   ↓ 子 Span を作成
Service C が伝播を継続

trace_id、session_id、request_id の違い

trace_id:1回の具体的な実行チェーン
session_id:複数ターンにわたる会話
request_id:アプリケーションが定義する1回の API リクエスト ID

1つの Session は複数の Trace を含み得る。session_idtrace_id の代わりに使ってはならない。


8. Resource、Semantic Conventions、Baggage

Resource

Resource は「誰がこのテレメトリを生成したか」を記述する。

service.name = "rag-api"
service.version = "1.4.2"
deployment.environment.name = "production"
cloud.region = "asia-northeast1"

Resource は通常、アプリケーション起動時に設定し、その Provider が生成するテレメトリとともにエクスポートする。どのシグナルをサポートするかは、利用する言語の SDK と各シグナル実装によって異なる。

Semantic Conventions

Semantic Conventions は統一されたフィールド命名規則である。各チームが HTTP、データベース、メッセージング、GenAI の操作を同じ規約で記録すれば、Backend は一貫した検索と表示を実現できる。

次のように理解するとよい。

セマンティック規約はデータ転送プロトコルではなく、テレメトリフィールドの共通辞書である。

OpenTelemetry は、GenAI Client、Agent、MCP、一部のモデルプロバイダー向けの専用セマンティック規約を整備している。本文公開時点で、これらは独立した GenAI セマンティック規約リポジトリへ移行しており、全体として Development 状態にある。フィールドや Span 構造は今後も変わり得るため、実装では採用するセマンティック規約のバージョンを固定する必要がある。

Baggage

Baggage は Context とともに伝播する業務上の Key-Value 情報である。

tenant.tier = "enterprise"
experiment.group = "prompt-v2"

Baggage は自動的に Span Attribute にはならない。アプリケーション側で明示的に読み取り、利用する必要がある。

API Key、個人情報、完全な Prompt などの機密データを Baggage に入れてはならない。下流サービスや第三者サービスまで伝播する可能性がある。


9. AI と Agent システムにおける OpenTelemetry の特別な価値

従来の Web リクエストは、比較的固定された経路を通る。

HTTP → Service → Database → Response

一方、Agent の実行経路はより動的である。

ユーザーの質問
→ モデルによる計画
→ 検索
→ Tool A
→ モデルによる再判断
→ Tool B
→ リトライまたはフォールバック
→ 最終回答

そのため、AI の可観測性では次の情報を記録する必要がある。

  • モデルとプロバイダー。
  • Prompt または Prompt のバージョン。
  • 入力、出力、キャッシュの Token 数。
  • モデルのレイテンシと終了理由。
  • Agent の Node と状態遷移。
  • Tool 名、引数 Schema、実行結果。
  • Retriever、Reranker、Top K、ドキュメント ID。
  • Guardrail。
  • リトライ、Fallback、Handoff。
  • コストとタスクの業務結果。

OpenTelemetry はこれらのステップを統一された Trace モデルに配置し、HTTP、データベース、Queue など従来のインフラ呼び出しと接続する。

GenAI Semantic Conventions

OpenTelemetry の GenAI セマンティック規約は、AI Client、Agent、MCP、モデル呼び出しにおける Span、Metric、Event の命名方法を定義する。これにより、異なる Framework が生成したテレメトリを共通 Backend で理解しやすくなる。ただし、現時点では Development 状態であり、完全に安定した長期契約として扱うべきではない。

OpenInference

OpenInference は OpenTelemetry の考え方を基盤とする、AI 専用の規約と計装 Plugin のエコシステムである。OpenAI、Anthropic、LangChain、LlamaIndex、Google ADK、MCP などを対象としている。特定の統合で公式 OTel GenAI 計装がまだ使いにくい場合に、AI 専用 Trace を迅速に取得する手段となる。

Langfuse、LangSmith、Phoenix

これらは AI の可観測性と評価を担う Backend であり、OpenTelemetry の代替ではない。OpenTelemetry Trace を直接または間接的に受信し、LLM や Agent に適した UI、コスト分析、Dataset、Experiment、Evaluation を提供する。


10. 可観測性と Evaluation は同じではない

OpenTelemetry が主に答えるのは次の問いである。

「Agent は何をしたか」

Evaluation が主に答えるのは次の問いである。

「Agent の処理は適切だったか」

たとえば次のように区別できる。

OpenTelemetry:
search_orders を呼び出した
引数は order_id=123
所要時間は 800ms
エラーなしで完了した

Evaluation:
そもそもこの Tool を呼ぶべきだったか
order_id は正しかったか
ユーザーの返金タスクは実際に完了したか
回答は Tool の結果に忠実だったか

成熟したシステムでは、通常この2つを接続する。

本番 Trace
→ ルール、ユーザーフィードバック、LLM Judge で採点
→ 失敗サンプルを Dataset へ追加
→ Prompt / モデル / Workflow を修正
→ オフライン Experiment
→ CI 回帰テスト
→ 段階的リリース

Trace は評価のためのデータ基盤になるが、それ自体が品質の結論を示すわけではない。


11. AI Agent に推奨する Trace 設計

基本方針は、1つのユーザータスクまたは1回の Agent Run を1本の Trace に対応させることである。

Trace: agent.run
├── request.validate
├── context.load
├── rag.retrieve
│   ├── query.embed
│   ├── dense.search
│   ├── sparse.search
│   ├── rrf.fuse
│   └── reranker.rank
├── llm.plan
├── tool.call
├── guardrail.check
├── llm.answer
└── result.persist

診断価値のあるステップだけに Span を作成する。小さな関数をすべて Span にすると、Trace がノイズで埋まり、コストも増える。

サービスの識別情報は、まず Resource に設定する。

service.version
deployment.environment.name

Agent Run の Span には、その実行に関する情報を記録する。公式規約が存在する場合は公式フィールドを使い、存在しない場合はアプリケーション固有の名前空間を使う。

gen_ai.agent.name
gen_ai.agent.version
gen_ai.conversation.id
app.release.git_sha
app.prompt.version
app.knowledge_base.version

モデル Span に推奨するフィールドは次のとおりである。

gen_ai.provider.name
gen_ai.request.model / gen_ai.response.model
gen_ai.usage.input_tokens / gen_ai.usage.output_tokens
gen_ai.response.finish_reasons
error.type
app.retry_count

レイテンシは Span の開始時刻と終了時刻で表現できる。独立した集約要件がある場合にのみ Metric として追加記録する。キャッシュ Token などの拡張フィールドを利用できるかは、採用するセマンティック規約のバージョンと計装実装によって異なる。

Tool Span に推奨するフィールドは次のとおりである。

gen_ai.tool.name
gen_ai.tool.type
error.type
app.tool.version
app.tool.success

RAG Span に推奨するフィールドは次のとおりである。

app.rag.index.name
app.rag.index.version
app.rag.top_k
app.rag.retrieved_document_ids
app.rag.reranker.name
app.rag.result_count

ここで示した app.rag.* は例示用のカスタム属性であり、OpenTelemetry 公式の RAG セマンティック規約ではない。

完全な Prompt、ユーザーの私有ドキュメント、Tool の生の戻り値、隠れた Chain-of-Thought をデフォルトで記録してはならない。


12. 推奨する本番アーキテクチャ

開発段階

Python AI App
├── OpenTelemetry 自動計装
├── 少数の手動 Agent Span
├── JSON stdout Logs
└── OTLP Exporter
Langfuse / Phoenix / LangSmith

迅速な検証に適しており、必ずしも Collector は必要ない。

本番前および本番段階

Python AI App
   ↓ OTLP
OpenTelemetry Collector
├── memory_limiter
├── batch
├── redaction / transform
├── sampling
└── exporters(sending queue / retry)
       ├── Langfuse / LangSmith / Phoenix
       ├── Tempo / Datadog
       ├── Prometheus
       └── Logs backend

Collector には次の重要な利点がある。

  • アプリケーションとベンダーの Backend を分離する。
  • 秘匿化を一元化する。
  • サンプリングを一元化する。
  • バッチ処理とリトライを提供する。
  • 1つのデータを複数の基盤へ送信する。
  • Backend 変更時のアプリケーション修正を減らす。

13. 本番環境のベストプラクティス

13.1 自動計装と手動計装を組み合わせる

自動計装は FastAPI、HTTP Client、データベース、Redis などの汎用呼び出しを対象とする。手動計装では Agent タスク、RAG、Tool、Guardrail、業務結果を補う。

13.2 可観測性基盤の障害で業務を停止させない

バッチ処理と非同期エクスポートを使う。Collector の Exporter には Sending Queue、指数バックオフを伴うリトライ、必要に応じた永続化を設定する。テレメトリ Backend が一時的に停止しても、AI アプリケーションは可能な限り処理を継続すべきである。同時に Queue 容量、データ破棄数、ディスク使用量を監視する。

13.3 本番環境で完全な入出力を無条件に記録しない

機密データはアプリケーションから出る前に秘匿化し、Collector で第2段階のフィルタリングを行う。少なくとも次の情報を保護する。

Authorization / Cookie / API Key
メールアドレス、電話番号、身分証明情報
ユーザーの私有ドキュメント
データベースが返す機密フィールド
完全な Prompt とモデル出力

13.4 隠れた Chain-of-Thought を記録しない

監査可能な構造化結果を記録する。

selected_tool
route
state_transition
validation_result
policy_decision

モデルの隠れた Chain-of-Thought に依存したり、それを保存したりしてはならない。

13.5 Metric Cardinality を制御する

Metric Attribute には低 Cardinality のフィールドだけを使う。

model_family
environment
status
tool_name
error_type

ユーザー ID、Trace ID、Prompt などの高 Cardinality 値は Trace または Log に置く。

13.6 固定ランダムサンプリングだけに依存しない

開発環境では Trace を100%保持してもよい。本番環境では正常リクエストをランダムに一部保持し、Tail Sampling によって次の Trace を優先的に残す。

エラー Trace
遅い Trace
高コスト Trace
高リスクな Tool 操作
異常なループ

Head Sampling はリクエスト開始時に判断するため低コストである。Tail Sampling は、より完全な Trace 情報を確認してから判断できるため精度の高いポリシーを実現できるが、Collector が状態を保持する必要があり、複雑度も高い。ユーザーの低評価などのフィードバックは通常、Tail Sampling の判断完了後に到着する。完了済みの判断へ直接影響できると仮定せず、Trace ID を通じて後続の評価データに関連付けるか、別の保持方式を使う。

13.7 Context を一貫して伝播する

HTTP の Context Propagation は一般に成熟している。Queue、定期 Job、データベース Job では Context の明示的な注入と抽出が必要になる場合が多い。これを行わないと、Worker の Trace が入口リクエストから切り離される。

13.8 Resource とバージョン情報を使う

少なくとも次を設定する。

service.name
service.version
deployment.environment.name

AI アプリケーションでは gen_ai.agent.version も記録し、app.prompt.versionapp.knowledge_base.versionapp.release.git_sha にはカスタム名前空間を使う。これらにより、リリース間の回帰を比較しやすくなる。

13.9 Collector 自体を監視する

Collector にも Queue の滞留、メモリ不足、エクスポート失敗、データ破棄が発生する。本番環境では、受信量、送信失敗、Queue 容量、破棄数を監視しなければならない。


14. 最小構成の Python Trace 例

次の例は単独で実行できる。まず依存パッケージをインストールする。

pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-http

ローカルの 4318 ポートで、OTLP/HTTP 対応の Collector または Backend が起動済みであることを前提とする。実際のプロジェクトでは、自動計装、Metric、ログ相関、秘匿化も追加するのが一般的である。

from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

resource = Resource.create(
    {
        "service.name": "my-rag-agent",
        "service.version": "1.0.0",
        "deployment.environment.name": "development",
    }
)

provider = TracerProvider(resource=resource)
provider.add_span_processor(
    BatchSpanProcessor(
        OTLPSpanExporter(
            endpoint="http://localhost:4318/v1/traces",
        )
    )
)
trace.set_tracer_provider(provider)

tracer = trace.get_tracer("my-rag-agent")


def retrieve(query: str) -> list[str]:
    return [f"example document for: {query}"]


def generate_answer(query: str, documents: list[str]) -> str:
    return f"answer based on {len(documents)} document(s)"


def run_agent(query: str) -> str:
    with tracer.start_as_current_span("agent.run") as root:
        root.set_attribute("gen_ai.agent.name", "rag-agent")
        root.set_attribute("app.prompt.version", "answer-v3")

        with tracer.start_as_current_span("rag.retrieve") as span:
            documents = retrieve(query)
            span.set_attribute("app.rag.result_count", len(documents))

        with tracer.start_as_current_span("llm.generate") as span:
            answer = generate_answer(query, documents)
            span.set_attribute("gen_ai.request.model", "example-model")

        return answer


if __name__ == "__main__":
    print(run_agent("What is OpenTelemetry?"))
    provider.force_flush()

このコードは次の Trace を生成する。

agent.run
├── rag.retrieve
└── llm.generate

その後、FastAPI の自動計装、HTTPX、データベース、Queue Context、Metrics、ログ相関を段階的に追加すればよい。例にある agent.runrag.retrievellm.generateapp.rag.result_count は、説明用のアプリケーション定義名である。プロジェクトで GenAI セマンティック規約を採用する場合は、固定したバージョンの Span 名と属性要件に従う。


15. 初学者によくある誤解

「OpenTelemetry は監視プラットフォームである」

誤りである。OpenTelemetry は主に収集、関連付け、処理、エクスポートを標準化する。実際の UI、ストレージ、分析は Backend プラットフォームが提供する。

「OTLP は Collector である」

誤りである。OTLP は転送プロトコルであり、Collector はデータを受信して処理するサービスである。

「Trace と Log は同じである」

誤りである。Trace は1回のリクエストの構造化された実行チェーンを示す。Log は特定のイベントとその詳細を記録する。

「Metric は多数の Trace を単純に足し合わせたものである」

厳密には異なる。Metric には独自のデータモデル、Instrument、集約体系がある。アプリケーションから直接記録することも、別のデータから生成することもできる。

「Instrument は Instrumentation のことである」

誤りである。Instrumentation は可観測性を追加するプロセスであり、Instrument は Counter や Histogram などの Metrics オブジェクトである。

「Session は1本の Trace である」

誤りである。複数ターンの Session は通常、複数の独立した Trace を含む。

「Trace があれば Evaluation は完了している」

誤りである。Trace は実行事実を記録する。品質を判断するには、ルール、Ground Truth、LLM Judge、人的フィードバック、または実際の業務結果が必要である。


16. 推奨する学習と導入の順序

第1段階:Trace だけを理解する

次を実装する。

1回の Agent Run = 1本の Trace
LLM、RAG、Tool = 子 Span

まず Backend の画面で、1回のリクエスト全体を確認できるようにする。

第2段階:Metrics と構造化ログを追加する

次を追加する。

リクエスト数
エラー率
レイテンシ Histogram
Token とコスト
JSON ログ + trace_id/span_id

第3段階:Collector を導入する

次を一元化する。

バッチ処理
秘匿化
サンプリング
リトライ
複数 Backend への配信

第4段階:Evaluation と接続する

ユーザーフィードバック、タスク成功、Tool の正確性、LLM Judge のスコアを Trace に関連付け、失敗事例を Dataset と CI 回帰テストへ送る。


まとめ

AI アプリケーション開発者にとって重要なのは、OpenTelemetry のすべての用語を一度に暗記することではない。まず次の流れを理解すればよい。

アプリケーションが計装によって Trace、Metric、Log を生成する
SDK が処理し、OTLP でエクスポートする
Collector が一元的に受信、加工、配信する
Langfuse、Tempo、Prometheus などの Backend が保存、表示、分析する

3つの中核シグナルは次のように区別できる。

Trace:このリクエストで何が起きたか
Metrics:システム全体が最近どのように動作しているか
Logs:特定の時点で何が起きたか

AI Agent における OpenTelemetry の中核的な価値は、モデル、検索、Tool、データベース、Queue、外部サービスを1本の追跡可能なチェーンへまとめることにある。Langfuse、LangSmith、Phoenix などは、その上に AI 専用の分析と評価機能を提供する。

成熟した設計とは、「すべてのデータを記録する」ことではない。

診断価値のあるデータを記録し、統一されたセマンティクスを使い、機密情報を保護し、コストを制御し、可観測性データを継続的な評価と改善へ活用する。


公式参考資料