Aller au contenu principal

Optimiser les tokens image

Maîtriser vos coûts en production

En production, les tokens image peuvent représenter une part significative de votre facture API. Une image en mode high consomme jusqu’à 1792 tokens — l’équivalent de plusieurs paragraphes de texte. Multipliez par des centaines ou des milliers de requêtes quotidiennes, et l’optimisation devient une nécessité.

Stratégie 1 : choisir le bon niveau de détail

Le paramètre detail est votre levier d’optimisation principal. L’erreur la plus courante est d’utiliser high par défaut alors que low ou auto suffisent dans la majorité des cas.

Matrice de décision

Tâche Détail recommandé Tokens estimés
Classification d'image low ~256
Description générale auto ~512-768
Alt text / accessibilité low ~256
Modération de contenu auto ~512-768
OCR / extraction de texte high ~1024-1792
Analyse de graphiques high ~1024-1792
Détection de défauts high ~1024-1792

Stratégie 2 : redimensionner avant l’envoi

Les images haute résolution (4K, 8K) sont rarement nécessaires pour l’analyse par IA. Redimensionner systématiquement vos images avant l’envoi réduit les tokens sans impact perceptible sur la qualité de l’analyse.

from PIL import Image
import io
import base64

class OptimiseurImage:
    TAILLES_PAR_TACHE = {
        "classification": (512, 512),
        "description": (1024, 1024),
        "ocr": (2048, 2048),
        "comparaison": (800, 800),
    }

    @staticmethod
    def optimiser(chemin, tache="description", qualite=85):
        taille_max = OptimiseurImage.TAILLES_PAR_TACHE.get(
            tache, (1024, 1024)
        )

        img = Image.open(chemin)

        # Ne pas agrandir les petites images
        if img.width <= taille_max[0] and img.height <= taille_max[1]:
            pass
        else:
            img.thumbnail(taille_max)

        # Convertir en JPEG pour réduire la taille
        if img.mode in ("RGBA", "P"):
            img = img.convert("RGB")

        buffer = io.BytesIO()
        img.save(buffer, "JPEG", quality=qualite)
        buffer.seek(0)

        encoded = base64.standard_b64encode(buffer.read()).decode()
        return f"data:image/jpeg;base64,{encoded}"

Stratégie 3 : pipeline en deux passes

Pour les volumes importants, utilisez un pipeline en deux passes — une première passe rapide en low pour trier, puis une seconde passe en high uniquement sur les images qui le nécessitent :

def pipeline_deux_passes(images):
    # Passe 1 : classification rapide (low)
    classifications = []
    for img in images:
        response = client.responses.create(
            model="grok-4",
            input=[
                {"type": "input_image", "image_url": img, "detail": "low"},
                {"type": "input_text", "text": "Classifie : document, photo, graphique, autre. Un mot."}
            ],
            store=False
        )
        classifications.append({
            "url": img,
            "type": response.output_text.strip().lower()
        })

    # Passe 2 : analyse détaillée (high) uniquement si nécessaire
    resultats = []
    for item in classifications:
        if item["type"] in ("document", "graphique"):
            detail = "high"
        else:
            detail = "auto"

        response = client.responses.create(
            model="grok-4",
            input=[
                {"type": "input_image", "image_url": item["url"], "detail": detail},
                {"type": "input_text", "text": "Analyse détaillée de cette image."}
            ],
            store=False
        )
        resultats.append(response.output_text)

    return resultats

Stratégie 4 : mise en cache

Si vous analysez les mêmes images plusieurs fois (tests, développement, démo), mettez en cache les résultats :

import hashlib
import json

cache = {}

def vision_avec_cache(image_url, prompt, detail="auto"):
    # Créer une clé unique
    cle = hashlib.sha256(
        f"{image_url}:{prompt}:{detail}".encode()
    ).hexdigest()

    if cle in cache:
        return cache[cle]

    response = client.responses.create(
        model="grok-4",
        input=[
            {"type": "input_image", "image_url": image_url, "detail": detail},
            {"type": "input_text", "text": prompt}
        ],
        store=False
    )

    cache[cle] = response.output_text
    return response.output_text

Monitorer et alerter

Mettez en place un suivi des coûts pour détecter les dérives :

def monitorer_tokens(response, seuil_alerte=5000):
    usage = response.usage
    image_tokens = usage.prompt_tokens_details.image_tokens

    if image_tokens > seuil_alerte:
        print(f"ALERTE : {image_tokens} tokens image (seuil : {seuil_alerte})")

    return {
        "image_tokens": image_tokens,
        "text_tokens": usage.prompt_tokens_details.text_tokens,
        "total": usage.total_tokens
    }

Points clés à retenir

  • Choisissez le niveau de detail adapté à la tâche — low quand c’est suffisant
  • Redimensionnez les images avant l’envoi pour réduire la consommation
  • Utilisez un pipeline en deux passes pour les gros volumes
  • Mettez en cache les résultats pour éviter les appels redondants
  • Monitorez les tokens image en production pour anticiper les coûts