Le Raisonnement Toujours Actif
Mis à jour le 29 juillet 2026
⚠️ Modèle déprécié (mise à jour du 28 juillet 2026) : les modèles Magistral sont dépréciés par Mistral, avec des retraits échelonnés jusqu’à mi-2026. Le raisonnement est désormais intégré aux modèles généralistes (Mistral Small 4, Medium 3.5). Les concepts de ce cours restent instructifs, mais ne construisez plus de nouveau projet sur Magistral — consultez le cours « Mistral en 2026 » pour la migration.
Une caractéristique fondamentale de Magistral
Contrairement au raisonnement ajustable de mistral-small-latest, où vous choisissez d’activer ou non la réflexion, les modèles Magistral raisonnent systématiquement. Il n’existe aucun paramètre pour désactiver le raisonnement. C’est une décision de conception délibérée, et elle a des implications concrètes sur vos coûts, votre latence et l’architecture de vos applications.
Pourquoi le raisonnement est permanent
Les modèles Magistral ont été entraînés avec le raisonnement intégré à leur architecture. Chaque inférence passe par une phase de réflexion avant de produire la réponse finale. Ce n’est pas une option ajoutée en surface : c’est la manière dont le modèle « pense ». La question la plus banale suit le même chemin qu’une démonstration.
from mistralai import Mistral
client = Mistral(api_key="VOTRE_CLE_API")
# Même pour une question simple, Magistral raisonne
response = client.chat.complete(
model="magistral-small-latest",
messages=[{"role": "user", "content": "Quelle est la capitale de la France ?"}]
)
# La réponse contient toujours un chunk thinking
for chunk in response.choices[0].message.content:
print(f"Type: {chunk.type}")
# Affichera : thinking puis text
Sur « Quelle est la capitale de la France ? », le modèle vérifie la question, confirme la réponse et la valide avant de la produire. Vous payez donc une réflexion là où un modèle classique aurait répondu en trois tokens.
Implications sur les coûts
Chaque requête génère des tokens de raisonnement en plus des tokens de la réponse finale. Sur une question triviale, le rapport devient franchement défavorable : là où une réponse directe consommerait une dizaine de tokens de sortie, Magistral en produit cinquante à cent, raisonnement inclus.
# Exemple de surcoût pour une question simple
# Question : "2 + 2 = ?" (5 tokens en entrée)
# Sans raisonnement : ~10 tokens de sortie
# Avec Magistral : ~50-100 tokens de sortie (raisonnement inclus)
La parade consiste à ne jamais laisser Magistral traiter ce qui ne le mérite pas. Un score de complexité, même approximatif, suffit à répartir le trafic sur trois régimes distincts — Small sans réflexion, Small avec réflexion, Magistral — et à réserver le plus coûteux aux cas qui le rentabilisent :
def choose_model(question, complexity_score):
"""Choisit le modèle selon la complexité.
Pour les tâches simples, inutile d'utiliser Magistral.
Réservez-le aux problèmes qui bénéficient du raisonnement.
"""
if complexity_score < 3:
# Tâche simple : Small sans raisonnement
return {
"model": "mistral-small-latest",
"reasoning_effort": "none"
}
elif complexity_score < 7:
# Tâche modérée : Small avec raisonnement
return {
"model": "mistral-small-latest",
"reasoning_effort": "high"
}
else:
# Tâche complexe : Magistral
return {
"model": "magistral-medium-latest"
}
Implications sur la latence
Le raisonnement systématique allonge aussi le temps de réponse, et de trois manières distinctes. Le temps de génération augmente mécaniquement puisqu’il y a davantage de tokens à produire. Le premier token utile — celui de la réponse finale — arrive plus tard, car le modèle commence par réfléchir. Et en streaming, les premiers chunks reçus sont de type thinking, pas text : une interface naïve affichera donc du brouillon avant la moindre réponse.
Mesurer ce délai vaut mieux que le supposer. Le code ci-dessous chronomètre l’arrivée du premier chunk text et n’affiche que celui-ci, laissant la réflexion invisible :
import time
response_stream = client.chat.stream(
model="magistral-medium-latest",
messages=[{"role": "user", "content": "Analysez cette architecture microservices..."}]
)
start = time.time()
first_answer_token = None
for event in response_stream:
delta = event.data.choices[0].delta
if hasattr(delta, "content") and delta.content:
for chunk in delta.content:
if chunk.type == "text" and first_answer_token is None:
first_answer_token = time.time() - start
print(f"\nPremier token de réponse après {first_answer_token:.1f}s")
if chunk.type == "text" and hasattr(chunk, "text"):
print(chunk.text, end="", flush=True)
Implications sur le design d’application
Trois conséquences pratiques en découlent. La première : ne faites pas de Magistral votre modèle générique. Il excelle sur les tâches de raisonnement, et l’employer pour de la simple génération de texte, de la traduction ou des réponses conversationnelles gaspille des ressources. Le contraste entre les deux appels suivants est éloquent — le premier fonctionne, mais brûle des tokens de réflexion pour traduire un mot ; le second exploite réellement ce pour quoi le modèle a été conçu.
# MAUVAISE utilisation de Magistral
response = client.chat.complete(
model="magistral-medium-latest",
messages=[{"role": "user", "content": "Traduis 'bonjour' en anglais."}]
)
# Fonctionne mais gaspille des tokens de raisonnement
# BONNE utilisation de Magistral
response = client.chat.complete(
model="magistral-medium-latest",
messages=[{"role": "user", "content": "Prouvez que pour tout n, n^3 - n est divisible par 6."}]
)
La deuxième : puisque le raisonnement est toujours présent, votre code doit toujours gérer les chunks thinking. Aucun branchement conditionnel « si le raisonnement est activé » n’a de sens ici, et l’extraction doit tenir compte du sous-tableau propre à Magistral.
def extract_magistral_response(response):
"""Extrait la réponse d'un modèle Magistral.
Toujours prévoir le chunk thinking car il est systématique.
"""
answer = ""
reasoning = ""
for chunk in response.choices[0].message.content:
if chunk.type == "thinking":
if hasattr(chunk, "thinking"):
reasoning = " ".join(
part.text for part in chunk.thinking
if hasattr(part, "text")
)
elif chunk.type == "text":
answer = chunk.text
return {"answer": answer, "reasoning": reasoning}
La troisième relève de l’expérience utilisateur. Si votre application expose Magistral à des utilisateurs finaux, communiquez sur le temps de réflexion plutôt que de laisser l’écran figé : un point affiché à chaque chunk thinking, puis un message de bascule, transforment une attente inquiétante en attente lisible.
def stream_with_indicator(client, messages):
"""Affiche un indicateur pendant la phase de réflexion."""
response_stream = client.chat.stream(
model="magistral-medium-latest",
messages=messages
)
is_thinking = True
for event in response_stream:
delta = event.data.choices[0].delta
if hasattr(delta, "content") and delta.content:
for chunk in delta.content:
if chunk.type == "text" and is_thinking:
is_thinking = False
print("\n--- Réflexion terminée ---\n")
if chunk.type == "thinking":
print(".", end="", flush=True)
elif chunk.type == "text" and hasattr(chunk, "text"):
print(chunk.text, end="", flush=True)
Ce qu’on ne peut pas faire
Soyons parfaitement clairs sur les limites. Vous ne pouvez pas désactiver le raisonnement : aucun paramètre reasoning_effort="none" n’existe pour Magistral. Vous ne pouvez pas non plus masquer les traces côté serveur, car les tokens de raisonnement sont toujours générés — et donc facturés. Et vous ne pouvez pas forcer une réponse sans réflexion : même un system prompt demandant explicitement de ne pas réfléchir laissera le modèle raisonner.
La seule manière d’éviter le raisonnement est d’utiliser un autre modèle, comme mistral-small-latest avec reasoning_effort="none".
Points clés à retenir
- Les modèles Magistral raisonnent toujours, sans possibilité de désactivation
- Cela implique un surcoût systématique en tokens et en latence
- Ne pas utiliser Magistral pour des tâches simples qui ne nécessitent pas de raisonnement
- Votre code doit toujours parser les chunks thinking
- Informez vos utilisateurs du temps de réflexion supplémentaire
- Pour les tâches simples, préférez
mistral-small-latestavecreasoning_effort="none"