生成AIを組み込んだ機能をリリースした後、「どのモデルが良かったのか」「プロンプトを変えて精度が上がったのか」「1回の処理にいくらかかっているのか」を説明できないことがあります。 LLMプロバイダーの管理画面を見れば、全体のトークン数や請求額は確認できます。 しかし、それだけでは、どの機能、利用者、プロンプトのバージョンが品質や原価へ影響したのかを特定できません。
この問題を解く仕組みがLLMオブザーバビリティです。 バックエンドで実行された処理をトレースとして記録し、モデル、プロンプト、トークン、コスト、遅延、エラー、評価スコアを同じ単位で比較できるようにします。
この記事では、AIサービスのバックエンドで何を計測し、どの単位で記録し、LangfuseやBraintrustなどのツールへどうつなげるかを整理します。
AIサービスの成果が見えないのは、LLM呼び出しがブラックボックスだから
一般的なアプリケーション監視では、HTTPリクエストの成功率、応答時間、例外、CPUやメモリの使用量を追います。 しかし、LLMを呼び出す機能では、HTTPステータスが200でも、回答が質問に答えていない、指定形式を守っていない、根拠にない内容を生成した、といった失敗が起こります。
反対に、回答品質だけを人間が確認しても、どのプロンプトとモデルが使われ、何回リトライし、いくらかかったのかが分からなければ改善できません。 LLMを使うバックエンドでは、従来のエラー監視に、モデル固有の利用量と出力品質を加える必要があります。
LLMオブザーバビリティで扱うデータは、主に次の三つです。
| 単位 | 記録するもの | 用途 |
|---|---|---|
| Trace | 一つのユーザー操作やバックグラウンド処理の全体 | 処理全体の原価、所要時間、成否を確認する |
| Span | 検索、LLM呼び出し、ツール実行、出力検証などの各工程 | 遅延や失敗が起きた工程を特定する |
| Score | 正確性、関連性、形式準拠、ユーザー評価など | 出力品質をプロンプトやモデルごとに比較する |
TraceとSpanは「何が起きたか」を記録し、Scoreは「その結果をどう評価したか」を記録します。 三つを同じ識別子で結び付けると、品質、速度、原価の関係を一つの画面で追えるようになります。
LLMオブザーバビリティでは何を計測するのか
最初からすべてのデータを保存する必要はありません。 ただし、後からプロンプトやモデルを比較するには、最低限の属性を同じ形式で残す必要があります。
| 分類 | 主な計測項目 | 確認できること |
|---|---|---|
| 実行条件 | プロバイダー、要求モデル、応答モデル、プロンプトID、プロンプトバージョン、temperature、最大出力長 | どの設定で結果が変わったか |
| 利用量 | 入力トークン、出力トークン、キャッシュ読み取り、キャッシュ作成、推論トークン | どの処理がトークンを消費したか |
| 原価 | LLM呼び出し単位、Trace単位、利用者単位、機能単位のコスト | 原価が増えた場所と原因 |
| 性能 | エンドツーエンドの時間、各Spanの時間、Time to First Token(最初のトークンが届くまでの時間)、p50(中央値)、p95(95パーセンタイル) | 利用者が待っている工程 |
| 信頼性 | エラー種別、タイムアウト、リトライ回数、フォールバック、レート制限、終了理由 | 障害と自動復旧の実態 |
| 品質 | 形式検証、正解との一致、根拠性、関連性、人間の評価、再生成、有人対応への移行 | 出力が業務上使えたか |
集計軸として、機能名、環境、アプリケーションのリリース、実験グループ、テナント、利用者も付けます。 利用者やテナントを識別する場合は、メールアドレスや氏名をそのまま送らず、バックエンド側で管理する仮名IDを使います。
トークン数は、可能であればプロバイダーのレスポンスに含まれる利用量を保存します。 ローカルのトークナイザーによる推定では、推論トークンやプロバイダー側のキャッシュを正しく数えられない場合があるためです。
キャッシュ済みトークンを入力トークンの内数として返すか、別の区分として返すかもプロバイダーによって異なります。 Langfuseのコスト計測資料が説明するように、重複する区分をそのまま合算すると二重計上になります。 バックエンドで独自の利用量スキーマへ変換する場合は、各区分を排他的にするのか、内数として扱うのかを先に決めます。
ツールがモデル名と単価表から算出するコストは、運用中の比較には使えます。 一方、長文コンテキスト、バッチ、キャッシュ、独自契約などの料金条件があるため、会計上の請求額はプロバイダーの明細と照合します。
バックエンドではプロンプト単体ではなく、リクエスト全体をトレースする
一つの回答を返すまでに、LLMを一回だけ呼ぶとは限りません。 RAG(検索拡張生成)による文書検索、入力の分類、複数モデルの呼び分け、ツール実行、出力の検証、失敗時の再試行が入ると、最後のLLM呼び出しだけを見ても原因を特定できません。
一つのユーザー操作をTrace、その中の工程をSpanとして記録します。
trace: support_answer
├── span: classify_intent
├── span: retrieve_documents
├── span: generate_answer
│ ├── span: llm_request_1
│ └── span: llm_request_2_retry
└── span: validate_output
この構造なら、回答生成の原価が高いのか、検索が遅いのか、出力検証で再試行が増えているのかを分けて確認できます。 複数ターンの会話は、一回の発話をTrace、会話全体をSessionまたはThreadとして束ねると扱いやすくなります。
計装方式は、特定ツールのSDKで直接送る方法、LLM SDKのラッパーを使う方法、AIゲートウェイを通す方法、OpenTelemetryで送る方法に分かれます。 既存のAPMと関連付ける場合は、分散トレースを共通形式で収集、送信するOpenTelemetryが候補になります。 HTTPリクエストからLLM呼び出しまで同じTrace IDを引き継げるためです。
OpenTelemetryのGenAI Semantic Conventionsでは、モデル、プロバイダー、入出力トークン、評価スコアなどを表す属性が定義されています。 バックエンド内の属性名をこの規約へ寄せておくと、送信先を変えるときの変換量を減らせます。 ただし、規約や各ツールの対応範囲は更新されるため、アプリケーションの業務ロジックへ送信先固有の属性を広げず、計装用の層に閉じ込めます。
プロンプト、回答、検索文書、ツール引数には、個人情報、認証情報、社内文書が含まれることがあります。 OpenTelemetryの属性仕様でも、入力メッセージやツール引数は機密情報を含み得るデータとして扱われています。 本文を既定で保存せず、マスキング後の内容だけを送る、失敗したTraceだけをサンプリングする、本文は自社ストレージへ残して観測基盤には参照IDだけを送る、といった設計が必要です。
精度は自動計測できないため、評価スコアをトレースへ紐づける
トークン数、遅延、エラー率は実行結果から計算できます。 しかし、「回答が正しいか」「業務に使えるか」は、観測ツールが自動的に決められる値ではありません。 AIサービスの機能ごとに合格条件を定義し、その結果をScoreとしてTraceまたは対象Spanへ追加します。
評価方法には、それぞれ向いている対象があります。
| 評価方法 | 向いている対象 | 注意点 |
|---|---|---|
| コードによる検証 | JSON Schema、必須項目、禁止語、分類ラベル、ツール引数 | 判定は安定するが、文章の有用性までは測れない |
| 正解データとの比較 | 分類、情報抽出、既知の質問、検索結果 | 期待値と評価用データセットの保守が必要 |
| LLM-as-a-Judge | 関連性、根拠性、網羅性、トーン | Judge自体にも揺れとコストがあるため、人間の評価と照合する |
| 人間と利用者の反応 | 承認、修正、再生成、低評価、有人対応への移行 | 回答されない評価や利用者層の偏りがある |
たとえば、構造化データを生成する機能なら、まずJSON Schemaへ適合したかを決定的に判定できます。 カスタマーサポートの回答なら、根拠となる規約を引用しているか、質問へ回答しているか、有人対応が必要な条件を見落としていないかを別々のScoreにします。 異なる失敗を一つの「精度」に合算すると、数字が下がった理由を追えません。
リリース前には、同じ評価用データセットを旧版と新版へ実行するオフライン評価を行います。 本番では、サンプリングしたTraceへコード評価、LLM-as-a-Judge、利用者の反応を追加するオンライン評価を行います。 評価の基本用語は「AI駆動開発の用語集にあるEvalsの解説」でも整理しています。
Scoreには値だけでなく、評価名、評価基準のバージョン、評価を行ったモデルまたはコード、人間のコメントを残します。 評価基準を変えた前後のScoreを同じ系列へ混ぜると、プロンプトの改善と採点方法の変更を区別できなくなるためです。
プロンプトとモデルのバージョンごとに品質、コスト、遅延を比較する
プロンプトを変更した結果を追うには、プロンプト本文をログへ残すだけでは不十分です。 変更されないプロンプトIDと、変更ごとに増えるバージョンをLLM呼び出しへ付けます。
少なくとも、次の情報をLLM呼び出しを表すSpanへ記録します。
- プロンプトIDとバージョン
- 要求したモデルと、実際に応答したモデル
- temperature、最大出力長などの生成設定
- RAGで使ったインデックスやデータセットのバージョン
- アプリケーションのリリース番号
- 評価実験のグループ
比較画面では、平均値だけでなく分布を見ます。 平均遅延が変わらなくてもp95が悪化していれば、一部の長い入力で待ち時間が増えています。 品質スコアが上がっても、出力トークンと再試行回数が増えていれば、原価と応答時間を引き換えにした改善です。
プロンプトやモデルの候補は、次の順序で比較します。
- 固定した評価用データセットで、品質スコア、コスト、遅延を比較する
- 合格した候補を本番の一部へ配信し、同じ項目を比較する
- 低評価、再生成、有人対応への移行など、本番でしか得られないScoreを確認する
- 良いケースだけでなく、悪化した入力群を新しい評価用データへ追加する
バックエンドで合格を判定できる機能なら、総LLMコストを合格した処理数で割った「成功した1タスクあたりの原価」も算出できます。 単価の低いモデルが再試行や人間の修正を増やす場合、1回のAPI料金だけで比較すると選択を誤ります。
主要なLLMオブザーバビリティツールを計測、評価、運用方式で比べる
LLMオブザーバビリティ製品は、ログを集めるだけの製品と、プロンプト管理や評価実験まで含む製品に分かれます。 2026年8月9日時点の公式ドキュメントをもとに、主要な選択肢を整理すると次のようになります。
| ツール | データの取り込み方 | 得意な範囲 | 向いている構成 |
|---|---|---|---|
| Langfuse | Python/TypeScript SDK、各種統合、OpenTelemetry、ゲートウェイ | Trace、プロンプト管理、コスト、評価、データセット、実験 | 一つの製品で計測からプロンプト改善までつなげたい。OSS版をセルフホストしたい |
| Braintrust | SDK、各種統合、OpenTelemetry | Trace、ダッシュボード、評価実験、本番スコアリング、CI | 評価用データセットと回帰テストを開発工程の中心に置きたい |
| LangSmith | LangChain/LangGraph統合、手動計装、OpenTelemetry | Trace、Thread、プロンプト、オフライン評価、オンライン評価 | LangChainやLangGraphを使う。エージェント内部の工程を追いたい |
| Arize Phoenix | OpenTelemetry、OpenInference、自動計装 | Trace、RAGとエージェントの評価、データセット、実験 | OpenTelemetry中心で組む。OSSをローカルまたは自社環境で動かしたい |
| Portkey | AIゲートウェイ、SDK、OpenTelemetry | Trace、コスト、プロンプト、ルーティング、再試行、キャッシュ、予算制御 | 複数プロバイダーの切り替えと運用制御も同じ経路へ集めたい |
| Helicone | AIゲートウェイ、プロキシ、OpenAI向け非同期ログ | リクエスト、Session、コスト、遅延、利用者分析、外部評価Scoreの集約 | 既存のLLM呼び出しへ小さな変更でログと原価計測を追加したい |
Langfuse、LangSmith、Braintrust、Phoenixは、Traceと評価用データセットを往復しながらプロンプトやモデルを比較する用途に向いています。 PortkeyとHeliconeは、LLMリクエストが通るゲートウェイ側でログ、コスト、再試行などを取得しやすい構成です。 Heliconeは公式のEval Scores資料で、評価自体は実行せず、外部の評価結果を集約する製品だと明記しています。
選定時には、ダッシュボードの見た目よりも、次の条件を確認します。
- 現在使っている言語、LLM SDK、エージェント基盤から計装できるか
- プロンプトIDとバージョンをTraceへ関連付けられるか
- コード評価、LLM-as-a-Judge、人間の評価を同じScoreとして扱えるか
- OpenTelemetryで既存のAPMやデータ基盤へも送れるか
- 保持期間、保存リージョン、アクセス制御、セルフホスト要件を満たすか
- ログ量、評価回数、保存容量を含む観測基盤自体の費用を見積もれるか
ツールを一つに決める必要はありません。 AIゲートウェイでリクエストを制御し、OpenTelemetryで既存のAPMとLLM専用の評価基盤へ送る構成も取れます。 ただし、同じ呼び出しを複数の計装ライブラリで囲むと、Spanやトークンが重複するため、どの層を原本にするかを決めます。
導入時はプロンプトID、機能、利用者を識別できる最小構成から始める
最初の計装では、すべてのプロンプト本文を保存したり、本番リクエストをすべてLLM-as-a-Judgeへ送ったりする必要はありません。 次の順序なら、バックエンドへの変更と評価費用を抑えながら比較可能なデータを作れます。
- 一つのユーザー操作またはジョブをTraceとする境界を決める
- 機能名、プロンプトID、プロンプトバージョン、モデル、環境、仮名化した利用者IDを付ける
- プロバイダーのレスポンスからトークン数、応答モデル、終了理由、エラー、所要時間を取得する
- 検索、ツール実行、再試行、出力検証をSpanへ分ける
- JSON Schemaや必須項目など、コードで判定できるScoreから追加する
- 本番の一部へ人間の評価、利用者の反応、LLM-as-a-Judgeを追加する
- プロンプトバージョン別に品質、p95遅延、Trace単位の原価を並べ、基準を外れた変化へアラートを設定する
計装処理は、LLM機能の応答経路から切り離します。 観測ツールへの送信失敗で本来の回答まで失敗させず、非同期送信、短いタイムアウト、バッファ、サンプリングを使います。 ただし、送信できなかったTrace数は別の運用メトリクスとして残します。
保存するデータについては、計測精度より先に境界を決めます。 入力と出力を保存しなくても、プロンプトのバージョン、モデル、トークン、遅延、エラー、評価結果は計測できます。 本文が調査に必要な場合だけ、マスキング、暗号化、閲覧権限、保持期間、削除手順を設計したうえで取得します。
LLMオブザーバビリティを導入すると、AIサービスの「精度」を自動で決めてもらえるわけではありません。 バックエンドで起きた処理と、自社が定義した評価結果を結び付け、変更前後を同じ条件で比較できるようになります。 最初の到達点は、あるプロンプトを変更したときに、品質、速度、原価のどれがどう変わったかを一つのTraceから説明できる状態です。
