Définir des schémas avec Pydantic
Mis à jour le 29 juillet 2026
Pydantic : le socle des Custom Structured Outputs en Python
Pydantic est la bibliothèque de validation de données la plus populaire en Python. Elle permet de définir des modèles de données avec des types stricts, et c’est exactement ce que l’API Mistral utilise pour les Custom Structured Outputs. Si vous travaillez en Python, Pydantic devient donc votre outil principal pour décrire les schémas de sortie : ce que vous écrivez dans une classe est ce que le modèle sera contraint de produire.
Bonne nouvelle pour l’installation : Pydantic est inclus comme dépendance du SDK Mistral. Si mistralai est déjà installé, vous n’avez rien à faire de plus.
pip install mistralai
# Pydantic v2 est inclus automatiquement
Une vérification rapide de la version évite les surprises, car la syntaxe des validateurs a changé entre les versions majeures :
import pydantic
print(pydantic.__version__) # 2.x requis
Définir un modèle simple
Un modèle Pydantic est une classe qui hérite de BaseModel, dans laquelle chaque attribut est un champ avec un type explicite.
from pydantic import BaseModel
class Contact(BaseModel):
name: str
email: str
phone: str
company: str
Ce modèle dit à Mistral : « ta sortie doit être un objet JSON avec exactement ces 4 champs, tous de type string. » Aucune instruction supplémentaire n’est nécessaire dans le prompt pour obtenir cette structure.
Les types que vous utiliserez
Pydantic supporte tous les types Python standards, et Mistral les comprend tous. Le modèle suivant les rassemble dans un cas réaliste — l’analyse d’un ticket de support — et montre comment ils se combinent : types de base pour les champs simples, Optional pour un assigné pas encore désigné, Enum pour une priorité qui ne peut prendre que quatre valeurs, listes pour les tags et les identifiants liés.
from pydantic import BaseModel
from typing import Optional
from enum import Enum
class Priority(str, Enum):
low = "low"
medium = "medium"
high = "high"
critical = "critical"
class TicketAnalysis(BaseModel):
# Types de base
title: str
description: str
ticket_id: int
confidence: float
is_urgent: bool
# Types optionnels
assignee: Optional[str] = None
# Enums (valeurs contraintes)
priority: Priority
# Listes
tags: list[str]
related_ids: list[int]
Voici le mémo correspondant :
| Type | Signification |
|---|---|
str | chaîne de caractères |
int | nombre entier |
float | nombre décimal |
bool | booléen (true/false) |
list[T] | liste d’éléments de type T |
Optional[T] | champ pouvant être null |
Enum | valeur parmi un ensemble fini |
L’enum mérite une mention particulière : c’est le seul moyen de garantir qu’une priorité ne vaudra jamais "très urgent" ou "P1" selon l’humeur du modèle.
Modèles imbriqués
Les données réelles sont rarement plates. Un contact appartient à une entreprise, qui possède une adresse. Pydantic laisse imbriquer les modèles autant que nécessaire, et Mistral suit la hiérarchie.
from pydantic import BaseModel
from typing import Optional
class Address(BaseModel):
street: str
city: str
postal_code: str
country: str
class Company(BaseModel):
name: str
industry: str
address: Address # Modèle imbriqué
class Person(BaseModel):
first_name: str
last_name: str
email: str
role: str
company: Company # Imbrication à deux niveaux
Le JSON produit reproduit exactement cette arborescence :
{
"first_name": "Marie",
"last_name": "Dupont",
"email": "[email protected]",
"role": "Directrice commerciale",
"company": {
"name": "TechVision SAS",
"industry": "Technologie",
"address": {
"street": "42 rue de la Paix",
"city": "Paris",
"postal_code": "75002",
"country": "France"
}
}
}
Le même mécanisme sert à extraire plusieurs éléments d’un coup : un modèle enveloppe une liste d’un autre modèle, et vous récupérez un catalogue complet en un appel.
from pydantic import BaseModel
class Product(BaseModel):
name: str
price: float
category: str
in_stock: bool
class Catalog(BaseModel):
products: list[Product]
total_count: int
Guider le modèle avec les descriptions
Le nom d’un champ ne dit pas tout. score peut désigner une note sur 10, un pourcentage ou une valeur entre 0 et 1 — le modèle doit deviner. Les descriptions lèvent cette ambiguïté : elles sont incluses dans le schéma JSON envoyé à Mistral et agissent comme des instructions par champ.
from pydantic import BaseModel, Field
class SentimentAnalysis(BaseModel):
sentiment: str = Field(
description="Le sentiment global : 'positif', 'négatif' ou 'neutre'"
)
score: float = Field(
description="Score de confiance entre 0.0 et 1.0"
)
keywords: list[str] = Field(
description="Les 3-5 mots-clés principaux du texte"
)
summary: str = Field(
description="Résumé en une phrase maximum"
)
Plus ces descriptions sont précises, meilleure sera la qualité de la sortie. C’est le levier le plus rentable de tout le dispositif : quelques mots bien choisis remplacent souvent un paragraphe entier de prompt.
Field sert aussi à poser des valeurs par défaut. Dans l’exemple suivant, la langue vaut "fr" si le modèle ne trouve pas l’information, le nombre de mots reste None s’il n’est pas déterminable, et les tags partent d’une liste vide grâce à default_factory.
from pydantic import BaseModel, Field
from typing import Optional
class ArticleMetadata(BaseModel):
title: str
author: str
language: str = Field(default="fr", description="Code langue ISO 639-1")
word_count: Optional[int] = None
tags: list[str] = Field(default_factory=list)
Les champs avec des valeurs par défaut seront remplis par le modèle s’il trouve l’information, ou laisseront la valeur par défaut sinon.
La validation ne se demande pas
Dernier avantage, et non le moindre : la validation est automatique. Si une valeur ne correspond pas au type déclaré, Pydantic lève immédiatement une ValidationError en indiquant précisément le champ fautif, sans que vous ayez écrit une seule ligne de contrôle.
from pydantic import ValidationError
try:
analysis = SentimentAnalysis(
sentiment="positif",
score="pas un nombre", # Erreur de type
keywords=["test"],
summary="Résumé"
)
except ValidationError as e:
print(e)
# 1 validation error for SentimentAnalysis
# score
# Input should be a valid number [type=float_parsing, ...]
Tout le code de vérification écrit à la main dans la leçon précédente disparaît ici, remplacé par la déclaration du modèle.
Points clés à retenir
- Pydantic
BaseModelest la base de tous les schémas Custom en Python - Utilisez des types explicites :
str,int,float,bool,list[T],Optional[T] - Les modèles imbriqués permettent des structures JSON complexes
Field(description=...)améliore la qualité de la sortie en guidant le modèle- La validation est automatique — les erreurs de type sont détectées immédiatement