mcpField
A
analyzing-mlflow-session

analyzing-mlflow-session

github.com/mlflowテスト・品質82966 回インストール2 日前に更新
リポジトリ

analyzing-mlflow-session について

MLflow traces に記録された複数ターンのチャットセッションを分析するスキルです。会話の効率的な再構成、評価結果の解釈、問題のあるターンの特定を開発者向けに支援します。

主な機能

  1. 01入出力スキーマの特定
  2. 02セッション trace のフィールド抽出
  3. 03評価結果と根拠の確認
  4. 04指定ターンのスパン調査
  5. 05障害とアプリケーションコードの関連付け

活用シーン

  1. 01trace からチャット会話を再構成
  2. 02エラーが始まったターンの特定
  3. 03複数ターンにわたる評価シグナルの調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mlflow/skills --skill analyzing-mlflow-session

インストール後、Claude Code で/analyzing-mlflow-sessionを入力して読み込まれたか確認します。

同梱ファイルscripts/discover_schema.shscripts/inspect_turn.sh

詳細

MLflow チャットセッションの分析

セッションとは?

セッションは、同じチャット会話またはユーザーのやり取りに属する複数のトレースをまとめたものです。セッション内の各トレースは、ユーザーの入力とシステムの応答からなる1つのターンを表します。セッション内のトレースは、トレースのメタデータに保存された共通のセッション ID で関連付けられています。

セッション ID は、トレースのメタデータにキー mlflow.trace.session として保存されます。このキーにはドットが含まれているため、フィルター構文に影響します(以下を参照)。このキーの値が同じトレースは、すべて同じセッションに属します。

会話の再構成

セッションの会話を再構成するには、複数の手順が必要です。最初のトレースから入出力のスキーマを確認し、セッション内のすべてのトレースから該当フィールドを効率的に抽出してから、必要に応じて特定のターンを調べます。すべてのターンについて完全なトレースを取得しないでください。代わりに、検索コマンドで --extract-fields を使用してください。

手順1:スキーマを確認する。 まず、セッション内のトレース ID を見つけ、そのトレースの完全な JSON を取得してスキーマを調べます。

# Get the first trace in the session
mlflow traces search \
  --experiment-id <EXPERIMENT_ID> \
  --filter-string 'metadata.`mlflow.trace.session` = "<SESSION_ID>"' \
  --order-by "timestamp_ms ASC" \
  --extract-fields 'info.trace_id' \
  --output json \
  --max-results 1 > /tmp/first_trace.json

# Fetch the full trace (always outputs JSON, no --output flag needed)
mlflow traces get \
  --trace-id <TRACE_ID_FROM_ABOVE> > /tmp/trace_detail.json

ルートスパン、つまり parent_span_id が null のスパン(親がないスパン)を見つけます。これはトレース内の最上位の操作です。

# Find the root span
jq '.data.spans[] | select(.parent_span_id == null)' /tmp/trace_detail.json

その attributes ディクショナリを調べ、ユーザー入力とシステム出力を保持するキーを特定します。たとえば、次のようなものがあります。

  • MLflow 標準属性:mlflow.spanInputs と mlflow.spanOutputs(MLflow Python クライアントによって設定)
  • カスタム属性:@mlflow.trace または mlflow.start_span() を介して、カスタム属性の記録とともに設定されるアプリケーション固有のキー
  • サードパーティの OTel 属性:GenAI Semantic Conventions、OpenInference、またはその他の計装規約に準拠したキー

これらの値の構造もアプリケーションによって異なります(例:query 文字列、messages 配列、複数のフィールドを持つディクショナリ)。実際の属性値を調べて形式を把握してください。

ルートスパンの入力または出力が空、あるいは存在しない場合、チャットターンのデータを直接保持しないラッパースパン(例:オーケストレーターやミドルウェア)の可能性があります。その場合は、直接の子スパンを調べ、チャットターンに対応する意味のある入出力を持つ、階層内で最も上位にあるスパンを見つけてください。

以下の例は、トレースが MLflow Python クライアントからのものであり(入出力を mlflow.spanInputs/mlflow.spanOutputs に保存)、該当するスパンがルートの直接の子であることを前提としています。実際には、該当するスパンは階層のさらに下にある場合があり、ほかのクライアントのトレースでは異なる属性キーが使用されていることもあります。必要に応じてスパンツリーを調べてください。

# Get the root span's ID
ROOT_ID=$(jq -r '.data.spans[] | select(.parent_span_id == null) | .span_id' /tmp/trace_detail.json)

# List immediate children of the root span with their inputs/outputs
jq --arg root "$ROOT_ID" '.data.spans[] | select(.parent_span_id == $root) | {name: .name, inputs: .attributes["mlflow.spanInputs"], outputs: .attributes["mlflow.spanOutputs"]}' /tmp/trace_detail.json

最初のトレースの評価も確認してください。セッションレベルの評価は、セッション内の最初のトレースに付与されます。これらはセッション全体を評価するもので(例:会話全体の品質、複数ターンにわたる一貫性)、最初のターンだけでなくセッション全体のどこかに問題があることを示す場合があります。最初のトレースには、その特定のターンに対するターンごとの評価も含まれる場合があります。

どちらのタイプも .info.assessments に表示されます。セッションレベルの評価は、metadata フィールドに mlflow.trace.session が含まれていることで判別できます。

# Show session-level assessments (exclude scorer errors)
jq '[.info.assessments[] | select(.feedback.error == null) | select(.metadata["mlflow.trace.session"]) | {name: .assessment_name, value: .feedback.value}]' /tmp/trace_detail.json

# Show per-turn assessments (exclude scorer errors)
jq '[.info.assessments[] | select(.feedback.error == null) | select(.metadata["mlflow.trace.session"] == null) | {name: .assessment_name, value: .feedback.value}]' /tmp/trace_detail.json

評価のエラーはトレースのエラーではありません。 評価に feedback.error フィールドがある場合、スコアラーまたは判定器が失敗したことを意味します。トレース自体に問題があるという意味ではありません。評価を使ってトレースの問題を特定する場合は、これらを除外してください。

評価値を解釈するときは、必ず理由を確認してください。 value だけでは誤解を招くことがあります。たとえば、value: "no" の user_frustration 評価は、スコアラーの設定によって「ユーザーの不満は検出されなかった」ことも、「不満のチェックに合格しなかった」(つまり、不満が存在する)ことも意味します。.rationale フィールド(最上位の評価フィールドであり、.feedback の中にはありません)は、その値が文脈上何を意味するのかを説明します。評価を抽出するときは理由も含めてください。

jq '[.info.assessments[] | select(.feedback.error == null) | {name: .assessment_name, value: .feedback.value, rationale: .rationale}]' /tmp/trace_detail.json

ステップ 2:すべてのセッショントレースを抽出します。 入力と出力を保持する属性キーがわかったら、--extract-fields を使ってセッション内のすべてのトレースを検索し、これらのフィールドと評価を取得します(出力がファイルに書き込まれる理由については、CLI 出力の処理を参照してください)。

mlflow traces search \
  --experiment-id <EXPERIMENT_ID> \
  --filter-string 'metadata.`mlflow.trace.session` = "<SESSION_ID>"' \
  --order-by "timestamp_ms ASC" \
  --extract-fields 'info.trace_id,info.state,info.request_time,info.assessments,info.trace_metadata.`mlflow.traceInputs`,info.trace_metadata.`mlflow.traceOutputs`' \
  --output json \
  --max-results 100 > /tmp/session_traces.json

次に、ファイルに対して bash コマンド(例:jq、wc、head)を使い、分析します。

上記の --extract-fields の例では、トレースのメタデータから mlflow.traceInputs/mlflow.traceOutputs を使用しています。ステップ 1 で確認した内容に応じて、フィールドのパスを調整してください。

評価には品質に関する判定(例:正確性、関連性)が含まれており、すべてのトレースを詳細に読むことなく、問題があったターンを特定するのに役立ちます。スコアラーのエラーを除外して、評価シグナルがあるターンを特定するには、次を実行します。

# List turns with their valid assessments (scorer errors filtered out)
jq '.traces[] | {
  trace_id: .info.trace_id,
  time: .info.request_time,
  state: .info.state,
  assessments: [.info.assessments[]? | select(.feedback.error == null) | {
    name: .assessment_name,
    value: .feedback.value
  }]
}' /tmp/session_traces.json

CLI 構文に関する注意事項:

  • すべての mlflow traces search コマンドで --experiment-id が必須です。指定しないと、コマンドは失敗します。
  • ドットを含むメタデータキーは、フィルター文字列と extract-fields でバッククォートを使ってエスケープする必要があります:metadata.`mlflow.trace.session`
  • シェルでの引用符:二重引用符の中にあるバッククォートは、bash によってコマンド置換として解釈されます(例:bash は `mlflow.trace.session` をコマンドとして実行しようとします)。値にバッククォートが含まれる場合は、外側の文字列に必ず単一引用符を使ってください。例:--filter-string 'metadata.\mlflow.trace.session` = "value"'`
  • --max-results のデフォルト値は 100 で、ほとんどのセッションには十分です。会話が長い場合は、最大値の 500 まで増やしてください。結果が 500 件返された場合は、ページネーションを使って残りを取得してください。

CLI 出力の処理

MLflow のトレース出力は大きくなることがあり、Claude Code の Bash ツールでは、パイプされたコマンドの出力上限が約 30KB です。出力がこの上限を超えると、パイプで渡されずファイルに保存されるため、エラーが表示されないまま失敗します。

安全な方法(常に機能します):

# Step 1: Save to file
mlflow traces search \
  --experiment-id <EXPERIMENT_ID> \
  [...] \
  --output json > /tmp/output.json

# Step 2: Process the file
cat /tmp/output.json | jq '.traces[0].info.trace_id'
head -50 /tmp/output.json
wc -l /tmp/output.json

MLflow CLI の出力を直接パイプに渡さないでください(例:mlflow traces search ... | jq '.')。これを行うと、出力が何も表示されないまま失敗することがあります。必ず最初にファイルへリダイレクトしてから、そのファイルに対してコマンドを実行してください。

特定のターンの詳細を確認するには(例:問題のあるターンを特定した後)、そのトレース全体を取得します。

mlflow traces get --trace-id <TRACE_ID> > /tmp/turn_detail.json

コードベースとの関連付け

  • セッション ID の割り当て:コードベース内で mlflow.trace.session が設定されている箇所を検索し、セッションの作成単位(ユーザーのログインごと、ブラウザーのタブごと、明示的な「新しい会話」アクションごとなど)を確認します。
  • コンテキストウィンドウの管理:各ターンで LLM に渡されるメッセージ履歴を、アプリケーションがどのように構築するかを確認します。一般的なパターンには、スライディングウィンドウ(直近 N 件のメッセージ)、古いターンの要約、全履歴の利用などがあります。この実装によって、モデルが参照するコンテキストが決まり、複数ターンにわたる問題の原因となることがよくあります。
  • メモリと状態:アプリケーションによっては、メッセージ履歴以外にもターン間で状態を保持しています(例:抽出したエンティティ、ユーザーの設定、蓄積されたツールの結果)。この状態がどのように保存され、ターン間で渡されるかを検索します。

参照スクリプト

script/ サブディレクトリには、各分析ステップですぐに実行できる bash スクリプトが含まれています。すべてのスクリプトは、前述の出力処理ルール(ファイルにリダイレクトしてから処理)に従います。

  • scripts/discover_schema.sh <EXPERIMENT_ID> <SESSION_ID> — セッション内の最初のトレースを見つけて詳細全体を取得し、ルートスパンの属性キーと入力/出力値を表示します。
  • scripts/inspect_turn.sh <TRACE_ID> — 特定のトレースを取得し、すべてのスパンを一覧表示して、エラースパンを強調し、評価を表示します。

例:チャットの5ターン目での誤回答

チャットの会話の5番目のメッセージで、チャットボットが誤った回答をしたとユーザーから報告がありました。

1. スキーマを確認し、会話を再構成します。

セッション内の最初のトレースを取得し、ルートスパンの属性を調べて、どのキーに入力と出力が格納されているかを確認します。このケースでは、mlflow.spanInputs にユーザーのクエリが、mlflow.spanOutputs にアシスタントの応答が格納されています。次に、セッション内のすべてのトレースを検索し、これらのフィールドを時系列順に抽出します。抽出した入力と出力を調べると、5ターン目の応答が誤っていることを確認でき、先行するターンが正しく見えるかどうかも分かります。

2. 誤りが前のターンで発生したかどうかを確認します。

3ターン目の応答には、ユーザーが指摘しなかった事実誤認が含まれています。4ターン目はその誤った情報を前提とし、5ターン目では誤りがさらに大きくなっています。根本原因は5ターン目ではなく、3ターン目にあります。

3. 根本原因となったターンを単一のトレースとして分析します。

3ターン目の完全なトレースを取得して分析します。アセスメント(ある場合)を確認し、スパンツリーをたどり、リトリーバーの結果を確認して、コードと照合します。リトリーバーが古いドキュメントを返したため、誤った回答につながりました。

4. 推奨事項。

  • 古いドキュメントを除外または更新するよう、リトリーバーのデータソースを修正します。
  • 会話全体に誤りが波及する前に検出できるよう、ターンごとのアセスメントを追加します。
  • 会話レベルで誤りを検出する方法(例:ターン間で回答の一貫性を確認する)を導入することを検討します。

コメント