Aller au contenu principal
Leçon 14 sur 14 · Workflows Mistral — Orchestration Durable

Observabilité et OpenTelemetry

Leçon 14 sur 14 Mis à jour le 2 novembre 2026 Avancé
Sur cette page
  1. Pourquoi observer vos workflows
  2. Nommer les activités pour la lisibilité
  3. Récupérer les traces par programmation
  4. Maîtriser l’échantillonnage
  5. Surveiller en production
  6. Déboguer un workflow échoué
  7. Récapitulatif du cours
  8. Points clés à retenir
  9. Testez vos connaissances

Leçon corrigée le 2 novembre 2026 d’après le code du SDK mistralai 3.7.0 : les méthodes de trace se trouvent sous client.workflows.executions, leur version asynchrone porte le suffixe _async (un await sur la version synchrone échoue), execution_id se passe par mot-clé, et les réponses exposent otel_trace_data, span_tree et events (les champs spans, activity_count ou error_count lus par l’ancienne version n’existent pas) ; le traceparent se passe en paramètre de l’exécution, l’en-tête HTTP étant déprécié. Sources : Workflow observability · client-python.

Pourquoi observer vos workflows

Un workflow en production peut enchaîner des dizaines d’activités, appeler plusieurs services externes, et durer de quelques secondes à plusieurs jours. Sans observabilité, diagnostiquer un problème revient à chercher une aiguille dans une botte de foin : vous savez que l’exécution a échoué, mais ni à quelle étape, ni après combien de tentatives, ni si le coupable est votre code ou une API tierce. La plateforme Workflows de Mistral intègre nativement OpenTelemetry pour répondre à cette question : chaque activité, chaque erreur, chaque durée est enregistrée comme un span dans une trace distribuée, sans instrumentation de votre part.

Deux notions structurent ce modèle. La trace représente l’ensemble du parcours d’une exécution, du déclenchement initial au résultat final. Le span, lui, est une opération individuelle à l’intérieur de cette trace : chaque activité en génère un automatiquement, portant son nom, son heure de début et de fin, sa durée d’exécution, son statut (succès ou erreur) et d’éventuels attributs personnalisés. Ces spans forment une hiérarchie — celui du workflow est le parent, ceux des activités sont ses enfants — qui restitue la structure complète de l’exécution.

Nommer les activités pour la lisibilité

Le paramètre name du décorateur d’activité détermine le libellé qui apparaîtra dans les traces. C’est un investissement de dix secondes à l’écriture qui vous en fera gagner beaucoup en incident.

import mistralai.workflows as workflows

@workflows.activity(name="Extraction du texte source")
async def extraire_texte(url: str) -> dict:
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
    return {"texte": response.text}

@workflows.activity(name="Analyse de sentiment Mistral")
async def analyser_sentiment(texte: str) -> dict:
    client = Mistral()
    response = await client.chat.complete_async(
        model="mistral-large-latest",
        messages=[
            {"role": "system", "content": "Analysez le sentiment."},
            {"role": "user", "content": texte}
        ]
    )
    return {"sentiment": response.choices[0].message.content}

@workflows.activity(name="Envoi de la notification email")
async def envoyer_notification(destinataire: str, contenu: str) -> dict:
    # ...
    return {"status": "envoyé"}

Mettez-vous à la place de la personne d’astreinte qui ouvre une vue de trace à trois heures du matin. Entre fetch_user_data et « Récupération du profil utilisateur », le second est immédiatement compréhensible, y compris par quelqu’un qui n’a jamais lu ce code.

Récupérer les traces par programmation

Le SDK expose trois méthodes d’accès, sous client.workflows.executions ; leur version asynchrone porte le suffixe _async. La première rend les données OpenTelemetry brutes — spans, durées, attributs, relations parent-enfant —, de quoi les réinjecter dans votre propre outil d’observabilité (Jaeger, Grafana Tempo…).

from mistralai.client import Mistral

client = Mistral()

# Données OpenTelemetry brutes de l'exécution
trace = await client.workflows.executions.get_workflow_execution_trace_otel_async(
    execution_id="exec_abc123def456"
)

print(f"Trace OTel : {trace.otel_trace_id}")
donnees_otel = trace.otel_trace_data  # trace complète, à réexporter vers votre backend

Quand vous cherchez surtout à savoir si l’exécution s’est bien passée et combien de temps elle a pris, le résumé suffit. Il porte le statut, la durée totale et l’arbre des spans, que l’on parcourt récursivement :

summary = await client.workflows.executions.get_workflow_execution_trace_summary_async(
    execution_id="exec_abc123def456"
)

print(f"Workflow : {summary.workflow_name} — statut {summary.status}")
print(f"Durée totale : {summary.total_duration_ms} ms")


def afficher(span, profondeur=0):
    fin = span.end_time_unix_nano or span.start_time_unix_nano
    duree_ms = (fin - span.start_time_unix_nano) / 1e6
    print(f"{'  ' * profondeur}{span.name} : {duree_ms:.0f} ms, {len(span.events)} événement(s)")
    for enfant in span.children or []:
        afficher(enfant, profondeur + 1)


if summary.span_tree:
    afficher(summary.span_tree)

La troisième méthode donne la liste chronologique des événements de l’exécution :

reponse = await client.workflows.executions.get_workflow_execution_trace_events_async(
    execution_id="exec_abc123def456",
    include_internal_events=False,  # écarter les événements internes de la plateforme
)

for event in reponse.events or []:
    print(event)

Le paramètre include_internal_events=False écarte les événements techniques de la plateforme pour ne conserver que ceux de votre workflow et de vos activités. Sur un workflow un peu long, la différence de lisibilité est considérable. Pour les journaux eux-mêmes — ceux qu’affiche Studio —, get_workflow_execution_logs les renvoie page par page.

Maîtriser l’échantillonnage

Par défaut, toutes les traces sont exportées : le worker échantillonne à 100 %. Pour fixer l’identifiant de trace ou contrôler l’échantillonnage d’une exécution, passez un traceparent au format W3C dans le corps de la requête d’exécution. Le worker utilise un échantillonneur fondé sur le parent : il suit votre décision, portée par le dernier champ (01 pour collecter, 00 pour ne pas collecter).

execution = await client.workflows.execute_workflow_async(
    workflow_identifier="mon_workflow",
    input={"données": "test"},
    traceparent="00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
)

Les SDK de Mistral le font d’eux-mêmes : à chaque exécution, ils transmettent le traceparent du span courant. Passer traceparent en en-tête HTTP reste accepté mais est déprécié, car un en-tête peut être réécrit en chemin ; utilisez le paramètre.

Surveiller en production

Cinq indicateurs suffisent à tenir un workflow sous contrôle : le taux de succès, c’est-à-dire le pourcentage d’exécutions qui terminent sans erreur ; la durée moyenne d’une exécution complète ; les durées P95 et P99, qui révèlent les exécutions les plus lentes que la moyenne masque ; le taux de retry par activité, dont l’élévation soudaine trahit un service externe instable bien avant que le taux de succès ne se dégrade ; et enfin l’identification de l’activité la plus lente, votre goulot d’étranglement.

Comme les traces respectent le standard OpenTelemetry, rien ne vous oblige à les consulter depuis le SDK : elles s’exportent vers Datadog via son collecteur OTel, vers Grafana et Tempo par le même mécanisme, vers Jaeger pour la visualisation de traces distribuées, ou vers New Relic via son exporteur dédié. Vos workflows rejoignent ainsi le tableau de bord où vit déjà le reste de votre infrastructure.

Déboguer un workflow échoué

Face à un échec, une procédure méthodique évite de partir dans les hypothèses.

  1. Récupérez l’ID d’exécution depuis les logs ou la réponse API
  2. Consultez le résumé de trace pour connaître le statut et repérer l’activité fautive dans l’arbre des spans
  3. Examinez les événements détaillés pour comprendre la séquence qui a mené à l’erreur
  4. Vérifiez les retries : l’activité a-t-elle été relancée ? Combien de fois ?
  5. Analysez le message d’erreur : timeout, erreur réseau, erreur métier ?

Les deux premières étapes se scriptent en quelques lignes, avec la fonction afficher vue plus haut, ce qui vous donne un outil de diagnostic réutilisable.

async def diagnostiquer_echec(execution_id: str):
    client = Mistral()
    executions = client.workflows.executions

    # Étape 1 : résumé et arbre des spans
    summary = await executions.get_workflow_execution_trace_summary_async(execution_id=execution_id)
    print(f"Statut : {summary.status}")
    if summary.span_tree:
        afficher(summary.span_tree)

    # Étape 2 : événements de votre code, dans l'ordre
    reponse = await executions.get_workflow_execution_trace_events_async(
        execution_id=execution_id,
        include_internal_events=False,
    )
    for event in reponse.events or []:
        print(event)

Le nombre de tentatives mérite une attention particulière : une activité qui échoue à la première tentative et une activité qui échoue après cinq retries ne racontent pas la même histoire, et n’appellent pas la même correction.

Récapitulatif du cours

Félicitations, vous avez terminé ce cours sur les Workflows Mistral. Le parcours vous a mené de l’orchestration durable et du mécanisme d’event sourcing jusqu’à l’installation du SDK (leçons 1 à 3), puis à la création d’activités, de workflows et de workers, à leur déclenchement et à leur test (leçons 4 à 7). Les leçons 8 à 11 ont posé les contraintes structurantes — déterminisme, inputs Pydantic, timeouts, limitations — avant d’ouvrir sur les patterns avancés de parallélisme et de continuation. Les trois dernières ont couvert les politiques de retry, l’obligation d’async I/O et l’observabilité avec OpenTelemetry.

La plateforme est en Public Preview : les APIs et fonctionnalités peuvent évoluer. Consultez régulièrement la documentation officielle sur docs.mistral.ai/workflows pour suivre les mises à jour.

Points clés à retenir

  • Chaque activité génère automatiquement des spans OpenTelemetry avec nom, durée et statut
  • Nommez vos activités avec le paramètre name pour faciliter le débogage
  • Trois méthodes d’accès aux traces, sous client.workflows.executions : OTel brut, résumé (statut, durée, arbre des spans) et événements détaillés
  • L’échantillonnage se contrôle par le paramètre traceparent de l’exécution (100 % par défaut ; l’en-tête HTTP est déprécié)
  • En production, surveillez le taux de succès, la durée et le taux de retry
  • Les traces OTel standard sont exportables vers Datadog, Grafana, Jaeger ou New Relic

Testez vos connaissances

Workflows durables : les règles du moteur avant la production.

1. Que garantit la plateforme Workflows de Mistral ?

Réponse : La durabilité : un workflow survit aux pannes et reprend où il en était — l’orchestration longue durée devient fiable par construction.

2. Activité, workflow, worker : qui fait quoi ?

Réponse : L’activité est l’unité de travail (appel externe, calcul), le workflow orchestre les activités, le worker exécute — la séparation qui permet reprise et scaling.

3. Qu'impose la règle de déterminisme ?

Réponse : Le code du workflow doit être rejouable à l’identique : pas d’aléatoire ni d’horloge directe dans l’orchestration — les effets non déterministes vivent dans les activités.

4. Comment gère-t-on les échecs transitoires ?

Réponse : Par la politique de retry des activités (tentatives, backoff) et les timeouts — l’échec est un cas normal, géré déclarativement plutôt qu’à la main.

5. Qu'apporte l'intégration OpenTelemetry ?

Réponse : L’observabilité standard : traces des exécutions, métriques et corrélation avec le reste de votre système — indispensable pour exploiter des workflows en production.

Durabilité, déterminisme, retry, observabilité : quatre règles qui font tenir les orchestrations longues — le moteur s’occupe du reste.