Aller au contenu principal

Configurer et contrôler les résultats web

Configurer et contrôler les résultats web

Activer Web Search prend une ligne ; en tirer des réponses fiables demande trois réglages que cette leçon détaille. Le premier décide de la quantité de web injectée dans le contexte, et il pèse directement sur votre facture. Le deuxième oriente les requêtes que le modèle formule lui-même — car c’est lui qui les écrit, pas vous. Le troisième concerne les citations, sans lesquelles une réponse sourcée n’est qu’une réponse affirmative.

Paramètre search_context_size

Le paramètre search_context_size contrôle la quantité de contenu web injecté dans le contexte du modèle. Il ne change ni le nombre de recherches ni leur qualité : il détermine combien de texte, une fois les pages trouvées, entre effectivement dans le prompt. C’est donc un arbitrage entre exhaustivité et coût, et il se règle par type de tâche, pas une fois pour toutes.

from openai import OpenAI

client = OpenAI()

# Contexte minimal : réponses rapides et concises
response = client.responses.create(
    model="gpt-5.6-terra",
    input="Quel est le PIB de la France en 2025 ?",
    tools=[{
        "type": "web_search_preview",
        "search_context_size": "low"
    }]
)

# Contexte moyen : bon compromis (defaut)
response = client.responses.create(
    model="gpt-5.6-terra",
    input="Resume les tendances du marche IA en Europe",
    tools=[{
        "type": "web_search_preview",
        "search_context_size": "medium"
    }]
)

# Contexte large : analyses approfondies
response = client.responses.create(
    model="gpt-5.6-terra",
    input="Compare les strategies IA de la France, l'Allemagne et les Pays-Bas",
    tools=[{
        "type": "web_search_preview",
        "search_context_size": "high"
    }]
)

Impact sur les coûts et la latence

La règle empirique tient en une phrase : montez d’un cran seulement quand la réponse obtenue vous a concrètement déçu. Une date, un chiffre, une confirmation factuelle n’exigent rien de plus que low, et y consacrer high revient à payer un dossier complet pour lire une ligne.

TailleTokens contexteLatenceCoûtUsage
lowMinimalRapideFaibleFaits simples, chiffres
mediumModéréStandardMoyenSynthèses, comparaisons
highMaximalPlus lentÉlevéAnalyses approfondies

Guider les requêtes de recherche par le prompt

Voici le point que l’on découvre généralement trop tard : le modèle formule ses propres requêtes de recherche. Vous écrivez « quelles sont les évolutions réglementaires récentes ? » et il traduit cela en mots-clés que vous ne voyez pas. La qualité des résultats dépend donc d’une reformulation sur laquelle vous n’avez qu’une prise indirecte — le prompt système. Nommez-y les sources qui font autorité dans votre domaine et la période qui vous intéresse : c’est ce qui déplace le plus l’aiguille.

response = client.responses.create(
    model="gpt-5.6-terra",
    instructions=(
        "Tu es un analyste de marche spécialisé en technologie européenne. "
        "Quand tu fais des recherches web, privilegia les sources institutionnelles "
        "(Commission européenne, INSEE, Eurostat) et les médias spécialisés "
        "(Les Echos, La Tribune, TechCrunch). "
        "Ignore les blogs personnels et les forums."
    ),
    input="Quel est l'état du financement des startups IA en France ?",
    tools=[{
        "type": "web_search_preview",
        "search_context_size": "high"
    }]
)

Extraire et structurer les citations

Les citations arrivent sous forme d’annotations attachées à la réponse, et non dans le texte lui-même. Cette séparation est une bonne nouvelle : elle vous permet d’afficher les sources comme vous l’entendez, de les vérifier, ou de refuser une réponse qui n’en comporte aucune. Dans toute application où la réponse engage — juridique, médical, financier —, traiter l’absence d’annotation comme une erreur est plus sûr que de faire confiance au texte.

def extraire_sources(response) -> list[dict]:
    """Extrait toutes les citations URL d'une réponse avec Web Search."""
    sources = []
    for item in response.output:
        if item.type == "message":
            for block in item.content:
                if hasattr(block, "annotations"):
                    for ann in block.annotations:
                        if ann.type == "url_citation":
                            sources.append({
                                "url": ann.url,
                                "titre": ann.title,
                                "extrait_debut": ann.start_index,
                                "extrait_fin": ann.end_index
                            })
    return sources

# Utilisation
response = client.responses.create(
    model="gpt-5.6-terra",
    input="Quelles sont les nouvelles règles RGPD pour l'IA en 2026 ?",
    tools=[{"type": "web_search_preview"}]
)

sources = extraire_sources(response)
for s in sources:
    print(f"  {s['titre']}: {s['url']}")

Pattern : recherche avec validation croisée

Une source unique reste une source unique, même trouvée par un modèle. Sur une information qui engage une décision, demandez explicitement la confirmation par plusieurs sources indépendantes et faites signaler les divergences plutôt que de les laisser arbitrer en silence : un désaccord entre deux sources est en soi une information, souvent plus utile que la moyenne des deux.

def recherche_validee(question: str, min_sources: int = 3) -> dict:
    """Recherche web avec exigence de sources multiples."""
    response = client.responses.create(
        model="gpt-5.6-terra",
        instructions=(
            f"Pour répondre a cette question, tu dois trouver au moins "
            f"{min_sources} sources independantes qui confirment l'information. "
            "Si les sources se contredisent, signale les divergences. "
            "Cite chaque source explicitement."
        ),
        input=question,
        tools=[{
            "type": "web_search_preview",
            "search_context_size": "high"
        }]
    )

    sources = extraire_sources(response)
    return {
        "reponse": response.output_text,
        "sources": sources,
        "fiabilite": "haute" if len(sources) >= min_sources else "a_verifier"
    }

Gérer l’absence de résultats

Reste le cas que l’on oublie de traiter : la recherche ne donne rien. Le risque n’est pas l’absence de réponse — c’est qu’à défaut de résultats, le modèle réponde depuis ses connaissances internes sans le signaler, et vous rende une information plausible mais périmée. Demandez-lui de le dire explicitement, et prévoyez la reformulation.

def recherche_avec_fallback(question: str) -> dict:
    """Recherche web avec detection d'échec et reformulation."""
    # Premiere tentative
    response = client.responses.create(
        model="gpt-5.6-terra",
        input=question,
        tools=[{"type": "web_search_preview"}]
    )

    sources = extraire_sources(response)

    if len(sources) == 0:
        # Reformulation automatique
        response = client.responses.create(
            model="gpt-5.6-terra",
            input=f"Reformule cette question pour une recherche web plus efficace, "
                  f"puis cherche : {question}",
            tools=[{"type": "web_search_preview", "search_context_size": "high"}]
        )
        sources = extraire_sources(response)

    return {
        "reponse": response.output_text,
        "sources": sources
    }

Web Search avec streaming

Une recherche web prend quelques secondes, parfois plus si le modèle enchaîne plusieurs requêtes. En streaming, l’utilisateur voit la réponse se construire au lieu de fixer un indicateur de chargement — et sur ce type de latence, la différence de perception est considérable pour un coût d’implémentation quasi nul.

stream = client.responses.create(
    model="gpt-5.6-terra",
    input="Quelles sont les actualités tech de la semaine ?",
    tools=[{"type": "web_search_preview"}],
    stream=True
)

for event in stream:
    if event.type == "response.output_text.delta":
        print(event.delta, end="", flush=True)
    elif event.type == "response.completed":
        # Extraire les sources a la fin
        sources = extraire_sources(event.response)
        print(f"\n\n--- {len(sources)} sources consultees ---")

Points clés à retenir

  • search_context_size contrôle le volume de données web injecté
  • Le prompt système guide le modèle vers les bonnes sources
  • Extrayez les annotations url_citation pour tracer les sources
  • Implémentez une validation croisée pour les informations critiques
  • Gérez l’absence de résultats avec reformulation automatique