Utiliser client.chat.parse()
Mis à jour le 29 juillet 2026
La méthode parse() : le cœur des Custom Structured Outputs
client.chat.parse() est l’équivalent structuré de client.chat.complete(). Au lieu de retourner du texte libre ou du JSON brut à parser, elle retourne directement un objet typé correspondant à votre modèle Pydantic. Le changement paraît cosmétique ; il supprime en réalité toute une couche de code.
Le contraste est le plus parlant côté à côté. Avec complete(), vous récupérez une chaîne et vous la transformez vous-même. Avec parse(), l’objet arrive prêt à l’emploi, et le JSON brut reste disponible si vous en avez besoin.
# JSON Mode — complete() retourne du texte JSON
response = client.chat.complete(
model="mistral-large-latest",
messages=messages,
response_format={"type": "json_object"}
)
raw_json: str = response.choices[0].message.content
data = json.loads(raw_json) # Parsing manuel
# Custom — parse() retourne un objet typé
response = client.chat.parse(
model="mistral-large-latest",
messages=messages,
response_format=MonSchema
)
obj: MonSchema = response.choices[0].message.parsed # Objet Pydantic
raw_json: str = response.choices[0].message.content # JSON brut aussi disponible
La différence tient dans l’accès à .parsed : un objet Pydantic directement exploitable, avec l’autocomplétion de votre IDE et la validation de types.
Un appel complet, de bout en bout
L’exemple suivant déroule les cinq étapes d’une extraction réelle : définir le schéma avec des descriptions parlantes, créer le client, appeler parse(), exploiter l’objet retourné, et récupérer au besoin la représentation JSON.
from mistralai import Mistral
from pydantic import BaseModel, Field
from typing import Optional
# 1. Définir le schéma
class BookInfo(BaseModel):
title: str = Field(description="Titre du livre")
authors: list[str] = Field(description="Liste des auteurs")
year: Optional[int] = Field(default=None, description="Année de publication")
genre: str = Field(description="Genre littéraire principal")
summary: str = Field(description="Résumé en 2-3 phrases")
# 2. Créer le client
client = Mistral(api_key="votre-clé-api")
# 3. Appeler parse()
response = client.chat.parse(
model="mistral-large-latest",
messages=[
{
"role": "system",
"content": "Tu es un bibliothécaire expert. Extrais les informations du livre mentionné."
},
{
"role": "user",
"content": "J'ai adoré '1984' de George Orwell. C'est un roman dystopique publié en 1949 qui décrit une société totalitaire sous surveillance permanente."
}
],
temperature=0
)
# 4. Utiliser l'objet parsé
book = response.choices[0].message.parsed
print(f"Titre : {book.title}")
print(f"Auteurs : {', '.join(book.authors)}")
print(f"Année : {book.year}")
print(f"Genre : {book.genre}")
print(f"Résumé : {book.summary}")
# 5. Le JSON brut est aussi disponible
raw = response.choices[0].message.content
print(f"\nJSON brut : {raw}")
Remarquez ce que le system prompt ne contient pas : aucune description du format attendu.
Le system prompt auto-prepended
C’est le SDK qui s’en charge. Quand vous utilisez parse(), Mistral ajoute automatiquement un préfixe au system prompt :
Your output should be an instance of a JSON object following this schema: { ... }
Ce préfixe contient le schéma JSON généré à partir de votre modèle Pydantic. Vous n’avez pas besoin de décrire le format dans votre prompt — le SDK le fait pour vous. Votre message système est donc libéré pour ce qu’il fait le mieux : donner du contexte métier et fixer des exigences de qualité, comme la précision des montants ou la conduite à tenir face à une donnée absente.
response = client.chat.parse(
model="mistral-large-latest",
messages=[
{
"role": "system",
# Pas besoin de décrire le format JSON — c'est automatique
# Concentrez-vous sur le CONTEXTE et la QUALITÉ
"content": """Tu es un analyste financier expert.
Sois précis dans les montants et les pourcentages.
Si une donnée n'est pas disponible dans le texte, utilise null."""
},
{"role": "user", "content": texte_rapport}
],
response_format=RapportFinancier
)
.parsed ou .content : deux usages distincts
L’objet typé, accessible via .parsed, est celui que vous manipulez dans votre logique applicative. Il expose les attributs avec leurs types, s’itère, se convertit en dictionnaire avec model_dump() et se sérialise avec model_dump_json().
book = response.choices[0].message.parsed
# Accès typé avec autocomplétion IDE
print(book.title) # str
print(book.authors) # list[str]
print(book.year) # Optional[int]
# Itération sur les listes
for author in book.authors:
print(f" - {author}")
# Conversion en dictionnaire
book_dict = book.model_dump()
# Sérialisation JSON
book_json = book.model_dump_json(indent=2)
Le JSON brut, lui, garde son utilité aux frontières du système : pour le logging, pour un stockage en base de données, ou pour transmettre la réponse telle quelle à une autre API.
raw = response.choices[0].message.content
# C'est une string JSON, utile pour :
# - Le logging
# - Le stockage en base de données
# - L'envoi à une autre API
import json
data = json.loads(raw)
Ce qui peut encore échouer
Le schéma garanti ne met pas votre code à l’abri de tout. L’API peut renvoyer une erreur réseau ou de service, et .parsed peut valoir None si la réponse a été interrompue. Le pattern ci-dessous traite les deux cas séparément — SDKError pour l’API, ValidationError pour le schéma — et ne relance qu’un nombre borné de fois.
from mistralai import Mistral
from mistralai.models import SDKError
from pydantic import ValidationError
client = Mistral(api_key="votre-clé-api")
def extract_structured(text: str, schema, max_retries: int = 2):
"""Extraction structurée avec gestion d'erreurs."""
for attempt in range(max_retries + 1):
try:
response = client.chat.parse(
model="mistral-large-latest",
messages=[
{"role": "system", "content": "Extrais les informations demandées."},
{"role": "user", "content": text}
],
response_format=schema,
temperature=0,
max_tokens=1024
)
parsed = response.choices[0].message.parsed
if parsed is None:
raise ValueError("Parsed est None — réponse peut-être tronquée")
return parsed
except SDKError as e:
print(f"Erreur API (tentative {attempt + 1}) : {e}")
if attempt == max_retries:
raise
except ValidationError as e:
print(f"Erreur de validation (tentative {attempt + 1}) : {e}")
if attempt == max_retries:
raise
# Utilisation
try:
book = extract_structured("'Le Petit Prince' de Saint-Exupéry, 1943", BookInfo)
print(f"Extrait : {book.title} par {', '.join(book.authors)}")
except Exception as e:
print(f"Échec définitif : {e}")
Le réflexe vu avec le JSON Mode reste valable ici : une réponse coupée par max_tokens produit un objet incomplet ou nul, et finish_reason vous le dit avant que vous ne le découvriez plus loin dans le pipeline.
response = client.chat.parse(
model="mistral-large-latest",
messages=messages,
response_format=MonSchema,
max_tokens=256
)
if response.choices[0].finish_reason != "stop":
print(f"Attention : finish_reason = {response.choices[0].finish_reason}")
# "length" = réponse tronquée, augmentez max_tokens
Points clés à retenir
client.chat.parse()remplaceclient.chat.complete()pour les Custom Structured Outputs.parsedretourne un objet Pydantic typé,.contentretourne le JSON brut- Le schéma est automatiquement ajouté au system prompt — inutile de décrire le format
- Vérifiez toujours
finish_reasonet gérez les erreursSDKErroretValidationError - Utilisez
model_dump()pour convertir l’objet parsé en dictionnaire Python