Aller au contenu principal

Implémenter les Predicted Outputs en Python

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

Voici le pattern minimal pour utiliser les Predicted Outputs :

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

En production, vous voudrez encapsuler la logique dans une classe réutilisable :

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

Voici un script de benchmark complet pour mesurer le gain dans votre contexte :

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

En production, anticipez les cas limites :

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 en production, gardez ces contraintes en tête :

  • Le paramètre n (nombre de complétions) est incompatible avec prediction
  • La position du contenu dans la réponse n’a pas d’importance : le modèle gère la correspondance
  • Fournir une mauvaise prédiction ne dégrade pas la qualité — seulement le gain de latence
  • Les deux seuls modèles compatibles sont 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