Guide · IA & agents
Recherche web citée avec Claude
Ajoutez web_search à l’API Messages, bornez les domaines et les appels, puis lisez les citations avant d’afficher la réponse.
Dans ce guide, la recherche web est l’outil serveur web_search de l’API Messages. Claude choisit la requête, l’API l’exécute, et la réponse arrive avec des citations. Vous fixez le nombre de recherches, les domaines autorisés, et ce qui peut être affiché.
Le stack est le SDK Python Anthropic et l’outil décrit sur Web search tool. L’installation est celle du SDK Python. Les commandes n’ont pas été rejouées le 2026-10-18.
Prérequis
- Python 3.10 ou plus récent, et
pip install anthropic. ANTHROPIC_API_KEYdans l’environnement.- La recherche web activée pour l’organisation. Si un administrateur l’a coupée dans la console, la requête qui inclut l’outil échoue en 400
invalid_request_error, avec un message qui dit que la recherche n’est pas activée. Ce n’est pas un code d’erreur à l’intérieur d’un résultat de recherche. - Un modèle qui accepte l’outil. La page dit de lire
capabilities.server_tools.web_search.supportedvia l’API Models avant d’envoyer. Les exemples de la page, le 2026-10-18, utilisentclaude-opus-5-5. Remplacez cet identifiant s’il n’est pas actif chez vous.
La recherche n’est pas disponible sur Amazon Bedrock, d’après la page. Sur Google Cloud, seule la version de base, sans filtrage dynamique, est indiquée. Ce guide reste sur l’API Claude et sur web_search_20250305, la version que la page utilise pour une recherche simple.
Les versions web_search_20260209 et web_search_20260318 ajoutent le filtrage dynamique. Leur allowed_callers vaut par défaut l’exécution de code, pas direct. Un modèle qui ne prend pas en charge l’appel programmatique renvoie un 400 tant que vous n’avez pas mis allowed_callers à ["direct"]. Pour un premier script, la version de base évite ce détour.
Architecture et frontière de confiance
Le modèle choisit une requête, le service Anthropic interroge le web, puis le modèle rédige à partir des résultats retenus. allowed_domains réduit le périmètre ; il ne certifie ni l’auteur, ni la date, ni l’exactitude d’une page. Le contenu récupéré reste une donnée non fiable. Il ne doit pas pouvoir changer les règles du programme ou déclencher seul un outil d’écriture, un achat ou un envoi.
Une citation montre quelle page a servi à la réponse. Elle ne garantit pas que la phrase résume fidèlement la page, ni que la page dit vrai. Ouvrez la source et contrôlez le passage. Les requêtes, résultats et réponses transitent par l’API ; la page de conservation Anthropic précise les conditions du zero data retention et ses exclusions. Ne présentez pas cette option comme active sans confirmation pour l’organisation, le modèle et la fonction utilisés.
Étape 1 : une question qui exige une page précise
Demandez un fait que vous pourrez ouvrir vous-même. Ici, une page de la documentation Python, pas une actu du jour et pas un cours de bourse. Si Claude répond sans bloc de recherche, vous n’avez pas une réponse issue du web, même si la phrase est juste.
import anthropic
MODEL = "claude-opus-5-5"
client = anthropic.Anthropic()
response = client.messages.create(
model=MODEL,
max_tokens=1024,
messages=[
{
"role": "user",
"content": (
"Cherche sur le web, avant de répondre, la page docs.python.org "
"qui documente pathlib.Path.read_text. "
"Cite l’URL. Si la recherche échoue, dis-le."
),
}
],
tools=[
{
"type": "web_search_20250305",
"name": "web_search",
"max_uses": 2,
"allowed_domains": ["docs.python.org"],
}
],
)
print(response.stop_reason)
print(response.usage)
for block in response.content:
print(block)
name doit être web_search. max_uses limite le nombre de recherches de la requête. Au-delà, le résultat est une erreur max_uses_exceeded, pas une quatrième page. allowed_domains et blocked_domains ne se mettent pas ensemble : les deux dans la même requête donnent un 400. Les entrées sont des domaines nus, avec un chemin optionnel, sans schéma. docs.python.org est valide. https://docs.python.org ne l’est pas.
user_location est optionnel. Si vous l’ajoutez, type doit être approximate, et country un code ISO 3166-1 alpha-2. Un code refusé est un 400. Ce script ne le définit pas, pour ne pas déplacer les résultats sans raison.
Vérification : la sortie contient un bloc server_tool_use dont le nom est web_search, puis un web_search_tool_result. S’ils manquent, ne présentez pas le texte comme une recherche.
Étape 2 : lire le résultat, y compris l’erreur en 200
Une recherche qui échoue, par exemple sur un plafond de débit, laisse souvent la requête HTTP en 200. L’erreur est dans le corps : content est alors un objet web_search_tool_result_error, avec error_code, et non une liste. Une recherche qui aboutit sans résultat renvoie une liste content vide. Une liste vide veut dire zéro page retenue, pas un échec du service.
Codes listés sur la page : too_many_requests, invalid_tool_input, max_uses_exceeded, query_too_long, request_too_large, unavailable. request_too_large arrive surtout avec une longue liste de domaines.
Chaque résultat de recherche porte url, title, page_age et encrypted_content. Pour continuer la conversation, renvoyez les blocs de l’assistant tels quels, y compris encrypted_content. S’il manque ou s’il a été modifié, la requête suivante échoue en 400.
Les citations sont toujours activées pour cet outil. Un objet web_search_result_location contient url, title, encrypted_index et cited_text. La page limite cited_text à 150 caractères. Ce champ, le titre et l’URL de citation ne comptent pas dans les tokens. Quand vous affichez la sortie de l’API telle quelle à un utilisateur, la page exige que les citations vers la source soient visibles. Si vous reformulez, la page renvoie à un avis juridique. Ce guide ne le remplace pas.
Vérification : ouvrez l’URL citée et retrouvez le sens de cited_text sur la page. Un titre seul ne suffit pas. Si error_code est présent, il n’y a pas de source à afficher.
Étape 3 : un tour long peut s’interrompre
stop_reason peut valoir pause_turn pendant une recherche longue. La reprise documentée consiste à renvoyer le message assistant en pause, inchangé, dans une nouvelle requête. Ce brouillon n’inclut pas cette boucle. Si vous la voyez, suivez la section de la page web search plutôt qu’un collage partiel.
Autre cas : si Claude appelle web_search et un outil client dans le même groupe d’appels parallèles, stop_reason vaut tool_use et la recherche ne part pas encore. Il faut renvoyer le résultat de l’outil client. Ce script n’a pas d’outil client. Si vous en ajoutez un, ne concluez pas que la recherche a eu lieu parce que le texte final est là.
response_inclusion n’existe qu’à partir de web_search_20260318. Le laisser sur la version 20250305 n’est pas dans les exemples de base. Ne l’ajoutez pas à ce script.
Vérification : notez stop_reason et, dans usage, le compteur web_search_requests tel que la page le montre dans l’objet d’usage. Un compteur à zéro et un texte affirmatif veulent dire que le modèle n’a pas recherché.
Ce qui peut casser
L’outil désactivé dans la console : 400, avant toute citation. Un domaine avec https:// : 400. allowed_domains et blocked_domains ensemble : 400. Un pays invalide dans user_location : 400.
Une version récente de l’outil, sans allowed_callers: ["direct"], sur un modèle qui ne fait pas d’appel programmatique : 400, avec un message qui demande ce réglage. La page dit que le filtrage dynamique lance la recherche depuis l’exécution de code, et que vous n’avez pas à ajouter vous-même l’outil d’exécution de code pour ce chemin. Ce n’est pas le chemin de ce brouillon.
encrypted_content modifié entre deux tours : 400 à la reprise. Un résultat vide n’est pas une erreur. Le traiter comme un échec réseau fait relancer une recherche inutile, et consomme max_uses.
Claude peut aussi répondre sans chercher, pour un fait qu’il juge stable. La page le dit. La phrase « cherche avant de répondre » pousse l’appel, elle ne le rend pas certain. D’où le contrôle sur server_tool_use. Le modèle ne doit pas être présenté comme un chercheur autonome : l’application borne ses domaines et ses appels, puis une personne contrôle les sources avant usage.
Comment vérifier
- Lancez le script. Relevez
stop_reason, le ou les blocsweb_search, eterror_codes’il y en a un. - Ouvrez chaque URL citée. Le
cited_textdoit s’y retrouver, dans la limite de 150 caractères documentée. - Relancez une fois avec un domaine volontairement sans schéma faux, par exemple une URL complète dans
allowed_domains, et constatez le 400. Remettez le domaine nu ensuite. - N’affichez pas la réponse à quelqu’un d’autre sans les citations, si vous montrez la sortie de l’API telle quelle.
Ces lancements n’ont pas été faits le 2026-10-18.
Sources
Ces pages ont été relues le 2026-10-19. Elles documentent les versions d’outil, max_uses, le filtre de domaines, les codes d’erreur, pause_turn, les champs de citation et les conditions de conservation. Le script n’a pas été exécuté.