Structured output e tool calling producono la stessa cosa: un oggetto JSON che rispetta uno schema. Cambia il contratto. Con lo structured output il JSON è la risposta finale; con un tool il JSON è una richiesta che la tua applicazione esegue e di cui rimanda il risultato al modello. Questo confronto è costruito dalla documentazione ufficiale di OpenAI, Anthropic, Google Gemini, Ollama e llama.cpp, letta il 31 ottobre 2026. Non contiene test o misure fatti per l'articolo.
In breve:
- Usa lo structured output quando vuoi la risposta in un formato preciso: estrazione di dati, classificazione, un oggetto da salvare o passare a un'altra API.
- Usa il tool calling quando il modello deve far fare qualcosa al tuo sistema prima di rispondere: leggere dati, chiamare un servizio, eseguire un'azione.
- OpenAI, Anthropic e Gemini tracciano lo stesso confine: formato della risposta da una parte, azione durante la conversazione dall'altra.
- In entrambi i casi conviene la modalità stretta (strict o constrained decoding): lo schema viene imposto in generazione, non solo suggerito.
- Schema valido non vuol dire valori giusti. Rifiuti, risposte troncate e valori sbagliati ma ben formati vanno gestiti nel codice.
- In locale, con Ollama e llama.cpp, la sintassi è simile ma il modello conta di più: lo schema va descritto anche nel prompt e il template della chat deve supportare i tool.
La domanda giusta
Non "JSON o tool?". È: dopo questo JSON il modello ha ancora bisogno di qualcosa dal tuo sistema?
Se la risposta è no, il JSON chiude il lavoro. Lo leggi, lo validi, lo usi. È structured output.
Se la risposta è sì, il JSON è una richiesta. La tua applicazione esegue la funzione, rimanda il risultato e il modello continua. È tool calling, e porta con sé un loop.
La guida di OpenAI agli structured outputs lo dice in modo diretto: se stai collegando il modello a strumenti, funzioni o dati del tuo sistema, usa il function calling. Se vuoi strutturare l'output con cui il modello risponde all'utente, usa un formato di risposta strutturato. La documentazione di Gemini sugli structured outputs ha una tabella con lo stesso confine: structured output per formattare la risposta finale, function calling per agire durante la conversazione.
Structured output: il JSON è la risposta
Con lo structured output passi uno schema JSON e il modello risponde rispettandolo. I casi tipici citati dalle tre documentazioni sono gli stessi: estrarre dati da testo libero, classificare in categorie fisse, generare un oggetto pronto per un'API.
Come si attiva, secondo le docs:
- OpenAI: lo schema va nel formato della risposta (
text.formatnella Responses API,response_formatin Chat Completions). OpenAI consiglia di usare sempre gli Structured Outputs al posto della vecchia JSON mode, che garantisce JSON valido ma non il rispetto dello schema. - Anthropic: lo schema va in
output_config.formatcontype: "json_schema". La documentazione di Claude spiega che l'output è vincolato con constrained decoding, quindi niente errori di parsing né campi obbligatori mancanti. - Gemini: in
response_formatsi impostamime_typeaapplication/jsone si passa lo schema nel camposchema. Gli SDK accettano modelli Pydantic e Zod.
Il punto in comune è che lo schema non è un'istruzione nel prompt. Il provider lo compila in una grammatica e limita i token che il modello può generare. Per questo la prima richiesta con uno schema nuovo può essere più lenta: OpenAI e Anthropic lo dicono entrambi, e Anthropic aggiunge che la grammatica compilata resta in cache per 24 ore dall'ultimo uso.
Tool calling: il JSON è una richiesta
Con il tool calling descrivi una o più funzioni (nome, descrizione, schema degli argomenti) e il modello decide se chiamarne una. Non la esegue lui. La guida di OpenAI al function calling descrive il flusso in cinque passi:
1. Richiesta al modello con i tool che può chiamare. 2. Il modello risponde con una chiamata a un tool. 3. La tua applicazione esegue il codice con gli argomenti ricevuti. 4. Seconda richiesta al modello con il risultato del tool. 5. Risposta finale, oppure altre chiamate.
Anthropic e Gemini descrivono lo stesso giro. La panoramica sul tool use di Claude distingue i client tool, che girano nella tua applicazione, dai server tool che Anthropic esegue per te, come la ricerca web. Gemini supporta chiamate in parallelo (più funzioni indipendenti nello stesso turno) e in sequenza (una chiamata che dipende dal risultato della precedente).
Il prezzo del tool calling è il loop. Ogni chiamata è un giro in più di richiesta e risposta, e le definizioni dei tool entrano nel contesto. OpenAI scrive che le funzioni sono iniettate nel messaggio di sistema, contano sul limite di contesto e sono fatturate come token di input. Anthropic aggiunge un prompt di sistema per il tool use, con il numero di token indicato per modello. Il loop e il suo costo sono il tema del pezzo sul tool engineering nel loop di un agente.
Il confronto in una tabella
Criterio | Structured output | Tool calling |
|---|---|---|
Cosa rappresenta il JSON | La risposta finale | Una richiesta da eseguire |
Chi agisce dopo | Il tuo codice, una volta | La tua applicazione, poi di nuovo il modello |
Giri di richiesta | Uno | Almeno due per ogni chiamata |
Casi tipici | Estrazione, classificazione, oggetti per un'API | Leggere dati, chiamare servizi, eseguire azioni |
Dove va lo schema | Formato della risposta | Parametri di ogni tool |
Garanzia sullo schema | Con la modalità strict o constrained | Con |
Costo in token | Prompt di formato aggiunto dal provider | Definizioni dei tool più i risultati, a ogni giro |
Modalità stretta: dove vale per i tool
La garanzia sullo schema non è automatica sui tool. Ogni provider ha un'opzione dedicata.
OpenAI consiglia di attivare sempre strict: true sulle funzioni. Sotto usa la stessa tecnologia degli Structured Outputs e richiede additionalProperties: false su ogni oggetto. Nella Responses API prova a normalizzare lo schema in modalità strict e, se non ci riesce, torna alla chiamata best effort; in Chat Completions il default resta non strict.
Anthropic ha la strict tool use: con strict: true nome e argomenti del tool rispettano lo schema. JSON output e strict tool use si possono usare insieme nella stessa richiesta: il primo controlla cosa dice Claude, il secondo come chiama le tue funzioni.
La guida di Gemini al function calling prevede quattro modalità: auto (default, il modello decide), any (deve chiamare una funzione), none (non può chiamarne) e validated (rispetto dello schema della funzione garantito).
C'è un limite pratico. Anthropic documenta tetti per richiesta: al massimo 20 tool strict, 24 parametri opzionali in totale tra tutti gli schemi strict, 16 parametri con tipi unione. Il consiglio è marcare strict solo i tool dove un argomento sbagliato fa danni, rendere obbligatori i parametri quando c'è un default ragionevole e appiattire gli oggetti annidati.
Cosa lo schema non garantisce
Uno schema rispettato dice che il JSON ha la forma giusta. Non dice che i valori sono giusti.
Le docs elencano tre casi da gestire:
- Rifiuti. Se il modello rifiuta per motivi di sicurezza, l'output può non rispettare lo schema. OpenAI espone un campo
refusalper riconoscerlo; Anthropic avverte che la risposta arriva comunque con status 200 e i token sono fatturati. - Risposte troncate. Se si raggiunge il limite di token, il JSON può essere incompleto. Entrambi i provider lo indicano come caso da controllare.
- Valori ben formati ma sbagliati. Gemini lo scrive esplicitamente: anche se il JSON è sintatticamente corretto, i valori vanno sempre validati nell'applicazione. Gemini ignora inoltre alcuni vincoli in fase di generazione (lunghezza delle stringhe, numero di proprietà) e chiede di verificarli lato client, per esempio con Pydantic o Zod.
Anthropic aggiunge un dettaglio utile: gli enum non hanno garanzia sulle maiuscole. Claude può restituire un valore che differisce dallo schema solo nella prima lettera, senza errore. Il consiglio è confrontare gli enum senza distinguere maiuscole e minuscole.
Per i tool vale la stessa regola, con più peso perché il JSON diventa un'azione. Gemini raccomanda di validare le chiamate prima di eseguirle. Un argomento valido per lo schema può comunque cancellare il record sbagliato. Come misurare questi errori in modo ripetibile è nel pezzo sulle eval per agenti.
Quanti tool dare al modello
Più tool non vuol dire risultati migliori. OpenAI consiglia di tenere piccolo il numero di funzioni disponibili all'inizio per avere più accuratezza, e di caricare quelle usate di rado solo quando servono con la tool search. Gemini indica un insieme attivo di 10-20 tool al massimo.
Se un'operazione non ha bisogno del risultato di un'altra chiamata, spesso non serve un tool. Uno structured output con un campo azione e il tuo codice che decide cosa fare è più semplice da testare. È la stessa logica del pezzo su quando un agente non serve.
Modelli piccoli e locali: Ollama e llama.cpp
In locale la sintassi è vicina a quella delle API cloud. Cambia quanto conta il modello.
La documentazione di Ollama sugli structured outputs prevede lo schema nel campo format. Consiglia di passare lo schema anche come testo nel prompt, per orientare il modello, e di abbassare la temperatura a 0 per risposte più deterministiche. Gli structured outputs funzionano anche tramite l'API compatibile con OpenAI con response_format. La stessa pagina segnala che il cloud di Ollama, al momento, non li supporta. Il tool calling di Ollama copre chiamate singole, parallele e il loop multi turno; la documentazione suggerisce di dire al modello che è dentro un loop e può fare più chiamate.
llama.cpp lavora con le grammatiche GBNF. Il README delle grammatiche spiega che llama-server converte un sottoinsieme di JSON Schema in grammatica, passato come json_schema o dentro response_format. Due avvertenze contano:
- Lo schema serve solo a vincolare l'output e non viene inserito nel prompt. Il modello non lo vede: se deve capire la struttura, va descritta nel prompt. Per il tool calling invece gli schemi sono iniettati.
- Le funzioni dello schema non supportate vengono saltate senza errori. Il README consiglia di convertire lo schema con lo script Python per vedere gli avvisi.
Per i tool, la documentazione sul function calling di llama.cpp richiede di avviare llama-server con --jinja e un template della chat che supporti i tool. Alcune famiglie hanno un formato nativo, come Llama 3.x, Qwen 2.5, Mistral Nemo e Hermes; per le altre c'è un gestore generico che può usare più token ed essere meno efficiente. Le chiamate in parallelo sono disattivate di default. C'è anche un avviso diretto: quantizzazioni molto spinte della cache KV possono degradare parecchio il tool calling.
Il quadro che esce dalle docs, per i modelli piccoli: la grammatica garantisce la forma, non la decisione. Un modello locale può produrre un JSON perfetto con il campo sbagliato, o chiamare un tool quando non serve. Uno schema piccolo e piatto, descritto anche nel prompt, è la scelta più prudente. Per esporre un modello locale con un'API compatibile con OpenAI c'è la guida su Ollama e vLLM in locale.
Cosa conviene fare adesso
- Per ogni chiamata al modello, chiediti se dopo il JSON serve ancora il tuo sistema. Se no, structured output.
- Attiva la modalità stretta:
strictsu OpenAI e Anthropic,validatedsu Gemini, grammatica su llama.cpp. - Valida comunque i valori nel codice e gestisci rifiuti e risposte troncate.
- Tieni pochi tool e schemi piatti, soprattutto con modelli piccoli.
- In locale descrivi lo schema anche nel prompt e controlla che il template della chat supporti i tool.
Per mettere in ordine i termini della serie, il punto di partenza è l'hub AI engineering.
Domande frequenti
01JSON mode e structured output sono la stessa cosa?
No. Nella documentazione di OpenAI la JSON mode garantisce solo un JSON valido, mentre gli Structured Outputs garantiscono anche il rispetto dello schema. OpenAI consiglia gli Structured Outputs quando il modello li supporta.
02Posso usare structured output e tool nella stessa richiesta?
Sì, con i provider che lo supportano. Anthropic permette JSON output e strict tool use insieme: tool chiamati con argomenti validi e risposta finale in JSON. Gemini lo consente in preview con i modelli della serie 3, anche insieme ai tool integrati.
03Lo schema rende inutile la validazione nel codice?
No. Lo schema garantisce la forma, non i valori. Rifiuti e risposte troncate possono uscire dallo schema, e Gemini chiede esplicitamente di validare i valori e gestire gli output corretti nella forma ma sbagliati nel contenuto.
04Perché la prima richiesta con uno schema nuovo è più lenta?
Il provider compila lo schema in una grammatica prima di generare. OpenAI e Anthropic lo indicano entrambi. Anthropic tiene in cache la grammatica per 24 ore dall'ultimo uso; cambiare la struttura dello schema o l'insieme dei tool la invalida.
05Con un modello locale conviene il tool calling o lo structured output?
Dipende dal compito, ma le docs suggeriscono prudenza. Con llama.cpp lo schema di output non entra nel prompt e il tool calling dipende dal template della chat. Se il modello non deve davvero chiamare il tuo sistema, uno structured output piccolo è più semplice da controllare.
06Quanti tool posso dare al modello?
Il meno possibile all'inizio. OpenAI consiglia un insieme iniziale piccolo e la tool search per il resto; Gemini indica 10-20 tool attivi al massimo; Anthropic limita a 20 i tool strict per richiesta.



