Aller au contenu principal

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
  • Literal remplace enum pour forcer des valeurs prédéfinies
  • str | None rend un champ optionnel (peut valoir null)
  • Field(description=...) améliore la qualité des réponses du modèle
  • Fonctionne avec parse() (automatique) et response_format (manuel)