通常の Web アプリケーションであれば、CPU 使用率やメモリ、HTTP ステータスコード、例外ログといった監視は、もう手慣れたものでしょう。Datadog や New Relic、Mackerel などの APM を入れ、ダッシュボードを眺めていれば、たいていの異常には先回りで気づけます。ところが、そのシステムに LLM 機能(チャット・要約・RAG・エージェントなど)を組み込んだ途端、それまで通用していた「見える化」が急に効かなくなった、と感じたことはないでしょうか。
「API コストが想定より膨らんだが、どの機能が原因か分からない」「応答が遅いというクレームが来たが、遅いのがモデルなのか自前処理なのかリトライなのか切り分けられない」「たまにおかしな回答を返すが、そのときのプロンプトと出力を後から追えず再現できない」。PoC や社内検証は問題なく通ったのに、本番で動かし始めてからこうした"AI 特有の見えなさ"に直面し、月末の請求や問い合わせのたびに後追いで原因調査をしている——これは多くのチームが通る道です。
難しいのは、LLM 呼び出しが従来の処理と性質が根本的に違うからです。決定的な関数呼び出しと違って出力は非決定的で、料金はリクエスト数ではなくトークン数に比例し、処理は外部 API に依存し、しかもプロンプトと応答を記録しておかないと「何が起きたか」を二度と再現できません。つまり、従来の監視で残しているテレメトリ(計測データ)だけでは、LLM 部分の異常を捉える情報がそもそも欠落しているのです。
この問題に対する答えは、ツールを増やすことではなく、まず「AI 特有の何を残すべきか」を設計として決め、それを OpenTelemetry(オープンテレメトリ。可観測性データの収集を標準化する OSS)の GenAI セマンティック規約 に沿って計装することにあります。標準に乗せておけば、Datadog でも Grafana でも OSS バックエンドでも、同じ計装で送り先を選べるようになります。
本記事では、AI 本番環境のログ・モニタリング設計の考え方を「何を残すか(設計)→ OpenTelemetry でどう計装するか(実装)→ どう気づくか(アラート)」の順で整理し、OpenTelemetry を使った計装の実例を、experimental(実験的)仕様の扱いも含めて解説します。特定 SDK の完全動作コードよりも、陳腐化しにくい「判断軸」に比重を置いて進めます。
なぜAI本番環境のログ管理・モニタリングは"普通の監視"だけでは足りないのか

最初にやるべきは、自分の監視のどこに穴が空いているのかを言語化することです。漠然とした「見えない」という不安を、「設計すべき具体的な対象」に変換できれば、手探り感は一気に減ります。
通常の監視でカバーできること・できないこと
従来の Web アプリ監視は、決定的な処理を前提に作られています。同じ入力には同じ出力が返り、処理時間はおおむね一定で、料金は基本的にリクエスト回数やインフラ稼働時間で決まります。だからこそ、CPU・メモリ・レスポンスタイム・エラー率・HTTP ステータスを見ていれば、異常の兆候を捉えられました。
LLM 呼び出しは、この前提をすべて崩します。
観点 | 通常の処理 | LLM 呼び出し |
|---|---|---|
出力 | 決定的(同じ入力→同じ出力) | 非決定的(同じ入力でも揺らぐ) |
料金 | リクエスト数・稼働時間に比例 | 入出力トークン数に比例 |
処理時間 | おおむね一定 | プロンプト長・出力長・モデルで大きく変動 |
再現性 | ログがなくても再現しやすい | プロンプト・応答を残さないと再現不能 |
依存 | 自前のコード・DB | 外部 LLM プロバイダの API に強く依存 |
つまり「HTTP 200 が返っていて、CPU も正常」でも、裏で LLM がトークンを浪費していたり、的外れな回答を返していたりすることが起こり得ます。従来の監視は「動いているか」は見られても、「LLM 部分が健全に・経済的に・正しく動いているか」を見る情報を持っていないのです。
AI運用で起きる3大トラブルと、それぞれが"見えない"理由
LLM を本番運用すると、典型的に次の3つのトラブルに遭遇します。本記事は一貫してこの3つを軸に進めます。
- コスト暴騰: トークン課金のため、プロンプトの肥大化・リトライ・ループするエージェントなどで請求が跳ね上がる。リクエスト数だけ見ていても気づけず、月末の請求書で初めて発覚する。
- レイテンシ劣化: 「応答が遅い」が起きても、原因が LLM 本体なのか、自前の前処理・後処理なのか、リトライやレート制限なのか切り分けられない。ストリーミングの有無でも「遅さ」の意味が変わる。
- 品質・安全性の劣化: モデル更新やプロンプト変更をきっかけに、空応答・的外れ・不適切な出力が増えても、エラーにはならないため監視に引っかからない。問い合わせが来てから後追いで気づく。
これらが"見えない"共通の理由は、従来のテレメトリにはトークン数・使用モデル・プロンプト・応答・終了理由といった LLM 固有の情報が含まれていないことに尽きます。逆に言えば、これらを意図して残せば、3大トラブルはどれも事前に検知可能になります。
本記事のアプローチ(「何を残すか=設計」→「どう計装するか=OpenTelemetry」の順で考える)
ありがちな失敗は、いきなり監視ツールを契約したり、サンプルコードをコピーして計装したりすることです。順序が逆になると、「とりあえず入れたが何を見ればいいか分からない」という、見えないのにダッシュボードだけ増えた状態に陥ります。
本記事では次の順序で進めます。
- 何を残すか(設計): LLM 呼び出し1回あたり、トレース・メトリクス・ログとして残すべきものをチェックリスト化する
- どう計装するか(実装): その設計を OpenTelemetry の GenAI 規約でどう実装するか(手動/自動/Collector)
- どう気づくか(アラート): 残したテレメトリを、コスト・レイテンシ・品質の異常検知にどう結びつけるか
設計を先に決めておけば、計装手段(手動か自動か)や監視ツール(Datadog か Grafana か)が変わっても、残すべきものはぶれません。これが手探り運用から抜け出す最短ルートです。
AI本番環境で"何を"ログ・メトリクスとして残すべきか(監視設計のチェックリスト)

ここが本記事の中心、設計編です。実装に入る前に、「LLM 呼び出し1回あたり、何をどの粒度で残すか」を決めます。観点はトレース・メトリクス・ログ(内容)の3つです。
トレースで残すもの(LLM呼び出し1回を1 spanとして可視化する)
トレースは「1リクエストが、どの処理を、どの順番で、どれだけの時間を使って通ったか」を木構造で記録する仕組みです。LLM 監視では、LLM 呼び出し1回を1つの span(処理区間)として扱うのが基本です。
1つの LLM span に残しておきたい情報は次のとおりです。
- 使用したプロバイダ・モデル名(例: どのモデルにフォールバックしたか)
- 入力トークン数・出力トークン数
- その呼び出しの所要時間
- 終了理由(finish reason: 正常終了か、長さ上限で打ち切られたか、フィルタで止まったか)
- リトライの有無・回数
- 上流(API ハンドラ)・下流(RAG 検索、ツール実行)の span との親子関係
親子関係が残っていることが特に重要です。「全体で5秒かかったうち、LLM 本体は1.2秒、残り3.8秒は自前のベクター検索だった」といった切り分けは、span のネスト構造があって初めて可能になります。
メトリクスで残すもの(トークン使用量・レイテンシ・初回応答時間・エラー率・推定コスト)
メトリクスは、個々のリクエストではなく、時系列で集計して傾向を見るための数値です。トレースが「1件の詳細」なら、メトリクスは「全体の健康診断」です。
最低限残したいメトリクスは次のとおりです。
- トークン使用量: 入力・出力それぞれの合計。コスト監視の土台になる
- 操作レイテンシ: LLM 呼び出しの所要時間の分布(後述の p95/p99 を見るため、平均値ではなく分布で持つ)
- 初回チャンクまでの時間(time to first token / first chunk): ストリーミング応答では、全体の完了時間よりも「最初の文字が出るまで」の体感が重要
- エラー率: 呼び出し失敗・タイムアウト・レート制限の割合
- 推定コスト: トークン使用量にモデル単価を掛けて算出。金額として見えると異常に気づきやすい
これらは、機能別(チャット/要約/RAG など)やモデル別にラベル(ディメンション)を付けて集計できるようにしておくと、後のアラート設計とトラブル切り分けが格段に楽になります。
ログ(内容)で残すもの(プロンプト・応答・ツール呼び出しと、機密/個人情報・サンプリングの注意)
トレースとメトリクスだけでは「数字」は分かっても、「なぜおかしな回答が出たか」は分かりません。それを追うには、プロンプトと応答の内容そのものを残す必要があります。
残す候補は次のとおりです。
- システムプロンプト・ユーザープロンプト
- モデルの応答(出力テキスト)
- ツール呼び出し(function calling)の引数と結果
- RAG であれば、検索でヒットしたドキュメントや渡したコンテキスト
ただし、内容ログには強い注意が必要です。
- 機密情報・個人情報(PII)の混入: プロンプトや応答にメールアドレス・氏名・社外秘が含まれることがある。何でも保存すると、ログ基盤がそのまま情報漏洩リスクになる。マスキングや項目除外を設計に組み込む(後述の Collector でのフィルタリングが有効)
- 量とコスト: 全リクエストの全文を保存するとログ量が膨大になる。サンプリング(一部のみ保存)や、エラー時・低スコア時のみ全文を残すといった方針を決める
- 保存可否のポリシー: そもそも自社・顧客のデータ取り扱い規約で、プロンプト・応答を保存してよいかを先に確認する
「何でも残す」ではなく「追跡に必要な最小限を、安全な形で残す」のが内容ログの設計です。
RAG・エージェント構成で増える監視ポイント(検索・ツール実行・多段の連鎖)
単純な1回の LLM 呼び出しなら上記で十分ですが、RAG やエージェントになると監視ポイントが増えます。これらは LLM 呼び出しが複数つながる構成なので、「どこで詰まったか」を追える設計が一段と重要になります。
- RAG: ベクター検索のレイテンシ、ヒット件数、検索結果の関連度、最終的にプロンプトへ詰め込んだコンテキスト量(トークン数)
- エージェント: 1タスクあたりの LLM 呼び出し回数、ツール実行の成否と所要時間、ループ(同じツールを呼び続ける暴走)の検知
- 多段の連鎖: 「検索→要約→生成」のように複数ステップがある場合、各ステップを子 span として残し、合計トークン・合計レイテンシをタスク単位で集計する
エージェントは「1タスクで LLM を何十回も呼び、トークンとコストが想定外に膨らむ」事故が起きやすい構成です。タスク単位の呼び出し回数と累積トークンを必ず見られるようにしておきましょう。
監視設計チェックリスト(最低限/推奨の2段階で整理した表)
ここまでをチェックリストにまとめます。まずは「最低限」を満たすことを目標にし、運用が回り始めたら「推奨」に拡張するのが現実的です。
観点 | 最低限(まずここから) | 推奨(運用が回り始めたら) |
|---|---|---|
トレース | LLM 呼び出し1回を1 span にし、モデル名・入出力トークン数・所要時間を残す | 終了理由・リトライ・上下流 span との親子関係まで残す |
メトリクス | トークン使用量・操作レイテンシ・エラー率 | 初回チャンク時間・推定コスト・機能別/モデル別ラベル |
ログ(内容) | エラー時のプロンプト・応答を残す(PII マスキング前提) | サンプリングで正常時も一部保存・ツール呼び出し内容 |
RAG/エージェント | (該当時)タスク単位の呼び出し回数・累積トークン | 検索ヒット件数・各ステップの子 span・ループ検知 |
この表が、自分のシステムに対する「最低限ここを計装すれば本番の異常に気づける」という監視設計の骨子になります。次は、これを OpenTelemetry でどう実装するかに進みます。
OpenTelemetryとGenAIセマンティック規約とは(AI監視の共通言語)

設計が決まったら、それを「何で」「どう」計装するかです。本記事が OpenTelemetry を勧める理由と、AI 監視の鍵になる GenAI セマンティック規約を押さえましょう。
OpenTelemetryの3シグナルと、AI監視でOpenTelemetryを選ぶ理由(ベンダー中立)
OpenTelemetry は、可観測性データの生成・収集を標準化する OSS プロジェクトです(OpenTelemetry 公式サイト)。扱うデータは大きく3種類(3シグナル)です。
- トレース: リクエストが処理を通る経路と時間(前述の span の木構造)
- メトリクス: 集計された時系列の数値(トークン使用量・レイテンシ分布など)
- ログ: タイムスタンプ付きのイベント記録(プロンプト・応答の内容など)
AI 監視で OpenTelemetry を選ぶ最大の理由は、ベンダーロックインを避けられることです。アプリ側を OpenTelemetry で一度計装しておけば、送り先(Datadog でも Grafana でも OSS の Jaeger / Prometheus でも)を、アプリのコードを書き換えずに切り替えられます。
LLM 監視ツールは市場の動きが速く、数か月単位で選択肢が変わります。特定ツールの独自 SDK で作り込むと、乗り換え時に計装を全部やり直すことになりかねません。標準に乗せておくことが、そのまま「計装の資産化」になります。
GenAIセマンティック規約(gen_ai.*)が解決すること
OpenTelemetry には、データの名前の付け方を統一する「セマンティック規約(semantic conventions)」があります。その中で、生成 AI 向けに定められているのが GenAI セマンティック規約で、gen_ai.* という名前空間(接頭辞)を使います(OpenTelemetry GenAI semantic conventions)。
これが解決するのは、「みんなが好き勝手な名前を付けると、後で集計・比較できなくなる」問題です。あるチームは model_name、別のチームは llm.model、また別のチームは ai_model と付けていたら、ツールを横断して「モデル別のコストを出す」ことができません。
GenAI 規約に沿って gen_ai.request.model のような標準名で残しておけば、プロバイダ(OpenAI / Anthropic など)が変わっても、監視ツールが変わっても、一貫した形のデータになります。ツール側も標準名を知っているので、専用のダッシュボードが自動で組まれるといった恩恵も受けられます。
代表的なGenAI属性・メトリクス
実務でよく使う代表的な属性・メトリクスを、用途付きで挙げます。名前は GenAI セマンティック規約に基づきますが、規約は更新が続いているため、実装時は必ず公式の最新仕様を確認してください。
名前 | 種別 | 用途 |
|---|---|---|
| 属性 | 操作の種類(chat / embeddings など) |
| 属性 | プロバイダ(openai / anthropic 等) |
| 属性 | リクエストで指定したモデル名 |
| 属性 | 実際に応答したモデル名(フォールバックの検知に有用) |
| 属性 | 入力トークン数 |
| 属性 | 出力トークン数 |
| 属性 | 終了理由(length 打ち切り・フィルタ等) |
| メトリクス | トークン使用量(集計・コスト監視の土台) |
| メトリクス | 操作の所要時間(レイテンシ分布) |
設計編で挙げた「残すべきもの」の多くが、すでに標準名として用意されていることが分かります。自前で名前を考える必要はなく、規約に従うだけで集計しやすいデータになります。
【重要】規約はexperimental(Development)ステータスである点と、移行期の二重出力という実務的対処
ここが、多くのエンジニアが「本番に入れてよいか」で立ち止まるポイントです。GenAI セマンティック規約は、執筆時点で experimental(実験的、Development ステータス) とされており、属性名やメトリクス名が将来変更される可能性があります。
experimental だからといって、使うべきでないわけではありません。実務的には次のように付き合います。
- 割り切って使う: トークン・レイテンシ・モデル名といった核心的な情報は、名前が多少変わっても残すべきものに変わりはない。「規約が固まるまで何も計装しない」より、「標準名で計装し、変更があれば追従する」ほうが圧倒的に得
- 二重出力で移行リスクを吸収する: OpenTelemetry には、旧名と新名の両方を一時的に出力する仕組みがある。環境変数
OTEL_SEMCONV_STABILITY_OPT_INで、安定版と新版を切り替えたり並行出力したりできる。これにより、規約更新時にダッシュボードやアラートが一斉に壊れるのを避けながら、段階的に移行できる - 名前を一箇所に集約する: 自前の手動計装では、属性名を定数として一箇所にまとめておけば、規約変更時の修正範囲を最小化できる
「公式が experimental だらけで判断できない」という不安に対する答えは、「中身は枯れた情報なので入れてよい。ただし名前の変更には二重出力と定数集約で備える」です。
OpenTelemetryでLLM呼び出しを計装する連携実例

設計と規約が分かったら、いよいよ実装です。ここでは陳腐化を避けるため、特定 SDK バージョンの完全動作コードではなく、最小の擬似コードと判断軸で骨子を示します。
手動計装の最小例(LLM呼び出しをspanで囲みgen_ai属性・トークン・内容を付与する)
最も基本的なのは、LLM 呼び出しを自前で span で囲み、gen_ai.* 属性を付ける手動計装です。考え方は次のとおりです。
# 擬似コード(言語・SDKに依存しない考え方の骨子)
with tracer.start_as_current_span("chat gpt-4o") as span:
# リクエスト側の属性
span.set_attribute("gen_ai.operation.name", "chat")
span.set_attribute("gen_ai.request.model", "gpt-4o")
response = call_llm(prompt) # 実際のLLM呼び出し
# レスポンス側の属性
span.set_attribute("gen_ai.response.model", response.model)
span.set_attribute("gen_ai.usage.input_tokens", response.usage.input_tokens)
span.set_attribute("gen_ai.usage.output_tokens", response.usage.output_tokens)
span.set_attribute("gen_ai.response.finish_reasons", response.finish_reason)
# トークン使用量はメトリクスにも記録(集計・コスト監視用)
token_usage_metric.record(
response.usage.output_tokens,
{"gen_ai.token.type": "output", "gen_ai.request.model": "gpt-4o"},
)
# 内容(プロンプト・応答)はspan eventやログとして(PIIに注意)
span.add_event("gen_ai.content", {"prompt": prompt, "completion": response.text})
ポイントは、「設計編のチェックリストで決めた項目(モデル・トークン・終了理由・内容)を、標準名の属性として span に貼る」だけ、ということです。プロンプト・応答の内容は span event やログイベントとして付与しますが、PII の扱いには引き続き注意します。手動計装は手間がかかる反面、自分のシステムに合わせて何を残すかを完全にコントロールできるのが利点です。
自動計装ライブラリを使う選択肢と手動とのトレードオフ
毎回手で span を書くのが現実的でない場合、自動計装(auto-instrumentation)ライブラリを使う選択肢があります。OpenAI / Anthropic などのクライアントライブラリの呼び出しをラップし、gen_ai.* 属性を自動で付けてくれるものです。OpenTelemetry エコシステムの計装ライブラリ群(OpenTelemetry の instrumentation 一覧)や、OpenLLMetry・OpenLIT といった OSS、各監視ベンダーが提供する OTel 連携などがあります。
手動と自動のトレードオフは次のとおりです。
観点 | 手動計装 | 自動計装ライブラリ |
|---|---|---|
導入の速さ | 遅い(自分で書く) | 速い(差し込むだけ) |
残す情報の制御 | 完全に制御できる | ライブラリ依存(足りない項目は手で補う) |
対応プロバイダ | 自分で書けば何でも | ライブラリの対応範囲に依存 |
仕様変更への追従 | 自分で対応 | ライブラリ更新に乗れる |
学習・把握 | 中身を理解しやすい | ブラックボックスになりやすい |
現実的なおすすめは、まず自動計装で素早く全体を可視化し、足りない項目(自前処理の span、独自のコスト計算など)を手動計装で補うハイブリッドです。自動計装ライブラリ自体も多くが experimental 段階なので、本番投入前に「自分が必要な属性を実際に出せているか」をステージングで確認しましょう。
本番はCollector経由が基本(バッファ・リトライ・機密フィルタ・サンプリングをコード外で制御)
本番運用で強く推奨されるのが、アプリから監視バックエンドへ直接送らず、間に OpenTelemetry Collector を挟む構成です(OpenTelemetry Collector)。Collector は、テレメトリを受け取り・加工し・送り出す中継コンポーネントです。
Collector を挟むことで、次のような運用上の制御をアプリのコードを触らずに実現できます。
- バッファリング・リトライ: バックエンドが一時的に落ちても、テレメトリを失わずに再送できる
- 機密情報のフィルタリング・マスキング: プロンプト・応答に含まれる PII を、Collector の処理(processor)で除去・マスクできる。内容ログの安全性をコード外で担保できるのが大きい
- サンプリング: ログ量とコストを抑えるため、保存する割合を Collector 側で調整できる
- 送り先の付け替え: 後述のとおり、送信先の変更を Collector の設定だけで完結できる
特に PII マスキングを Collector に寄せられるのは重要です。アプリ側は「とりあえず内容を送る」だけにし、「何を消すか」は Collector の設定で一元管理する、という分離ができると、漏洩リスクの管理がぐっと楽になります。
送信先はベンダー中立(同じ計装で監視基盤を選べる・乗り換えられる)
ここまでの構成の総まとめが、送信先のベンダー中立性です。アプリを OpenTelemetry で計装し、Collector を挟んでおけば、最終的なデータの送り先は自由に選べます。
- 商用 APM(Datadog / New Relic など。多くが GenAI セマンティック規約に対応を進めている)
- Grafana スタック(Tempo / Loki / Prometheus / Mimir など)
- OSS の可観測性バックエンド(Jaeger、ClickHouse 系など)
しかも、複数のバックエンドに同時に送ることも、後から乗り換えることも、Collector の設定変更だけで済みます。「今は手元の OSS で見て、将来チームが大きくなったら商用 APM へ」といった移行も、計装をやり直さずに実現できます。これが、最初に標準へ乗せておくことの最大の見返りです。
コスト・レイテンシ・品質劣化に気づくためのアラート設計

残して計装したテレメトリは、ダッシュボードで眺めるだけでは「後追い」のままです。最後の仕上げとして、3大トラブルを閾値で先に検知するアラート設計に落とし込みます。
コスト暴騰に気づく(トークン使用量起点の推定コスト・機能別/日次の急増検知)
コスト監視で最初に押さえるべきは、コストはリクエスト数ではなくトークン数に相関するという点です。リクエスト数が横ばいでも、プロンプトの肥大化やリトライ、エージェントのループでトークンが跳ね上がれば、コストは急増します。
具体的なアラート設計は次のとおりです。
- トークン使用量メトリクスにモデル単価を掛けて推定コストを算出し、ダッシュボードに金額で表示する
- 日次の推定コストが、前日比・前週同曜日比で一定割合を超えたらアラート
- 機能別(チャット/要約/RAG/エージェント)にコストを分解し、特定機能だけが急増していないか監視する
- エージェントは1タスクあたりの呼び出し回数・累積トークンに上限アラートを設け、ループ暴走を早期に止める
「月末の請求で発覚」から「その日のうちに急増を検知」へ変えるのが目標です。
レイテンシ劣化に気づく(durationと初回応答時間のp95/p99・原因の切り分け)
レイテンシは平均値で見ると、一部の遅いリクエストが埋もれます。p95 / p99(95・99 パーセンタイル=遅いほうから数えて上位の値) で見るのが鉄則です。
- LLM 操作の
gen_ai.client.operation.durationの p95/p99 を監視し、閾値超過でアラート - ストリーミング応答では、完了時間だけでなく初回チャンクまでの時間(time to first token)を別に監視する。体感速度はここで決まる
- 原因の切り分けは、トレースの親子関係が効く。全体の duration が悪化したとき、LLM span 自体が遅いのか、その外側(自前の前処理・ベクター検索・リトライ)が遅いのかを span のネストで特定する
- レート制限(429)やリトライの増加もレイテンシ悪化の典型要因なので、エラー率と併せて見る
「遅い」というクレームに対し、「LLM 本体は正常で、遅いのは自前のベクター検索だった」とすぐ答えられる状態を目指します。
品質・安全性の劣化に気づく(エラー率・finish reason・フォールバック率・自動評価メトリクスの限界)
品質劣化はエラーにならないため、最も気づきにくいトラブルです。それでも、間接的な兆候はテレメトリで捉えられます。
- エラー率: 呼び出し失敗・タイムアウトの増加
- 終了理由(finish reason):
length(長さ上限での打ち切り)の急増は、出力が途中で切れている兆候。フィルタによる停止の増加も監視する - 空応答・フォールバック率: 空の応答や、上位モデルから下位モデルへフォールバックした割合(
gen_ai.request.modelとgen_ai.response.modelの差)が増えていないか - 自動評価メトリクス: 接地性(ハルシネーションの少なさ)・関連性・一貫性などをスコア化する手法もある(Azure の生成 AI アプリ監視など)。ただしこれらはそれ自体が LLM 等による推定であり、完全ではない。あくまで「傾向の変化を捉える早期警報」として使い、最終判断は人手のレビューやユーザーフィードバックと組み合わせる
品質監視は「自動で100点判定する」ことを目指さず、「劣化の兆候に早く気づき、人が確認するきっかけを作る」と割り切るのが現実的です。
アラート疲れを避ける段階設計(重大度の段階・通知先の出し分け)
最後に、アラートを増やしすぎて「狼少年化」し、誰も見なくなる失敗を避けます。
- 重大度を段階に分ける: 「即対応(深夜でも起こす)=コスト急増・全面エラー」「翌営業日確認=p99 のじわじわ悪化・finish reason の微増」のように分類する
- 通知先を出し分ける: 緊急はオンコール(電話・PagerDuty 等)、非緊急はチャットのデイリーダイジェストへ
- 閾値は運用しながら調整する: 最初から完璧な閾値は引けない。まず緩めに置き、誤報・見逃しを見ながらチューニングする
- まず1つから始める: いきなり全部のアラートを組まず、最もダメージの大きい「日次コスト急増」など1つから始める
「全部を監視する」より「重要な異常を、適切な人に、適切な緊急度で届ける」ほうが、結果として早く障害に気づけます。
AI本番監視を始めるためのステップとよくある質問
ここまでで設計・実装・アラートの全体像が見えました。最後に、最小の第一歩と、導入をためらわせる具体的な疑問への回答をまとめます。
スモールスタートの段階導入ステップ
すべてを一度に揃える必要はありません。次の順で段階的に広げるのが現実的です。
- 1呼び出しを可視化する: まず1つの LLM 呼び出しを手動 span で囲み、モデル名・入出力トークン数・所要時間を残す。トレースが見えるだけで、切り分けの土台ができる
- メトリクスを足す: トークン使用量・レイテンシ・エラー率を集計メトリクスにし、機能別ラベルを付ける
- Collector を挟む: 本番化のタイミングで Collector を入れ、PII マスキングとサンプリングをコード外に寄せる
- アラートを1つ組む: 最もダメージの大きい「日次コスト急増」など、1つのアラートから始める
- 広げる: 自動計装の導入、RAG/エージェントの監視、品質メトリクスへと、運用が回ってから拡張する
完璧な監視を目指して動けなくなるより、「1呼び出しが見える」状態をまず作ることが、手探り運用から抜け出す最初の一歩です。
よくある質問(FAQ)
Q. OpenTelemetry の GenAI 規約は本番に入れて大丈夫ですか?(experimental の扱い)
A. 入れて問題ありません。規約は experimental(Development)ステータスのため属性名が変わる可能性はありますが、トークン・レイテンシ・モデル名といった残すべき情報の中身は枯れています。名前変更には、環境変数 OTEL_SEMCONV_STABILITY_OPT_IN による二重出力と、属性名の定数化で備えれば、ダッシュボードやアラートが一斉に壊れる事態を避けられます。
Q. 監視のオーバーヘッドはどれくらいですか? A. 実用上は軽微です。OpenTelemetry のテレメトリは非同期でバッチ送信され、そもそも LLM 呼び出し自体が秒単位の処理なので、span 付与やメトリクス記録のコストは相対的にごく小さくなります。内容ログを全リクエスト分フルで保存するとログ量が増えるので、そこはサンプリングで調整します。
Q. プロンプトや応答をログに残してよいですか? A. 「無条件に残してよい」わけではありません。プロンプト・応答には機密情報や個人情報が混入しうるため、(1) 自社・顧客のデータ取り扱い規約で保存可否を確認する、(2) Collector で PII をマスキング・除去する、(3) サンプリングやエラー時のみ全文保存にして量を抑える、という3点を設計に組み込んだうえで残します。
Q. Datadog などの既存 APM とどう併用しますか? A. 既存 APM を OpenTelemetry の送信先の1つとして使えます。アプリを OpenTelemetry で計装し、Collector から既存 APM へ送れば、従来のインフラ・Web 監視と LLM 監視を同じツール上で統合できます。多くの商用 APM が GenAI セマンティック規約への対応を進めており、標準名で送れば専用ビューが利用できる場合もあります。
Q. LangChain / RAG / エージェントでも同じ考え方で計装できますか? A. できます。「LLM 呼び出し1回を1 span として、標準属性を残す」という基本は共通です。RAG ではベクター検索を、エージェントでは各ステップやツール実行を子 span として追加し、タスク単位で累積トークン・呼び出し回数を集計すれば、多段構成でも「どこで詰まったか・どこでコストが膨らんだか」を追えます。
まとめ
AI 本番環境のログ管理・モニタリングが難しいのは、LLM 呼び出しが非決定的で、トークン課金で、外部 API に依存し、内容を残さないと再現できない——という、従来の監視が前提としていなかった性質を持つからでした。だからこそ、ツールを増やすのではなく、設計から考えることが近道になります。
本記事の要点は、次の3層に整理できます。
- 何を残すか(設計): LLM 呼び出し1回を1 span にし、モデル名・入出力トークン・所要時間・終了理由を残す。集計メトリクスとして使用量・レイテンシ・推定コストを持ち、内容ログは PII に注意して必要最小限を残す
- どう計装するか(実装): OpenTelemetry の GenAI セマンティック規約(
gen_ai.*)に沿って、手動または自動で計装する。本番は Collector を挟み、マスキング・サンプリング・送信先の制御をコード外に寄せる - どう気づくか(アラート): コストはトークン起点で日次・機能別に急増検知、レイテンシは p95/p99 とトレースの親子関係で切り分け、品質は finish reason・フォールバック率・自動評価で兆候を捉える
GenAI 規約は experimental ですが、中身は枯れた情報なので、二重出力と属性名の定数化で名前変更に備えれば、本番投入をためらう理由にはなりません。そして OpenTelemetry の最大の利点は、ベンダー中立で計装が資産になることです。一度標準に乗せておけば、監視ツールが変わっても、プロバイダが変わっても、残すべきものはぶれません。
「請求が来てから・クレームが来てから」の後追い運用から、「閾値で先に気づく」運用へ。その第一歩は、1つの LLM 呼び出しを span で可視化することから始まります。



