Passa al contenuto principale

Programmatic Tool Calling

Avanzato
What you'll learn
  • Capire cosa succede davvero quando Claude chiama il tuo tool da dentro una sandbox — e perché il tuo tool gira comunque sulla tua macchina
  • Abilitarlo correttamente con allowed_callers, e sapere perché non è un confine di sicurezza
  • Conoscere i numeri reali: cosa fa risparmiare, su quali carichi di lavoro, e dove invece ti costa
  • Evitare le cinque modalità di errore che producono 400 e TimeoutError in produzione

Il problema che risolve

Il tool use classico è una conversazione. Claude chiede una chiamata a un tool, tu rispondi, l'intero risultato finisce nella finestra di contesto, Claude lo legge e chiede la successiva. Venti lookup significano venti passaggi di inferenza e venti payload grezzi che restano nel contesto per sempre.

Gran parte di quel payload è spreco. Se vuoi sapere quali di venti dipendenti hanno sforato il budget spese, Claude non ha bisogno di ogni singola voce — gli servono quei pochi nomi. Ma nel tool use classico le voci devono passare attraverso il modello per essere filtrate da lui.

Il programmatic tool calling ribalta la cosa. Claude scrive uno script Python, lo script chiama i tuoi tool in un loop, filtra i risultati, e al modello torna solo ciò che lo script stampa. I dati grezzi non entrano mai nella finestra di contesto.

Cosa succede davvero

Ecco la parte che quasi ogni riassunto di questa funzionalità sbaglia: il tuo tool non gira dentro la sandbox. Il container di Anthropic non ha accesso al tuo database.

Quello che accade davvero è che il codice Python di Claude si mette in pausa a metà esecuzione, l'API restituisce la chiamata a te, e l'interprete riprende quando rispondi:

Guided walkthrough1 of 5
  1. Gira dentro il container di code execution. I tuoi tool appaiono a quel codice come funzioni Python async — una per tool, ciascuna prende un singolo dict di argomenti e restituisce una stringa.

Poiché le funzioni sono async, Claude può fare fan-out con asyncio.gather e colpire dieci tool in parallelo — cosa che il tool use classico può solo approssimare con blocchi tool paralleli.

Che aspetto ha davvero il codice generato da Claude

import json

rows = json.loads(await query_database({"sql": "<sql>"}))
top = sorted(rows, key=lambda r: r["revenue"], reverse=True)[:5]
print(f"Top 5 customers: {top}")

Nota il json.loads. La funzione del tool restituisce una stringa — il testo letterale del tool_result che rimandi indietro. Se la descrizione del tuo tool non dice "restituisce una lista di righe come oggetti JSON", Claude non ha modo di sapere che può deserializzare quella cosa, e tratterà i tuoi dati come un blob opaco. La frase sul formato di output nella descrizione del tool smette di essere documentazione e diventa codice portante. È la singola riga con più leva che scriverai adottando questa funzionalità.

Come attivarlo

Un campo sul tool che vuoi far chiamare dal codice, più il tool di code execution nella richiesta:

Abilitare la chiamata programmatica su un tool

{
"name": "query_database",
"description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
"input_schema": { "type": "object", "properties": { "sql": { "type": "string" } }, "required": ["sql"] },
"allowed_callers": ["code_execution_20260120"]
}

allowed_callers assume tre forme:

ValoreSignificato
["direct"]Tool use classico. È il default quando il campo viene omesso.
["code_execution_20260120"]Claude viene guidato a chiamarlo solo da dentro il codice.
["direct", "code_execution_20260120"]Entrambi. La documentazione lo sconsiglia — scegline uno, così Claude riceve un segnale non ambiguo.

Ogni blocco tool_use nella risposta porta ora un caller: o {"type": "direct"} oppure un caller di code execution il cui tool_id corrisponde al blocco server_tool_use che ha eseguito lo script. È così che attribuisci una chiamata allo script che l'ha fatta.

Non è un confine di sicurezza

La documentazione è insolitamente esplicita su questo, e vale la pena ripeterlo perché è facile assumere il contrario: allowed_callers controlla come il tool viene presentato a Claude. Non è un blocco rigido a livello di API. Claude è fortemente guidato a rispettarlo — ma il tuo client deve comunque essere pronto a ricevere un tool_use diretto per qualunque tool definisca, e non devi usare questo campo come meccanismo di autorizzazione. L'autorizzazione sta nel tuo handler del tool, dov'è sempre stata.

I numeri

Le cifre riportate da Anthropic stessa, così puoi giudicare se la complessità vale la pena:

  • Su task di ricerca complessi, l'uso medio è sceso da 43.588 a 27.297 token — una riduzione del 37%.
  • Sui benchmark GIA l'accuratezza è salita dal 46,5% al 51,2%; sul knowledge retrieval interno, dal 25,6% al 28,5%. Meno token e risposte migliori, perché il modello ragiona su conclusioni invece di annegare in payload grezzi.
  • Sui benchmark di ricerca agentica (BrowseComp, DeepSearchQA), aggiungere la chiamata programmatica sopra ai tool di ricerca di base ha migliorato le prestazioni in media dell'11% usando il 24% di token di input in meno.
  • Latenza: orchestrare più di 20 chiamate a tool in un unico blocco di codice elimina oltre 19 passaggi di inferenza.

La forma del vantaggio è il segnale rivelatore. Conviene quando hai 3+ chiamate dipendenti, un loop, un filtro o un fan-out. Non porta nulla — e ti costa un container — quando a Claude serve esattamente una chiamata e vuole comunque leggere l'intera risposta.

Watch out
  • Claude Haiku 4.5 accetta i tipi di tool più recenti ma NON supporta il programmatic tool calling né la persistenza dello stato REPL che ne dipende. Lì le versioni più nuove si comportano silenziosamente come code_execution_20250825. Se stai instradando su Haiku per risparmiare, non stai ottenendo questa funzionalità — e non riceverai nessun errore che te lo dica.

Quanto costa

Il programmatic tool calling viene fatturato come code execution, e la code execution si fattura a ora-container, non a chiamata:

  • 1.550 ore gratuite al mese, per organizzazione.
  • Oltre quella soglia, 0,05 $ all'ora, per container.
  • Il tempo di esecuzione ha un minimo di 5 minuti — uno script da due secondi fattura comunque cinque minuti di container.
  • Se alleghi file alla richiesta, il tempo di esecuzione viene fatturato anche se il tool non viene mai invocato, perché i file vengono comunque precaricati su un container.
  • È gratuito quando la stessa richiesta usa anche web search o web fetch (web_search_20260209 / web_fetch_20260209 o successivi).

Due conseguenze da interiorizzare. Primo, il minimo di 5 minuti significa che tanti container di breve durata è il pattern costoso; riusare un solo container lungo una sessione è quello economico. Secondo, questa funzionalità non è idonea alla Zero Data Retention — se la ZDR è un requisito contrattuale per te, questo è un muro, non una manopola da regolare.

I cinque modi in cui si rompe

Guided walkthrough1 of 5
  1. Quando ci sono chiamate a tool programmatiche pendenti, il tuo messaggio di risposta deve contenere SOLO blocchi tool_result. Non testo più risultati. Non risultati seguiti da una frase gentile. Solo blocchi tool_result.

Le stringhe di versione, decodificate

Tutte e tre le versioni di code execution sono generalmente disponibili e non richiedono nessun beta header:

VersioneCosa aggiunge
code_execution_20250825La baseline. Bash + Python + operazioni su file. Supportata su ogni modello attuale.
code_execution_20260120Aggiunge la persistenza dello stato REPL e il programmatic tool calling. È quella che ti serve.
code_execution_20260521Runtime identico a 20260120. L'unica differenza è che la descrizione del tool informa Claude del limite di 90 secondi di wall-clock per cella Python, così può fare il budget delle celle lunghe. Una cella che sfora il limite restituisce un return_code diverso da zero con stato detection_timeout.

Quest'ultima riga è un bel pezzo di design API da notare: un bump di versione il cui intero contenuto è un prompt migliore per il modello. Entrambe le stringhe sono intercambiabili dentro allowed_callers, e le risposte etichettano sempre il caller come code_execution_20260120 indipendentemente da quale hai dichiarato.

Il container stesso non ha accesso a internet — Claude non può fare pip install a runtime, quindi hai a disposizione il set di librerie preinstallate (pandas, numpy, scipy, scikit-learn, statsmodels e affini) e nulla di più. I container vengono messi in checkpoint dopo circa cinque minuti di inattività, sono ripristinabili per ID, e scadono 30 giorni dopo la creazione.

Quando usarlo

Usa il programmatic tool calling quando il modello viene impiegato come loop e filtro più che come ragionatore: lookup in batch su N entità, terminazione anticipata appena una condizione è soddisfatta, selezione condizionale del tool in base a un risultato intermedio, oppure schiacciare un dump di log da 200 KB nelle dieci righe che contano.

Usa invece il Tool Search Tool quando il tuo problema è che le definizioni si mangiano il contesto prima ancora che venga fatta una sola chiamata — marca i tool con defer_loading: true e Claude li carica su richiesta. I due sono complementari, non alternativi: la tool search trova il tool giusto, la chiamata programmatica lo esegue a basso costo. Se le tue definizioni di tool superano i 10K token circa, probabilmente ti servono entrambi.

E se stai affrontando la cosa dall'altro capo — un agente il cui contesto sta annegando nei risultati dei tool MCP — parti da Costo in token di MCP e Context Engineering, perché i token più economici restano quelli che non invii mai.

Check yourself

0/5
  1. Dove viene eseguito davvero il tuo tool durante il programmatic tool calling?
  2. Puoi affidarti a allowed_callers per impedire che un tool venga invocato direttamente?
  3. Il tuo agente instrada su Claude Haiku 4.5 per risparmiare e passa code_execution_20260120. Cosa succede?
  4. Quando c'è una chiamata a tool programmatica pendente, cosa può contenere il tuo messaggio di risposta?
  5. Uno script da due secondi gira in un container nuovo. Quanto tempo di code execution viene fatturato?
Premi Invio o Spazio per girare la carta. Usa le frecce sinistra e destra per spostarti tra le carte.Termine mostrato.
1 / 7

Fonti e approfondimenti