Trackio documentation

Exécuter des expériences ML avec des agents

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Exécuter des expériences ML avec des agents

Trackio est conçu dès le départ pour prendre en charge l’expérimentation ML autonome pilotée par des agents LLM. Ce guide explique comment structurer votre code d’entraînement, configurer les alertes et mettre en place la boucle de rétroaction afin qu’un agent puisse lancer des expériences, les surveiller, réagir aux problèmes et itérer sur les hyperparamètres — le tout sans intervention humaine.

Pourquoi Trackio pour les agents ?

La plupart des outils de suivi d’expériences supposent qu’un humain surveille un tableau de bord. Trackio offre aux agents un accès programmatique de premier ordre via plusieurs canaux :

  • CLI avec sortie JSON — chaque commande trackio prend en charge --json, ce qui facilite son analyse dans n’importe quel langage
  • API Python — trackio.Api() fournit un accès direct aux exécutions, aux métriques et aux alertes
  • API HTTP / MCP — le tableau de bord Trackio expose des points de terminaison d'API Gradio et peut fonctionner en tant que serveur MCP, permettant aux LLM d'appeler directement des outils
  • Alertes avec des webhooks — les agents peuvent insérer des appels trackio.alert() comme des instructions d’affichage et les interroger ultérieurement
  • since filtering — interrogation efficace des nouvelles alertes sans relire l'historique complet

La boucle de rétroaction de l'agent

Une boucle d'expérimentation autonome typique ressemble à ceci :

┌─────────────────────────────────────┐
│  1. Agent writes training script    │
│     with trackio.init(), log(),     │
│     and alert() calls               │
├─────────────────────────────────────┤
│  2. Agent launches the script       │
├─────────────────────────────────────┤
│  3. Agent polls for alerts and      │
│     metrics while training runs     │
├─────────────────────────────────────┤
│  4. Agent reads results, decides    │
│     next hyperparameters            │
├─────────────────────────────────────┤
│  5. Agent writes a new script       │
│     and repeats from step 1         │
└─────────────────────────────────────┘

Le reste de ce guide détaille chaque étape avec du code concret.

Étape 1 : Structurer le code d’entraînement pour les agents

L’idée clé est qu’un agent peut insérer des appels trackio.alert() de la même manière qu’il insérerait des instructions print() pour le débogage. Les alertes sont plus structurées que les instructions print : elles disposent d’un titre, d’une description facultative, d’un niveau de gravité, et sont automatiquement persistées et interrogeables.

Voici un script d’entraînement rédigé comme le ferait un agent, avec des alertes à chaque point de décision :

import trackio
import torch

trackio.init(
    project="cifar10-hparam-search",
    name="run-lr0.001-bs64",
    config={
        "learning_rate": 0.001,
        "batch_size": 64,
        "optimizer": "adamw",
        "epochs": 50,
        "weight_decay": 1e-4,
    },
)

model = build_model()
optimizer = torch.optim.AdamW(
    model.parameters(), lr=0.001, weight_decay=1e-4
)

best_val_loss = float("inf")
patience_counter = 0
patience_limit = 5

for epoch in range(50):
    train_loss = train_one_epoch(model, train_loader, optimizer)
    val_loss, val_acc = evaluate(model, val_loader)

    trackio.log({
        "train_loss": train_loss,
        "val_loss": val_loss,
        "val_accuracy": val_acc,
        "learning_rate": optimizer.param_groups[0]["lr"],
    })

    # Alert on loss divergence
    if train_loss > 10.0:
        trackio.alert(
            title="Training diverged",
            text=f"train_loss={train_loss:.4f} at epoch {epoch}. "
                 "Learning rate is likely too high.",
            level=trackio.AlertLevel.ERROR,
        )
        break

    # Alert when validation stops improving
    if val_loss < best_val_loss:
        best_val_loss = val_loss
        patience_counter = 0
        torch.save(model.state_dict(), "best_model.pt")
    else:
        patience_counter += 1
        if patience_counter >= patience_limit:
            trackio.alert(
                title="Early stopping triggered",
                text=f"No improvement for {patience_limit} epochs. "
                     f"Best val_loss={best_val_loss:.4f} at epoch "
                     f"{epoch - patience_limit}.",
                level=trackio.AlertLevel.WARN,
            )
            break

    # Alert on overfitting
    if epoch > 10 and (train_loss < 0.1 and val_loss > 1.5):
        trackio.alert(
            title="Overfitting detected",
            text=f"train_loss={train_loss:.4f} vs val_loss={val_loss:.4f}. "
                 "Consider adding regularization or reducing model capacity.",
            level=trackio.AlertLevel.WARN,
        )

    # Alert on good results
    if val_acc > 0.93:
        trackio.alert(
            title="High accuracy reached",
            text=f"val_accuracy={val_acc:.4f} at epoch {epoch}.",
            level=trackio.AlertLevel.INFO,
        )

trackio.alert(
    title="Training complete",
    text=f"Final val_loss={val_loss:.4f}, val_accuracy={val_acc:.4f}. "
         f"Best val_loss={best_val_loss:.4f}.",
    level=trackio.AlertLevel.INFO,
)
trackio.finish()

Les alertes ici ne s'adressent pas uniquement aux humains — ce sont des signaux structurés que l'agent lira plus tard pour décider de la suite à donner.

Lignes directrices pour des alertes adaptées aux agents

  • Utilisez ERROR pour les conditions qui doivent arrêter l'exécution (divergence, perte NaN, mémoire insuffisante).
  • Utilisez WARN pour les conditions suggérant que les hyperparamètres doivent être modifiés (surapprentissage, arrêt anticipé, convergence lente).
  • Utilisez INFO pour les jalons (entraînement terminé, précision élevée atteinte, point de contrôle enregistré).
  • Inclure des valeurs numériques dans text afin que l'agent puisse les analyser et en tirer des conclusions.
  • Inclure des suggestions actionnables dans text (par exemple, « Le taux d’apprentissage est probablement trop élevé ») pour aider l’agent à décider quoi modifier.

Étape 2 : Lancement du script

L'agent peut lancer le script dans un sous-processus ou un processus en arrière-plan. Dans la plupart des frameworks d'agents, cela revient simplement à exécuter une commande shell :

python train.py

Si l’agent utilise un LLM connecté à MCP, il peut également lancer des scripts via un outil shell.

Étape 3 : Surveillance pendant l’entraînement

Pendant l’exécution de l’entraînement, l’agent interroge les alertes et les métriques. L’indicateur --since rend cette opération efficace : seules les nouvelles alertes depuis la dernière vérification sont renvoyées.

Interrogation via CLI

# First poll — get all alerts
trackio get alerts --project "cifar10-hparam-search" --run "run-lr0.001-bs64" --json

# Subsequent polls — only new alerts
trackio get alerts --project "cifar10-hparam-search" --since "2025-06-15T14:30:00" --json

Interrogation via l'API Python

import trackio
from datetime import datetime, timezone

api = trackio.Api()
last_check = None

while training_is_running():
    alerts = api.alerts(
        "cifar10-hparam-search",
        run="run-lr0.001-bs64",
        since=last_check,
    )
    if alerts:
        last_check = alerts[0]["timestamp"]  # alerts are sorted newest-first
        for a in alerts:
            print(f"[{a['level'].upper()}] {a['title']}: {a['text']}")

            if a["level"] == "error":
                # Stop the run and re-plan
                handle_error(a)

    time.sleep(30)

Interrogation via MCP

Si le tableau de bord Trackio fonctionne en tant que serveur MCP, l’agent peut appeler directement l’outil get_alerts via le protocole MCP. Consultez Trackio en tant qu’API et serveur MCP pour les instructions de configuration.

Étape 4 : Lecture des résultats et décision des prochaines étapes

Une fois l’exécution terminée, l’agent lit les résultats complets :

# Get run summary (metrics, config, step count)
trackio get run --project "cifar10-hparam-search" --run "run-lr0.001-bs64" --json

# Get the loss curve
trackio get metric --project "cifar10-hparam-search" --run "run-lr0.001-bs64" --metric "val_loss" --json

# Get all alerts (the most useful signal for decision-making)
trackio get alerts --project "cifar10-hparam-search" --run "run-lr0.001-bs64" --json

Les alertes fournissent un résumé concis de ce qui s’est produit pendant l’entraînement. Au lieu d’analyser des milliers de valeurs de métriques, l’agent peut lire quelques alertes pour comprendre :

  • La formation a-t-elle divergé ? → Baissez le taux d'apprentissage
  • A-t-il sur-apprendu ? → Ajoutez de la régularisation ou réduisez la capacité
  • A-t-il effectué un arrêt anticipé ? → Les hyperparamètres sont dans la bonne fourchette mais pourraient nécessiter un réglage
  • A-t-il atteint une haute précision ? → Cette configuration fonctionne bien

Étape 5 : Itération sur les hyperparamètres

L'agent utilise les alertes de l'exécution précédente pour choisir de nouveaux hyperparamètres. Voici un exemple concret de la logique de décision qu'un agent pourrait suivre :

import json
import subprocess
import trackio

api = trackio.Api()

# Read alerts from the last run
alerts = api.alerts("cifar10-hparam-search", run="run-lr0.001-bs64")

# Read the config from the last run
runs = api.runs("cifar10-hparam-search")
last_run = [r for r in runs if r.name == "run-lr0.001-bs64"][0]
config = last_run.config

# Decision logic based on alerts
new_config = dict(config)
for alert in alerts:
    if "diverged" in alert["title"].lower():
        new_config["learning_rate"] = config["learning_rate"] * 0.1
    elif "overfitting" in alert["title"].lower():
        new_config["weight_decay"] = config.get("weight_decay", 1e-4) * 10
    elif "early stopping" in alert["title"].lower():
        new_config["learning_rate"] = config["learning_rate"] * 0.5
    elif "high accuracy" in alert["title"].lower():
        # This config is good — try fine-tuning
        new_config["learning_rate"] = config["learning_rate"] * 0.5
        new_config["epochs"] = config["epochs"] + 20

L'agent génère ensuite un nouveau script d'entraînement avec la configuration mise à jour et le lance, en répétant la boucle.

Comparaison des exécutions

Après plusieurs itérations, l’agent peut comparer toutes les exécutions du projet :

# List all runs
trackio list runs --project "cifar10-hparam-search" --json

# Get a summary of each run
trackio get run --project "cifar10-hparam-search" --run "run-lr0.001-bs64" --json
trackio get run --project "cifar10-hparam-search" --run "run-lr0.0001-bs64" --json

En Python :

api = trackio.Api()
runs = api.runs("cifar10-hparam-search")

for run in runs:
    alerts = run.alerts()
    errors = [a for a in alerts if a["level"] == "error"]
    warns = [a for a in alerts if a["level"] == "warn"]
    infos = [a for a in alerts if a["level"] == "info"]
    print(f"{run.name}: {len(errors)} errors, {len(warns)} warnings, {len(infos)} info")

Envoi d'alertes à l'agent via des Webhooks

Si votre framework d’agent dispose d’un point de terminaison HTTP ou peut recevoir des messages de Slack/Discord, vous pouvez utiliser des webhooks pour envoyer des alertes à l’agent en temps réel au lieu de faire du polling :

trackio.init(
    project="cifar10-hparam-search",
    webhook_url="https://hooks.slack.com/services/T.../B.../xxx",
)

De cette manière, les alertes sont acheminées vers un canal Slack surveillé par l’agent, fermant ainsi la boucle sans aucun mécanisme de sonde. Consultez le guide des alertes pour des instructions détaillées de configuration pour Slack et Discord.

Exemple complet : Recherche autonome d’hyperparamètres

Voici un exemple complet et autonome qui rassemble l’ensemble. Ce script exécute une simple recherche de grille d’hyperparamètres avec des décisions automatisées basées sur des alertes :

import trackio
import random
import time

def run_experiment(config):
    """Simulate a training run. Replace with real training code."""
    run = trackio.init(
        project="auto-hparam-search",
        config=config,
    )

    lr = config["learning_rate"]
    best_val_loss = float("inf")
    patience = 0

    for epoch in range(config["epochs"]):
        # Simulated metrics — replace with real training
        noise = random.gauss(0, lr * 10)
        train_loss = max(0.01, 1.0 / (epoch + 1) + noise)
        val_loss = train_loss + random.uniform(0, 0.3)
        val_acc = max(0, min(1, 1.0 - val_loss + random.uniform(-0.05, 0.05)))

        trackio.log({
            "train_loss": train_loss,
            "val_loss": val_loss,
            "val_accuracy": val_acc,
        })

        if train_loss > 5.0:
            trackio.alert(
                title="Training diverged",
                text=f"train_loss={train_loss:.4f}, lr={lr}",
                level=trackio.AlertLevel.ERROR,
            )
            break

        if val_loss < best_val_loss:
            best_val_loss = val_loss
            patience = 0
        else:
            patience += 1
            if patience >= 5:
                trackio.alert(
                    title="Early stopping",
                    text=f"Best val_loss={best_val_loss:.4f}",
                    level=trackio.AlertLevel.WARN,
                )
                break

        time.sleep(0.05)

    trackio.alert(
        title="Run complete",
        text=f"Final val_loss={val_loss:.4f}, val_acc={val_acc:.4f}, "
             f"best_val_loss={best_val_loss:.4f}",
        level=trackio.AlertLevel.INFO,
    )
    trackio.finish()
    return run.name


def analyze_and_decide(api, project, run_name, config):
    """Read alerts from a run and suggest new hyperparameters."""
    alerts = api.alerts(project, run=run_name)

    new_config = dict(config)
    for alert in alerts:
        title = alert["title"].lower()
        if "diverged" in title:
            new_config["learning_rate"] *= 0.1
        elif "early stopping" in title:
            new_config["learning_rate"] *= 0.5
        elif "run complete" in title and "val_acc" in (alert.get("text") or ""):
            # Slight refinement
            new_config["learning_rate"] *= 0.8
            new_config["epochs"] += 10

    return new_config


api = trackio.Api()
project = "auto-hparam-search"

config = {
    "learning_rate": 0.01,
    "batch_size": 64,
    "epochs": 30,
}

for iteration in range(5):
    print(f"\n--- Iteration {iteration + 1} ---")
    print(f"Config: {config}")

    run_name = run_experiment(config)
    config = analyze_and_decide(api, project, run_name, config)

Cet exemple est autonome et utilise des métriques simulées. Remplacez le corps de la fonction run_experiment par votre code d’entraînement réel et le schéma reste le même.

Utiliser les alertes avec Transformers et TRL

Lors de l’utilisation de report_to="trackio" avec le Trainer de Hugging Face, le TrackioCallback intégré gère automatiquement trackio.init(), trackio.log() et trackio.finish(). Étant donné que trackio.init() est appelé avant le début de l’entraînement, l’exécution en cours est définie et trackio.alert() fonctionne depuis n’importe quel autre callback du même processus.

Pour ajouter des alertes, écrivez un petit TrainerCallback et passez-le au Trainer via callbacks= :

Transformers

import trackio
from transformers import Trainer, TrainerCallback, TrainingArguments

class AlertCallback(TrainerCallback):
    def on_log(self, args, state, control, logs=None, **kwargs):
        if "trackio" not in args.report_to or logs is None:
            return
        loss = logs.get("loss")
        if loss is not None and loss > 5.0:
            trackio.alert(
                title="Training loss spike",
                text=f"loss={loss:.4f} at step {state.global_step}. "
                     "Consider lowering the learning rate.",
                level=trackio.AlertLevel.ERROR,
            )

    def on_evaluate(self, args, state, control, metrics=None, **kwargs):
        if "trackio" not in args.report_to or metrics is None:
            return
        eval_loss = metrics.get("eval_loss")
        if eval_loss is not None and eval_loss > 2.0:
            trackio.alert(
                title="High eval loss",
                text=f"eval_loss={eval_loss:.4f} at step {state.global_step}.",
                level=trackio.AlertLevel.WARN,
            )

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        report_to="trackio",
        project="my-project",
        output_dir="./output",
        num_train_epochs=3,
        eval_strategy="steps",
        eval_steps=100,
    ),
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    callbacks=[AlertCallback()],
)
trainer.train()

Un agent générant ce code n'a besoin que de définir la classe AlertCallback avec les bonnes conditions, puis de l'ajouter à la liste callbacks. Le schéma est le même quel que soit le modèle ou le jeu de données.

TRL

La même approche fonctionne avec les formateurs TRL tels que GRPOTrainer ou SFTTrainer. Voici un exemple pour l'apprentissage par renforcement avec des alertes sur l'effondrement de la récompense et la divergence KL :

import trackio
from transformers import TrainerCallback

class RLAlertCallback(TrainerCallback):
    def on_log(self, args, state, control, logs=None, **kwargs):
        if "trackio" not in args.report_to or logs is None:
            return

        reward = logs.get("train/reward")
        if reward is not None and reward < -1.0:
            trackio.alert(
                title="Reward collapse",
                text=f"reward={reward:.4f} at step {state.global_step}. "
                     "Consider lowering the learning rate or checking the "
                     "reward model.",
                level=trackio.AlertLevel.ERROR,
            )

        kl = logs.get("train/kl")
        if kl is not None and kl > 10.0:
            trackio.alert(
                title="KL divergence too high",
                text=f"kl={kl:.4f} at step {state.global_step}. "
                     "The policy is drifting too far from the reference model.",
                level=trackio.AlertLevel.WARN,
            )

        completion_length = logs.get("train/completion_length")
        if completion_length is not None and completion_length < 5.0:
            trackio.alert(
                title="Completions too short",
                text=f"Mean completion length={completion_length:.1f} tokens. "
                     "The model may be collapsing to short outputs.",
                level=trackio.AlertLevel.WARN,
            )

Passez-le ensuite à n'importe quel formateur TRL :

from trl import GRPOTrainer, GRPOConfig

trainer = GRPOTrainer(
    model=model,
    config=GRPOConfig(
        report_to="trackio",
        project="rl-experiment",
        output_dir="./output",
    ),
    train_dataset=dataset,
    callbacks=[RLAlertCallback()],
)
trainer.train()

Conseils pour les agents rédigeant des callbacks d'alerte

  • Gardez les conditions simples. Chaque bloc if doit vérifier une seule métrique par rapport à un seul seuil. Cela permet à un agent d’ajouter, de supprimer ou d’ajuster facilement des conditions entre les exécutions.
  • Incluez la valeur de la métrique et l'étape dans text. Cela fournit à l'agent des chiffres concrets sur lesquels raisonner lors du choix des hyperparamètres suivants.
  • Incluez des suggestions actionnables. Des formulations comme « Pensez à réduire le taux d’apprentissage » aident l’agent à décider de la modification à apporter ensuite.
  • Utilisez on_evaluate pour les métriques d'évaluation. Les métriques d'évaluation ne sont disponibles que dans on_evaluate, et non dans on_log. Les métriques d'entraînement comme loss apparaissent dans on_log.

Résumé des bonnes pratiques

  1. Utilisez les alertes comme des signaux structurés, et non comme de simples notifications. Incluez des valeurs numériques et des suggestions actionnables dans text afin que l’agent puisse les analyser et y réagir.

  2. Utilisez les niveaux de gravité de manière cohérente. ERROR = arrêtez-vous et changez d'approche. WARN = ajustez les paramètres. INFO = jalon atteint.

  3. Effectuez des requêtes avec since pour plus d’efficacité. Enregistrez l’horodatage de la dernière alerte traitée et transmettez-le en tant que since lors de la requête suivante afin d’éviter de relire les anciennes alertes.

  4. Conservez toutes les exécutions dans le même projet. Cela permet à l'agent de comparer les exécutions côte à côte et de consulter l'historique complet de ce qui a été essayé.

  5. Journaliser la configuration à chaque exécution. Passez toujours config= à trackio.init() afin que l’agent puisse relire quels hyperparamètres ont produit quels résultats.

  6. Utilisez l’interface en ligne de commande avec --json pour les scripts d’agents. La sortie JSON est fiable à analyser et ne sera pas altérée si le format lisible par l’humain change.

  7. Envisagez MCP pour une intégration étroite. Si votre framework d’agents prend en charge MCP, l’exécution de trackio show --mcp-server permet à l’agent d’appeler directement les outils Trackio sans générer de sous-processus.

Update on GitHub