Gli LLM non accedono al tuo codice: ti consegnano una richiesta e tu esegui la funzione. Questo semplice fatto smentisce il mito secondo cui "il modello chiama magicamente la mia routine Python" e costringe gli sviluppatori a ripensare il debugging e la sicurezza.
Il ciclo di dispatch, passo dopo passo
Quando un modello linguistico (LLM) ha bisogno di uno strumento, segue una sequenza deterministica:
- Pianificazione – il modello decide che è necessaria un'azione (ad es., "rimborsa un pagamento").
- Generazione di una richiesta – produce un testo strutturato — solitamente JSON — che indica lo strumento e fornisce gli argomenti.
- Parsing – la tua applicazione o un framework di supporto legge quel testo.
- Matching – il framework cerca il nome nel registro delle funzioni reali che hai esposto.
- Validazione – controlla che gli argomenti corrispondano allo schema della funzione e che il chiamante sia autorizzato.
- Esecuzione – la funzione corrispondente viene eseguita nel tuo ambiente, svolgendo il lavoro.
- Ritorno – il risultato viene impacchettato e inviato nuovamente al modello per ulteriori ragionamenti.
Pensa all'LLM come a un pianificatore, al framework come a un dispatcher e alla funzione come al lavoratore che effettivamente sposta dati o denaro.
Perché il mito della "magia" persiste
La maggior parte degli sviluppatori vede una singola riga di output del modello che sembra una chiamata a una funzione e assume che il modello abbia eseguito l'operazione stesso. Il termine "tool calling" nella documentazione dei provider fa sembrare che il modello stia invocando direttamente il codice.
In realtà, il modello produce solo testo che descrive una chiamata. Il tuo processo svolge il lavoro pesante: ricerca, controllo dei tipi, applicazione dei permessi e gestione degli errori.
Framework che nascondono i meccanismi interni
Librerie come PydanticAI e LangChain astraggono il ciclo in modo che tu possa concentrarti sulla logica di business. Esse eseguono automaticamente:
- Validazione degli argomenti rispetto a uno schema (ad es., un modello Pydantic).
- Applicazione dei permessi, assicurando che l'utente possa attivare lo strumento.
- Riprova in caso di errore, tornando al modello quando uno strumento restituisce un errore.
- Protezione da cicli infiniti, limitando il numero di chiamate consecutive agli strumenti.
- Mantenimento dello stato della conversazione, integrando i risultati degli strumenti nel dialogo.
Anche con questi aiuti, il pattern rimane lo stesso: il modello non esegue mai codice.
Supporto nativo al tool-calling dei provider
Alcuni provider offrono un'interfaccia di "tool-calling" nativa che standardizza le definizioni degli strumenti e i formati delle richieste. Questo facilita l'integrazione, ma non elimina la fase di dispatch. Devi comunque scrivere (o importare) il codice che esegue effettivamente l'operazione richiesta.
Il debugging diventa più facile quando rinomini il problema
Invece di incolpare un "agente confuso", di' che il problema è che "la risposta del modello non conteneva chiamate agli strumenti". La distinzione è importante:
- Nessuna chiamata allo strumento (No tool call) – il modello ha risposto direttamente o non è riuscito a generare una richiesta formattata correttamente.
- Richiesta malformata (Malformed request) – il JSON è sintatticamente errato o mancano campi obbligatori, quindi il dispatcher lo rifiuta.
- Errore di validazione (Validation failure) – gli argomenti non corrispondono allo schema, innescando un errore prima dell'esecuzione.
Categorizzare i fallimenti ti permette di registrare ogni fase del ciclo e individuare dove le cose sono andate fuori strada.
Consigli pratici per una pipeline affidabile
- Tratta l'output del modello come un input non attendibile. Esegui ogni richiesta attraverso una validazione deterministica prima di invocare qualsiasi codice con effetti collaterali (side-effecting).
- Registra la richiesta grezza e il risultato di ogni fase di validazione. Questo crea una traccia riproducibile quando qualcosa va storto.
- Imposta limiti espliciti sulle chiamate consecutive agli strumenti; un ciclo infinito può esaurire le risorse o raggiungere i limiti di velocità (rate limits).
- Avvolgi ogni funzione in un blocco try/except che restituisca un oggetto di errore strutturato comprensibile dal modello, suggerendo un nuovo tentativo o un fallback aggraziato.
- Separa i controlli dei permessi dalla logica di business. Verifica i diritti del chiamante prima che la funzione venga eseguita, specialmente per azioni privilegiate come "elimina utente".
- Usa definizioni basate su schema (ad es., modelli Pydantic) in modo che il framework possa generare automaticamente lo schema JSON che il modello deve seguire.
Cosa monitorare in futuro
Man mano che i provider perfezionano le API di tool-calling nativo, aspettati contratti più rigidi intorno ai formati delle richieste e codici di errore più ricchi. Questi cambiamenti renderanno la validazione più semplice e permetteranno agli sviluppatori di costruire barriere di sicurezza più strette. Tieni d'occhio gli aggiornamenti delle librerie: molte stanno aggiungendo il supporto integrato per le nuove funzionalità dei provider.
Punti chiave
L'LLM è un sofisticato generatore di testo, non un esecutore. Il tuo codice rimane l'unica autorità che esegue le azioni, e il dispatcher che costruisci (o importi) è il gatekeeper che valida, autorizza ed esegue tali azioni. Riformulare il workflow elimina il mito della "magia", affina il debugging e impone la disciplina di sicurezza di cui ogni sistema in produzione ha bisogno.
