LLMオブザーバビリティとは?AIの呼び出しをトレースで追う

LLMオブザーバビリティとは?AIの呼び出しをトレースで追う

2026年10月14日、Anthropic は Claude API の OpenTelemetry エクスポートをベータとして公開しました。

Messages API のリクエストや Claude Managed Agents のセッションを、自分の監視基盤でトレースとして見られるようにする機能です。

こうした「AI の呼び出しを外から観察できるようにする取り組み」は、LLM オブザーバビリティと呼ばれています。

トレースとスパンの考え方、共通の属性名、プロンプトを残すかどうかの判断が分かると、どの監視ツールを選んでも同じ物差しで AI の動きを追えます。

LLMオブザーバビリティとは

LLM オブザーバビリティは、LLM を使うアプリの中で、何がどの順で起き、どれだけの時間とトークンを使ったかを後から確かめられる状態にすることです。

オブザーバビリティそのものは、ログ・メトリクス・トレースからシステムの内部を推し量る考え方で、LLM 専用の言葉ではありません。

オブザーバビリティとは?監視との違いと3つの信号

LLM のアプリで特に見たくなるのは、ふつうの Web アプリにはない次のような情報です。

  • どのモデルに、どんな操作(チャット・埋め込みなど)を頼んだか
  • 入力と出力にそれぞれ何トークン使ったか
  • モデルがなぜ生成を止めたか(最後まで書いたのか、上限で切れたのか)
  • エージェントがどのツールを、どの順で呼んだか

エージェントは 1 回の依頼の中で、モデルとツールのあいだを何度も行き来します。

最終的な答えだけを見ても、どこで遅くなり、どこで失敗したかは分かりません。

途中の往復を 1 つずつ記録しておくのが、LLM オブザーバビリティの出発点になります。

トレースとスパンで1回の依頼を分解する

OpenTelemetry は、ベンダーに依存せずにテレメトリを集めて送るための標準です。

OpenTelemetry のドキュメントでは、トレースはリクエストがアプリの中をたどる経路の全体像、スパンはその中の 1 つの作業単位と説明されています。

スパンには名前、開始と終了の時刻、親スパンの ID、属性などが入ります。

親子関係をたどると、1 回の依頼が木の形で見えるわけです。

参考: OpenTelemetry 公式ドキュメント「Traces」

Traces

Claude のドキュメントには、tool runner(SDK がツールを実行して結果をモデルに返す仕組み)を使ったリクエストのトレース例が載っています。

API 側で動くウェブ検索と、アプリ側の get_weather ツールを使う例です。

公式の図を、スパンの親子関係だけに簡略化して書き直すと次のようになります。

answer_question                         # アプリが始めたスパン
└─ anthropic.messages.tool_runner       # SDK のツール実行ループ
   ├─ anthropic.messages.create         # 1 回目のリクエスト
   │  ├─ anthropic.model_request        # モデルへの依頼
   │  ├─ anthropic.tool_use web_search  # API 側で実行されるツール
   │  └─ anthropic.model_request        # get_weather を使いたいと返す
   ├─ anthropic.custom_tool_use get_weather
   └─ anthropic.messages.create         # 2 回目(ツールの結果を渡す)
      └─ anthropic.model_request        # 最終回答
# 実際は各リクエストに SDK 側と API 側のスパンが 1 つずつある(ここでは 1 段にまとめた)

この形で残っていれば、遅かったのが 2 回目のリクエストなのか、get_weather の実行なのかを切り分けられます。

共通の名前を決めるGenAIセマンティック規約

スパンに付ける属性の名前がツールごとにばらばらだと、監視基盤の側で毎回読み替えが必要になります。

そこで OpenTelemetry は、生成 AI 向けのセマンティック規約(GenAI semantic conventions)として、属性の名前と値の付け方を定めています。

規約の文書は以前は OpenTelemetry のセマンティック規約のリポジトリにありましたが、いまは生成 AI 専用のリポジトリに移っています。

参考: OpenTelemetry の GenAI セマンティック規約のリポジトリ

GitHub - open-telemetry/semantic-conventions-genai

推論のスパンでよく使う属性は次のとおりです。

属性中身規約に載っている値の例
gen_ai.operation.name操作の種類chat、embeddings、execute_tool
gen_ai.provider.name提供元anthropic、openai、aws.bedrock
gen_ai.request.model依頼したモデルの名前gpt-4
gen_ai.usage.input_tokens入力のトークン数100
gen_ai.usage.output_tokens出力のトークン数180
gen_ai.response.finish_reasons生成を止めた理由stop、length

推論のスパン名は {gen_ai.operation.name} {gen_ai.request.model} の形、たとえば「chat gpt-4」にするよう定められています。

エージェント向けには、エージェントを呼び出す invoke_agent や、ツールを実行する execute_tool といった操作名も用意されています。

この規約の状態は、2026年10月16日に確かめた時点で Development(開発中)で、安定版にはなっていません。

属性の名前が変わることもあるので、計装を書くときはその時点の文書を確かめてから使うと安心です。

Claude の API と SDK もこの規約の属性を使っていて、規約に対応した監視基盤なら追加の設定なしでスパンを読み取れると説明されています。

プロンプトと応答を残すかどうか

LLM のトレースでいちばん悩むのが、プロンプトと応答の本文をスパンに入れるかどうかです。

本文があれば失敗の原因を会話ごと読めますが、利用者の個人情報や社外秘の資料まで監視基盤に流れることになります。

GenAI の規約は、指示・入力・出力を機微で大きなデータとして扱っています。

そのため計装ライブラリは既定では記録せず、利用者が選んだときだけ記録する(オプトイン)形にするよう求めています。

規約が挙げている選択肢は次の 3 つです。

  • 既定では、指示・入力・出力を記録しない
  • スパンの属性(gen_ai.input.messages など)に記録する
  • 本文は外部のストレージに置き、スパンには参照だけを残す

規約は、属性に記録する方法を、量が扱えて規制の心配がない場面(本番前の環境など)向けとしています。

一方で、外部のストレージに置く方法は、量が問題になる本番環境や、機微なデータを安全に扱う必要がある場面に勧めています。

Claude の OpenTelemetry エクスポートも同じ考え方で、送り先ごとに 2 つのモードから選びます。

モードスパンに入るもの
Metadata only(既定)ID、所要時間、状態、トークン数、エージェントやツールの名前など
Full content上の内容に加えて、モデルへのプロンプトと応答

Full content で 1 つのスパンに入る本文は、既定で 0.75 MB までです。

超えた分は削られ、anthropic.content.truncated が true になります。

HIPAA・FERPA・K-12 のデータ取り扱いの制限を Anthropic と結んでいる組織では、モードにかかわらず API 側のエクスポートはメタデータだけになります。

Claude Code の OpenTelemetry 出力でも、スパンの中のプロンプトやツールの入出力は既定で伏せられています。

OTEL_LOG_USER_PROMPTS などの環境変数を、項目ごとに有効にしたときだけ記録される作りです。

本文を残すと、その中身は監視基盤の閲覧権限と保存期間の設定で管理されることになります。

Full content に切り替える前に、監視基盤の閲覧権限と保存期間が社内のルールに合っているかを確かめてください。

トークンを二重に数える落とし穴

トレースからトークンの使用量を集計するときは、同じトークンを二重に数えないように気をつけます。

Claude のドキュメントによると、SDK と API の両方でトレースすると、1 つのリクエストに anthropic.messages.create という同じ名前のスパンが 2 つできます。

SDK 側はスパンの種類が CLIENT、その子の API 側は SERVER です。

種類で見分けて、片方だけを合計します。

API 側のスパンでも、anthropic.messages.create とその下の anthropic.model_request の両方に使用量が載るため、どちらか一方だけを足します。

もう 1 つの注意点は、gen_ai.usage.input_tokens がすでにプロンプトキャッシュの読み書きの分を含んでいることです。

GenAI の規約も、入力のトークン数にはキャッシュされたトークンを含めるよう定めています。

キャッシュの属性を入力のトークン数に足し直すと、入力を多く見積もってしまいます。

プロンプトキャッシュとは?API料金を下げる仕組みを整理

さらに、スパンの配送はベストエフォートで、届かないスパンもあると明記されています。

エクスポートされたスパンは、利用量の完全な記録ではありません。

API キーごとの利用量を漏れなく追いたいときは、Usage API を使うよう案内されています。

どこから始めるか

Claude の API には、SDK でトレースする方法と、API 側からトレースを送る方法の 2 つがあります。

方法設定する場所必要な権限見えるもの
SDK のトレースアプリのコード不要SDK からのリクエスト、tool runner が動かすツール
API のトレースClaude Console で送り先を追加adminどのクライアントのリクエストも、各モデル呼び出し、サーバーツール、Managed Agents のターン

両方を設定すると、SDK と API のスパンが 1 つのトレースにつながります。

送り先は OTLP を受け付ける監視基盤ならどれでもよく、ドキュメントには Datadog、Grafana Cloud、Honeycomb、Langfuse、Sentry などが連携先として並んでいます。

参考: Claude 公式ドキュメント「OpenTelemetry for the Claude API」

OpenTelemetry for the Claude API

Claude Code を使っているなら、環境変数だけでメトリクスとイベントを OpenTelemetry で送れます。

トレースはベータで既定ではオフなので、CLAUDE_CODE_ENHANCED_TELEMETRY_BETA も合わせて有効にします。

次は公式ドキュメントのクイックスタートとトレースの節をもとにした書式の例で、手元では実行していません。

# テレメトリを有効にする(必須)
export CLAUDE_CODE_ENABLE_TELEMETRY=1
# トレース(ベータ)を有効にする
export CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1
export OTEL_TRACES_EXPORTER=otlp
# 送り先(値はクイックスタートの例)
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
claude

Claude Code のトレースでは、プロンプトごとに claude_code.interaction というルートのスパンができます。

その下に、API の呼び出し(claude_code.llm_request)やツールの実行(claude_code.tool)が子のスパンとして並びます。

参考: Claude Code 公式ドキュメント「Monitoring」

Monitoring - Claude Code Docs

最後に

LLM オブザーバビリティは、新しい道具の名前というより、OpenTelemetry のトレースを AI の呼び出しに当てはめた考え方です。

共通の属性名で記録し、本文を残すかどうかを意識して選ぶことが、どの監視基盤を使う場合でも土台になります。

まずはメタデータだけのトレースで、どのステップに時間とトークンが掛かっているかを眺めるところから始められます。

以上です。

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

CAPTCHA