Observabilité et OpenTelemetry
Mis à jour le 29 juillet 2026
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. La première rend les données OpenTelemetry complètes, utile pour parcourir tous les spans ou les réexporter.
from mistralai import Mistral
client = Mistral()
# Récupérer les données OTel complètes
trace = await client.get_workflow_execution_trace_otel(
execution_id="exec_abc123def456"
)
# La trace contient tous les spans au format OTel standard
for span in trace.spans:
print(f"Activité : {span.name}")
print(f"Durée : {span.duration_ms} ms")
print(f"Statut : {span.status}")
print()
Quand vous cherchez seulement à savoir si l’exécution s’est bien passée et combien de temps elle a pris, le résumé suffit et évite de manipuler le détail.
summary = await client.get_workflow_execution_trace_summary(
execution_id="exec_abc123def456"
)
print(f"Workflow : {summary.workflow_name}")
print(f"Durée totale : {summary.total_duration_ms} ms")
print(f"Nombre d'activités : {summary.activity_count}")
print(f"Erreurs : {summary.error_count}")
La troisième méthode donne accès aux événements individuels, avec un filtrage fin.
events = await client.get_workflow_execution_trace_events(
execution_id="exec_abc123def456",
include_internal_events=False # Exclure les événements internes de la plateforme
)
for event in events:
print(f"Type : {event.type}")
print(f"Timestamp : {event.timestamp}")
print(f"Données : {event.data}")
print()
Le paramètre include_internal_events=False écarte les événements techniques de la plateforme — scheduling, replay — pour ne conserver que les événements métier : démarrages et fins d’activité, erreurs. Sur un workflow un peu long, la différence de lisibilité est considérable.
Maîtriser le volume avec l’échantillonnage
En production, collecter 100 % des traces peut générer un volume de données important, et donc un coût de stockage proportionnel. La plateforme supporte l’échantillonnage par parent (parent-based sampling), piloté par le header traceparent transmis lors du déclenchement du workflow. Si le flag de sampling y est activé, la trace est collectée ; sinon, elle est ignorée.
Pour diagnostiquer un problème sur une exécution précise, forcez la collecte avec le flag 01.
execution = await client.workflows.execute_workflow_async(
workflow_identifier="mon_workflow",
input={"données": "test"},
# Le flag "01" dans le traceparent active le sampling
headers={"traceparent": "00-trace_id-span_id-01"}
)
Inversement, sur des exécutions de routine dont vous n’avez rien à apprendre, le flag 00 désactive la collecte.
# Le flag "00" désactive le sampling
headers={"traceparent": "00-trace_id-span_id-00"}
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.
- Récupérez l’ID d’exécution depuis les logs ou la réponse API
- Consultez le résumé de trace pour identifier l’activité en erreur
- Examinez les événements détaillés pour comprendre la séquence qui a mené à l’erreur
- Vérifiez les retries : l’activité a-t-elle été retried ? Combien de fois ?
- Analysez le message d’erreur : timeout, erreur réseau, erreur métier ?
Ces étapes se scriptent en quelques lignes, ce qui vous donne un outil de diagnostic réutilisable.
async def diagnostiquer_echec(execution_id: str):
client = Mistral()
# Étape 1 : Résumé
summary = await client.get_workflow_execution_trace_summary(execution_id)
print(f"Statut : {summary.status}")
print(f"Erreurs : {summary.error_count}")
# Étape 2 : Événements détaillés
events = await client.get_workflow_execution_trace_events(
execution_id,
include_internal_events=False
)
for event in events:
if event.type == "activity_failed":
print(f"Activité échouée : {event.data['activity_name']}")
print(f"Erreur : {event.data['error_message']}")
print(f"Tentative : {event.data['attempt']}")
Le champ attempt 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
namepour faciliter le débogage - Trois méthodes d’accès aux traces : OTel brut, résumé et événements détaillés
- L’échantillonnage est contrôlé par le header
traceparentlors du déclenchement - 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.