agent-observability-trace-rca について
agent-observability-trace-rcaは、Datadog LLM tracesを調べ、本番LLMアプリの障害を診断するエージェントスキルです。評価結果、実行時エラー、構造上の異常に応じて分析経路を選び、MCPツールまたはpupコマンドラインを利用します。
主な機能
- 01利用可能なシグナルから分析モードを選択
- 02トレースとスパンの検索・調査
- 03スパン階層をたどったエラー追跡
- 04評価スコアと推論内容の確認
- 05エージェント実行タイムラインの調査
- 06MCPツールまたはpupコマンドラインの利用
活用シーン
- 01LLM評価失敗の原因特定
- 02本番トレース内の実行時エラーの調査
- 03レイテンシやエージェントループの異常分析
- 04評価器や期間ごとの障害比較
MCP 対応
Datadog LLM Observability MCPツールが利用可能な場合はそれを使い、そうでない場合は同等のpupコマンドライン呼び出しにワークフローを置き換えます。スパンを検索し、評価、トレース、コンテンツの詳細を取得します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ datadog-labs/ agent-skills --skill agent-observability-trace-rcaインストール後、Claude Code で/agent-observability-trace-rcaを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/__init__.pyevaluator.pyexample_config.jsonexecutor.pyevals/data/llm_obs_trace_rca_v1.jsonevals/prompts/judge_rubric.txt詳細
バックエンド
検出 — 各呼び出しの開始時に、何かを実行する前に、使用するバックエンドを決定します。
- ユーザーが呼び出しのどこかに
--backend pupを指定した場合 → ほかの MCP ツールの有無にかかわらず、ただちに pup モードを使用します。手順 2~4 はスキップします。 - 有効なツールリストに MCP ツールがあるか確認します。判定の基準は、使用可能なツールに
mcp__datadog-llmo-mcp__list_llmobs_evalsが含まれているかどうかです。 - MCP ツールがある場合 → 一貫して MCP モードを使用します。このスキルのワークフローのセクションに記載されたとおりに MCP ツールを呼び出します。
- MCP ツールがない場合 → Bash で
pup --versionを実行し、pupが実行可能か確認します。"version"を含む JSON レスポンスが返れば、pup が利用可能です。 - pup が応答した場合 → 一貫して pup モードを使用します。このファイルの末尾にあるツールリファレンスの付録に従って、すべての MCP ツール呼び出しを対応する pup の呼び出しに置き換えます。
- どちらも利用できない場合 → 処理を停止し、次の内容をユーザーに伝えます。
"Datadog MCP サーバーも pup CLI も利用できません。MCP サーバー(
claude mcp add --scope user --transport http datadog-llmo-mcp 'https://mcp.datadoghq.com/v1/mcp?toolsets=llmobs')を接続するか、pup をインストールしてください。"
--backend pup は呼び出し引数のどこに指定しても受け付けられ、残りの引数をスキルのロジックに渡す前に取り除きます。
pup の呼び出しルール:
- Bash で呼び出します:
pup llm-obs <subcommand> [flags] - pup は常に JSON を出力します。MCP の結果のように JSON を
[{"type": "text", "text": "<json>"}]から取り出す必要はありません。直接解析してください。 - pup が認証エラーを返した場合は、
pup auth loginを実行するようユーザーに伝え、処理を停止します。 - 並列化:1 回のメッセージで複数の Bash ツール呼び出しを発行します(呼び出しごとに pup コマンドを 1 つ指定)。
- 時間指定フラグ:pup は期間を表す文字列(
1h、7d、30m)および RFC3339 タイムスタンプを受け付けます。now-を先頭に付けた文字列は使用しないでください。スキルの--timeframe引数を変換する際は、接頭辞を取り除きます:now-7d→7d、now-24h→24h、now-30d→30d。 pup llm-obs spans searchの--summaryは、ペイロードのフィールドを重要なメタデータのみに絞ります。コンテンツが不要な一括処理や検索の段階で使用してください。
呼び出し ID: 各呼び出しの開始時、MCP ツールを呼び出す前に、8 文字の 16 進数の呼び出し ID(例:3a9f1c2b)を生成します。呼び出し全体を通して同じ ID を使用してください。
インテントタグ付け: MCP ツールを呼び出すたびに、telemetry.intent の先頭に skill:agent-observability-trace-rca[<inv_id>] — を付け、その後に呼び出しの理由を記述します。最初の MCP ツール呼び出しのみ、代わりに skill:agent-observability-trace-rca:start[<inv_id>] — を使用します(:start サフィックスに注意してください)。最初の呼び出しの例:skill:agent-observability-trace-rca:start[3a9f1c2b] — task-cruncher に設定されている評価を検出し、分析モードを推定するフェーズ 0
エージェントのオブザーバビリティトレース RCA — 本番環境の LLM トレースから根本原因を分析
本番環境のトレースを検索し、症状から根本原因までスパンツリーをたどって、LLM アプリケーションが失敗する理由を診断します。このスキルは、利用可能なシグナルに基づいて最適な分析モードを自動的に選択します。
| モード | シグナル | 自動選択される条件 |
|---|---|---|
| 評価シグナル | LLM ジャッジの判定と推論(合格率/不合格率、スコアリング) | アプリに評価器が設定されている場合 |
| エラーシグナル | 実行時エラー(@status:error、エラー種別、スタックトレース) | 評価器が設定されていない場合、またはユーザーがエラー/クラッシュについて明示的に尋ねた場合 |
| 汎用 | 構造上の異常(レイテンシ、エージェントのループ、検索のミス) | mode=generic による明示的な上書き、またはフェーズ 1 で強いシグナルが見つからない場合 |
モードは最初のユーザー向け出力で (質問せずに)通知され、1 行の上書きヒントが示されます。
方法
解決 → 検索 → 観察 → オープンコーディング → 軸足コーディング → 根本原因の追跡 → 推奨事項
使い方
What's wrong with <ml_app> over the last <timeframe>
Why is <ml_app> failing today
Analyze eval failures for <eval_name> on <ml_app>
Look at the errors on <ml_app> over the last <timeframe>
Root-cause low scores on <eval_name>
入力
| 入力 | 必須 | デフォルト | 説明 |
|---|---|---|---|
ml_app | はい(または eval_name) | — | 分析するアプリケーションです。 |
eval_name | いいえ | — | 対象とする評価器を1つ以上指定します。Eval Signal モードが有効になります。複数の評価を分析する場合は、リストを渡します。 |
timeframe | いいえ | now-24h | どのくらい前までさかのぼって調べるかを指定します。 |
mode | いいえ | 推定 | 明示的なモード指定です:eval、errors、generic。推定を完全にスキップします。 |
failure_filter | いいえ | — | 範囲を絞り込みます:"errors"(Error Signal パスにルーティング)、"high latency"(取得後に所要時間で並べ替え)、"low scores on <eval>"(eval_name に昇格)、ツール名またはスパン名(@name:<x> クエリ)。 |
ml_app と eval_name のどちらも指定されていない場合は、ユーザーに確認してください。
利用可能なツール
評価の検出と概要
| ツール | 目的 |
|---|---|
list_llmobs_evals | ml_app に設定されているすべての評価を検出します。Phase 0 のモード推定で使用します。 |
get_llmobs_eval_aggregate_stats | 指定した期間における評価の合格率/不合格率またはスコア分布を取得します。 |
get_llmobs_evaluator | 評価器の完全な設定を取得します:プロンプトテンプレート、評価基準、スパンフィルター、サンプリング、プロバイダー。非推奨の get_llmobs_eval_config の代わりに使用してください。 |
トレースとスパンの探索
| ツール | 目的 |
|---|---|
search_llmobs_spans | タグ、スパン種別、ステータス、クエリ構文でスパンを検索します。カーソルでページネーションします。Phase 1 の開始点です。 |
get_llmobs_span_details | メタデータ、評価(スコア、ラベル、推論)、status、エラーフィールド、所要時間、および利用可能なフィールドとサイズを示す content_info マップを取得します。 |
get_llmobs_span_content | スパンフィールドの実際の内容を取得します。path パラメーターで JSONPath による対象の抽出をサポートします。 |
get_llmobs_trace | スパン種別ごとのスパン数を含む、スパンツリーとしてトレース階層全体を取得します。 |
find_llmobs_error_spans | エラー種別、メッセージ、スタック、伝播コンテキストを含む、トレース内のすべてのエラースパンを取得します。 |
expand_llmobs_spans | 折りたたまれたトレースノードの子を読み込みます。 |
get_llmobs_agent_loop | エージェント実行の時系列(LLM 呼び出し、ツール呼び出し、判断)を取得します。空を返す場合があります。Phase 4b のフォールバックを参照してください。 |
get_llmobs_span_content の主なパターン
| フィールド | パス | 取得できる内容 |
|---|---|---|
messages | $.messages[0] | システムプロンプト(最初のメッセージ。通常は system ロール) |
messages | $.messages[-1] | 最後のアシスタントの応答 |
messages | (パスなし) | ツール呼び出しを含む会話全体 |
input / output | — | スパンの入出力 |
documents | — | 取得されたドキュメント(RAG アプリ) |
metadata | — | カスタムメタデータ(プロンプトのバージョン、機能フラグ、ユーザーセグメント) |
search_llmobs_spans の使用方法
query 文字列には必ず @ml_app:"<ml_app>" を含めてください。構造化された ml_app パラメーターは信頼できず、他のアプリのスパンを返すことがあります。 構造化パラメーターだけに頼らないでください。
便利なクエリフラグメント — スペースで結合します(AND):
| 目的 | クエリ |
|---|---|
| エラーのみ | @status:error |
| スパンに評価が存在する | @evaluations.custom.<eval_name>:*(存在のみ。合否はクエリではなく get_llmobs_span_details から読み取ります) |
| 名前で特定のツールを指定 | @name:<tool_name> |
専用パラメーター(span_kind、root_spans_only、ml_app)は query と併用できますが、query は tags より優先されます。
並列化のルール
get_llmobs_span_details:trace_idごとにspan_idsをグループ化し、各トレースのspan_idsを最大20件のバッチに分割します。1ページ分のすべてのバッチを単一のメッセージで送信してください。get_llmobs_span_content:各呼び出しは独立しています。必ずすべてを単一のメッセージで送信してください。get_llmobs_trace/find_llmobs_error_spans/get_llmobs_agent_loop:異なるトレースに対する呼び出しは、単一のメッセージで並列化してください。- パイプラインの並列処理:1ページ目の結果について、すぐに
get_llmobs_span_detailsを開始してください。すべてのページの収集を待たないでください。
分析ワークフロー
出力の規律:フェーズ 0~5 は内部分析です。これらのフェーズでユーザーに表示する出力は、フェーズ 1 のシグナル概要と、フェーズ 2 および 3 の必須チェックポイントのみです。推論を説明したり、中間的な調査結果を要約したり、フェーズ 4 の詳細調査結果を文章として出力したりしないでください。詳細な調査結果はすべて、フェーズ 6 のレポートにのみ記載してください。
フェーズ 0:入力を解決してモードを推定する
最初に、分類コンテキストを確認します。 会話内に # Session Classification Summary ヘッダーがあるか確認してください。見つかった場合は、以下のステップ 0Sに進み、それ以外のフェーズ 0 のステップとフェーズ 1 をすべてスキップします。
ステップ 0S — 分類出力から失敗バケットを抽出する
標準的な引き継ぎ形式は、# Session Classification Summary セクション内のユニットごとの詳細テーブルです。ユニットごとに 1 行を抽出します。
| フィールド | ソース |
|---|---|
trace_id | ID 列のリンク URL:リンクの href から trace_id= または session_id= クエリパラメーターを解析します |
verdict | Verdict 列 |
failure_mode | Failure Mode 列(合格した行では none) |
detail | Reason 列 — フェーズ 2 の推論入力として使用します(評価ジャッジの推論やエラーメッセージと同じ役割) |
app_type | # Session Classification Summary のヘッダー行から取得します(例:Root span kind: agent)。存在しない場合は LLM を使用します |
失敗バケット = verdict が no または partial のすべての行です。
- 5 件未満の場合 → 信頼度が低いことを記録し、そのまま続行します。
- 空の場合 → 「分類出力に失敗は見つかりませんでした」と報告して終了します。
続行する前に、この概要を提示します。
## Classification Overview (from agent-observability-session-classify)
**ml_app**: <from summary header> | **Classified**: N | **Failures (no+partial)**: F | **Pass rate**: X%
| Failure Mode | Count |
|---|---|
...
Proceeding to Phase 2 using F failure traces. Mode inference bypassed — classification verdict is the signal.
その後、フェーズ 1 をスキップし、フェーズ 2 に直接進みます。以下を引き継ぎます。
- フェーズ 2 の推論入力:
(trace_id, span_id, detail)のタプル — 評価の推論やエラーメッセージと同じ構造です - フェーズ 4 のナビゲーション:各トレースブロックの
app_typeを使って、スパンのナビゲーション戦略を選びます - フェーズ 2~7:完全に変更せず実行します — 失敗バケットの構造は、情報源にかかわらず同一です
標準的な解決(分類コンテキストがない場合):
ml_appもeval_nameも指定されていない場合 → ユーザーに尋ねます。eval_nameが指定されていてml_appが指定されていない場合も →ml_appを尋ねます(eval 名はグローバルに一意ではありません。これがないと、スパン検索で同じ eval 名を共有するすべてのアプリから結果が返されます)。timeframeが指定されていない場合 →now-24hをデフォルトとして使用します。failure_filterを解決します(モード推定の前に行います)。"errors"→ エラーシグナルモードを強制します"low scores on <eval>"→eval_name=<eval>として扱い、その後推定を続けます"high latency"→ フェーズ 1 用に記録します(取得後、duration でソート)。推定を続けます- ツール名/スパン名 → フェーズ 1 用のクエリフラグメント
@name:<x>として記録します。推定を続けます
- モードを解決します(
modeが明示的に指定されている場合はスキップします)。eval_nameが指定されている → 評価シグナル- ユーザーがエラー/例外/クラッシュに明示的に言及している → エラーシグナル
- それ以外 →
list_llmobs_evals_by_ml_app(ml_app)を呼び出します。- eval が返された場合 → 評価シグナル
- eval が返されなかった場合 → エラーシグナル(フェーズ 1 で自動選択したことを伝えます)
eval_nameに複数の値がある場合は、フェーズ 1 用に記録します。eval ごとに並列検索を実行し、(trace_id, span_id)を基準に統合して重複を除去します。
フェーズ 1:問題のあるスパンを見つける
モードごとに 3 つの経路があります。どの経路も、モードを示し、1 行の上書きヒントを含むシグナル概要で終了します。
モード切り替えの処理:どのチェックポイントでも、ユーザーが「[error|eval|generic] モードに切り替えて」と言った場合は、新しいモードでフェーズ 1 を再開します。フェーズ 0 の入力は再解決しません。
自動切り替え:選択したモードでデータが見つからない場合(設定済み eval が 0 件、または対象期間のエラースパンが 0 件)は、ジェネリックモードへの切り替えを伝えて続行します。停止して尋ねる必要はありません。
評価シグナルの経路
Step 1a: 評価の概要(並列)
各評価について、以下の両方を1つの並列バッチで呼び出します。
get_llmobs_eval_aggregate_stats(eval_name, from, to)get_llmobs_evaluator(eval_name)
集計統計の解釈:
total_count == 0→ 「データなし」と記録します。この評価はスキップします(これが唯一の評価である場合は、Generic に切り替えます)。- Boolean の
pass_rate == 1.0→ 「合格率100%」と記録します。これが唯一の評価でない限り、スキップします。 - 失敗のある Boolean → 件数と
pass_rateを記録します。続行します。 - 評価基準のある Score → 分布と合否件数を記録します。続行します。
- 評価基準のない Score → 失敗を推定します。下位四分位、または二峰性の場合は中央値未満を対象にします。レポートでは「推定失敗」と表記します。
- 評価基準のある Categorical →
top_valuesと合否を記録します。続行します。 - 評価基準のない Categorical → 文脈から推定します(例:「error」、「incomplete」、「off_topic」は失敗の可能性が高いです)。本当に判断が曖昧な場合は、ユーザーに確認します。
評価設定の解釈:
- 設定が返された場合(カスタム)→
prompt_template、assessment_criteria、parsing_type、output_schemaを保存します。 - 設定が nil の場合(OOTB)→ プロンプトは確認できないと記録します。
キャリブレーションの相互確認:2つの評価で名前のプレフィックスが同じでも型が異なる場合(例:foo-boolean と foo-score)、重複する期間の合格率を比較します。差が20%を超える場合は、Evaluator Calibration Discrepancy としてレポートに記載します。
Step 1b: 失敗スパンの収集
各評価について:
search_llmobs_spans(query="@evaluations.custom.<eval_name>:*", from, limit=50)。複数の評価がある場合は、評価ごとに検索を並列実行し、結果セットを統合して(trace_id, span_id)で重複を除去します。- 失敗が15~20件以上になるか、次のページがなくなるまでページネーションします。合計200スパンを上限とします。
get_llmobs_span_detailsをtrace_idのバッチごとに呼び出します(並列化ルールに従います)。- 各行から assessment、value、reasoning、span_id、trace_id、span_kind、content_info を抽出します。
- Step 1a のしきい値を使って、合格と失敗のバケットに分けます。
JSON 型評価のフォールバック:@evaluations.custom.<eval_name>:* の検索結果が0スパンでも、get_llmobs_eval_aggregate_stats で total_count > 0 が確認できた場合、その評価は JSON 型であり、スコアはこのフィールドにインデックス化されていません。次の方法に切り替えます。評価対象のスパン名またはスパン種別で検索し(スパンフィルターは get_llmobs_evaluator で確認します)、get_llmobs_span_content(field="output") で出力ペイロード内の JSON 判定フィールドを調べます。
Step 1c: シグナルの概要(評価シグナル)
## Signal Summary: `{ml_app}` · Eval Signal
(Inferred from {N} configured eval(s). Say `switch to error mode` or `switch to generic mode` to change.)
**Timeframe**: {from} → {to}
| Eval | Type | Total | Pass Rate | Status |
|------|------|------:|:---------:|--------|
| eval_1 | boolean | 4,891 | 37.3% | ⚠ Investigating |
| eval_2 | score | 1,200 | — (inferred threshold) | ⚠ Investigating |
| eval_3 | boolean | 500 | 99.2% | ✓ Healthy |
**Collected**: {pass_count} passing, {fail_count} failing.
評価が1つだけの場合は、表ではなく1行のヘッダーにまとめます。
エラーシグナルの経路
Step 1a: エラースパンのサンプル取得
search_llmobs_spans(query="@ml_app:\"<ml_app>\" @status:error", from=timeframe, limit=50)。エラースパンが30件以上になるか、次のページがなくなるまでページネーションします。
Step 1a.5: ソフトエラーのスキャン
MCP ツールスパンは @status:ok を報告しながら、出力ペイロードに "isError": true を含むことがあります。これらは @status:error クエリでは検出されず、ハードエラーを上回る場合があります。
search_llmobs_spans(query="@ml_app:\"<ml_app>\" @status:ok", span_kind="tool", from=timeframe, limit=20) を呼び出します。結果から5~10件をサンプルとして選び、get_llmobs_span_content(field="output") を並列で呼び出します。いずれかのペイロードに "isError": true が含まれている場合は、エラー頻度の表に MCP ソフトエラー を別の行として追加し、次の注記を付けます:(status:ok だがペイロード内は isError:true — @status:error ではクエリ不可)。
Step 1b: エラー種別ごとにグループ化
スパンを error_type タグでグループ化し、頻度の表を作成します。一部のスパンに error_type タグがない場合は、Step 1d で取得した get_llmobs_span_details の error.type フィールドで補完します。
Step 1c: スタックトレースの取得(並列)
件数が上位3~4件のエラー種別について、それぞれ代表的なトレース ID を2~3件選びます。選択したすべてのトレースに対して find_llmobs_error_spans(trace_id) を並列で呼び出します。次の項目を抽出します。
- エラーメッセージとスタックトレース
- 起点となるスパンの種別と名前
- エラーが子から親へ伝播するか(カスケード)、または個別に発生しているか
ステップ 1d:スパンの詳細を取得
各エラータイプの代表的なスパンについて、get_llmobs_span_details を呼び出します(並列化ルールに従ってください)。content_info、span_kind、duration を抽出します。
ステップ 1e:シグナルの概要(エラーシグナル)
## Signal Summary: `{ml_app}` · Error Signal
(No evals configured — analyzing runtime errors. Say `switch to eval mode` or `switch to generic mode` to change.)
**Timeframe**: {from} → {to} | **Total error spans sampled**: {N}
| Error Type | Spans | Cascade? | Origin Span Kind |
|------------|------:|:--------:|-----------------|
| TimeoutError | 42 | Yes | tool |
| APIError 429 | 18 | No | tool |
| ValueError | 7 | No | llm |
| MCP soft errors (isError:true) | 23 | No | tool |
汎用パス
ステップ 1a:評価のヘルスチェック(評価が設定されている場合)
Phase 0 で list_llmobs_evals が評価を返した場合、有効な各評価に対して get_llmobs_eval_aggregate_stats を並列で呼び出します。total_count: 0 の有効な評価は 評価設定の不備 としてフラグ付けし、シグナルの概要の異常テーブルに重大度「高」の行として含めます。
ステップ 1b:広範なスパン検索
search_llmobs_spans(query="@ml_app:\"<ml_app>\"", root_spans_only=true, from=timeframe, limit=50)。failure_filter が指定されている場合は絞り込みを適用します(ツール/スパン名 → @name:<x> クエリ、"high latency" → ステップ 1c の後に結果セットを duration で並べ替えます)。30 件以上のスパンが得られるまでページネーションします。
ステップ 1c:スパンの詳細を取得
トレース ID ごとにまとめて get_llmobs_span_details を呼び出します。
ステップ 1d:構造上の異常で順位付け
ヒューリスティックを使ってスパンを分類します。
durationの上位 10 パーセンタイル(レイテンシの外れ値)- ツール/LLM の反復回数が N 回を超えるエージェントスパン(長時間実行されるループ)
- 0 件のドキュメントを返す検索スパン(RAG の検索漏れ)
- 想定されるステップが子スパンのセットに欠けているワークフロースパン(子スパンの構成の中央値と比較)
- トークン効率:LLM スパン全体で
non_cached_input_tokens ≈ input_tokensかどうかを確認します。アプリに安定したシステムプロンプト(1k トークン超)があり、キャッシュヒット率が 0%の場合は、重大度「高」としてフラグ付けします。システムプロンプトでcache_control: ephemeralを有効にすると、入力トークンのコストを 60~90%削減できます。
ステップ 1e:シグナルの概要(汎用)
## Signal Summary: `{ml_app}` · Generic
(Analyzing structural anomalies. Say `switch to eval mode` or `switch to error mode` to change.)
**Timeframe**: {from} → {to} | **Sampled**: {N} root spans
| Anomaly Type | Count |
|---|:---:|
| Latency outliers (>p90) | 12 |
| Long agent loops (>8 iterations) | 5 |
| RAG retrieval misses | 3 |
| Zero prompt cache utilization | All LLM spans |
| Broken eval configurations | 2 |
フェーズ 1.5:アプリのプロファイルと根本原因の所在を特定する
収集したスパン全体で content_info と span_kind を確認します。これにより、フェーズ 4 の戦略を決めます。
アプリのプロファイル(content_info に基づく):
| シグナル | アプリのプロファイル | フェーズ 4 の戦略 |
|---|---|---|
content_info に messages がある | LLM/チャットアプリ | messages[0] からシステムプロンプトを抽出し、会話の流れを確認します |
content_info に documents がある | RAG アプリ | LLM の出力と併せて、検索品質を確認します |
トレースに agent の span kind が含まれる | エージェントアプリ | まず get_llmobs_agent_loop を試します。空の結果が返された場合は、子スパンを再構成します(フェーズ 4b を参照) |
messages.count > 10 | 長い会話 | コンテキストのあふれがないか確認します |
content_info に metadata がある | カスタムメタデータあり | メタデータ値(プロンプトのバージョン、機能フラグなど)によるクラスタリングを確認します |
LLM Experiments のトレース:ルートスパンに
span_kind: experimentがあり、構造化フィールドinput、output、expected_outputを含む場合は、Datadog LLM Experiments のトレースです。各スパンは、実行されたデータセットレコード 1 件を表します。品質シグナルは、LLM のサブスパンのメッセージではなく、get_llmobs_span_contentを使ってルートスパンのinput/output/expected_outputフィールドから読み取ります。サブスパンのメッセージには、スタブやプレースホルダーの内容が含まれることがあります。実験スパンに関連付けられた評価は、実行時に Experiments フレームワークによって計算されるため、Datadog のオンライン評価器として登録されていない場合があります(get_llmobs_evaluatorは 404 を返します)。
根本原因が存在する可能性が高い場所 — 症状を示すスパンの種類別:
| 症状を示す span kind | 症状の例 | ただし、根本原因は多くの場合…… |
|---|---|---|
llm | LLM の応答が不適切(評価でフラグが立つ、出力が誤っている) | 親エージェント(指示が不適切)、兄弟の検索(コンテキストが不適切)、兄弟のツール(データが不適切) |
agent | オーケストレーションが不適切 | 子スパン(誤ったツール呼び出し、誤ったルーティング)、エージェントループ全体 |
tool | ツールの結果が不適切 | 親LLM(誤ったパラメーターを渡した)、ツールの実装 |
workflow | 全体の出力が不適切 | 子サブスパン(最初に逸脱したステップはどれか) |
retrieval | 検索結果が不適切 | クエリの構築(親)、インデックス/埋め込み設定(トレースの外) |
重要な洞察:評価結果、エラーメッセージ、レイテンシの外れ値といったシグナルは、単独のスパンにフラグを立てます。これは症状の報告であり、診断ではありません。根本原因は多くの場合、別のスパンにあります。不適切な指示を出した親、不適切なコンテキストを提供した兄弟、誤った判断をした子などです。フェーズ 4 ではツリーをたどって根本原因を見つけます。
フェーズ 2:オープンコーディング — 初期の失敗カテゴリ分け
目的:行ごとのエビデンスを読み、具体的な失敗カテゴリの初期案を作成します。問題のある行をすべてまとめ、シグナルが何を検出したかではなく、アプリの動作をカテゴリで表します。
モードごとの行単位の「推論入力」:
- Eval Signal:
get_llmobs_span_detailsによる評価と推論 - Error Signal:
find_llmobs_error_spansによるエラーメッセージとスタックトレースの抜粋 - Generic:その行が検出された構造上の異常を示す1行の説明
ショートカット:
- 問題のある行が15件未満:フェーズ 2 と 3 をまとめて1回で実施します。チェックポイントは引き続き出力します。
- 80%を超える行が同じ推論/エラー/症状を共有:支配的なパターンを使ってフェーズ 4 に進みます。チェックポイントは引き続き出力します。
- 問題のある行が50件を超える:約50件をサンプリングして分類体系を作成し、その後、さらに10~15件をスポットチェックします。
-
フェーズ 1 の行単位のシグナルを使用します — 再取得しないでください。推論が不十分な場合(一般的、空、またはアプリのコンテキストがないスタックトレースのみの場合)に限り、該当するスパンに対して
get_llmobs_span_content(field="input"/"output")を呼び出します。 -
eval 設定が読み込まれている場合(Eval Signal)は、早い段階で次のように区別します。
- アプリの失敗:出力が eval の基準に実際に違反している
- eval の失敗:出力は妥当に見えるが、eval の基準が厳しすぎる、または曖昧である
-
各パターンは具体的にします:「エージェントが価格計算に計算機ではなく検索を呼び出した」 — 「ツールの問題」ではありません。
必須チェックポイント
**Open coding**: {N} problematic rows → {K} initial categories: {Category1} ({count}), {Category2} ({count}), ...
フェーズ 3:軸コーディング — 失敗の分類体系を精緻化
目的:影響度順に並べた3~8個の最終カテゴリを作成します。
- 統合:発生回数が3回未満のカテゴリは、親カテゴリにまとめるか、ノイズとして除外します。
- 分割:失敗の30%を超えるカテゴリは、より具体的なサブカテゴリに分割します。必要に応じて追加のスパンコンテンツを取得します。
- 検証:カテゴリごとに代表例を2~3件確認し、ラベルが適切かを確かめます。
- 順位付け:
priority = count × severity(severity:high / medium / low)。
必須チェックポイント
**Axial coding**: {merges/splits/drops}. Final categories:
1. {Category} ({count}, {pct}%) — {severity}
2. ...
フェーズ 4:根本原因分析 — 症状から根本原因をたどる
目的:シグナルはスパンを検出しています。それが症状です。トレースツリーをたどり、実際の根本原因を特定します。根本原因は、多くの場合、別のスパンにあります。
上位3カテゴリそれぞれについて、代表的なトレースを2~3件選びます。
ステップ 4a:トレース構造とエラー(並行して実施)
代表的なトレースごとに、1回のメッセージで次を呼び出します。
get_llmobs_trace(trace_id)— スパン階層を確認し、症状が現れたスパンと、その親/兄弟/子スパンを特定しますfind_llmobs_error_spans(trace_id)— トレース内のあらゆる場所にランタイムエラーがないか確認します
ランタイムと動作の区別:症状が現れたスパン上またはその近くにエラーがある場合、根本原因は動作上の問題ではなく、ランタイムの失敗である可能性があります。まずこれを確認します。
分散トレースのフォールバック:get_llmobs_trace が「cannot find parent」を返すか、空のスパンリストを返す場合(Ray ベースまたはマルチプロセス実行でよく発生します)は、フェーズ 1 で収集した span_id に対して get_llmobs_span_details を使用し、start_ms 順に並べて手動でトレースを再構成します。
Step 4b: 根本原因を特定する(並列)
症状が発生したスパンの種類(Phase 1.5 の情報)を使用します。すべての呼び出しを1つのメッセージ内で実行します。
症状が llm スパンにある場合(最も一般的):
- 症状スパンに対して
get_llmobs_span_content(field="messages", path="$.messages[0]")— システムプロンプト - 症状スパンに対して
get_llmobs_span_content(field="messages")— 受け取った完全なコンテキスト - 兄弟の検索スパン(存在する場合)に対して
get_llmobs_span_content(field="documents") - 兄弟のツールスパン(存在する場合)に対して
get_llmobs_span_content(field="input") - 親のエージェント/ワークフロースパンに対して
get_llmobs_span_content(field="messages", path="$.messages[0]")
症状が agent スパンにある場合:
get_llmobs_agent_loop(trace_id, span_id)— 意思決定のタイムライン全体 (最初に試してください。反復回数が0の場合は、以下のフォールバックを使用します)- 子スパンに対する
get_llmobs_span_details—start_msで並べ替えて、実行タイムラインを再構成します - 問題がありそうな子スパンに対して
get_llmobs_span_content(field="input"/"output")
エージェントループのフォールバック(get_llmobs_agent_loop が反復回数0を返す場合):get_llmobs_span_details の結果を start_ms で並べ替えて、タイムラインを再構成します。span_kind でグループ化して、LLM → ツール → LLM の順序を特定します。このフォールバックが必要になることはよくあります。多くのアプリでは get_llmobs_agent_loop が空を返します。
症状が tool スパンにある場合:
- 症状スパンに対して
get_llmobs_span_content(field="input")— どのパラメーターで呼び出されたかを確認します - 親の LLM スパンに対して
get_llmobs_span_content(field="messages")— LLM は呼び出しを正しく構成したかを確認します
症状が workflow スパンにある場合:
- すべての子スパンに対する
get_llmobs_span_details— 最初に逸脱したステップを特定します - 逸脱した子スパンに対して
get_llmobs_span_content(field="input"/"output")
次の情報も必ず取得します:
- 症状スパンに対して
get_llmobs_span_content(field="metadata")— クラスタリングのシグナル(プロンプトのバージョン、機能フラグ)
Step 4c: 診断する — 症状から根本原因へ
各カテゴリについて、因果関係をたどります。
- 症状 — シグナルが検出した内容(評価の推論、エラーメッセージ、異常に関する注記)。シグナルが確認したのは単独の1つのスパンのみであり、その推論は浅い可能性があります。
- トレースコンテキスト — 周辺のスパンから分かる内容(親の指示、兄弟のデータ、子の判断)。
- 根本原因 — 問題が発生した具体的なスパンと意思決定の時点。多くの場合、症状スパン自体ではありません。
評価の問題が疑われる場合(Eval Signal、設定が読み込まれている場合):評価基準と証拠を比較します。プロンプトが曖昧ではありませんか? 基準が厳しすぎませんか?
根本原因のカテゴリ:
| カテゴリ | 説明 |
|---|---|
| システムプロンプトの不備 | 症状スパンまたはその親スパンにある指示が不明確、不足、または矛盾している |
| ツールの不足 | 必要なツールが存在しない、またはパラメーターの粒度が粗すぎる |
| ツールの誤用 | 誤ったツールまたは誤ったパラメーターが使用された — 多くの場合、エージェントループまたは親の LLM から確認できます |
| ルーティング/引き継ぎエラー | 誤ったサブエージェントが選択された(マルチエージェントシステム) |
| 検索の失敗 | RAG が無関係なコンテキスト、またはコンテキストなしを返した — 兄弟の検索スパンを確認します |
| コンテキストのあふれ | コンテキスト長が原因で重要な情報が失われた |
| 上流データの問題 | 兄弟または親のスパンが不適切なデータを提供し、それが症状スパンに波及した |
| 実行時エラー | ツール/API の失敗、タイムアウト、例外 — find_llmobs_error_spans から確認できます |
| 評価器の較正不良 | 評価基準が誤検知/見逃しを引き起こす(Eval Signal モードのみ) |
フェーズ 5:推奨事項の生成
目標:トレースの証拠に基づいた、具体的で実行可能な推奨事項を提示します。一般的なアドバイスではなく、トレースから引用した変更前・変更後の引用を含む、実際のテキスト/コードの変更を提示します。
推奨事項の種類:システムプロンプトの編集(実際のプロンプトを引用し、変更前・変更後を提示)、ツールの不足/誤用(エージェントのループのステップを参照)、ルーティング/引き継ぎの修正、検索の修正(取得した内容と必要な内容を提示)、評価プロンプトの編集(評価の変更には再検証が必要であることを明記。評価シグナルのみ)、その他。
コードベースにアクセスできる状態で Claude Code を実行する場合:コードベース内でシステムプロンプト、ツール定義、ルーティングロジックを検索します。具体的な差分を提案します。ファイルを変更する前に、必ず確認を求めてください。
フェーズ 6:RCA レポートの作成
以下の出力形式に従って、レポート全体を作成します。これが主な成果物です。チャットに直接出力してください。
フェーズ 7:分析後のアクション
**アクションを自動的に実行しないでください。**レポートを提示した後、次に何を行いたいかをユーザーに尋ねてください。
- レポートを
agent-observability-rca-{ml_app}-{date}.mdに保存する - 修正を適用する(コードベースを利用できる場合)
- 残りのカテゴリーをさらに詳しく調査する
- Datadog ノートブックにエクスポートする — pup モードでは、
pup notebooks createでノートブックを作成し、pup notebooks edit NOTEBOOK_ID --file /tmp/nb_cells.jsonでセクションを追加します(ツールリファレンスを参照) - 対象期間を延長して再実行する(現在の期間が
now-24hの場合は、たとえばnow-7d)
ユーザーがオプション 4 を選んだ場合は、以下のノートブック作成フォールバック手順に従ってください。
-
mcp__datadog-mcp-core__create_datadog_notebookを次の内容で呼び出します。name:Agent Observability RCA: {ml_app} ({mode}) — YYYY-MM-DDtype:reporttime_span:1wcells:セクションごとに 1 つのセル(以下の「ノートブックのセル構成」を参照)
-
MCP の呼び出しが失敗した場合は、諦める前にエラーを確認します。
- 認証/権限エラー(401、403) → 中止して、ユーザーに伝えます。
- フィールド検証エラー(エラーメッセージに特定のフィールドが示されている) → そのフィールドを修正し、MCP 呼び出しを一度だけ再試行します。
- その他のエラー(バインディング、シリアライズ、予期しない応答) → pup にフォールバックします。
- ノートブックのペイロードを、完全な API エンベロープ
{"data": {"attributes": {"name": "...", "time": {...}, "cells": [...]}, "type": "notebooks"}}として/tmp/nb_rca_{ml_app}.jsonに書き込みます。 pup notebooks create --file /tmp/nb_rca_{ml_app}.jsonを実行します。- pup も利用できない場合は、ノートブックの内容全体を Markdown としてチャットに出力し、ユーザーが利用できるようにします。
- ノートブックのペイロードを、完全な API エンベロープ
-
どちらかの方法で作成に成功したら、URL を単独の行に出力します。
RCA report exported to notebook: <url>
URL は目立つように出力してください。同じセッションで次に /eval-bootstrap が実行された場合、この URL が検出され、評価スイートを同じノートブックに追加するかどうかが提示されます。
ノートブックのセル構成
| セル | 内容 |
|---|---|
| 1 — 概要 | 構造化されたヘッダー(以下の概要セルの形式を参照し、厳密に従ってください) |
| 2 — シグナルの概要 | モード固有のヘルステーブル |
| 3 — 障害の分類 | 分類テーブル |
| 4…N — 障害モード | 障害モードごとに 1 セル |
| N+1 — アクションプラン + 制限事項 | アクションプランの表 + 箇条書き |
ノートブックの書式ルール(すべてのセルに適用):
- トリプルバッククォートのコードブロックは使用しないでください — プロンプト/評価基準にはブロック引用(
>)を、短い値にはインラインコード(`)を使用します - 証拠は表で示します — 箇条書きは使用しません
- ツールの入力は表で示します — 引数 | 誤った渡し値 | 正しい方法
- アクションプランは表で示します — 優先度 | アクション | 確信度 | 影響
出力形式
概要セル(ノートブックのセル 1/レポートのヘッダー)
概要セルは、次の正確な構成に従う必要があります。説明の段落は使用しないでください。番号付きの調査結果をインラインで記載しないでください。アプリの説明は最大 1 文です。
## `{ml_app}` · {Eval Signal | Error Signal | Generic} · {timeframe}
**Date**: {YYYY-MM-DD} | **Profile**: {short app profile} | **Model**: `{model(s)}`
{One sentence: what does this app do?}
| Metric | Value |
|--------|-------|
{mode-appropriate rows — see below}
### Findings
- **{Finding 1}** (~{pct}%): one-line root cause description
- **{Finding 2}** (~{pct}%): one-line root cause description
- **{Finding 3}** (if present): one-line root cause description
### Recommendations
- **{Recommendation 1}**: specific next step tied to Finding 1
- **{Recommendation 2}**: specific next step tied to Finding 2
*Sample: {N} spans analyzed. Confidence: High | Medium | Low — {one-line reason if Medium or Low}.*
モードに応じた指標の行:
評価シグナル:
| Eval | `{eval_name}` ({type}) |
| Spans evaluated | {total_count} |
| Pass rate | {pass_rate}% ({pass_count} pass / {fail_count} fail) |
| Top failure mode | {name} (~{pct}%) |
| Evals configured | {N} |
エラーシグナル:
| Error spans | {N} confirmed |
| Top error type | `{type}` ({pct}%) |
| Affected operation | `{span_name}` |
| Cascade pattern | Isolated / Cascading |
| Evals configured | {N} (none = no quality signal) |
汎用:
| Spans sampled | {N} root spans |
| Top anomaly | {type}: {count} spans |
| Error spans | {N} (0 = structurally healthy) |
| Evals configured | {N} (none = no quality signal) |
シグナルサマリーテーブル
Step 0S(分類コンテキスト)から開始する場合は、シグナルサマリーテーブルを次の内容に置き換えます。
## Classification Signal Summary
**Source**: agent-observability-session-classify | **ml_app**: {app} | **Signal**: content-only | content+evals
| Metric | Value |
|--------|-------|
| Traces classified | N |
| Failures in corpus (no+partial) | F |
| Pass rate | X% |
| Failure modes | list |
*Root cause analysis is based on per-trace classification verdicts, not automated eval judge reasoning.*
それ以外の場合は、モードに応じて適切なバリエーションを選びます。
Eval シグナル — Eval ごとに 1 行:
| Eval | 種類 | 合計 | 合格率 | ステータス |
|---|---|---|---|---|
| eval_1 | boolean | 4,891 | 37.3% | ⚠ 調査中 |
エラーシグナル — エラーの種類ごとに 1 行:
| エラーの種類 | Span 数 | カスケード? | 起点 Span の種類 |
|---|---|---|---|
| TimeoutError | 42 | はい | tool |
汎用 — 異常の種類ごとに 1 行:
| 異常の種類 | 件数 |
|---|---|
| レイテンシの外れ値(>p90) | 12 |
失敗の分類
| # | 失敗モード | トレース | % | 重大度 | 根本原因 |
|---|---|---|---|---|---|
| 1 | ... | ... | ...% | 高 | ツールの誤用 |
失敗モードのセクション(上位 3~5 モードごとに 1 つ)
## Failure Mode N: [Name]
**Count**: {n} spans, {t} traces | **Severity**: High/Medium/Low | **Root Cause**: [Category]
[3–5 sentences: what goes wrong, when, what triggers it, causal chain.]
**Evidence**
{Use the mode-appropriate column set:}
Eval Signal — Trace | Judge verdict | What the trace revealed:
| Trace | Judge verdict | What the trace revealed |
|---|---|---|
| [69de86a7...](https://app.datadoghq.com/llm/traces?query=trace_id:{full_id}) | fail | Parent agent has no date format instruction |
Error Signal — Trace | Behavior | Version:
| Trace | Behavior | Version |
|---|---|---|
| [69de86a7...](https://app.datadoghq.com/llm/traces?query=trace_id:{full_id}) | 7 parallel calls, all 400 | v107624932 |
Generic — Trace | Anomaly | Signal:
| Trace | Anomaly | Signal |
|---|---|---|
| [69de86a7...](https://app.datadoghq.com/llm/traces?query=trace_id:{full_id}) | 94s, 12 tool calls | Latency outlier |
{For tool misuse — add a tool inputs table:}
**Tool inputs (100% of sampled calls)**
| Argument | Value passed (wrong) | Correct approach |
|---|---|---|
| `query` | `"monitor_id:123 group_status:alert"` | `"monitor_id:123"` (name/tag only) |
{For Eval Signal — add judge reasoning as a blockquote:}
> "{quoted judge reasoning}"
**Root cause**: [WHY this happens — specific span, parameter, or prompt.]
**Fix**:
BEFORE: [actual text from trace]
AFTER: [proposed replacement]
**Impact**: Eliminates ~{n} spans / {timeframe}.
優先順位付きアクションプラン
| 優先度 | アクション | 確信度 | 影響 |
|---|---|---|---|
| 1 | monitor_groups_search のスキーマを修正 — group_states パラメーターを追加 | 高 | 7 日間で約 21 件の Span を解消 |
モードが Generic で、Eval が設定されていない場合は、アクションプランの最後に必ず次の行を追加します。
| N | 少なくとも 1 つの評価器を設定する | 高 | 今後の RCA で Eval Signal モードを利用可能にします — アプリには継続的な品質シグナルが現在ありません |
制限事項とフォローアップ
追加データやフォローアップアクションが必要な項目の箇条書きリストです。
運用ルール
- 根拠に基づく:すべての主張で、クリック可能なトレースリンクを使って Span ID を参照します:Trace {first_8}...。
- 症状より根本原因:「モデルが誤った回答をした」ではなく、「システムプロンプトで日付形式を指定していない」とします。
- 計算根拠を示す:「多くの失敗」ではなく、「47 件の失敗(34%)」とします。
- 不確実性を正直に伝える:例が 5 件未満の場合は暫定的な結果です。その旨を明記します。
- PII を匿名化する:メールアドレスや名前は記載しません。ユーザー ID/組織 ID は使用できます。
- MCP 結果の解析に関する安全性:MCP ツールの結果を反復処理するスクリプトを書く前に、生の構造を確認します。最上位のキーと、ペイロードがコンテンツブロック内にネストされているか(例:
[{'type': 'text', 'text': '<json>'}])を確認してください。必要に応じて内部のペイロードを取り出し、json.loads()で読み込みます。MCP の結果がそのまま dict や list であると決めつけてはいけません。
ツールリファレンス
この付録は pup モードでのみ適用されます。MCP モードでは、ワークフローの各セクションに記載されたツール名を直接使用します。
Span とトレース
| MCP ツール | pup コマンド |
|---|---|
search_llmobs_spans(query, ml_app, from, to, limit, cursor, root_spans_only, span_kind, summary) | pup llm-obs spans search --query "@ml_app:A [other_filters]" [--from F] [--to T] [--limit N] [--cursor C] [--root-spans-only] [--span-kind K] [--summary] — ml_app でフィルタリングするには、常に --query "@ml_app:A" を使用してください。--ml-app A フラグは信頼性が低く、他のアプリの Span を気付かないうちに返すことがあります。 |
get_llmobs_span_details(trace_id, span_ids, from, to) | pup llm-obs spans get-details --trace-id T --span-ids S1,S2,... |
get_llmobs_span_content(trace_id, span_id, field, path) | pup llm-obs spans get-content --trace-id T --span-id S --field F [--path P] |
get_llmobs_trace(trace_id, include_tree) | pup llm-obs spans get-trace --trace-id T [--include-tree] |
get_llmobs_agent_loop(trace_id, span_id) | pup llm-obs spans get-agent-loop --trace-id T [--span-id S] |
find_llmobs_error_spans(trace_id) | pup llm-obs spans find-errors --trace-id T |
expand_llmobs_spans(trace_id, span_ids, max_depth, filter_kind) | pup llm-obs spans expand --trace-id T --span-ids S1,S2,... [--max-depth N] [--filter-kind K] |
評価ツール
| MCP ツール | pup コマンド |
|---|---|
list_llmobs_evals() | pup llm-obs evals list(ml_app でクライアント側から絞り込み) |
list_llmobs_evals_by_ml_app(ml_app) | pup llm-obs evals list-by-ml-app --ml-app A |
get_llmobs_evaluator(eval_name) | pup llm-obs evals get-evaluator EVAL_NAME |
get_llmobs_eval_aggregate_stats(eval_name, ml_app, from, to) | pup llm-obs evals get-aggregate-stats EVAL_NAME [--ml-app A] [--from F] [--to T] |
ノートブック
| MCP ツール | pup コマンド |
|---|---|
create_datadog_notebook(name, cells, ...) | pup notebooks create --title "TITLE" --file /tmp/nb_cells.json — 正確なフラグは pup notebooks create --help で確認してください |
edit_datadog_notebook(id, cells, append_only=true) | pup notebooks edit NOTEBOOK_ID --file /tmp/nb_cells.json(現在のノートブックを取得し、指定されたセルを追加して書き戻します) |
セルファイルは、セルオブジェクトの JSON 配列です。
[{"attributes": {"definition": {"type": "markdown", "text": "## Section\n\nContent."}}, "type": "notebook_cells"}]