Aller au contenu principal

Optimisation bout-en-bout : du prompt au réseau

Mis à jour le 28 juillet 2026

L’optimisation est un système, pas un paramètre

Réduire la latence et les coûts d’une application LLM ne se limite pas à choisir un modèle plus rapide. C’est une chaîne d’optimisations qui va du prompt jusqu’à la configuration réseau, et le maillon le plus faible impose sa loi au reste. Une équipe qui divise par deux la taille de son prompt système mais laisse son serveur ouvrir une connexion TLS neuve à chaque requête récupérera d’une main ce qu’elle perd de l’autre.

L’ordre dans lequel vous traitez ces leviers compte aussi. Le prompt vient en premier parce qu’il agit à la fois sur le coût et sur la latence, et qu’il ne demande aucun changement d’infrastructure. Les paramètres d’appel viennent ensuite, puis le réseau, puis la façon dont votre application consomme la réponse. Cette leçon vous guide à travers chaque levier dans cet ordre.

Optimiser le prompt

Chaque token en entrée coûte du temps et de l’argent, et la plupart des prompts de production portent l’héritage de leur phase de prototypage : des consignes ajoutées une par une, chacune reformulant la précédente. Le premier réflexe consiste à réécrire le prompt sous forme dense, en supprimant les tournures d’adresse et les répétitions sans toucher aux contraintes réellement transmises au modèle.

# ❌ Prompt verbeux
prompt_long = """
Vous êtes un assistant expert en analyse financière. Vous devez toujours
répondre de manière professionnelle et structurée. Vous devez utiliser
des données chiffrées quand c'est possible. Vous devez éviter le jargon
inutile. Vous devez être concis mais complet.
Analysez le rapport trimestriel suivant : ...
"""

# ✅ Prompt optimisé (même résultat, moins de tokens)
prompt_court = """Rôle : analyste financier senior.
Contraintes : structuré, chiffré, concis.
Tâche : analysez ce rapport trimestriel : ..."""

Les deux versions transmettent exactement les mêmes cinq contraintes ; la seconde le fait sans les cinq « Vous devez » qui n’apportent rien au modèle. Sur un service qui traite dix mille rapports par jour, cette réécriture de trente secondes se paie tous les jours.

Choisir le bon modèle par tâche

Le deuxième levier tient au fait que tous les appels ne nécessitent pas le même modèle. Router une extraction de champs vers un modèle de raisonnement élevé, c’est payer une capacité que la tâche n’utilise pas, et attendre plus longtemps pour un résultat identique.

Type de tâcheModèle recommandéRaison
Classification / extractiongpt-5.6-lunaRapide, économique
Raisonnement complexegpt-5.6-terra en raisonnement mediumBon ratio qualité/coût
Tâches critiquesgpt-5.6-sol en raisonnement élevéMeilleure qualité, plus lent
Gros volumegpt-5.6-luna via Batch API-50 % du prix

En pratique, ce choix se codifie dans une fonction de routage plutôt que dans la tête des développeurs, sans quoi le modèle par défaut finit toujours par gagner :

import openai

client = openai.OpenAI()

def routeur_modele(tache: str, complexite: str) -> str:
    """Sélectionne le modèle optimal selon la tâche."""
    if complexite == "faible":
        return "gpt-5.6-luna"
    elif tache in ("raisonnement", "mathématiques", "code"):
        return "gpt-5.6-terra"
    elif complexite == "critique":
        return "gpt-5.6-sol"
    return "gpt-5.6-terra"

def appel_optimise(prompt: str, tache: str, complexite: str) -> str:
    modele = routeur_modele(tache, complexite)
    response = client.responses.create(
        model=modele,
        input=prompt,
    )
    return response.output_text

Optimiser les paramètres API

Une réponse trop longue coûte du temps de génération que personne ne lira. Spécifiez donc systématiquement max_output_tokens : c’est une limite stricte, elle protège autant votre facture que votre interface, et elle évite qu’un prompt mal formulé ne parte en digression de deux mille mots.

response = client.responses.create(
    model="gpt-5.6-terra",
    input="Résumez ce texte en une phrase.",
    max_output_tokens=100,  # Limite stricte
    temperature=0.0,         # Déterministe = plus rapide
)

Les paramètres d’échantillonnage jouent dans le même sens. Fixer temperature=0 rend les réponses déterministes et légèrement plus rapides, ce qui est exactement ce que vous voulez pour une extraction ou une classification, où la créativité n’est pas un atout mais une source de variance. Réduire top_p à 0,1 restreint l’espace de recherche et accélère la génération ; réservez ce réglage aux tâches où une seule formulation est acceptable, et gardez les valeurs par défaut là où la richesse de la réponse fait partie du produit.

Optimiser le réseau

Le trajet des paquets se paie sur chaque appel, et il est invisible dans vos métriques applicatives. L’API OpenAI est principalement hébergée aux États-Unis, côte Est : placer votre serveur applicatif dans la même région que l’endpoint représente un gain potentiel de 50 à 150 millisecondes de latence réseau. Pour une application conversationnelle, c’est une fraction sensible du TTFT.

Le second gain vient de la réutilisation des connexions. Sans pool, chaque requête rejoue le handshake TLS, ce qui ajoute plusieurs allers-retours avant même que la première donnée utile ne circule. Un client HTTP configuré une fois pour toutes règle le problème :

import httpx

# Client avec pool de connexions persistantes
client_http = httpx.Client(
    base_url="https://api.openai.com/v1",
    timeout=60.0,
    limits=httpx.Limits(
        max_connections=20,
        max_keepalive_connections=10,
    ),
)

Optimiser le post-traitement

Le dernier maillon est souvent celui qu’on oublie : une application qui reçoit la réponse en streaming mais attend la fin pour l’afficher annule tout le bénéfice du streaming. Traitez la réponse au fil de l’eau plutôt qu’après réception complète.

async def traitement_progressif(prompt: str):
    """Traite chaque chunk dès sa réception."""
    stream = client.responses.create(
        model="gpt-5.6-terra",
        input=prompt,
        stream=True,
    )

    buffer = ""
    for event in stream:
        if event.type == "response.output_text.delta":
            buffer += event.delta
            # Traitement par phrase complète
            if buffer.endswith((".", "!", "?")):
                yield buffer.strip()
                buffer = ""

Le découpage par phrase complète est un compromis délibéré : émettre chaque token produit un affichage nerveux, attendre le paragraphe entier redonne l’impression d’attente. La phrase est l’unité que le lecteur consomme naturellement. Reprenez ce pattern dès que votre interface doit afficher, lire à voix haute ou envoyer par flux ce que le modèle produit.

Points clés à retenir

  • Optimisez le prompt d’abord : moins de tokens = moins de latence et de coût
  • Routez vers le bon modèle selon la complexité de la tâche
  • Limitez max_output_tokens et utilisez temperature=0 quand c’est possible
  • Réutilisez les connexions HTTP et traitez les réponses en streaming