AI Agentのトレースは、1回の実行にLLM CallやTool Callが数百単位で並ぶことも珍しくありません。実行が失敗したことは分かっても、原因になった1つの処理にたどり着くまでに時間がかかります。
Langfuse v4は、この「探す」工程を作り直したリリースです。
v3ではTraceを開いてから中を掘り下げるのが基本でした。v4では、問題のあるLLM CallやTool Callそのものを、複数のTraceをまたいで直接検索できます。そこから異常が起きた時間帯へ移動し、同じ条件のまま傾向をグラフで確認し、しきい値を超えたら通知を受け取る。この一連の流れがつながりました。
土台にあるのは、Langfuseが「Observations-first」と呼ぶデータモデルの変更です。内部のテーブル構造も大きく変わっていますが、本記事では設計そのものより、日々の調査と運用がどう変わるのかを中心に扱います。
v4はLangfuse Cloudとセルフホスト版の双方で正式に利用できます。セルフホスト版は、2026年7月29日にv4.0.0として初回GAリリースされました。なお、本記事の「v4」はLangfuse本体のバージョンを指します。後述するSDKのメジャーバージョンとは別の体系です。
Langfuse v3とv4の主な違い#
| やりたいこと | Langfuse v3 | Langfuse v4 |
|---|---|---|
| エラー箇所を探す | Traceを入口に、内部の処理へ掘り下げる使い方が中心 | エラーになったLLM CallやTool CallをObservationsテーブルから横断検索 |
| 遅い処理を探す | TraceやObservationを個別に確認 | Observationをレイテンシー条件で絞り込む |
| 高コストな処理を探す | Trace全体のコストから原因を確認 | Generation単位でコストを比較 |
| 入出力から対象を探す | 既存の検索やフィルターを利用 | inputとoutputの全文検索を構造化フィルターと併用 |
| 傾向を見る | カスタムダッシュボードを作成 | ObservationsテーブルをChart表示へ切り替え |
| 異常を検知する | APIや外部監視基盤と組み合わせる | Langfuse上でMonitorを設定 |
| APIから分析する | Trace、Observation、MetricsのAPIを用途別に利用 | Observations API v2とMetrics API v2で行取得と集計を分離 |
| 本番のLLM-as-a-Judgeを実行する | Trace単位のEvaluatorを利用 | Observation単位のEvaluatorが推奨 |
| 大量データを扱う | JOINと読み取り時の重複排除が負荷になりやすい | Observation中心のデータモデルで負荷を抑える |
v3にもObservationsテーブルやフィルターはありました。v4で変わったのは、Observationが調査や分析の中心に置かれたことです。
Langfuseは、この設計を「Observations-first data model」と呼んでいます。公式説明では、大規模プロジェクトで長期間を対象としたダッシュボードが少なくとも10倍高速化し、大量データのテーブル初期表示も秒単位からミリ秒単位へ改善したとされています。
この方針転換は、記録の仕方にも及んでいます。v4では、Trace自身にinputとoutputを持たせる方式が非推奨になりました。テーブル、LLM-as-a-Judge、Exportはいずれも、関連するObservation(通常はRoot Observationや該当するLLM Call)のinputとoutputを参照します。リクエスト全体の入出力はRoot Observationへ、個別処理の入出力はそれぞれのObservationへ記録する、という整理です。
Traceを開く前に、問題のある処理を探す#
v3では、問題が起きたTraceを見つけ、その中にあるLLM CallやTool Callを確認する流れが一般的でした。
Traceを探す
↓
Traceを開く
↓
問題のある処理を探す単純なチャットアプリであれば、この方法でもそれほど困りません。一方、AI Agentでは、1つのTraceに多数のLLM Call、Tool Call、Retrieval、Sub-agentの処理が含まれます。
実際に調べたいのは、次のような内容です。
- エラーが増えているTool Call
- レイテンシーが悪化したモデル呼び出し
- コストを押し上げているGeneration
- 低い評価が集中しているRetriever
v4では、こうした処理をObservationsテーブルから直接検索します。
問題のあるObservationを探す
↓
対象のLLM CallやTool Callを確認する
↓
必要に応じてTrace全体を見るTraceのWaterfall表示は引き続き利用できます。個々の処理を横断して調べるときはObservationを使い、1回の実行全体の流れや因果関係を追うときはTraceを見る、という使い分けになります。
inputやoutputから対象を特定する#
本番環境で問い合わせを受けたとき、Trace IDまで分かっているケースは多くありません。利用者から届くのは、たとえば次のような情報です。
返金について質問したら、途中でエラーになった。
この場合、「返金」という入力内容や、画面に表示されたエラーメッセージが手掛かりになります。
画面上部の全文検索では、TraceとObservationのinputおよびoutputを検索できます。期間、環境、Observation Type、モデル、ログレベルなどの条件とも組み合わせられます。
Filter Search Barでは、次のような形式で条件を入力します。
level:ERROR type:TOOL environment:production latency:>2サイドバーのフィルターと同じ条件をテキストで操作でき、比較演算子やワイルドカード、入力補完にも対応しています。条件はURLに保存されるため、調査中の絞り込みをそのままリンクで共有できます。
Filter Search Barにフィールド名を付けずに語句を入力した場合は、ID、名前、input、outputが横断検索されます。対象を片方に限定したい場合は、input:またはoutput:を付けます。
全文検索は単純な部分一致ではなく、ClickHouseのトークンベース検索です。検索語はトークン単位で照合され、複数の検索語は連続したフレーズとして扱われます。公式ドキュメントでは、errorはerrorに一致する一方、errorsには一致しないと説明されています。
Observations API v2では、UIの検索対象に加えて、指定したキーの文字列metadataにもmatches条件を利用できます。なお、inputとoutputのmatchesは大文字と小文字を区別しませんが、metadataに対するmatchesは区別します。
Pulseから異常が起きた時間帯へ移動する#
問題が発生していることは分かっていても、いつから始まったのか判断できない場合があります。
Observationsテーブルの上部にあるPulseでは、選択した期間を時間帯ごとに区切り、次の指標を確認できます。
- Observation数
- 合計コスト
- レイテンシーのp95またはp50
初期状態ではObservation数が表示されます。コストでは時間帯ごとの合計額、レイテンシーではp95または中央値のp50を選べます。

特定の時間帯だけ棒が高くなっていれば、その時間帯で処理件数、コスト、またはレイテンシーが増えています。棒をクリックすると、Observationsテーブルが該当時間帯に絞り込まれます。複数の棒をドラッグして、少し広い期間を選ぶこともできます。
スパイクを見つける
↓
該当する時間帯を選ぶ
↓
その時間帯のObservationを確認する大量の行を並べ替えて原因を探すより、異常が起きた時間帯から入る方が対象を絞り込めます。
ただし、Pulseには2つの制約があります。1つは、Observationsテーブルを特定のUserまたはSessionだけに絞って表示している場合、Pulseが表示されないことです。
もう1つは、すべてのフィルターがPulseの集計に使われるわけではないことです。レイテンシー、コスト、Token数の数値フィルター、Score、metadata、コメント、全文検索、input:やoutput:による検索、has:による存在チェックなどが有効な場合、Pulseは無効になります。テーブル側には引き続き条件が適用されるため、Pulseが表と異なる対象を集計しているように見えることはありません。
調査中の条件を、そのままグラフにする#
Observationsテーブルは、TableとChartを切り替えられます。たとえば、次のような条件でObservationを絞り込んだとします。
type = generation
environment = production
model = model-aChartへ切り替えると、同じ期間と、Chart側で扱えるフィルターを使ってデータが可視化されます。設定できる主な項目は次のとおりです。
- Line、Area、Bars、Ranked、Pie、Numberなどの表示形式
- 件数、レイテンシー、コスト、Tokenの指標
- モデル、名前、ログレベル、Type、環境などの分類軸
集計方法は指標によって選択肢が変わります。レイテンシーでは平均、p50、p95、p99、最大、最小を、コストとTokenでは合計、平均、p95、最大を選べます。件数に集計方法の選択肢はありません。
継続して確認したい内容であれば、そのままカスタムダッシュボードへ追加できます。保存されるのは、グラフの形式、指標、集計方法、分類軸、適用可能なフィルターです。表示期間は追加先のダッシュボードで設定します。
Pulseと同様に、すべてのフィルターがグラフに反映されるわけではありません。全文検索、metadata、Score、コメント、数値条件、has:による存在チェックなど、集計チャートで扱えない条件は画面上で無効化されます。どの条件がChartに反映されていないかは、その場で確認できます。
Langfuse上で異常を監視する#
問題を見つけやすくなっても、毎日画面を確認し続ける運用には限界があります。
v4のMonitors and Alertsでは、ObservationやScoreから計算した指標にしきい値を設定できます。過去のデータからベースラインを学習して逸脱を自動判定する仕組みではなく、利用者が演算子としきい値を明示する、しきい値監視です。
監視できる内容の例は次のとおりです。
- 平均レイテンシーが設定した上限を超えた
- p95コストが設定した上限を超えた
- 品質スコアが設定した下限を下回った
- Observation数が設定した下限を下回った
- Boolean Scoreの成功率が一定値を下回った
Alertの前段階としてWarningのしきい値を設定できるほか、評価期間、データがない場合の扱い、異常が継続した場合の再通知も指定できます。通知先はSlack、Webhook、GitHub Actionsです。
品質スコアが基準を下回る
↓
Slackへ通知する
↓
対象のObservationを調査するv3でも、Public APIや外部の監視基盤を組み合わせれば、同様の仕組みは作れました。v4では、よく使う監視条件をLangfuse上で設定し、通知までつなげられます。MonitorsはLangfuse Cloudの各プランと、セルフホスト版v4以降で利用できます。
2026年8月時点で、Langfuse Cloudの組織あたりMonitor数の上限は、Hobbyが2件、Coreが20件、Proが50件、Enterpriseが100件です。セルフホスト版にはMonitor数の上限がありません。
Root Observationだけを表示することもできる#
Observations-firstでは、すべてのLLM CallやTool Callが一覧に並びます。Trace一覧に比べて行数は確実に増えます。
Python SDK v4.7.0以降、またはJS/TS SDK v5.4.0以降を使っているプロジェクトでは、Observationsテーブルを初期状態で開いた際に、Is Root Observation = trueが自動的に設定されます。これにより、たとえば次のようなアプリケーションの入口を中心に表示できます。
- 1回のユーザーリクエスト
- 1回のAgent実行
- 1回のバックグラウンド処理
子のLLM CallやTool Callを横断検索する場合は、Rootのフィルターを外します。
通常時
Root Observationを中心に見る
問題調査時
Rootフィルターを外して個々の処理を見る保存済みViewや共有URLに別の条件がある場合は、その設定が優先されます。一度Rootフィルターを外すと、その選択も記憶されます。また、Root Observationが1件も見つからず、ほかのObservationが存在する場合は、一覧が空に見えないようLangfuseがRootフィルターを自動的に解除します。
LangfuseのRoot Observationには、物理的な親を持たないObservationだけでなく、SDKがアプリケーションの入口としてマークしたApp Rootも含まれます。そのため、OTelコンテキスト上では親Spanを持っていても、LangfuseではRoot Observationとして扱われる場合があります。
Observations API v2でも、物理的な親を示すparentObservationIdと、論理的なRootであることを示すisRootObservationは別のフィールドとして扱われています。
APIは行データと集計データで使い分ける#
v4では、UIだけでなく、データ取得用のAPIもObservation中心に整理されています。主に使うのは次の2つです。
| API | 主な用途 |
|---|---|
| Observations API v2 | 個々のObservationを取得する |
| Metrics API v2 | コスト、Token、件数、レイテンシー、Scoreなどを集計する |
Observations API v2は、Span、Generation、Eventなどの行データを取得するためのAPIです。
fieldsパラメーターを使い、core、basic、io、metadata、model、usage、metricsなど、必要なフィールドグループだけを指定できます。指定しなかったグループのフィールドは、nullではなくレスポンス自体から省略されます。
ページングにはカーソル方式を採用しています。レスポンスのmeta.cursorを次のリクエストへ渡し、続きを取得します。1ページあたりのデフォルト件数はv1、v2ともに50件で、最大取得件数はv1の100件からv2では1,000件へ増えています。
Metrics API v2は、すべてのObservationを取得して利用者側で集計するのではなく、Langfuse側で計算した結果を返します。たとえば、次のような用途に使えます。
- モデル別の合計コスト
- 環境別のObservation数
- 日別のToken使用量
- Observation名別の平均レイテンシー
- Numeric、Categorical、Boolean Scoreの集計
v2ではobservationsを中心としたViewと、Score種別ごとのViewが提供されています。id、traceId、userId、sessionIdなどの高カーディナリティな項目はフィルターには使えますが、GROUP BYの対象にはできません。
社内ダッシュボードやコスト配賦、定期レポートでは、集計をLangfuse側に寄せることで、取得件数とアプリ側の処理を減らせます。
評価対象を個々の処理に絞る#
AgentのTraceには、複数のLLM Call、Tool Call、Retrieval、Sub-agentが含まれます。Trace全体をまとめて評価すると、スコアが低いことは分かっても、原因となった処理までは特定できない場合があります。
v4では、本番トラフィックに対するLLM-as-a-Judgeの対象として、Observation単位のEvaluatorが推奨されています。たとえば、次のように対象を分けられます。
- 最終回答を生成したGeneration
- 検索結果を返したRetriever
- 特定のTool Call
- Sub-agentを表すObservation
Observation単位のEvaluatorは、対象となったObservationのinput、output、metadataを評価に利用します。兄弟や子のObservationを自動的に読み込むわけではないため、処理全体の入出力を評価したい場合は、それらを記録したLogical Root Observationを対象にします。
Trace単位のEvaluatorの扱い#
Trace単位のEvaluatorは非推奨になりました。ただし、切り替え猶予があります。
セルフホスト版の移行では、書き込みモードをlegacy、dual、events_onlyから選びます。これはサーバーの環境変数LANGFUSE_MIGRATION_V4_WRITE_MODEで指定する、デプロイ全体の設定です。組織やプロジェクト単位では切り替えられません。
Trace単位のEvaluatorと、レガシーなDatasetベースのEvaluatorは、legacyとdualで運用している間は動作を続け、UI上はLegacyと表示されます。
一方、v4の既定であるevents_onlyへ切り替えた時点で、これらは停止します。v4のデータモデルではサポートされないためです。legacyとdualは移行用の一時的なモードであり、将来のメジャーバージョンで削除されることが公式に明言されています。恒久的な運用モードとして使えるものではないため、events_onlyへ切り替えるまでにObservation単位のEvaluatorへ移行しておく必要があります。
なおdualの期間中は、新しい画面に切り替えるかどうかをUIのトグルでユーザーごとに選べます。書き込みはデプロイ全体で1つ、読み取りはユーザーごと、という構成です。
Scoreの付与先は変わっていない#
Score自体がObservation専用になったわけではありません。Trace、Observation、Session、Dataset RunへのScore付与は引き続き利用できます。なお、LangfuseではExperimentとDataset Runが同じ意味で使われる場合があります。
これまでTraceに付けていたScoreやコメントは、対応するRoot Observation上に表示されます。
これらの変更を支えるObservations-first#
ここまで紹介した機能の土台にあるのが、Observations-firstのデータモデルです。
v3では、TraceとObservationを別々のエンティティとして扱っていました。概念的には次のような構造です。
traces
├─ trace_id
├─ user_id
├─ session_id
└─ tags
observations
├─ observation_id
├─ trace_id
├─ model
├─ latency
└─ cost「特定ユーザーのLLM利用コスト」を計算するには、Trace側のuser_idとObservation側のcostを、trace_idで結び付ける必要があります。
v4では、Trace単位で利用する属性を各Observationにも持たせます。
observations
├─ observation_id
├─ trace_id
├─ user_id
├─ session_id
├─ tags
├─ model
├─ latency
└─ cost特定ユーザーのGenerationや、特定Session内のTool Callを、Observation側のデータだけで検索できる構造です。Traceは同じtrace_idを共有するObservationの論理的なグループとして扱われ、user_id、session_id、tags、metadataなどのTrace属性は、対応SDKのコンテキスト伝播を通じて各Observationへ持たされます。
同じ値を複数のObservationへ保存するため、データには重複が生まれます。その代わり、検索時のJOINを減らせます。
v3ではTraceとObservationのJOINに加え、ReplacingMergeTreeに書き込まれた複数バージョンから最新行を選ぶ処理も、長期間のクエリで負荷になっていました。v4は、wideで原則として不変なObservationモデルを採用し、JOINと読み取り時の重複排除を避けています。
「1つのObservationテーブル」は論理モデルの話#
Langfuseはv4について、概念的には1つのObservationテーブルであると説明しています。これは論理モデルの話で、Langfuseの全データが物理的に1つのClickHouseテーブルへ保存されるわけではありません。
Observation関連の新しい読み取りモデルは、主に次の2つの物理テーブルで構成されています。
| テーブル | 役割 |
|---|---|
events_full | input、output、metadataを含む完全なObservationデータを保持 |
events_core | 一覧や集計に使う軽量なプロジェクション |
events_coreは、events_fullからMaterialized Viewによって生成されます。サイズが大きくなりやすいinput、output、metadataを切り詰め、テーブルやグラフのクエリを軽くしています。
概略化すると、次の構成です。
Observationを書き込む
│
▼
events_full
完全なデータ
│
│ Materialized View
▼
events_core
一覧・集計向けテーブルやChartでは主にevents_coreを使い、個別のObservationの完全な内容が必要な場合はevents_fullを参照します。
Scoresなど、Observation以外のデータまでこの2テーブルに統合されたわけではありません。つまりv4の変更は、ClickHouseの物理テーブルを1個にまとめたという話ではなく、TraceとObservationを別々の読み取りモデルとして扱うのをやめ、Trace属性を含むObservation中心の論理モデルへ統一した、という変更です。
まとめ#
v3のTrace中心の画面は、1件のリクエストを追う用途では今も十分に機能します。1 Traceあたりの処理数が少ないチャットボットのようなアプリケーションであれば、v4に移っても体感は大きく変わらないかもしれません。
差が出るのは、「どのTraceが失敗したか」ではなく「どのTool Callがエラーを返しているか」を起点に調べたいときです。
セルフホスト版で移行を検討するなら、書き込みモードの切り替えが分かれ目になります。events_onlyにした時点で、Trace単位のEvaluatorに加えて、非推奨の読み取りAPI(traces、observations、sessions、scores、metrics、dataset runs)とレガシーなバッチ取り込みAPIが停止します。SDKのバージョン、API利用箇所、Evaluatorの3つを先に棚卸ししておくと安全です。