Aller au contenu principal

Implémenter les Predicted Outputs en Python

Mis à jour le 29 juillet 2026

Du concept au code de production

Vous comprenez le principe des Predicted Outputs et leurs cas d’usage. Cette leçon vous donne le code Python complet, prêt à intégrer dans vos applications, avec gestion d’erreurs et mesure de performance.

Implémentation de base

Le pattern minimal tient en un paramètre : prediction, auquel vous passez le contenu attendu. Tout le reste de l’appel est inchangé — même modèle, mêmes messages, même traitement de la réponse. C’est ce qui rend la fonctionnalité facile à adopter, et tout aussi facile à retirer si la mesure ne confirme pas le gain :

from mistralai import Mistral

client = Mistral(api_key="votre-clé-api")

code_source = """
import pandas as pd

def load_data(filepath):
    df = pd.read_csv(filepath)
    df['date'] = pd.to_datetime(df['date'])
    df = df.dropna(subset=['value'])
    return df

def compute_stats(df):
    return {
        'mean': df['value'].mean(),
        'median': df['value'].median(),
        'std': df['value'].std()
    }
"""

prompt = (
    "Ajoutez un paramètre 'separator' à la fonction load_data "
    "(défaut ',') et utilisez-le dans read_csv. "
    "Répondez uniquement avec le code complet modifié."
)

response = client.chat.complete(
    model="codestral-latest",
    messages=[
        {"role": "user", "content": prompt},
        {"role": "user", "content": code_source}
    ],
    prediction={"type": "content", "content": code_source}
)

code_modifie = response.choices[0].message.content
print(code_modifie)

Classe utilitaire pour la production

L’encapsulation a ici un intérêt qui dépasse la propreté du code : elle centralise la décision d’activer ou non la prédiction. C’est précisément le genre de réglage qu’on veut pouvoir couper d’un coup — si un déploiement révèle des prédictions systématiquement fausses, vous désactivez en un point au lieu de chasser le paramètre dans toute la base de code :

from mistralai import Mistral
import time
from dataclasses import dataclass


@dataclass
class PredictionResult:
    content: str
    latency_ms: float
    tokens_input: int
    tokens_output: int
    model: str


class PredictedEditor:
    """Éditeur de contenu utilisant les Predicted Outputs."""

    def __init__(self, api_key: str, model: str = "mistral-large-latest"):
        self.client = Mistral(api_key=api_key)
        self.model = model

    def edit(
        self,
        original: str,
        instruction: str,
        system_prompt: str | None = None
    ) -> PredictionResult:
        """Édite un contenu avec prédiction de sortie."""
        messages = []

        if system_prompt:
            messages.append({"role": "system", "content": system_prompt})

        messages.extend([
            {"role": "user", "content": instruction},
            {"role": "user", "content": original}
        ])

        start = time.perf_counter()

        response = self.client.chat.complete(
            model=self.model,
            messages=messages,
            prediction={"type": "content", "content": original}
        )

        latency = (time.perf_counter() - start) * 1000

        choice = response.choices[0]
        return PredictionResult(
            content=choice.message.content,
            latency_ms=round(latency, 1),
            tokens_input=response.usage.prompt_tokens,
            tokens_output=response.usage.completion_tokens,
            model=self.model
        )

    def edit_code(self, code: str, instruction: str) -> PredictionResult:
        """Raccourci pour l'édition de code."""
        return self.edit(
            original=code,
            instruction=instruction,
            system_prompt=(
                "Vous êtes un assistant de programmation. "
                "Répondez uniquement avec le code modifié, "
                "sans explication ni markdown."
            )
        )

    def edit_text(self, text: str, instruction: str) -> PredictionResult:
        """Raccourci pour l'édition de texte."""
        return self.edit(
            original=text,
            instruction=instruction,
            system_prompt=(
                "Vous êtes un éditeur de texte professionnel. "
                "Appliquez la modification demandée en préservant "
                "le style et la structure du texte original. "
                "Répondez uniquement avec le texte modifié."
            )
        )

Utilisation de la classe

editor = PredictedEditor(api_key="votre-clé-api", model="codestral-latest")

# Éditer du code
result = editor.edit_code(
    code=mon_fichier_python,
    instruction="Remplacez tous les print() par des appels logging.info()"
)

print(f"Latence : {result.latency_ms} ms")
print(f"Tokens : {result.tokens_input} in / {result.tokens_output} out")
print(result.content)

Benchmark : avec vs sans prédiction

Ne sautez pas cette étape : le gain des Predicted Outputs dépend entièrement de la justesse de vos prédictions, qui dépend de vos données — aucun chiffre lu dans une documentation ne remplace la mesure sur vos propres cas. Le script compare les deux modes sur les mêmes entrées, et sa sortie vous donne la réponse en secondes :

import statistics

def benchmark_prediction(
    client, model, messages, prediction_content, runs=5
):
    """Compare la latence avec et sans Predicted Output."""
    times_normal = []
    times_predicted = []

    for _ in range(runs):
        # Sans prédiction
        start = time.perf_counter()
        client.chat.complete(model=model, messages=messages)
        times_normal.append((time.perf_counter() - start) * 1000)

        # Avec prédiction
        start = time.perf_counter()
        client.chat.complete(
            model=model,
            messages=messages,
            prediction={"type": "content", "content": prediction_content}
        )
        times_predicted.append((time.perf_counter() - start) * 1000)

    avg_normal = statistics.mean(times_normal)
    avg_predicted = statistics.mean(times_predicted)
    gain_pct = (1 - avg_predicted / avg_normal) * 100

    return {
        "sans_prediction_ms": round(avg_normal, 1),
        "avec_prediction_ms": round(avg_predicted, 1),
        "gain_pourcentage": round(gain_pct, 1),
        "runs": runs
    }

Gestion des erreurs

La gestion d’erreurs est simple ici, pour une raison structurelle : une prédiction fausse n’est pas une erreur. Le modèle l’ignore et génère normalement — vous perdez le gain de latence, jamais la qualité. Les vrais cas limites sont ailleurs :

def safe_edit(editor, original, instruction):
    """Édition avec gestion d'erreurs robuste."""
    try:
        result = editor.edit(original, instruction)

        # Vérifier que la réponse n'est pas vide
        if not result.content or len(result.content.strip()) < 10:
            raise ValueError("Réponse trop courte ou vide")

        return result

    except Exception as e:
        # Fallback : réessayer sans prédiction
        print(f"Predicted Output échoué ({e}), fallback standard...")
        response = editor.client.chat.complete(
            model=editor.model,
            messages=[
                {"role": "user", "content": instruction},
                {"role": "user", "content": original}
            ]
        )
        return PredictionResult(
            content=response.choices[0].message.content,
            latency_ms=0,
            tokens_input=response.usage.prompt_tokens,
            tokens_output=response.usage.completion_tokens,
            model=editor.model
        )

Contraintes à connaître

Avant de déployer, trois points méritent d’être intégrés à votre revue de code. D’abord, le paramètre n (générations multiples) est incompatible avec prediction : si votre pipeline demande plusieurs complétions, il faudra choisir. Ensuite, la correspondance entre prédiction et sortie est gérée par le modèle quelle que soit la position du contenu dans la réponse — vous n’avez pas d’alignement à préparer. Enfin, et c’est ce qui rend la fonctionnalité sûre à déployer : une mauvaise prédiction ne dégrade jamais la qualité de la réponse, elle fait seulement perdre le gain de latence. Le pire scénario est donc simplement un retour à la vitesse normale, sur les deux modèles compatibles (mistral-large-latest et codestral-latest).

Points clés à retenir

  • Le paramètre prediction s’ajoute simplement à l’appel chat.complete()
  • Encapsulez la logique dans une classe réutilisable pour la production
  • Mesurez systématiquement le gain avec un benchmark avant de déployer
  • Prévoyez un fallback sans prédiction en cas d’erreur
  • Une mauvaise prédiction ne dégrade pas la qualité, seulement la latence