こちらを読んでいたのですが、なかなかLoggedModelが腑に落ちず。
Claudeに質問、相談しながら以下をまとめました。以下を読み進めるには、この文脈でのアプリケーションを理解しておくことをお勧めします。
この文脈におけるアプリケーションは、生成AIアプリケーション、特に LLM(大規模言語モデル)を活用したアプリケーションを指しています。MLflowの観点では、mlflow.set_active_model()
で追跡される任意の粒度のコードをアプリケーションと呼んでいます
具体例
- LLMベースのチャットアプリケーション
- OpenAI APIやDatabricksでホストされているLLMを使用
- ユーザーの入力を受け取り、AIモデルから応答を生成
- カスタマーサポートエージェント
-
以下のコード例では
app_name = "customer_support_agent"
という名前が使用されている - 顧客からの問い合わせに自動応答するシステム
-
以下のコード例では
アプリケーションの構成要素
@mlflow.trace
def my_app(input: str):
# LLMに対してリクエストを送信
response = client.chat.completions.create(
model=model_name,
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": input},
],
)
return response.choices[0].message.content
アプリケーションのバージョン管理対象
- コードベース: Gitで管理されるPythonコード
-
設定パラメータ:
- 使用するLLMモデル(例:
gpt-4o-mini
、databricks-claude-sonnet-4
) - 温度設定(
temperature: 0.7
) - 検索戦略(
retrieval_strategy: "vector_search_v3"
)
- 使用するLLMモデル(例:
- プロンプトテンプレート: システムプロンプトやユーザープロンプトの構造
つまり、この文脈でのアプリケーションとは、LLMを活用してユーザーとの対話や特定タスクを実行する生成AIソフトウェアシステム全体を指しており、MLflowを使ってそのバージョン履歴、パフォーマンス、設定を追跡・管理することを目的としています。
これらのアプリケーションはMLflowによってバージョン管理され、特定時点のアプリケーションのスナップショットがLoggedModelです。LoggedModelは「アプリケーションそのもの」ではなく、「アプリケーションの特定バージョンのスナップショット」です。
1つのアプリケーションは複数のLoggedModelを持ち、各LoggedModelはアプリケーションの異なる時点・設定・バージョンを表現します。 アプリケーション:LoggedModel = 1:N の関係です。
これらの図もClaudeに作ってもらいましたが、ようやく関係性がわかってきました。
開発から本番へのフロー
機能間の相互作用マトリクス
アプリケーションはLoggedModelを作成、Tracingを起動・作成し、Evaluationによって評価、Monitoringによって監視される。LoggedModelはアプリケーションのバージョンであり、トレースにリンクする、などなど。
前振りが長くなりましたが本編をどうぞ。新たな概念なので、実際にコードを動かすことを強くお勧めします。
目次
LoggedModelとは
概要
LoggedModelは、生成AIアプリケーションのバージョンを追跡するためのメタデータハブです。アプリケーションのコード自体を保存するのではなく、Gitコミットハッシュなどの外部リソースへの参照を記録し、トレースや評価結果を一元管理します。
従来のMLflow Modelとの違い
従来のMLflow Model
├─ モデルファイル(model.pkl, model.h5)
├─ 依存関係(requirements.txt)
├─ MLmodel設定ファイル
├─ カスタムコード
└─ デプロイ可能なパッケージ
LoggedModel(GenAI向け)
├─ メタデータ(名前、ID、パラメータ)
├─ 外部参照(Gitコミットハッシュなど)
├─ 関連付け(トレース、評価結果)
└─ コード本体は含まない
重要: LoggedModelは従来のMLflow Modelとは異なる新しい概念です。
従来のモデル管理との違い
基本概念
コアコンポーネント
1. name(名前)
ユーザーが指定する識別子。人間が読みやすい形式。
# 例
"customer_support_agent-git-a1b2c3d4"
"my-app-v1.2.3"
"chatbot-prod-20251001"
特徴:
- ユーザーが自由に指定可能
- 同じExperiment内で同じnameを指定すると、既存のLoggedModelを再利用
- 異なるExperiment内では、同じnameでも別のLoggedModelが作成される
2. model_id(モデルID)
MLflowが自動生成する一意の識別子(UUID)。
# 例
"e8f7a3b9c2d14e5f6a7b8c9d0e1f2a3b"
特徴:
- MLflowが自動生成(ユーザー指定不可)
- Experiment内で一意(実質的にグローバル一意)
- 変更不可(一度生成されたら永久に同じ)
- プログラムでの操作に使用
3. 一意性のスコープ
Databricks Workspace
└─ MLflow Tracking Server
├─ Experiment A
│ ├─ LoggedModel 1 (model_id: 一意)
│ └─ LoggedModel 2 (model_id: 一意)
│
└─ Experiment B
├─ LoggedModel 3 (model_id: 一意)
└─ LoggedModel 4 (model_id: 一意)
- model_idはExperiment内で厳密に一意
- 異なるExperiment間では、UUIDの性質上実質的に一意
set_active_model()の仕組み
基本動作
active_model_info = mlflow.set_active_model(name="my-app-v1")
内部処理フロー:
1. 指定されたnameでLoggedModelを検索
├─ 存在する → 既存のLoggedModelを返す
└─ 存在しない → 新規作成し、UUIDを生成
2. スレッドローカルストレージに保存
thread_local.active_model_id = "e8f7a3b9..."
3. ActiveModelオブジェクトを返す
├─ name: "my-app-v1"
└─ model_id: "e8f7a3b9..."
トレース自動紐付けの仕組み
# ステップ1: アクティブモデルを設定
mlflow.set_active_model(name="my-app-v1")
# → スレッド内に model_id="e8f7..." を保存
# ステップ2: トレース付き関数を実行
@mlflow.trace
def my_app(input: str):
return result
result = my_app("質問")
# → MLflowがトレース作成時にスレッドの状態をチェック
# → トレースに metadata.mlflow.modelId="e8f7..." を自動付与
重要なポイント:
- アプリケーションを「特定」しているのではなく、「文脈(コンテキスト)」を設定
-
set_active_model()
呼び出し後の全てのトレースが自動的に紐付く - 呼び出しタイミングが重要: アプリ実行前に必ず呼び出す
スレッドローカルストレージ
# マルチスレッド環境でも混ざらない
def thread_a():
mlflow.set_active_model(name="app-a")
result = my_app("test") # ← app-aに紐付く
def thread_b():
mlflow.set_active_model(name="app-b")
result = my_app("test") # ← app-bに紐付く
# 並行実行しても、各スレッドで独立した状態を持つ
主要機能
1. パラメータ管理
アプリケーションの設定情報を記録します。
app_params = {
"llm": "gpt-4o-mini",
"temperature": 0.7,
"max_tokens": 1000,
"retrieval_strategy": "vector_search_v3",
"embedding_model": "text-embedding-ada-002"
}
mlflow.log_model_params(
model_id=active_model_info.model_id,
params=app_params
)
保存可能な型:
- 文字列
- 数値
- ブール値
複雑な構造の保存:
import json
complex_config = {
"retrieval": {"top_k": 5, "threshold": 0.8},
"llm": {"model": "gpt-4o", "temperature": 0.7}
}
mlflow.log_model_params(
model_id=model_id,
params={
"config": json.dumps(complex_config)
}
)
2. タグ管理
メタデータとしてのラベル情報を追加します。
active_model_info = mlflow.set_active_model(
name="my-app-v1",
tags={
"team": "data-science",
"environment": "production",
"version": "1.2.3",
"approved_by": "alice@example.com",
"jira_ticket": "DS-1234"
}
)
# 後から追加も可能
mlflow.set_tag("deployment_date", "2025-10-01")
3. トレース管理
アプリケーション実行の詳細ログが自動的に関連付けられます。
mlflow.set_active_model(name="my-app-v1")
@mlflow.trace
def my_app(input: str):
response = llm_call(input)
return response
# 各実行がトレースとして記録され、自動的に紐付く
result1 = my_app("質問1") # Trace T001
result2 = my_app("質問2") # Trace T002
トレースに含まれる情報:
- 入力(input)
- 出力(output)
- 実行時間(duration)
- スパン(LLM呼び出しの詳細: トークン使用量、レイテンシなど)
- エラー情報
- メタデータ(model_idを含む)
4. 評価結果の紐付け
評価実行の結果をLoggedModelに関連付けます。
from mlflow.genai import scorers
eval_dataset = [
{"inputs": {"input": "質問1"}},
{"inputs": {"input": "質問2"}},
]
eval_result = mlflow.genai.evaluate(
data=eval_dataset,
predict_fn=my_app,
model_id=active_model_info.model_id,
scorers=scorers.get_all_scorers()
)
評価結果に含まれる情報:
- メトリクス(relevance, coherence, groundednessなど)
- 評価テーブル(各入力・出力・スコア)
- 評価実行時のトレース
実装方法
ステップ1: 環境準備
pip install --upgrade "mlflow[databricks]>=3.1.0" openai
ステップ2: 基本アプリケーション作成
import mlflow
from databricks.sdk import WorkspaceClient
# トレーシングを有効化
mlflow.openai.autolog()
# MLflow設定
mlflow.set_tracking_uri("databricks")
mlflow.set_experiment("/Shared/my-experiment")
# OpenAIクライアント初期化
w = WorkspaceClient()
client = w.serving_endpoints.get_open_ai_client()
model_name = "databricks-claude-sonnet-4"
# アプリケーション定義
@mlflow.trace
def my_app(input: str):
response = client.chat.completions.create(
model=model_name,
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": input},
],
)
return response.choices[0].message.content
ステップ3: バージョン追跡の実装
パターンA: Gitコミットハッシュを使用(推奨)
import subprocess
app_name = "customer_support_agent"
try:
git_commit = (
subprocess.check_output(["git", "rev-parse", "HEAD"])
.decode("ascii")
.strip()[:8]
)
version_identifier = f"git-{git_commit}"
except subprocess.CalledProcessError:
version_identifier = "local-dev"
logged_model_name = f"{app_name}-{version_identifier}"
# 重要: アプリ実行前に呼び出す
active_model_info = mlflow.set_active_model(name=logged_model_name)
print(f"Active LoggedModel: {active_model_info.name}")
print(f"Model ID: {active_model_info.model_id}")
パターンB: シンプルなバージョン番号
version = "v1.2.3"
active_model_info = mlflow.set_active_model(name=f"my-app-{version}")
パターンC: タイムスタンプベース
from datetime import datetime
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
active_model_info = mlflow.set_active_model(name=f"my-app-{timestamp}")
ステップ4: パラメータの記録
app_params = {
"llm": "gpt-4o-mini",
"temperature": 0.7,
"retrieval_strategy": "vector_search_v3",
}
mlflow.log_model_params(
model_id=active_model_info.model_id,
params=app_params
)
ステップ5: アプリケーション実行
# これらの呼び出しは同じLoggedModelに紐付く
result = my_app(input="What is MLflow?")
print(result)
result = my_app(input="What is Databricks?")
print(result)
ステップ6: トレースの確認
UIでの確認
MLflow Experiment UI
├─ トレースタブ
│ └─ 各トレースとそのバージョン情報を表示
│
├─ バージョンタブ
│ └─ LoggedModelの一覧とパラメータ、紐付けられたトレース
│
└─ 評価タブ
└─ 評価結果の詳細
プログラムでの確認
# 特定LoggedModelのトレースを検索
traces = mlflow.search_traces(
filter_string=f"metadata.`mlflow.modelId` = '{active_model_info.model_id}'"
)
print(f"関連トレース数: {len(traces)}")
for trace in traces:
print(f"Trace ID: {trace.request_id}")
print(f"Input: {trace.inputs}")
print(f"Output: {trace.outputs}")
# LoggedModelの詳細情報を取得
import datetime
logged_model = mlflow.get_logged_model(model_id=active_model_info.model_id)
print(f"Model ID: {logged_model.model_id}")
print(f"Name: {logged_model.name}")
print(f"Created: {datetime.datetime.fromtimestamp(logged_model.creation_timestamp / 1000)}")
# パラメータを確認
print("\nパラメータ:")
for param_name, param_value in logged_model.params.items():
print(f" {param_name}: {param_value}")
ステップ7: 評価の実行
from mlflow.genai import scorers
eval_dataset = [
{"inputs": {"input": "What is the most common aggregate function in SQL?"}},
]
mlflow.genai.evaluate(
data=eval_dataset,
predict_fn=my_app,
model_id=active_model_info.model_id,
scorers=scorers.get_all_scorers()
)
実装のウォークスルー
元記事に沿って、実際に動かしてみます。
%pip install --upgrade "mlflow[databricks]>=3.1.0" openai
%restart_python
ステップ 1: サンプル アプリケーションを作成する
import mlflow
from databricks.sdk import WorkspaceClient
# MLflowの自動ロギングを有効化し、アプリケーションにトレーシングを追加
mlflow.openai.autolog()
# MLflowのトラッキング先をDatabricksに設定
mlflow.set_tracking_uri("databricks")
mlflow.set_experiment("/Workspace/Users/takaaki.yayoi@databricks.com/20250930_prompt_evaluation/mlflow_logged_model")
# DatabricksホストのLLMに接続するOpenAIクライアントを作成
w = WorkspaceClient()
client = w.serving_endpoints.get_open_ai_client()
# 利用するLLMモデル名を指定
model_name = "databricks-claude-sonnet-4-5"
# traceデコレーターを使ってアプリケーションのエントリーポイントをキャプチャ
@mlflow.trace
def my_app(input: str):
# この呼び出しは`mlflow.openai.autolog()`によって自動でインスツルメントされます
response = client.chat.completions.create(
model=model_name, # この例ではDatabricksホストのLLMを使用しています。AI GatewayやModel Servingエンドポイントにも置き換え可能です。OpenAIの認証情報を使う場合はgpt-4oなど有効なOpenAIモデル名に変更してください。
messages=[
{
"role": "system",
"content": "あなたは親切なアシスタントです。",
},
{
"role": "user",
"content": input,
},
],
)
return response.choices[0].message.content
result = my_app(input="MLflowとは?")
print(result)
# MLflowとは
**MLflow**は、機械学習のライフサイクル全体を管理するためのオープンソースプラットフォームです。Databricksが開発し、2018年にリリースされました。
## 主な特徴
### 1. **4つの主要コンポーネント**
- **MLflow Tracking**: 実験の記録と比較
- パラメータ、メトリクス、成果物の記録
- 実験結果の可視化と比較
- **MLflow Projects**: 再現可能な実験環境
- コードのパッケージング
- 依存関係の管理
- **MLflow Models**: モデルのデプロイ
- 様々な形式でのモデル保存
- 複数のデプロイ先への対応
- **MLflow Registry**: モデルのバージョン管理
- モデルのライフサイクル管理
- ステージング(開発、本番など)
## メリット
- 🔄 **再現性**: 実験を簡単に再現可能
- 📊 **可視化**: 実験結果を比較しやすい
- 🔧 **フレームワーク非依存**: TensorFlow、PyTorch、scikit-learnなど様々なライブラリに対応
- 🚀 **デプロイ簡易化**: モデルのデプロイが容易
機械学習プロジェクトの実験管理やモデル管理を効率化したい場合に非常に有用なツールです。
ステップ 2: アプリのコードにバージョン追跡を追加する
上のセルを以下のように変更します。重要なのはactive_model_info = mlflow.set_active_model(name=logged_model_name)
。これを実行することで、以降に生成されるトレースがLoggedModelに紐づけられるようになります。
import subprocess
# アプリケーション名とバージョン識別子を定義
app_name = "customer_support_agent"
# バージョン管理のために現在のgitコミットハッシュを取得
try:
git_commit = (
subprocess.check_output(["git", "rev-parse", "HEAD"])
.decode("ascii")
.strip()[:8]
)
version_identifier = f"git-{git_commit}"
except subprocess.CalledProcessError:
version_identifier = "local-dev" # gitリポジトリ外の場合のフォールバック
logged_model_name = f"{app_name}-{version_identifier}"
# アクティブなモデルコンテキストを設定
active_model_info = mlflow.set_active_model(name=logged_model_name)
print(
f"アクティブなLoggedModel: '{active_model_info.name}', モデルID: '{active_model_info.model_id}'"
)
# traceデコレーターを使ってアプリケーションのエントリーポイントをキャプチャ
@mlflow.trace
def my_app(input: str):
# この呼び出しは`mlflow.openai.autolog()`によって自動でインスツルメントされます
response = client.chat.completions.create(
model=model_name, # この例ではDatabricksホストのLLMを使用しています。AI GatewayやModel Servingエンドポイントにも置き換え可能です。OpenAIの認証情報を使う場合はgpt-4oなど有効なOpenAIモデル名に変更してください。
messages=[
{
"role": "system",
"content": "あなたは親切なアシスタントです。",
},
{
"role": "user",
"content": input,
},
],
)
return response.choices[0].message.content
result = my_app(input="MLflowとは?")
print(result)
MLflowエクスペリメントが作成されるのでアクセスします。開いた際に種類を聞かれることがありますが、生成AIを選択します。
デフォルトでトレースタブには上のアプリケーションの呼び出しで生成されたトレースが表示されています。
ここで、バージョンタブをクリックします。ここにLoggedModelが表示されています。
ステップ 3: (省略可能) パラメーターの記録
active_model_info = mlflow.set_active_model(name=logged_model_name)
の後にlog_model_params
を呼び出すとアクティブなモデルにパラメーターも記録されます。以下の例はダミーデータなので、実際には実態に即したものにすべきです。
app_params = {
"llm": "gpt-4o-mini",
"temperature": 0.7,
"retrieval_strategy": "vector_search_v3",
}
# Log params
mlflow.log_model_params(model_id=active_model_info.model_id, params=app_params)
set_active_model
でアクティブなモデルが変更されない限り、トレースは同じLoggedModelに記録されます。
result = my_app(input="Databricksとは?")
print(result)
アプリケーションに変更があったものとして、別の名前でset_active_model
を呼び出すと、異なるバージョンのLoggedModelとして記録されます。
# Set the active model context
active_model_info = mlflow.set_active_model(name="new-name-set-manually")
print(
f"Active LoggedModel: '{active_model_info.name}', Model ID: '{active_model_info.model_id}'"
)
app_params = {
"llm": "gpt-4o",
"temperature": 0.7,
"retrieval_strategy": "vector_search_v4",
}
# Log params
mlflow.log_model_params(model_id=active_model_info.model_id, params=app_params)
# This will create a new LoggedModel
result = my_app(input="What is GenAI?")
print(result)
リネージ管理
リネージ(系譜)とは
「どのバージョンのアプリケーションが、どのような実行結果を生み出したか」という追跡可能な関係性
リネージの構造:
コードバージョン → 実行 → 結果
↓ ↓ ↓
Git commit Traces Outputs
↓ ↓ ↓
LoggedModel ←─────┴──────┘
(メタデータハブ)
リネージの4層構造
レベル1: コードバージョン → LoggedModel
# Gitコミットハッシュを名前に含める
git_commit = "a1b2c3d4"
logged_model_name = f"customer_support-git-{git_commit}"
active_model_info = mlflow.set_active_model(name=logged_model_name)
# コードの復元
# $ git checkout a1b2c3d4
レベル2: LoggedModel → パラメータ
# アプリケーションの設定を記録
app_params = {
"llm": "gpt-4o-mini",
"temperature": 0.7,
"git_commit": git_commit,
}
mlflow.log_model_params(
model_id=active_model_info.model_id,
params=app_params
)
レベル3: LoggedModel → トレース
# 実行ごとのトレースが自動的に紐付く
mlflow.set_active_model(name="app-git-a1b2c3d4")
result1 = my_app("質問1") # Trace T001 → model_id紐付け
result2 = my_app("質問2") # Trace T002 → model_id紐付け
result3 = my_app("質問3") # Trace T003 → model_id紐付け
レベル4: LoggedModel → 評価結果
# 評価結果をLoggedModelに紐付け
eval_result = mlflow.genai.evaluate(
data=eval_dataset,
predict_fn=my_app,
model_id=active_model_info.model_id,
scorers=scorers
)
リネージの可視化
LoggedModel (customer_support-git-a1b2c3d4)
├─ コードバージョン: git-a1b2c3d4
├─ パラメータ:
│ ├─ LLM: gpt-4o-mini
│ ├─ 温度: 0.7
│ └─ 検索戦略: vector_search_v3
├─ トレース:
│ ├─ T001: "質問1" → "回答1" (1.2s, 150 tokens)
│ ├─ T002: "質問2" → "回答2" (0.9s, 120 tokens)
│ └─ T003: "質問3" → "回答3" (1.5s, 180 tokens)
└─ 評価結果:
└─ E001:
├─ relevance: 0.85
├─ coherence: 0.92
└─ groundedness: 0.88
複数バージョンの比較
# バージョンv1のトレースを取得
model_v1 = mlflow.set_active_model(name="app-git-v1")
traces_v1 = mlflow.search_traces(
filter_string=f"metadata.`mlflow.modelId` = '{model_v1.model_id}'"
)
# バージョンv2のトレースを取得
model_v2 = mlflow.set_active_model(name="app-git-v2")
traces_v2 = mlflow.search_traces(
filter_string=f"metadata.`mlflow.modelId` = '{model_v2.model_id}'"
)
# 比較分析
avg_time_v1 = sum(t.execution_time_ms for t in traces_v1) / len(traces_v1)
avg_time_v2 = sum(t.execution_time_ms for t in traces_v2) / len(traces_v2)
print(f"v1 平均実行時間: {avg_time_v1}ms")
print(f"v2 平均実行時間: {avg_time_v2}ms")
print(f"改善率: {(avg_time_v1 - avg_time_v2) / avg_time_v1 * 100:.1f}%")
コード管理との関係
重要な理解
LoggedModelはコード自体を管理しません。
LoggedModelが管理するもの:
├─ ✅ メタデータ(名前、ID、タイムスタンプ)
├─ ✅ パラメータ(設定値)
├─ ✅ タグ(ラベル情報)
├─ ✅ 関連付け(トレース、評価結果へのリンク)
└─ ❌ コード本体 ← 管理しない!
Gitハッシュの役割
Gitコミットハッシュを名前に含めても、それは文字列として記録されるだけです。
# これを実行すると...
git_commit = "a1b2c3d4"
active_model_info = mlflow.set_active_model(name=f"my-app-git-{git_commit}")
# LoggedModelに保存されるのは:
# name: "my-app-git-a1b2c3d4" ← 文字列として保存
# コード本体: 保存されない
# コードを取得するには、手動でGitを操作
# $ git checkout a1b2c3d4
LoggedModelとGitの関係図
┌─────────────────────┐ ┌──────────────┐
│ LoggedModel │ │ Git Repository│
│ ├─ name: "app-git- │ 参照 │ ├─ commit: │
│ │ a1b2c3d4" │ -----→ │ │ a1b2c3d4 │
│ ├─ model_id: ... │ │ └─ コード本体 │
│ └─ params: {...} │ └──────────────┘
└─────────────────────┘
↓
LoggedModelはGitと直接連携しない
文字列として名前に含まれているだけ
コード管理の選択肢
選択肢1: Git(推奨)
import subprocess
git_commit = subprocess.check_output(
["git", "rev-parse", "HEAD"]
).decode("ascii").strip()[:8]
active_model_info = mlflow.set_active_model(name=f"my-app-git-{git_commit}")
# 利点:
# ✅ コードの完全な復元が可能
# ✅ 変更履歴の追跡
# ✅ チーム開発に適している
# ✅ 業界標準
# 欠点:
# ⚠️ Gitリポジトリが必要
# ⚠️ コミットの手間
選択肢2: バージョン番号(Git不要)
version = "v1.2.3"
active_model_info = mlflow.set_active_model(name=f"my-app-{version}")
# 利点:
# ✅ シンプル
# ✅ Gitなしで動作
# 欠点:
# ❌ コードの復元は手動管理が必要
# ❌ 変更履歴が見えない
選択肢3: タイムスタンプ(実験向け)
from datetime import datetime
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
active_model_info = mlflow.set_active_model(name=f"my-app-{timestamp}")
# 利点:
# ✅ 最速でイテレーション
# 欠点:
# ❌ 再現性なし
# ❌ 本番運用には不適切
選択肢4: パラメータで変更履歴を管理
# Git不使用でも、パラメータで「何が変わったか」を記録
# バージョン1
active_model_info = mlflow.set_active_model(name="my-app-v1")
mlflow.log_model_params(
model_id=active_model_info.model_id,
params={
"llm": "gpt-4o-mini",
"temperature": 0.7,
"change_log": "Initial version"
}
)
# バージョン2
active_model_info = mlflow.set_active_model(name="my-app-v2")
mlflow.log_model_params(
model_id=active_model_info.model_id,
params={
"llm": "gpt-4o-mini",
"temperature": 0.5, # 変更
"change_log": "Reduced temperature from 0.7 to 0.5"
}
)
Git使用 vs Git不使用の比較表
側面 | Git使用 | Git不使用 |
---|---|---|
コードの復元 | ✅ git checkout で完全復元 |
❌ 手動管理が必要 |
変更履歴 | ✅ Git履歴で全て追跡 | ⚠️ パラメータで代替可能 |
チーム協業 | ✅ 標準的なワークフロー | ⚠️ 別の方法で共有が必要 |
セットアップ | ⚠️ Gitリポジトリが必要 | ✅ すぐに開始可能 |
ローカル開発 | ⚠️ コミットが必要 | ✅ 即座にテスト可能 |
本番運用 | ⭐⭐⭐⭐⭐ 強く推奨 | ❌ 推奨しない |
ベストプラクティス
1. 命名規則の統一
# 推奨パターン
"{app_name}-git-{commit_hash}"
"{app_name}-{env}-{version}"
# 例
"chatbot-git-a1b2c3d4"
"customer_support-prod-v1.2.3"
"recommendation-dev-exp-001"
2. set_active_model()の呼び出しタイミング
# ✅ 正しい順序
active_model_info = mlflow.set_active_model(name=logged_model_name)
result = my_app(input="質問")
# ❌ 間違った順序(トレースが紐付かない)
result = my_app(input="質問")
active_model_info = mlflow.set_active_model(name=logged_model_name)
ルール: 必ずアプリケーション実行前にset_active_model()
を呼び出す
3. 重要なパラメータの記録
# 最低限記録すべきパラメータ
essential_params = {
"llm": model_name,
"temperature": temperature,
"git_commit": git_commit, # コードバージョン
"deployment_timestamp": datetime.now().isoformat(),
"environment": os.getenv("ENV", "dev")
}
mlflow.log_model_params(
model_id=active_model_info.model_id,
params=essential_params
)
4. タグを活用したメタデータ管理
active_model_info = mlflow.set_active_model(
name=logged_model_name,
tags={
"team": "data-science",
"project": "customer-support",
"stage": "production",
"approved_by": "alice@example.com",
"jira_ticket": "DS-1234"
}
)
5. 環境ごとのバージョン管理
import os
def get_version_identifier():
"""環境に応じたバージョン識別子を取得"""
env = os.getenv("ENVIRONMENT", "dev")
if env == "prod":
# 本番: Gitタグ必須
try:
git_tag = subprocess.check_output(
["git", "describe", "--tags", "--exact-match"]
).decode("ascii").strip()
return f"prod-{git_tag}"
except subprocess.CalledProcessError:
raise ValueError("本番環境ではGitタグが必須です")
elif env == "staging":
# ステージング: Gitコミット
git_commit = subprocess.check_output(
["git", "rev-parse", "HEAD"]
).decode("ascii").strip()[:8]
return f"staging-git-{git_commit}"
else:
# 開発: タイムスタンプでOK
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
return f"dev-{timestamp}"
version = get_version_identifier()
active_model_info = mlflow.set_active_model(name=f"my-app-{version}")
6. 本番環境での環境変数使用
# 開発環境: コード内で設定
active_model_info = mlflow.set_active_model(name="my-app-v1")
# 本番環境: 環境変数を使用
import os
model_id = os.getenv("MLFLOW_ACTIVE_MODEL_ID")
if model_id:
# 環境変数が設定されている場合は使用
# (コード変更不要でバージョン管理)
pass
else:
# 設定されていない場合は通常通り
active_model_info = mlflow.set_active_model(name="my-app-v1")
7. 定期的なリネージ監査
def audit_lineage(model_id):
"""LoggedModelのリネージを監査"""
model = mlflow.get_logged_model(model_id=model_id)
traces = mlflow.search_traces(
filter_string=f"metadata.`mlflow.modelId` = '{model_id}'"
)
report = {
"model_name": model.name,
"model_id": model_id,
"params": model.params,
"total_traces": len(traces),
"date_range": {
"first": min(t.timestamp for t in traces) if traces else None,
"last": max(t.timestamp for t in traces) if traces else None
}
}
return report
# 使用例
report = audit_lineage(active_model_info.model_id)
print(json.dumps(report, indent=2))
よくある質問
Q1: LoggedModelとMLflow Modelの違いは?
A: 別物です。
MLflow Model(従来)
└─ デプロイ可能なパッケージ
├─ モデルファイル
├─ コード
└─ 依存関係
LoggedModel(GenAI向け)
└─ メタデータハブ
├─ バージョン識別
├─ トレース・評価の紐付け
└─ コード参照(Git等)
Q2: Gitコミットは必須?
A: いいえ、必須ではありません。
- 本番運用では強く推奨
- 開発・実験段階では任意
- バージョン番号やタイムスタンプでも動作
Q3: コードはどこに保存される?
A: LoggedModelには保存されません。
- Gitで管理(推奨)
- または別途手動で保存
- LoggedModelはコードへの「参照」のみを記録
Q4: model_idは指定できる?
A: いいえ、MLflowが自動生成します。
- UUID形式
- Experiment内で一意
- 変更不可
Q5: 同じnameで複数回呼び出すと?
A: 同じExperiment内なら、既存のLoggedModelを再利用します。
# 1回目
info1 = mlflow.set_active_model(name="my-app-v1")
print(info1.model_id) # "e8f7a3b9..."
# 2回目(同じname)
info2 = mlflow.set_active_model(name="my-app-v1")
print(info2.model_id) # "e8f7a3b9..." (同じ!)
Q6: 異なるExperimentで同じnameを使うと?
A: 別のLoggedModelが作成されます。
# Experiment A
mlflow.set_experiment("/Shared/exp-a")
info_a = mlflow.set_active_model(name="my-app-v1")
# model_id: "e8f7a3b9..."
# Experiment B
mlflow.set_experiment("/Shared/exp-b")
info_b = mlflow.set_active_model(name="my-app-v1")
# model_id: "f9a8b7c6..." (異なる!)
Q7: トレースが紐付かない場合は?
A: 以下を確認してください。
-
set_active_model()
をアプリ実行前に呼び出しているか -
@mlflow.trace
デコレータが付いているか -
mlflow.openai.autolog()
が有効になっているか
# 正しい順序
mlflow.openai.autolog()
active_model_info = mlflow.set_active_model(name="my-app-v1")
@mlflow.trace
def my_app(input: str):
return result
result = my_app("test")
Q8: 本番環境でのベストプラクティスは?
A: 以下を推奨します。
- Gitタグを使用したバージョン管理
- 環境変数
MLFLOW_ACTIVE_MODEL_ID
の使用 - CI/CDパイプラインでの自動化
- 重要なパラメータの必須記録
- タグによる承認履歴の記録
Q9: ファイルやアーティファクトは保存できる?
A: LoggedModelには直接保存できません。
# ❌ LoggedModelには保存できない
# mlflow.log_artifact("file.txt")
# ✅ 代わりに、MLflow Runに保存
with mlflow.start_run():
mlflow.log_artifact("file.txt")
または、Model Servingにデプロイする場合のみ、mlflow.pyfunc.log_model()
でコードをパッケージ可能(従来のMLflow Modelの機能)。
Q10: プロンプトのバージョン管理は?
A: MLflow Prompt Registryを併用します(別機能)。
LoggedModelと自動的に連携し、プロンプトのバージョンも追跡できます。詳細は公式ドキュメントを参照してください。
まとめ
LoggedModelの核心
LoggedModel = 生成AIアプリのバージョン追跡システム
役割:
├─ バージョン識別(name, model_id)
├─ メタデータ管理(params, tags)
├─ リネージ追跡(traces, evaluations)
└─ コード参照(Git hash等)
できないこと:
├─ コード本体の保存
├─ モデルファイルの保存
└─ 任意のファイル保存
キーポイント
- メタデータハブ: コードではなく、メタデータと関連付けを管理
-
自動紐付け:
set_active_model()
後のトレースが自動的に紐付く - Git推奨(必須ではない): コード管理はGitが最適だが、他の方法でも動作
-
Experiment内で一意:
model_id
はExperiment内で一意に管理 - 本番運用に最適: トラブルシューティング、A/Bテスト、監査対応に有効
推奨される使い方
フェーズ | コード管理 | LoggedModel名 | 重要度 |
---|---|---|---|
実験 | 任意 | "my-app-exp-{n}" |
⭐ |
開発 | Gitブランチ | "my-app-dev-{timestamp}" |
⭐⭐⭐ |
ステージング | Gitコミット | "my-app-staging-git-{hash}" |
⭐⭐⭐⭐ |
本番 | Gitタグ(必須) | "my-app-prod-{tag}" |
⭐⭐⭐⭐⭐ |
始め方
-
mlflow.set_active_model(name="...")
を呼び出す - アプリケーションを実行
- UIでトレースを確認
- 必要に応じてパラメータ・タグを追加
- 評価を実行してバージョン比較
シンプルな開始から、段階的に洗練された運用へと移行できるのがLoggedModelの強みです。
参考リンク: