Suivez les versions des applications basées sur Git avec MLflow
Ce guide montre comment suivre les versions de votre application GenAI lorsque le code de votre application réside dans Git ou un système de contrôle de version similaire. Dans ce workflow, un LoggedModel MLflow agit comme un hub de métadonnées , reliant chaque version conceptuelle d'application à son code externe spécifique (tel qu'un commit Git) et à ses configurations. Ce LoggedModel peut ensuite être associé à des entités MLflow telles que des traces et des exécutions d'évaluation.
Le Link est essentiel au suivi des versions : l'appel mlflow.set_active_model(name=...) LoggedModel de cette fonction lie les traces de votre application à une Link. Si le name n'existe pas, un nouveau LoggedModel est automatiquement créé.
Ce guide couvre les points suivants :
- Suivez les versions de votre application à l’aide de
LoggedModels. - Link les exécutions d'évaluation à votre
LoggedModel.
Databricks suggère d’utiliser LoggedModels avec le registre de prompts de MLflow. Si vous utilisez le registre de prompts, chaque version de prompt est automatiquement associée à votre LoggedModel. Voir le suivi des versions de prompts avec les versions d’application.
Prérequis
-
Installez MLflow et les packages requis
Bashpip install --upgrade "mlflow[databricks]>=3.1.0" openai -
Créez une Experimentation MLflow en suivant le guide de démarrage rapide de configuration de votre environnement.
Étape 1 : Créer un exemple d'application
Le code suivant crée une application simple qui demande une réponse à un LLM.
- Initialisez un client OpenAI pour vous connecter aux LLM hébergés sur Databricks ou aux LLM hébergés par OpenAI.
- Databricks-hosted LLMs
- OpenAI-hosted LLMs
Utilisez databricks-openai pour obtenir un client OpenAI qui se connecte aux LLM hébergés sur Databricks. Sélectionnez un modèle parmi les modèles de fondation disponibles.
import mlflow
from databricks_openai import DatabricksOpenAI
# Enable MLflow's autologging to instrument your application with Tracing
mlflow.openai.autolog()
# Set up MLflow tracking to Databricks
mlflow.set_tracking_uri("databricks")
mlflow.set_experiment("/Shared/docs-demo")
# Create an OpenAI client that is connected to Databricks-hosted LLMs
client = DatabricksOpenAI()
# Select an LLM
model_name = "databricks-claude-sonnet-4"
Utilisez le SDK OpenAI natif pour vous connecter aux modèles hébergés par OpenAI. Sélectionnez un modèle parmi les modèles OpenAI disponibles.
import mlflow
import os
import openai
# Ensure your OPENAI_API_KEY is set in your environment
# os.environ["OPENAI_API_KEY"] = "<YOUR_API_KEY>" # Uncomment and set if not globally configured
# Enable auto-tracing for OpenAI
mlflow.openai.autolog()
# Set up MLflow tracking to Databricks
mlflow.set_tracking_uri("databricks")
mlflow.set_experiment("/Shared/docs-demo")
# Create an OpenAI client connected to OpenAI SDKs
client = openai.OpenAI()
# Select an LLM
model_name = "gpt-4o-mini"
-
Créer l’application d’exemple :
Python# Use the trace decorator to capture the application's entry point
@mlflow.trace
def my_app(input: str):
# This call is automatically instrumented by `mlflow.openai.autolog()`
response = client.chat.completions.create(
model=model_name, # This example uses a Databricks hosted LLM - you can replace this with any AI Gateway or Model Serving endpoint. If you provide your own OpenAI credentials, replace with a valid OpenAI model e.g., gpt-4o, etc.
messages=[
{
"role": "system",
"content": "You are a helpful assistant.",
},
{
"role": "user",
"content": input,
},
],
)
return response.choices[0].message.content
result = my_app(input="What is MLflow?")
print(result)
Étape 2 : ajoutez le suivi de version au code de votre application
Une version LoggedModel sert d'enregistrement central (hub de métadonnées) pour une version spécifique de votre application. Il n'a pas besoin de stocker le code de l'application lui-même. Au lieu de cela, il pointe vers l'emplacement où votre code est géré (tel qu'un hachage de commit Git).
Utilisez mlflow.set_active_model() pour déclarer le LoggedModel avec lequel vous travaillez actuellement, ou pour en créer un nouveau. Cette fonction renvoie un objet ActiveModel contenant le model_id, ce qui est utile pour les opérations ultérieures.
En production, vous pouvez définir la variable d’environnement MLFLOW_ACTIVE_MODEL_ID au lieu d’appeler set_active_model(). Consultez le guide de suivi des versions en production.
Le code suivant utilise le hash du commit Git actuel comme nom du modèle, de sorte que votre version de modèle n’augmente que lorsque vous validez. Pour créer un nouveau LoggedModel pour chaque modification de votre base de code, consultez la fonction d’assistance qui crée un LoggedModel unique pour toute modification de votre base de code, même si elle n’est pas validée dans Git.
Insérez le code suivant en haut de votre application à partir de l’étape 1. Dans votre application, vous devez appeler set_active_model() AVANT d’exécuter le code de votre application .
# Keep original imports
### NEW CODE
import subprocess
# Define your application and its version identifier
app_name = "customer_support_agent"
# Get current git commit hash for versioning
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" # Fallback if not in a git repo
logged_model_name = f"{app_name}-{version_identifier}"
# Set the active model context
active_model_info = mlflow.set_active_model(name=logged_model_name)
print(
f"Active LoggedModel: '{active_model_info.name}', Model ID: '{active_model_info.model_id}'"
)
### END NEW CODE
### ORIGINAL CODE BELOW
### ...
Étape 3 : (facultatif) Enregistrer les parameter
Vous pouvez enregistrer les paramètres de configuration clés qui définissent cette version de votre application directement dans le LoggedModel en utilisant mlflow.log_model_params(). Ceci est utile pour enregistrer des éléments tels que les noms des LLM, les paramètres de température ou les stratégies de récupération qui sont liés à cette version du code.
Ajoutez le code suivant sous le code de l’étape 3 :
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)
Étape 4 : Exécutez l'application
- Appelez l'application pour voir comment le LoggedModel est créé et suivi.
# These 2 invocations will be linked to the same LoggedModel
result = my_app(input="What is MLflow?")
print(result)
result = my_app(input="What is Databricks?")
print(result)
- Pour simuler une modification sans commit, ajoutez les lignes suivantes pour créer manuellement un nouveau modèle enregistré.
# 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)
Étape 5 : Afficher les traces liées au LoggedModel
Utiliser l’interface utilisateur
Accédez à l’interface utilisateur de l’Experimentation MLflow. Dans le Traces tab , vous pouvez voir la version de l’application qui a généré chaque trace (notez que la première trace n’aura pas de version associée, car nous avons appelé l’application sans appeler set_active_model() au préalable). Dans l’onglet Versions , vous pouvez voir chaque LoggedModel ainsi que ses paramètres et les traces associées.

Utiliser le SDK
Vous pouvez utiliser search_traces() pour effectuer une query sur les traces à partir d'un LoggedModel:
import mlflow
traces = mlflow.search_traces(
filter_string=f"metadata.`mlflow.modelId` = '{active_model_info.model_id}'"
)
print(traces)
Vous pouvez utiliser get_logged_model() pour obtenir des détails sur LoggedModel:
import mlflow
import datetime
# Get LoggedModel metadata
logged_model = mlflow.get_logged_model(model_id=active_model_info.model_id)
# Inspect basic properties
print(f"\n=== LoggedModel Information ===")
print(f"Model ID: {logged_model.model_id}")
print(f"Name: {logged_model.name}")
print(f"Experiment ID: {logged_model.experiment_id}")
print(f"Status: {logged_model.status}")
print(f"Model Type: {logged_model.model_type}")
creation_time = datetime.datetime.fromtimestamp(logged_model.creation_timestamp / 1000)
print(f"Created at: {creation_time}")
# Access the parameters
print(f"\n=== Model Parameters ===")
for param_name, param_value in logged_model.params.items():
print(f"{param_name}: {param_value}")
# Access tags if any were set
if logged_model.tags:
print(f"\n=== Model Tags ===")
for tag_key, tag_value in logged_model.tags.items():
print(f"{tag_key}: {tag_value}")
Étape 6 : Link les résultats de l'évaluation au LoggedModel
Pour évaluer votre application et lier les résultats à cette version LoggedModel, consultez Link Evaluation Results and Traces to App Versions. Ce guide explique comment utiliser mlflow.genai.evaluate() pour évaluer les performances de votre application et associer automatiquement les métriques, les tables d'évaluation et les traces à votre version LoggedModel spécifique.
import mlflow
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())
Affichez les résultats dans les onglets Versions et Evaluations de l’interface utilisateur de l’expérience MLflow :

Fonction d’assistance pour compute un hash unique pour toute modification de fichier
La fonction d’assistance ci-dessous génère automatiquement un nom pour chaque LoggedModel en fonction de l’état de votre dépôt. Pour utiliser cette fonction, appelez set_active_model(name=get_current_git_hash()).
get_current_git_hash() génère un identifiant unique et déterministe pour l’état actuel d’un repository Git en renvoyant soit le hash du commit HEAD (pour les repos propres), soit une combinaison du hash HEAD et d’un hash des modifications non validées (pour les repos modifiés). Cela garantit que les différents états du repository produisent toujours des identifiants différents, de sorte que chaque modification de code entraîne un nouveau LoggedModel.
import subprocess
import hashlib
import os
def get_current_git_hash():
"""
Get a deterministic hash representing the current git state.
For clean repositories, returns the HEAD commit hash.
For dirty repositories, returns a combination of HEAD + hash of changes.
"""
try:
# Get the git repository root
result = subprocess.run(
["git", "rev-parse", "--show-toplevel"],
capture_output=True, text=True, check=True
)
git_root = result.stdout.strip()
# Get the current HEAD commit hash
result = subprocess.run(
["git", "rev-parse", "HEAD"], capture_output=True, text=True, check=True
)
head_hash = result.stdout.strip()
# Check if repository is dirty
result = subprocess.run(
["git", "status", "--porcelain"], capture_output=True, text=True, check=True
)
if not result.stdout.strip():
# Repository is clean, return HEAD hash
return head_hash
# Repository is dirty, create deterministic hash of changes
# Collect all types of changes
changes_parts = []
# 1. Get staged changes
result = subprocess.run(
["git", "diff", "--cached"], capture_output=True, text=True, check=True
)
if result.stdout:
changes_parts.append(("STAGED", result.stdout))
# 2. Get unstaged changes to tracked files
result = subprocess.run(
["git", "diff"], capture_output=True, text=True, check=True
)
if result.stdout:
changes_parts.append(("UNSTAGED", result.stdout))
# 3. Get all untracked/modified files from status
result = subprocess.run(
["git", "status", "--porcelain", "-uall"],
capture_output=True, text=True, check=True
)
# Parse status output to handle all file states
status_lines = result.stdout.strip().split('\n') if result.stdout.strip() else []
file_contents = []
for line in status_lines:
if len(line) >= 3:
status_code = line[:2]
filepath = line[3:] # Don't strip - filepath starts exactly at position 3
# For any modified or untracked file, include its current content
if '?' in status_code or 'M' in status_code or 'A' in status_code:
try:
# Use absolute path relative to git root
abs_filepath = os.path.join(git_root, filepath)
with open(abs_filepath, 'rb') as f:
# Read as binary to avoid encoding issues
content = f.read()
# Create a hash of the file content
file_hash = hashlib.sha256(content).hexdigest()
file_contents.append(f"{filepath}:{file_hash}")
except (IOError, OSError):
file_contents.append(f"{filepath}:unreadable")
# Sort file contents for deterministic ordering
file_contents.sort()
# Combine all changes
all_changes_parts = []
# Add diff outputs
for change_type, content in changes_parts:
all_changes_parts.append(f"{change_type}:\n{content}")
# Add file content hashes
if file_contents:
all_changes_parts.append("FILES:\n" + "\n".join(file_contents))
# Create final hash
all_changes = "\n".join(all_changes_parts)
content_to_hash = f"{head_hash}\n{all_changes}"
changes_hash = hashlib.sha256(content_to_hash.encode()).hexdigest()
# Return HEAD hash + first 8 chars of changes hash
return f"{head_hash[:32]}-dirty-{changes_hash[:8]}"
except subprocess.CalledProcessError as e:
raise RuntimeError(f"Git command failed: {e}")
except FileNotFoundError:
raise RuntimeError("Git is not installed or not in PATH")
Étapes suivantes
- Si vous devez regrouper du code avec le
LoggedModel, consultez Package code for Databricks Model Serving.