Ces 15 exercices de niveau intermédiaire sont conçus pour plus de pratique. Ces exercices suivent une progression logique, des bases de Pydantic à son application dans des workflows LLM complexes comme le “tool calling”. Ces exercices vous aident à améliorer vos compétences techniques à savoir utiliser Pydantic pour générer des sorties structurées à partir de LLM, en s’assurant que les réponses suivent un format spécifique que votre application peut traiter de manière fiable. Vous apprendrez également les compétences de validation de données pour gérer une grande variété de besoins de formatage et de structuration de données dans tout système logiciel. Vous construirez un système avec validation de données à chaque étape, en utilisant les modèles Pydantic pour valider tout, depuis les entrées utilisateur et les réponses LLM jusqu’à la définition des paramètres pour l’appel d’outils. Essayez de travailler chaque exercice et vous pouvez cliquer pour voir la correction et l’explication.
Exercice 1 : Création d'un Modèle de Base
Exercice
Créez un modèle Pydantic nommé Utilisateur pour représenter un utilisateur avec un id (entier), un nom (chaîne de caractères) et une date_inscription (objet datetime).
Solution
from pydantic import BaseModel from datetime import datetimeclass Utilisateur(BaseModel): id: int nom: str date_inscription: datetime # Exemple d’instanciation utilisateur_valide = Utilisateur( id=101, nom=”Alice”, date_inscription=”2023-10-27T10:00:00″ ) print(utilisateur_valide)
Explication
Pour créer un modèle Pydantic, on définit une classe qui hérite de pydantic.BaseModel. Les attributs de la classe sont déclarés avec des “type hints” (annotations de type) Python. Pydantic utilise ces annotations pour valider et convertir les données d’entrée. Dans l’exemple, la chaîne de caractères “2023-10-27T10:00:00” est automatiquement convertie en un objet datetime valide.
Exercice 2 : Gestion des Champs Optionnels et des Valeurs par Défaut
Exercice
Modifiez le modèle Utilisateur pour que le nom ait une valeur par défaut de “Anonyme” et ajoutez un champ optionnel email qui doit être une chaîne de caractères.
Solution
from pydantic import BaseModel
from datetime import datetime
from typing import Optional
class Utilisateur(BaseModel):
id: int
nom: str = "Anonyme"
date_inscription: datetime
email: Optional[str] = None
# Exemples d'instanciation
user1 = Utilisateur(id=1, date_inscription="2023-01-01")
print(user1)
# > id=1 nom='Anonyme' date_inscription=datetime.datetime(2023, 1, 1, 0, 0) email=None
user2 = Utilisateur(id=2, date_inscription="2023-01-02", email="test@example.com")
print(user2)
# > id=2 nom='Anonyme' date_inscription=datetime.datetime(2023, 1, 2, 0, 0) email='test@example.com'
Explication
Valeur par défaut : En assignant une valeur à l’attribut (nom: str = “Anonyme”), on le rend optionnel lors de l’instanciation. Si aucune valeur n’est fournie, la valeur par défaut est utilisée.
Champ optionnel : Pour un champ qui peut être présent ou totalement absent (valeur None), on utilise typing.Optional[Type]. Par convention, on lui donne également None comme valeur par défaut.
Exercice 3 : Validation de Types Spécifiques (EmailStr)
Exercice
Créez un modèle Contact avec un champ nom (chaîne) et un champ adresse_email qui doit être un email valide. Tentez de l’instancier avec une adresse email invalide pour observer l’erreur.
Solution
from pydantic import BaseModel, EmailStr, ValidationError
class Contact(BaseModel):
nom: str
adresse_email: EmailStr
# Instanciation valide
contact_valide = Contact(nom="Bob", adresse_email="bob@example.com")
print(contact_valide)
# Tentative d'instanciation invalide
try:
Contact(nom="Charlie", adresse_email="charlie-is-not-an-email")
except ValidationError as e:
print(e)
Explication
Pydantic fournit des types spécialisés pour des validations communes. EmailStr est un de ces types. Il vérifie que la chaîne de caractères fournie respecte le format standard d’une adresse email. Si le format est incorrect, Pydantic lève une ValidationError avec un message explicite, ce qui est crucial pour nettoyer les données en amont d’un workflow LLM.
Exercice 4 : Modèles Imbriqués (Nested Models)
Exercice
Créez un modèle Article avec un titre et un contenu. Créez ensuite un modèle Blog qui contient un nom_blog et une liste_articles (une liste d’objets Article).
Solution
from pydantic import BaseModel
from typing import List
class Article(BaseModel):
titre: str
contenu: str
class Blog(BaseModel):
nom_blog: str
liste_articles: List[Article]
# Données d'exemple (simulant un JSON reçu)
data = {
"nom_blog": "Mon Blog Tech",
"liste_articles": [
{"titre": "Pydantic est puissant", "contenu": "..."},
{"titre": "Les LLMs en pratique", "contenu": "..."}
]
}
# Validation et instanciation
mon_blog = Blog.model_validate(data)
print(mon_blog.model_dump_json(indent=2))
Explication
Pydantic gère nativement les modèles imbriqués. En déclarant liste_articles: List[Article], Pydantic s’attend à recevoir une liste. Il itère sur chaque élément de cette liste et tente de le valider en utilisant le modèle Article. Cela permet de construire des structures de données complexes et de les valider en une seule passe.
Exercice 5 : Validateur Personnalisé (field_validator)
Exercice
Créez un modèle CritiqueProduit avec note (entier) et commentaire (chaîne). Ajoutez un validateur pour s’assurer que la note est toujours comprise entre 1 et 5 (inclus).
Solution
from pydantic import BaseModel, field_validator
class CritiqueProduit(BaseModel):
note: int
commentaire: str
@field_validator('note')
@classmethod
def note_must_be_in_range(cls, v: int) -> int:
if not 1 <= v <= 5:
raise ValueError('La note doit être entre 1 et 5')
return v
# Exemple
critique_ok = CritiqueProduit(note=5, commentaire="Excellent !")
print(critique_ok)
try:
CritiqueProduit(note=6, commentaire="Trop bien !")
except ValueError as e:
print(e)
Explication
Le décorateur @field_validator(‘nom_du_champ’) permet de définir une fonction de validation personnalisée.
La méthode doit être une méthode de classe (@classmethod).
Elle prend la valeur du champ (v) en argument.
Elle effectue la logique de validation. Si la validation échoue, elle doit lever une exception (typiquement ValueError ou AssertionError).
Si la validation réussit, elle doit retourner la valeur (potentiellement transformée).
Partie 2 : Pydantic pour Valider les Entrées et Sorties de LLM
Exercice 6 : Extraire une Entité Simple depuis un Texte de LLM
Exercice
Un LLM a généré le texte suivant : “Le ticket de support #TS-481516 concerne un problème de connexion.”. Créez un modèle Pydantic TicketInfo pour extraire uniquement l’ID du ticket. Vous devrez utiliser une étape de pré-traitement (regex) avant de valider.
Solution
import re
from pydantic import BaseModel
class TicketInfo(BaseModel):
ticket_id: str
llm_output = "Le ticket de support #TS-481516 concerne un problème de connexion."
# Étape 1 : Pré-traitement pour extraire l'information
match = re.search(r'#([A-Z]{2}-\d+)', llm_output)
if match:
extracted_id = match.group(1)
# Étape 2 : Validation avec Pydantic
ticket = TicketInfo(ticket_id=extracted_id)
print(ticket)
# > ticket_id='TS-481516'
else:
print("Aucun ID de ticket trouvé.")
Explication
Ceci illustre un workflow classique : le LLM produit du texte libre, et nous devons en extraire des informations structurées.
On utilise un outil de traitement de texte (ici, une expression régulière) pour isoler la donnée qui nous intéresse.
On passe ensuite cette donnée extraite au modèle Pydantic. Pydantic s’assure que la donnée est du bon type (str dans ce cas) et la structure dans un objet propre, prêt à être utilisé par le reste de l’application.
Exercice 7 : Gérer une Sortie LLM Incomplète
Exercice
Un LLM devait extraire un nom et un email, mais n’a trouvé que le nom : “L’utilisateur s’appelle Jean Dupont.”. Votre modèle Contact requiert un nom et un email. Comment gérer cette situation en utilisant votre modèle ? (Ceci est un exercice de réflexion).
Exercice (Question Théorique) : Que se passera-t-il si vous essayez de créer une instance du modèle Contact (de l’exercice 3) avec uniquement le nom ? Quelle serait une meilleure définition du modèle pour gérer ce cas ?
Solution
L’instanciation Contact(nom=”Jean Dupont”) échouera avec une ValidationError car le champ adresse_email est manquant.
Une meilleure définition du modèle pour gérer les données potentiellement manquantes serait de rendre les champs optionnels :
from pydantic import BaseModel, EmailStr
from typing import Optional
class ParsedContact(BaseModel):
nom: Optional[str] = None
adresse_email: Optional[EmailStr] = None
Explication
Les LLMs ne garantissent pas de toujours trouver toutes les informations demandées. En définissant les champs du modèle de sortie comme Optional, on rend notre système plus robuste. Après la tentative de parsing, on peut vérifier programmatiquement quels champs ont été remplis (if parsed_data.email is not None: …) et agir en conséquence (par exemple, demander à l’utilisateur de compléter l’information).
Exercice 8 : Utiliser des Enum pour Classifier une Sortie LLM
Exercice
Un LLM analyse le sentiment d’un commentaire. La sortie doit être “POSITIF”, “NÉGATIF” ou “NEUTRE”. Créez un modèle Pydantic AnalyseSentiment qui valide que la sortie du LLM est bien l’une de ces trois valeurs.
Solution
from pydantic import BaseModel
from enum import Enum
class Sentiment(str, Enum):
POSITIF = "POSITIF"
NEGATIF = "NÉGATIF"
NEUTRE = "NEUTRE"
class AnalyseSentiment(BaseModel):
sentiment: Sentiment
# Simulation de sorties LLM
llm_output1 = "POSITIF"
llm_output2 = "INCONNU"
analyse1 = AnalyseSentiment(sentiment=llm_output1)
print(analyse1) # > sentiment=<Sentiment.POSITIF: 'POSITIF'>
try:
AnalyseSentiment(sentiment=llm_output2)
except ValueError as e:
print(e)
Explication
Utiliser une classe Enum de Python est la méthode la plus propre pour restreindre un champ à un ensemble de valeurs prédéfinies. Pydantic s’intègre parfaitement avec Enum. Si le LLM produit une valeur qui n’est pas dans l’énumération, la validation échoue. C’est essentiel pour les tâches de classification, de routage ou de modération, où la sortie doit appartenir à une catégorie stricte.
Exercice 9 : Utiliser des Alias de Champs (Field)
Exercice
Votre LLM renvoie un JSON avec la clé “user_name”. Cependant, votre code Python interne utilise la convention nom_utilisateur. Créez un modèle Pydantic Profil qui mappe la clé entrante “user_name” à l’attribut nom_utilisateur.
Solution
from pydantic import BaseModel, Field
class Profil(BaseModel):
nom_utilisateur: str = Field(alias=’user_name’)
age: int
# Simulation de données JSON d’un LLM
llm_json_data = {
“user_name”: “j.doe”,
“age”: 30
}
profil = Profil.model_validate(llm_json_data)
print(profil)
# > nom_utilisateur=’j.doe’ age=30
# L’exportation utilise aussi l’alias par défaut
print(profil.model_dump(by_alias=True))
# > {‘user_name’: ‘j.doe’, ‘age’: 30}
Explication
Field est une fonction de Pydantic qui permet de configurer des métadonnées pour un champ. L’argument alias est particulièrement utile dans les workflows LLM. Il permet de découpler le schéma de données de l’API externe (le LLM) du schéma de données interne à votre application, ce qui rend le code plus propre et plus facile à maintenir.
Exercice 10 : Parser une Liste d'Objets Structurés
Exercice
Un LLM a extrait une liste de livres d’un texte et l’a formatée en JSON. Créez les modèles Pydantic nécessaires pour valider la structure suivante : une liste de livres, où chaque livre a un titre et un auteur.
Solution
from pydantic import BaseModel, TypeAdapter
from typing import List
class Livre(BaseModel):
titre: str
auteur: str
# Simulation de la sortie JSON du LLM
llm_json_output = """
[
{"titre": "Dune", "auteur": "Frank Herbert"},
{"titre": "1984", "auteur": "George Orwell"}
]
"""
import json
data = json.loads(llm_json_output)
# Utilisation de TypeAdapter pour valider une liste à la racine
LivresListAdapter = TypeAdapter(List[Livre])
liste_livres_validee = LivresListAdapter.validate_python(data)
print(liste_livres_validee)
Explication
Lorsque la structure de données que vous souhaitez valider est un type complexe (comme List[Livre]) à la racine, et non un BaseModel, TypeAdapter est l’outil approprié. Il permet d’appliquer la logique de validation de Pydantic à n’importe quel type Python. Ici, il parcourt la liste et valide chaque dictionnaire par rapport au modèle Livre.
Partie 3 : Demande de Sortie Structurée et Tool Calling
Exercice 11 : Utilisation de instructor pour Forcer une Sortie Structurée
Exercice
Imaginez que vous utilisez la bibliothèque instructor pour patcher un client OpenAI. Votre objectif est d’extraire des informations structurées à partir d’un texte.
Définissez un modèle Pydantic Personne avec les champs nom (str) et age (int).
Écrivez le pseudo-code Python (en simulant l’appel à l’API OpenAI) qui utiliserait instructor pour forcer le LLM à répondre avec une instance du modèle Personne à partir du texte fourni.
Contexte :
Texte d’entrée : “Marc a 32 ans et est ingénieur logiciel. Sa sœur, Léa, a 28 ans.”
Objectif : Extraire les informations sur la première personne mentionnée.
Solution
# Prérequis : supposons que openai est installé et configuré
# pip install instructor openai
import instructor
import openai
from pydantic import BaseModel
# Configuration du client (à adapter avec votre clé API)
# client = openai.OpenAI()
# 1. Patcher le client avec instructor
# client = instructor.patch(client)
# 2. Définir le modèle Pydantic de la réponse attendue
class Personne(BaseModel):
nom: str
age: int
# 3. Écrire le pseudo-code de l'appel API
def extraire_personne(texte: str) -> Personne:
"""
Cette fonction simule l'appel à un LLM via instructor
pour extraire une entité Personne du texte.
"""
print(f"Extraction des informations depuis le texte : '{texte}'")
# Ceci est la partie cruciale de l'appel avec instructor
# L'argument `response_model` indique au LLM le format de sortie désiré.
# personne_extraite = client.chat.completions.create(
# model="gpt-3.5-turbo",
# response_model=Personne,
# messages=[
# {"role": "user", "content": f"Extraire le nom et l'âge de la première personne mentionnée dans le texte : {texte}"}
# ]
# )
# Pour simuler la réponse sans appel API réel :
personne_extraite = Personne(nom="Marc", age=32)
return personne_extraite
# Appel de la fonction
texte_source = "Marc a 32 ans et est ingénieur logiciel. Sa sœur, Léa, a 28 ans."
resultat = extraire_personne(texte_source)
print("\nRésultat extrait et validé :")
print(resultat)
# > Résultat extrait et validé :
# > nom='Marc' age=32
Explication
Cet exercice aborde la méthode la plus moderne et la plus robuste pour obtenir des sorties structurées : passer le schéma de données directement dans l’appel API.
instructor.patch : Cette ligne (commentée) modifie le client OpenAI pour lui ajouter la capacité de comprendre le paramètre response_model.
response_model=Personne : C’est le cœur du mécanisme. Au lieu de simplement demander au LLM de “répondre en JSON”, nous lui fournissons le schéma Pydantic complet. En coulisses, instructor convertit ce schéma en une description que le LLM (s’il est compatible, comme les modèles OpenAI) peut utiliser pour formater sa sortie avec une très haute fiabilité.
Retour Direct : La fonction ne retourne pas une chaîne de caractères à parser, mais directement une instance de Personne. instructor gère le parsing et la validation. Si le LLM renvoie des données mal formées, instructor peut même tenter de les corriger ou de relancer l’appel, rendant le processus encore plus robuste.
Exercice 12 : Définition d'un Outil (Tool) pour un Agent LLM
Exercice
Vous construisez un agent capable de gérer une playlist musicale. L’un de ses outils est ajouter_chanson_playlist. Cet outil nécessite deux arguments : nom_chanson et nom_artiste. Définissez un modèle Pydantic AjouterChansonParams qui servira à valider les arguments que le LLM fournira pour cet outil.
Solution
from pydantic import BaseModel, Field
class AjouterChansonParams(BaseModel):
"""
Modèle pour valider les paramètres de l'outil 'ajouter_chanson_playlist'.
Chaque champ inclut une description pour aider le LLM à comprendre son utilité.
"""
nom_chanson: str = Field(..., description="Le titre exact de la chanson à ajouter.")
nom_artiste: str = Field(..., description="Le nom de l'artiste ou du groupe qui a interprété la chanson.")
# Simulation : Le LLM a analysé la requête utilisateur "Ajoute Bohemian Rhapsody de Queen à ma playlist"
# et a généré les arguments suivants.
arguments_llm = {
"nom_chanson": "Bohemian Rhapsody",
"nom_artiste": "Queen"
}
# Validation des arguments avant d'appeler la fonction
parametres_valides = AjouterChansonParams(**arguments_llm)
print("Paramètres validés pour l'outil :")
print(parametres_valides)
# > Paramètres validés pour l'outil :
# > nom_chanson='Bohemian Rhapsody' nom_artiste='Queen'
Explication
Le “Tool Calling” (ou “Function Calling”) est une capacité clé des LLM modernes. Pydantic est le standard de facto pour définir la signature de ces outils.
Un Modèle par Outil : La bonne pratique est de créer un modèle Pydantic distinct pour les arguments de chaque outil. Cela garantit une validation claire et isolée.
Field et Descriptions : Nous utilisons pydantic.Field. Le premier argument, …, signifie que le champ est obligatoire. L’argument description est crucial : lorsque ce schéma Pydantic est envoyé au LLM, les descriptions aident le modèle à comprendre le rôle de chaque paramètre et à fournir des valeurs plus précises.
Workflow : Dans un agent réel, le processus serait :
a. L’utilisateur envoie une requête.
b. Le LLM analyse la requête et décide d’appeler l’outil ajouter_chanson_playlist.
c. Il extrait les arguments et les formate en JSON.
d. Votre code reçoit ce JSON, le valide avec AjouterChansonParams, et seulement si la validation réussit, exécute la fonction Python correspondante.
Exercice 13 : Routage de Tâches basé sur des Modèles Pydantic
Exercice
Un LLM de support client doit router les requêtes vers deux services différents : la facturation ou le support technique.
Créez un modèle RequeteFacturation avec id_facture (str) et montant (float).
Créez un modèle RequeteSupportTechnique avec type_produit (str) et description_probleme (str).
À partir d’une requête utilisateur, le LLM doit choisir l’un des deux modèles et remplir ses champs. Simulez ce processus : validez les données JSON ci-dessous en utilisant le modèle approprié.
Contexte :
Requête utilisateur : “Mon imprimante modèle X-500 ne se connecte plus au WiFi. Le voyant clignote en rouge.”
Sortie JSON du LLM : {‘type_produit’: ‘Imprimante X-500’, ‘description_probleme’: ‘Problème de connexion WiFi, voyant rouge clignotant.’}
Solution
from pydantic import BaseModel
from typing import Union
class RequeteFacturation(BaseModel):
id_facture: str
montant: float
class RequeteSupportTechnique(BaseModel):
type_produit: str
description_probleme: str
# Sortie simulée du LLM pour la requête donnée
sortie_llm = {
'type_produit': 'Imprimante X-500',
'description_probleme': 'Problème de connexion WiFi, voyant rouge clignotant.'
}
# Logique de routage
def router_requete(donnees: dict):
try:
# Essayer de valider en tant que requête technique
requete = RequeteSupportTechnique(**donnees)
print("Routage vers : Support Technique")
return requete
except ValidationError:
pass # Ignorer l'erreur et essayer le modèle suivant
try:
# Essayer de valider en tant que requête de facturation
requete = RequeteFacturation(**donnees)
print("Routage vers : Facturation")
return requete
except ValidationError:
# Si aucun modèle ne correspond
print("Erreur : Impossible de router la requête, format inconnu.")
return None
# Simulation du routage
requete_routee = router_requete(sortie_llm)
print("Détails de la requête :", requete_routee)
Explication
Cet exercice montre comment Pydantic peut être utilisé pour implémenter une logique de routage. En demandant à un LLM de structurer sa sortie pour correspondre à l’un des N modèles possibles, on peut ensuite déterminer la nature de la requête.
Définition des Routes : Chaque “route” ou “tâche” possible est définie par un modèle Pydantic clair (RequeteFacturation, RequeteSupportTechnique).
Logique de Validation Séquentielle : La fonction router_requete tente de valider les données d’entrée contre chaque modèle, l’un après l’autre. Le premier qui réussit détermine la route à prendre.
Robustesse : Le try…except ValidationError est le mécanisme clé ici. Il nous permet de tester un modèle sans que l’application ne plante si les données ne correspondent pas.
Application : Dans un système plus avancé (utilisant instructor par exemple), on pourrait utiliser Union[RequeteFacturation, RequeteSupportTechnique] comme response_model pour que le LLM choisisse lui-même le format le plus approprié, simplifiant encore plus la logique de routage.
Exercice 15 : Cas d'Usage Complet - Mini-Workflow d'Agent
Exercice
Synthétisez les concepts précédents dans un mini-workflow. Un agent doit planifier un voyage.
Étape 1 : Valider l’entrée. Créez un modèle DemandeVoyage pour valider la requête initiale de l’utilisateur : destination (str) et budget (float, doit être > 0).
Étape 2 : Extraction par LLM. Créez un modèle PlanVoyage que le LLM devra remplir. Il doit contenir ville_hotel (str), nombre_etoiles_hotel (int, entre 1 et 5), et activite_suggeree (str).
Étape 3 : Simuler le workflow.
a. Validez une entrée utilisateur simulée avec DemandeVoyage.
b. Utilisez les informations validées pour simuler un prompt et une réponse structurée du LLM.
c. Validez la réponse du LLM avec le modèle PlanVoyage.
Solution
from pydantic import BaseModel, Field, ValidationError
# --- Étape 1: Modèle de validation d'entrée ---
class DemandeVoyage(BaseModel):
destination: str
budget: float = Field(..., gt=0) # gt: greater than
# --- Étape 2: Modèle de sortie structurée du LLM ---
class PlanVoyage(BaseModel):
ville_hotel: str
nombre_etoiles_hotel: int = Field(..., ge=1, le=5)
activite_suggeree: str
# --- Étape 3: Simulation du workflow complet ---
def executer_workflow_voyage(entree_utilisateur: dict):
print("--- Début du Workflow ---")
# a. Valider l'entrée utilisateur
try:
demande = DemandeVoyage(**entree_utilisateur)
print(f"Demande utilisateur validée : {demande}")
except ValidationError as e:
print(f"Erreur dans la demande initiale : {e}")
return
# b. Simuler le prompt et la réponse du LLM
prompt_pour_llm = (
f"Génère un plan de voyage pour {demande.destination} "
f"avec un budget de {demande.budget} euros. "
f"Suggère un hôtel et une activité."
)
print(f"\nPrompt (simulé) pour le LLM : \"{prompt_pour_llm}\"")
# Réponse simulée du LLM (structurée en JSON)
reponse_llm_json = {
"ville_hotel": "Paris",
"nombre_etoiles_hotel": 4,
"activite_suggeree": "Visite du musée du Louvre"
}
print(f"\nRéponse (simulée) du LLM : {reponse_llm_json}")
# c. Valider la sortie du LLM
try:
plan = PlanVoyage(**reponse_llm_json)
print(f"\nPlan de voyage validé avec succès : {plan}")
print("--- Fin du Workflow ---")
return plan
except ValidationError as e:
print(f"Erreur : Le LLM a renvoyé une structure invalide : {e}")
return
# Exécution avec des données valides
entree = {"destination": "Paris", "budget": 1500.0}
plan_final = executer_workflow_voyage(entree)
Explication
Cet exercice final rassemble tout le cycle de vie des données dans une application basée sur un LLM.
Validation en Amont (DemandeVoyage) : On s’assure que les données fournies par l’utilisateur sont saines avant de faire quoi que ce soit. C’est le “garde-fou” de l’application. gt=0 garantit un budget positif.
Contrat de Sortie (PlanVoyage) : On définit clairement ce que l’on attend du LLM. C’est le contrat que le LLM doit respecter. La contrainte ge=1, le=5 sur le nombre d’étoiles assure une donnée cohérente.
Flux de Données : Le workflow montre comment les données structurées et validées de la première étape (demande) sont utilisées pour construire le prompt. Ensuite, la sortie du LLM est elle-même validée par un autre modèle (plan).
Ce cycle complet de Valider l’Entrée -> Traiter -> Valider la Sortie est la pierre angulaire de la construction d’applications fiables et prévisibles avec des LLM. Pydantic est l’outil parfait pour mettre en œuvre ce pattern à chaque étape.