Il determinismo incontra le probabilità: perché il function calling con i LLM è diverso dallo sviluppo software classico


André Martin
André Martin
5 giugno 2026  - 6 min di lettura
Il determinismo incontra le probabilità: perché il function calling con i LLM è diverso dallo sviluppo software classico

Sintesi

In VoiceBooker vediamo ogni giorno che i grandi modelli linguistici non si comportano come il software classico deterministico. Le loro risposte si basano su probabilità, quindi anche con lo stesso input il comportamento può variare. Questo emerge molto rapidamente nel function calling. I modelli moderni sono molto più affidabili delle generazioni precedenti, ma prompt precisi, debugging accurato e la comprensione delle interazioni di contesto restano essenziali per ottenere risultati prevedibili. Per mantenere stabili e affidabili le applicazioni IA, gli End-to-End-Tests automatizzati aiutano a verificare in modo sistematico il comportamento del bot e a individuare presto le regressioni.

Introduzione

Chi proviene dallo sviluppo software classico spesso vive un piccolo shock culturale quando lavora con i large language model (LLM). Per decenni siamo stati abituati a costruire sistemi deterministici: se un programma produce un errore per un certo input, correggiamo il codice - e una volta che la correzione funziona, possiamo presumere che funzionerà di nuovo con lo stesso input. Stesso input, stesso output. È il mondo in cui gli sviluppatori hanno vissuto per decenni. Con gli LLM, la realtà è diversa.

Dai programmi deterministici alle macchine probabilistiche

Un large language model non funziona come un programma classico con alberi decisionali fissi. È guidato dalle probabilità. Ogni risposta, ogni decisione e ogni function call è il risultato di uno scoring statistico dei possibili passi successivi. Questo porta a un fenomeno che all'inizio frustra molti sviluppatori: Un flusso conversazionale identico può produrre risultati diversi in due esecuzioni. Si può pensare alla roulette: il contesto è lo stesso, ma il risultato può comunque variare. Gli sviluppatori che arrivano dal mondo di API, database e business logic spesso trovano questa mancanza di determinismo insolita o addirittura problematica.

Le nostre prime esperienze con il function calling

Quando nel 2023 abbiamo provato per la prima volta a gestire una prenotazione di appuntamenti tramite un LLM, a tratti siamo quasi impazziti. Il flusso della conversazione era identico:

  • l'utente indica il suo desiderio di appuntamento
  • il bot raccoglie le informazioni necessarie
  • la funzione di prenotazione dovrebbe essere chiamata

Eppure succedeva questo: Nel primo test la funzione veniva chiamata correttamente. Nel secondo test, con un flusso praticamente identico, improvvisamente non veniva più eseguita. Per chi sviluppa software classico, all'inizio sembra un bug. In realtà, spesso non si tratta di un errore del sistema, ma della naturale conseguenza di un modello probabilistico che interpreta il contesto e prende decisioni sulla base delle probabilità.

La buona notizia: i modelli stanno diventando sempre più affidabili

Dall'epoca dei primi GPT-3.5, è cambiato moltissimo. I modelli moderni sono molto migliori in:

  • instruction following
  • tool usage
  • function calling
  • comprensione del contesto
  • rispetto di prompt complessi

La prevedibilità è quindi migliorata in modo enorme. Resta comunque un equilibrio importante tra affidabilità e latenza.

Perché più determinismo spesso significa più latenza

Molti dei modelli più forti di oggi lavorano in modo più strutturato e affidabile rispetto ai predecessori. Il prezzo da pagare è spesso un maggiore effort di reasoning. In parole semplici: Il modello pensa più a lungo, analizza più contesto e quindi prende decisioni più robuste. Questo aumenta la probabilità che una funzione desiderata venga chiamata correttamente. Allo stesso tempo, aumenta il tempo di risposta.

Nel voice, in particolare, questo può diventare un problema. Un assistente telefonico che impiega diversi secondi a ragionare su ogni function call appare presto innaturale per chi chiama. Per questo molti sistemi in produzione usano intenzionalmente modelli più piccoli e veloci. Questi modelli offrono latenze eccellenti e chiamano le funzioni in modo sorprendentemente affidabile - ma solo se i prompt lasciano il minor spazio possibile all'interpretazione. Bastano piccoli cambiamenti di contesto per far interpretare in modo diverso un flusso che prima funzionava perfettamente.

Quando le function call smettono improvvisamente di avvenire

Un pattern tipico nella pratica: Un bot funziona in modo affidabile per settimane. Poi viene introdotta una modifica al prompt apparentemente innocua. All'improvviso una certa funzione viene chiamata solo sporadicamente - o per niente. In queste situazioni, conviene non dare subito la colpa al modello. Spesso la causa è un'interazione inattesa tra più istruzioni. Una nuova regola può entrare in conflitto, senza volerlo, con un'istruzione già esistente. Il modello si trova quindi davanti a obiettivi contrastanti e decide, in modo comprensibile, di non chiamare la funzione.

Prompt debugging invece di code debugging

Mentre gli sviluppatori software classici fanno debug del codice, gli sviluppatori LLM fanno sempre più spesso debug dei prompt. Un approccio che ha funzionato bene da noi: scarichiamo il transcript completo in JSON - inclusi system prompt, definizioni degli strumenti e input utente - e poi lasciamo che un altro LLM analizzi perché si è verificato un certo comportamento. I risultati sono spesso sorprendenti. Molto spesso il modello individua contraddizioni o ambiguità che avevamo noi stessi trascurato mentre scrivevamo il prompt. Non di rado finiamo per essere d'accordo con il modello: a un'analisi più attenta, l'istruzione davvero non era abbastanza precisa o entrava in conflitto con un'altra istruzione. È interessante notare che anche gli esseri umani reagiscono spesso in modo simile in queste situazioni. Se due istruzioni sono formulate in modo incoerente, lo spazio interpretativo è inevitabile.

Dagli unit test ai bot test

Un'altra lezione importante dalla pratica: I test manuali non scalano. Chiunque verifichi ogni modifica del bot con chat o chiamate di prova manuali perde rapidamente moltissimo tempo. Per questo in VoiceBooker abbiamo introdotto gli End-to-End-Tests. Un bot può chiamare un altro bot o chattare con esso. Per esempio, un bot di test può ricevere questo compito:

Prenota un tavolo per quattro persone martedì alle 18.

Poiché il bot di test è programmabile, parametri come data, ora o numero di persone possono essere variati automaticamente. In pratica, questo crea unit test per la conversational AI. I vantaggi sono evidenti:

  • scenari di test ripetibili
  • regression test automatici
  • validazione rapida delle modifiche al prompt
  • rilevamento precoce di cambiamenti comportamentali inattesi

Soprattutto in modalità chat, centinaia di casi di test possono essere eseguiti in poco tempo, perché il throughput è limitato soprattutto dalla latenza dei modelli utilizzati.

Conclusione

Il cambiamento mentale più grande nel lavorare con gli LLM è probabilmente abbandonare l'idea di un determinismo assoluto. Gli LLM non sono programmi classici. Sono macchine probabilistiche. Questo però non significa che i sistemi affidabili siano impossibili. Con prompt precisi, definizioni pulite degli strumenti, debugging sistematico dei prompt e End-to-End-Tests automatizzati, oggi è possibile costruire applicazioni IA notevolmente robuste e prevedibili. La differenza chiave rispetto allo sviluppo software classico è che non si ottimizza più soltanto il codice - si modella sempre di più il comportamento di un sistema intelligente. Ed è proprio qui che si trovano sia la sfida più grande sia il fascino più forte dello sviluppo IA moderno.

Tag
LLMChiamate di funzionePrompt engineeringTestAffidabilitàTecnico