Le streaming d'outils à granularité fine transmet l'entrée d'un outil à votre client au fur et à mesure que Claude la génère, sans mise en mémoire tampon côté serveur ni validation JSON. Le fait de sauter l'étape de mise en mémoire tampon réduit le temps jusqu'au premier fragment d'un paramètre volumineux, tel qu'un document ou un bloc de code, et les fragments arrivent via les mêmes événements de Streaming de messages que l'utilisation d'outils standard.
Tous les modèles prennent en charge le streaming d'outils à granularité fine sur l'API Claude, Amazon Bedrock, Claude Platform sur AWS, Google Cloud et Microsoft Foundry. Pour l'utiliser, définissez eager_input_streaming sur true pour tout outil défini par l'utilisateur pour lequel vous souhaitez activer le streaming à granularité fine, et activez le streaming sur votre requête.
Le champ eager_input_streaming est facultatif. Le définir sur true active le streaming à granularité fine pour cet outil, et l'omettre vous donne le streaming standard avec mise en mémoire tampon, dans lequel l'API met en mémoire tampon et valide chaque valeur de paramètre avant de la renvoyer en streaming. L'exception est une requête qui envoie encore l'ancien en-tête bêta fine-grained-tool-streaming-2025-05-14, qui active le streaming à granularité fine pour les outils qui laissent le champ non défini. Le champ par outil remplace cet en-tête, et un false explicite conserve le streaming avec mise en mémoire tampon pour un outil même lorsqu'une requête l'envoie encore. Consultez la Référence des outils pour la définition du champ.
L'exemple suivant active le streaming à granularité fine pour un outil make_file et demande à Claude un long poème, afin que l'entrée de l'outil soit suffisamment volumineuse pour observer son arrivée en streaming :
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=65536,
model="claude-opus-5",
tools=[
{
"name": "make_file",
"description": "Write text to a file",
"eager_input_streaming": True,
"input_schema": {
"type": "object",
"properties": {
"filename": {
"type": "string",
"description": "The filename to write text to",
},
"lines_of_text": {
"type": "array",
"description": "An array of lines of text to write to the file",
},
},
"required": ["filename", "lines_of_text"],
},
}
],
messages=[
{
"role": "user",
"content": "Can you write a long poem and make a file called poem.txt?",
}
],
) as stream:
for event in stream:
if event.type == "input_json":
print(event.partial_json, end="", flush=True)
final_message = stream.get_final_message()
print()
for block in final_message.content:
if block.type == "tool_use":
print(f"Complete tool input: {block.input}")Chaque onglet active le streaming à granularité fine pour l'outil make_file. Les onglets SDK affichent chaque fragment d'entrée dès son arrivée, puis affichent l'entrée complète accumulée une fois le flux terminé. L'onglet cURL montre le flux d'événements brut, et l'onglet CLI utilise jq pour n'afficher que les fragments. Comme les fragments affichés se rejoignent pour former l'entrée complète de l'outil, le poème remplit votre terminal au fur et à mesure que Claude l'écrit :
{"filename": "poem.txt", "lines_of_text": ["The Wanderer's Journey", "", "I.", "", "Beneath the vast and star-strewn sky,", "Where silver moonbeams softly lie,", ...
Complete tool input: {"filename": "poem.txt", "lines_of_text": ["The Wanderer's Journey", ...]}Sans eager_input_streaming, l'API met en mémoire tampon et valide chaque valeur de paramètre avant de la renvoyer en streaming, donc rien ne s'affiche pour un paramètre volumineux tant que Claude n'a pas fini de le générer. Avec lui, les fragments commencent à arriver dès que Claude commence le paramètre, et ils sont généralement plus longs, avec moins de coupures au milieu des mots.
Le contrat d'accumulation est le même que pour le streaming d'utilisation d'outils standard, donc cette section s'applique avec et sans eager_input_streaming. Consultez Input JSON delta dans Streaming de messages pour le format des événements. Le streaming d'outils à granularité fine change ce que vous pouvez supposer du résultat : le serveur diffuse les fragments en streaming sans les valider, donc la chaîne accumulée pourrait ne pas être du JSON valide.
Lorsqu'un bloc de contenu tool_use est diffusé en streaming, l'événement initial content_block_start contient input: {} (un objet vide). Il s'agit d'un espace réservé. L'entrée réelle arrive sous la forme d'une série d'événements input_json_delta, chacun portant un fragment de chaîne partial_json. Pour assembler l'entrée complète, concaténez ces fragments et analysez le résultat lorsque le bloc se ferme.
Lorsque votre SDK fournit un assistant d'accumulation (comme le font les onglets Python, TypeScript, Go, Java et Ruby de l'exemple précédent), il s'en charge pour vous. Le modèle manuel est destiné aux SDK sans assistant, ou lorsque vous voulez un contrôle total sur la façon dont l'entrée est assemblée.
Le contrat d'accumulation :
content_block_start avec type: "tool_use", initialisez une chaîne vide : input_json = ""content_block_delta avec type: "input_json_delta", ajoutez : input_json += event.delta.partial_jsoncontent_block_stop, analysez la chaîne accumuléeProtégez l'analyse, comme le font les exemples SDK suivants. Une réponse peut également s'arrêter à max_tokens au milieu d'un paramètre. Vérifiez la raison d'arrêt et décidez s'il faut réessayer la requête avec un max_tokens plus élevé ou réparer l'entrée partielle.
L'incohérence de type entre le input: {} initial (objet) et partial_json (chaîne) est intentionnelle. L'objet vide marque l'emplacement dans le tableau de contenu. Les chaînes delta construisent la valeur réelle.
client = anthropic.Anthropic()
tool_inputs: dict[int, str] = {} # index -> accumulated JSON string
with client.messages.stream(
model="claude-opus-5",
max_tokens=1024,
tools=[
{
"name": "get_weather",
"description": "Get current weather for a city",
"eager_input_streaming": True,
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
}
],
messages=[{"role": "user", "content": "Weather in Paris?"}],
) as stream:
for event in stream:
match event.type:
case "content_block_start" if event.content_block.type == "tool_use":
tool_inputs[event.index] = ""
case "content_block_delta" if event.delta.type == "input_json_delta":
tool_inputs[event.index] += event.delta.partial_json
case "content_block_stop" if event.index in tool_inputs:
raw_input = tool_inputs[event.index]
try:
parsed = json.loads(raw_input)
except json.JSONDecodeError:
# Il n'est pas garanti que la chaîne accumulée soit du JSON valide.
# Voir « Gestion du JSON invalide dans les réponses d'outils » sur cette page.
print(f"Invalid tool input: {raw_input}")
else:
print(f"Tool input: {parsed}")Avec le streaming d'outils à granularité fine, l'entrée accumulée pour un appel d'outil peut être du JSON invalide ou incomplet. Lorsque c'est le cas, vous ne pouvez pas exécuter l'outil, alors signalez plutôt l'échec à Claude. Le content d'un résultat d'outil n'a pas besoin d'être du JSON, mais envelopper la chaîne brute dans un objet JSON sous une seule clé indique sans ambiguïté à Claude que vous avez reçu du JSON invalide, et préserve l'entrée d'origine pour le débogage :
{
"INVALID_JSON": "<the unparseable input you received>"
}Renvoyez l'enveloppe, sérialisée en chaîne, comme content d'un bloc de contenu de résultat d'outil avec is_error défini sur true :
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"is_error": true,
"content": "{\"INVALID_JSON\": \"<the unparseable input you received>\"}"
}Comprenez comment fonctionne la fenêtre de contexte, comment la réflexion étendue et l'utilisation d'outils y sont comptabilisées, et comment gérer le contexte à mesure que les conversations s'allongent.
Diffusez en streaming les réponses de l'API Messages de manière incrémentale avec des événements envoyés par le serveur, y compris les deltas de texte, d'utilisation d'outils et de réflexion étendue.
Analysez les blocs tool_use, formatez les réponses tool_result et gérez les erreurs avec is_error.
Répertoire des outils fournis par Anthropic et référence pour les propriétés facultatives de définition d'outils.
Was this page helpful?