Pydantic BaseModel en profondeur
Pydantic : le compagnon idéal
Pydantic est la bibliothèque Python de référence pour la validation de données. Avec les sorties structurées de Grok, elle devient un outil indispensable : vous définissez vos schémas comme des classes Python, et le modèle remplit ces classes automatiquement.
Bases de Pydantic pour les structured outputs
Un modèle Pydantic se crée en héritant de BaseModel. Chaque attribut avec une annotation de type devient un champ du schéma JSON :
from pydantic import BaseModel
class Produit(BaseModel):
nom: str
prix: float
en_stock: bool
categorie: str
Ce modèle génère automatiquement le schéma JSON équivalent. Vous n’avez rien d’autre à écrire.
Types Python supportés
Voici la correspondance entre les types Python et les types JSON Schema :
class ExempleComplet(BaseModel):
# Scalaires
texte: str # → "type": "string"
nombre: float # → "type": "number"
entier: int # → "type": "number"
actif: bool # → "type": "boolean"
# Optionnels
note: str | None # → anyOf string/null
# Collections
tags: list[str] # → array de strings
scores: list[float] # → array de numbers
# Énumérations
niveau: str # + enum dans le Field
Modèles imbriqués
La véritable puissance de Pydantic réside dans l’imbrication des modèles :
class Adresse(BaseModel):
rue: str
ville: str
code_postal: str
pays: str
class Competence(BaseModel):
nom: str
niveau: str # "debutant", "intermediaire", "expert"
annees: int
class Candidat(BaseModel):
prenom: str
nom: str
email: str
adresse: Adresse
competences: list[Competence]
disponible: bool
pretention_salariale: float | None
Quand vous passez Candidat comme response_format, le modèle remplira toute la hiérarchie : l’adresse complète, chaque compétence avec ses détails, etc.
Enum avec Pydantic
Pour forcer des valeurs prédéfinies, utilisez Literal de Python :
from typing import Literal
class Ticket(BaseModel):
titre: str
description: str
priorite: Literal["basse", "moyenne", "haute", "critique"]
statut: Literal["ouvert", "en_cours", "resolu", "ferme"]
type: Literal["bug", "feature", "documentation"]
Le modèle ne pourra retourner que les valeurs listées. Toute autre valeur est impossible.
Utilisation avec parse()
response, ticket = client.chat.parse(
model="grok-4.20-reasoning",
messages=[{
"role": "user",
"content": "Le bouton de connexion ne fonctionne pas sur mobile"
}],
response_format=Ticket
)
print(ticket.priorite) # "haute"
print(ticket.type) # "bug"
print(ticket.statut) # "ouvert"
Utilisation avec response_format
response = client.chat.create(
model="grok-4.20-reasoning",
messages=[{
"role": "user",
"content": "Le bouton de connexion ne fonctionne pas sur mobile"
}],
response_format=Ticket
)
ticket = Ticket.model_validate_json(
response.choices[0].message.content
)
Valeurs par défaut et documentation
Vous pouvez ajouter des descriptions à vos champs avec Field. Ces descriptions aident le modèle à mieux comprendre ce que vous attendez :
from pydantic import BaseModel, Field
class AnalyseSentiment(BaseModel):
texte_original: str = Field(
description="Le texte analysé tel quel"
)
sentiment: Literal["positif", "negatif", "neutre"] = Field(
description="Le sentiment dominant du texte"
)
score_confiance: float = Field(
description="Score de confiance entre 0.0 et 1.0"
)
mots_cles: list[str] = Field(
description="Les 3 à 5 mots-clés les plus significatifs"
)
Les descriptions dans Field sont incluses dans le schéma JSON envoyé au modèle. Elles améliorent la qualité des réponses.
Points clés à retenir
- Pydantic convertit automatiquement vos classes Python en schémas JSON
- L’imbrication de modèles permet de structurer des données complexes
Literalremplaceenumpour forcer des valeurs prédéfiniesstr | Nonerend un champ optionnel (peut valoirnull)Field(description=...)améliore la qualité des réponses du modèle- Fonctionne avec
parse()(automatique) etresponse_format(manuel)