なぜデータモデルから理解するのか

前章まででLangfuseの立ち位置を俯瞰しました。本章からは内部に深く潜ります。 まず データモデル から始めるのは、Langfuseの全機能(Tracing、Prompt Management、Evaluation、Dataset)が 共通のエンティティ上に積み重ねられた設計だからです。ここを理解せずにSDKやUIの使い方だけ覚えても、 「なぜこの機能はこう動くのか」が腹落ちしません。

5大エンティティの全体像

erDiagram
  USER ||--o{ TRACE : has
  SESSION ||--o{ TRACE : groups
  TRACE ||--o{ OBSERVATION : contains
  OBSERVATION ||--o{ OBSERVATION : nests
  TRACE ||--o{ SCORE : has
  OBSERVATION ||--o{ SCORE : has
  SESSION ||--o{ SCORE : has
  PROMPT ||--o{ GENERATION : linked
  DATASET ||--o{ DATASETITEM : contains
  DATASET ||--o{ DATASETRUN : executes
  DATASETRUN ||--o{ DATASETRUNITEM : records
  DATASETRUNITEM ||--|| TRACE : produces
  DATASETRUNITEM ||--o{ SCORE : has
Langfuseの5大エンティティと関係: User/Session がTraceをグループ化、Traceが複数Observationを木構造で持ち、Scoreは任意レベルに付与可能。PromptはGenerationにリンク、DatasetはDatasetRun経由でTraceを生成する
エンティティ 役割 親子関係
Trace 1リクエスト/1操作の最上位コンテナ 親なし。Observationを複数内包
Observation Trace内の個別ステップ(Span/Generation/Event) Trace配下、再帰ネスト可
Score 評価結果の唯一の保存形式(numeric/categorical/boolean) Trace/Observation/Session/DatasetRunItemに付与
Prompt バージョン管理されるプロンプトオブジェクト 独立。Generationにリンクされる
Dataset / DatasetRun ゴールドセットと実行記録 Dataset → DatasetItem / DatasetRun → DatasetRunItem → Trace

Trace — 最上位コンテナ

Trace はユーザーリクエストまたは単一操作に対応する最上位の観測単位です。 チャットボットなら「1問1答」、RAGアプリなら「1クエリの処理全体」、エージェントなら「1ユーザー指示の完了まで」が1 Traceに相当します。

Traceが持つ主要属性:

属性 用途
id string (UUID互換) ユニークID。W3C Trace Contextと互換
name string トレース名("chat"、"rag-query"等の論理名)
user_id string? エンドユーザー識別子。集計・分析の軸
session_id string? 会話セッションID。マルチターン会話をグループ化
tags string[] 第一階層のフィルタ用タグ
metadata object? 任意のkey-value属性(全observationに伝播)
input / output any トレース全体の入力・出力
release string? アプリのリリース識別(v1.2.3、Gitハッシュ等)
version string? プロンプト/モデル構成の論理バージョン
environment string "production" / "staging" / "development" 等

Observation — Span / Generation / Event の3種

Traceの内部で「何が起きたか」を記録するのが Observation です。 Langfuseは OpenTelemetryのSpanを拡張し、Observationを以下の3種に分類しています。

タイプ 用途 追加属性 典型例
Span 汎用処理(非LLM) なし(基本属性のみ) DB クエリ、ツール実行、ビジネスロジック、前処理
Generation LLM呼び出し model / model_parameters / usage_details(input/output tokens)/ cost_details / prompt_name / prompt_version OpenAI chat.completions、Anthropic messages.create
Event durationを持たない点イベント なし エラー発生、ユーザーアクション、システム状態変化

さらに2025年以降、UIの表示用に「意味的タイプ」も導入されました: agent / tool / chain / retriever / evaluator / embedding / guardrail。 これらは内部的には Span/Generation の特殊化で、ダッシュボードでのアイコンとグルーピングに使われます。

graph TD
  T[Trace: user-chat-request] --> O1[Span: parse-input]
  T --> O2[Span: rag-pipeline]
  O2 --> O21[Span/retriever: vector-search]
  O2 --> O22[Span/retriever: bm25-search]
  O2 --> O23[Generation/embedding: embed-query]
  T --> O3[Span/chain: generate-answer]
  O3 --> O31[Generation: gpt-4o call]
  O3 --> O32[Event: validation-passed]
  T --> O4[Span/tool: send-response]

  style T fill:#3b82f6,stroke:#1d4ed8,color:#fff
  style O2 fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style O3 fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style O31 fill:#f97316,stroke:#ea580c,color:#fff
  style O23 fill:#f97316,stroke:#ea580c,color:#fff
  style O32 fill:#14b8a6,stroke:#0d9488,color:#fff
実アプリのObservation階層例。RAGアプリで1リクエストを処理する中で、Span(汎用)とGeneration(LLM呼び出し・Embedding)とEvent(検証通過)が木構造で記録される

Generation の追加属性が重要な理由

Generation にはLLM呼び出しに必要な全情報が一級属性として格納されます。 modelinput/output tokenscostprompt バージョンを汎用タグに詰め込むのではなく、 専用フィールドに型付きで保存するため、ダッシュボードで「モデル別コスト推移」「プロンプトバージョン別レイテンシ」といった集計が即座にできます。

Level — エラーパス可視化

Observationには level 属性があり、DEBUG / DEFAULT / WARNING / ERROR の4段階で重要度を示します。 statusMessage と併用することで、ダッシュボードでエラーパスを素早く絞り込めます。

Score — 評価結果の唯一の保存形式

Score はLangfuseで「評価」の結果を表現する唯一のオブジェクトです。 重要なのは「人間アノテーション」「LLM-as-a-Judge」「ユーザーフィードバック」「外部EvalツールからのAPI送信」が すべてScoreに統合される点。これによりソースを横断した比較や集計ができます。

属性 説明
name string スコア名("correctness"、"toxicity"等)
value number | string | boolean スコア値
dataType NUMERIC / CATEGORICAL / BOOLEAN 値の型
source API / ANNOTATION / EVAL 発生源(APIから送信 / 人間アノテーション / Evaluator実行)
comment string? 任意の理由説明
trace_id / observation_id / session_id / dataset_run_item_id string? 付与対象(いずれか)

Prompt — Immutableバージョン + 可変Label

Prompt はLangfuseでバージョン管理されるプロンプトオブジェクトです。text(単一文字列)と chat(role/content配列)の2種類があり、 バージョンは整数(1, 2, 3...)で immutable(不変)に蓄積されます。完全な監査履歴です。

バージョンが immutable だと「本番が参照するバージョンを切り替える仕組み」が必要です。これを担うのが Label です。

Label 性質 用途
production デフォルト・本番参照先 SDK.get_prompt()のデフォルトで参照される
latest 自動更新 最新バージョンを自動的に指す
staging 任意 本番前の段階的リリース
カスタム 任意 A/Bテスト、機能フラグ、チーム別など
Protected Label 権限ロック ロールベースの変更制御
graph LR
  subgraph Immutable[Immutable バージョン]
    V1[v1]
    V2[v2]
    V3[v3]
    V4[v4]
  end
  subgraph Labels[可変Label(ポインタ)]
    LP[production] -.指す.-> V2
    LS[staging] -.指す.-> V3
    LL[latest] -.自動.-> V4
    LA[custom:experiment-a] -.指す.-> V4
  end

  style V1 fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style V2 fill:#3b82f6,stroke:#1d4ed8,color:#fff
  style V3 fill:#f97316,stroke:#ea580c,color:#fff
  style V4 fill:#14b8a6,stroke:#0d9488,color:#fff
  style LP fill:#3b82f6,stroke:#1d4ed8,color:#fff
  style LS fill:#f97316,stroke:#ea580c,color:#fff
  style LL fill:#14b8a6,stroke:#0d9488,color:#fff
  style LA fill:#14b8a6,stroke:#0d9488,color:#fff
Prompt のバージョンとLabelの関係。バージョンはimmutable、Labelは可変ポインタ。productionラベルの付け替えでロールバックもA/Bテスト切替も実現

Linked Generation — プロンプトと生成の紐付け

プロンプトを取得して使うだけではLangfuseはバージョン追跡できません。 Generation 実行時に prompt パラメータを渡して明示的にリンクすることで、 Promptバージョン単位のレイテンシ・コスト・スコア中央値が自動集計されるようになります。

Dataset / DatasetRun / Experiment

Dataset(データセット)は入力と期待出力のテストケース集合(ゴールドセット)です。 これに対してLLMアプリを流して実行結果を記録するのが DatasetRun(実験)です。

エンティティ 役割 主要属性
Dataset テストケース集合 name / description / metadata
DatasetItem 個別テストケース input / expectedOutput / metadata / sourceTraceId / status(ACTIVE/ARCHIVED)
DatasetRun Dataset全体の実行 name / metadata / Dataset参照
DatasetRunItem 個別実行結果 Trace参照 / DatasetItem参照
graph LR
  D[Dataset\nname: qa-gold-set] --> I1[Item 1\ninput / expectedOutput]
  D --> I2[Item 2]
  D --> I3[Item N]
  D --> R1[DatasetRun\nname: v2-prompt-test]
  R1 --> RI1[RunItem → Trace\n+ Score]
  R1 --> RI2[RunItem → Trace\n+ Score]
  D --> R2[DatasetRun\nname: v3-prompt-test]
  R2 --> RI3[RunItem → Trace\n+ Score]

  style D fill:#3b82f6,stroke:#1d4ed8,color:#fff
  style R1 fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style R2 fill:#14b8a6,stroke:#0d9488,color:#fff
Dataset/DatasetRun/DatasetRunItemの関係。1つのDatasetに対して複数のDatasetRun(異なるプロンプトバージョン・モデル・設定)を実行し、RunItem単位でスコアを比較することで回帰を検知する

詰まりやすい概念 Top 5

①: Trace vs Span vs Generation

初学者が最も混乱するポイント。正しい関係は:

  • Trace = 1リクエスト全体(ユーザーの1操作に1:1対応)
  • Observation = Trace内の作業単位の親型(Span/Generation/Event の共通親)
  • Span = Observation の一種(汎用処理)
  • Generation = Observation の一種(LLM呼び出し専用、model/usage/cost追加)
  • Event = Observation の一種(durationなし)

「Span と Generation は別物」ではなく、「Observation という共通親の型ヴァリアント」と理解するのが正解です。 OpenTelemetryのspanに type属性を加えて拡張したもの、とも言えます。

②: Score と Evaluation の関係

Evaluation は「評価する行為・仕組み」、Score は「評価結果の唯一の永続形式」。 LLM-as-a-Judge・人間アノテーション・ユーザーフィードバック・外部Evalツールからの送信 — 全てがScoreとして記録されます。 source フィールド(API / ANNOTATION / EVAL)でソースを区別します。

③: Session と User の境界

user_id は「誰」の恒常的識別子、session_id は「1つの会話セッション」の識別子です。 1 Userが複数 Sessionを持つのは自然ですが、Sessionは Userの子エンティティではなく、両方ともTraceレベルで独立に付く「タグ的」属性です。 「Session テーブルに User 外部キーがある」わけではない、と覚えておくと混乱しません。

④: Prompt Linking のタイミング

Promptを langfuse.get_prompt() で取得した時点ではリンクされません。 Generation 実行時に prompt パラメータを渡して初めてリンクが作成されます。 LangChain統合では PromptTemplate.metadata["langfuse_prompt"] にセットすることで自動リンクされます。

⑤: V3のIngestion Flow(非同期性)

v3アーキテクチャでは、SDKが送信したトレースは以下のフローで処理されます(詳細は第5章):

  1. Webコンテナが受信 → S3 に書き込み → Redis にポインタをキューイング
  2. Workerコンテナが Redis からデキュー → S3 から本体取得 → ClickHouse へバルクINSERT

そのため 「送った直後はClickHouseに存在しない」タイミングがあります。E2Eテストで送信→即検索はレースが起きるので、 適切な待機またはflush後のポーリングが必要です。

OpenTelemetry との用語対応

LangfuseはOTelに準拠しつつ、LLMアプリ固有の概念を独自に追加しています。対応表は以下の通りです。

OpenTelemetry Langfuse 備考
Span Observation(Span/Generation/Event) Langfuseは3亜種に拡張
Span attributes Langfuse専用属性 + gen_ai.* + metadata.attributes 優先順位: langfuse.* > gen_ai.* > metadata.attributes
Resource attributes metadata.resourceAttributes 単なるメタデータ扱い
trace_id / span_id 同じ形式(32/16 hex) そのまま互換
(なし) Session / User Langfuse独自、Trace属性として伝播
(なし) Score Langfuse独自の評価専用エンティティ
SpanKind Observation type(agent/tool/retriever等) LLMアプリ特化の意味付け

理解度チェック

問題 0 / 50%
Q1

Langfuseの Observation について正しい記述はどれですか?

キーボード: 1〜4 で選択、Enter で回答