Qualche settimana fa un commercialista di Brescia ci ha scritto una domanda molto concreta: il vostro chatbot può davvero emettere una bozza di fattura dentro il mio Fattura24, o si limita a dire al cliente che la farò io quando torno in studio?
La domanda, per quanto banale sembri, è lo spartiacque fra due epoche dell’assistente AI aziendale. Fino al 2023 l’AI conversazionale era un recupero di FAQ ben scritto: sapeva rispondere, non sapeva agire. Nel 2024 è cambiato tutto con l’arrivo in produzione del function calling, e nel 2025-2026 è diventato lo standard su cui si costruiscono gli assistenti che fanno operazioni reali dentro i gestionali.
In TrueReply questa distinzione è architetturale. Le linee standard di TrueReply includono il function calling con tool HTTP custom e webhook firmati HMAC-SHA256. La versione Custom, su preventivo, estende lo stesso meccanismo a gestionali proprietari e verticali italiani dove l’integrazione chiavi in mano non esiste.
Questa guida spiega come funziona il function calling a livello tecnico, quali gestionali italiani si prestano meglio, come scriviamo gli schemi JSON delle funzioni, quali guardrail servono quando l’AI agisce su dati contabili e fiscali, e come pianifichiamo una timeline di 21 giorni fra ambiente di staging e produzione.
Cosa intendiamo per function calling
Function calling, nella terminologia OpenAI, o tool_use nella terminologia Anthropic, o function calling di Gemini in casa Google, è il meccanismo con cui un modello linguistico emette non più solo testo in risposta, ma una chiamata strutturata a una funzione esterna. Il modello dichiara: voglio eseguire la funzione crea_bozza_fattura con questi parametri, presentati in JSON che rispetta lo schema che hai definito.
Il runtime del sistema intercetta quella richiesta, la valida, esegue la funzione verso il sistema esterno (un gestionale, un CRM, un PMS), raccoglie la risposta e la rimanda al modello. A quel punto il modello continua la conversazione con il risultato, spiegando al cliente cosa è successo.
La differenza pratica fra un assistente AI informativo e un agente AI transazionale è questa. Il primo risponde. Il secondo risponde ed esegue. Il primo sposta lavoro umano di qualche minuto. Il secondo lo elimina.
Perché il function calling ha cambiato il gioco
Prima del function calling, provare a far fare azioni a un assistente AI significava regole fragili: pattern matching, intent classification, workflow rigidi costruiti a mano. Se il cliente scriveva la frase leggermente diversa da come l’avevi prevista, l’assistente collassava.
Il function calling sposta il carico sul modello stesso. Il modello legge il messaggio, ragiona in linguaggio naturale, decide se serve un’azione, sceglie la funzione giusta fra quelle disponibili, estrae i parametri dal testo del cliente e li formatta secondo schema. Non devi più scrivere regole: devi scrivere buoni schemi e buone descrizioni.
Esempio concreto. Un cliente scrive a TrueReply di un hotel: mi servirebbe una doppia per le due notti del 15 e 16 maggio, se avete disponibilità. Con il function calling il modello deduce automaticamente che deve invocare check_disponibilita con parametri check_in 2026-05-15, check_out 2026-05-17, adulti 2, tipo_camera doppia. Nessuna regex, nessun intent classifier. Il modello fa il lavoro.
L’architettura tecnica di un assistente AI con function calling
Lo stack minimale è questo. Un layer di orchestrazione tiene la conversazione. Il modello LLM riceve il messaggio, la cronologia e la lista delle funzioni disponibili con i loro schemi. Il modello risponde o con un messaggio testuale o con una tool call strutturata. L’orchestratore, se vede una tool call, la passa a un dispatcher. Il dispatcher autentica, fa retry, rate limit, logga e chiama l’endpoint esterno (il gestionale). La risposta torna al modello, che produce il messaggio finale per il cliente.
In TrueReply questa pipeline gira interamente in Italia, con prompt di sistema in italiano, instructions per la chiamata funzione in italiano, e modelli multilingua che ormai maneggiano benissimo la nostra lingua anche in contesti tecnici. L’aspetto fondamentale è che ogni tool HTTP definito dal cliente diventa, lato modello, una funzione invocabile. Se il cliente ha un endpoint autenticato su api.miogestionale.it/clienti/{id}, quell’endpoint diventa funzione lookup_cliente con il suo schema dei parametri.
Sei pattern di function calling ricorrenti
Nell’esperienza TrueReply i casi d’uso si riducono quasi sempre a sei famiglie. Qui sotto la tabella con input e output schematici, che poi riprendiamo negli esempi dei gestionali italiani.
| Funzione | Input principale | Output tipico | Irreversibile |
|---|---|---|---|
| check_disponibilita | risorsa, finestra temporale | elenco slot liberi | no |
| lookup_cliente | telefono o email o partita IVA | anagrafica cliente | no |
| create_record | tipo record, campi obbligatori | id nuovo record | si se contabile |
| crea_bozza_fattura | cliente_id, righe, aliquota IVA | id bozza, link anteprima | no (bozza) |
| check_stock | sku, quantita | disponibilità magazzino | no |
| aggiorna_stato | record_id, nuovo_stato | ok, timestamp | si |
La colonna irreversibile è fondamentale. Se la funzione crea entità fiscalmente rilevanti o sposta stock reali, l’AI non deve poterla invocare senza controllo umano. Torneremo su questo nella sezione dei guardrail.
Uno schema JSON function, fatto bene
Uno schema JSON leggibile dal modello deve descrivere ogni campo con un nome parlante, un tipo preciso, una descrizione in italiano chiara e, quando serve, un enum o una regex di vincolo. Ecco l’esempio che usiamo per la bozza fattura in Fattura24, semplificato.
{
"name": "crea_bozza_fattura",
"description": "Crea una bozza di fattura nel gestionale Fattura24. La bozza resta non inviata finche l'utente amministrativo la conferma dal pannello.",
"parameters": {
"type": "object",
"properties": {
"cliente_id": {
"type": "string",
"description": "ID anagrafica del cliente in Fattura24. Se non noto, invocare prima lookup_cliente."
},
"righe": {
"type": "array",
"items": {
"type": "object",
"properties": {
"descrizione": { "type": "string" },
"quantita": { "type": "number", "minimum": 0.01 },
"prezzo_unitario": { "type": "number", "minimum": 0 },
"aliquota_iva": {
"type": "string",
"enum": ["22", "10", "5", "4", "0"],
"description": "Aliquota IVA applicata in Italia. Usa 22 se in dubbio e conferma all'utente."
}
},
"required": ["descrizione", "quantita", "prezzo_unitario", "aliquota_iva"]
},
"minItems": 1
},
"metodo_pagamento": {
"type": "string",
"enum": ["bonifico", "carta", "contanti", "rid"]
},
"data_documento": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Data documento in formato ISO. Se non specificata, usare la data odierna."
},
"note": {
"type": "string",
"maxLength": 300
}
},
"required": ["cliente_id", "righe", "metodo_pagamento", "data_documento"]
}
}Quando il cliente scrive allo strumento frasi come prepara una bozza al cliente Rossi di 800 euro più IVA per consulenza di aprile, pagamento bonifico, il modello compila autonomamente questo schema. Prima però fa un passo che nello schema è raccomandato dalla descrizione stessa: invoca lookup_cliente per ottenere cliente_id a partire da Rossi.
L’invocazione e la risposta sul gestionale
Una volta che il modello emette la tool call, il runtime la traduce in una chiamata HTTP autenticata. Per Fattura24 l’endpoint pubblico documentato usa un apiKey e accetta JSON. Schematicamente la richiesta in uscita assomiglia a questa.
POST https://www.app.fattura24.com/api/v0.3/SaveDocument
Content-Type: application/json
{
"apiKey": "xxxxxxxx",
"document": {
"documentType": "P",
"customerId": "98231",
"date": "2026-04-23",
"paymentMethodName": "Bonifico",
"rows": [
{
"description": "Consulenza fiscale aprile 2026",
"qty": 1,
"price": 800,
"vatCode": "22",
"vatDescription": "22%"
}
],
"status": "draft"
}
}La risposta del gestionale torna al dispatcher, che la normalizza e la rimanda al modello in forma di tool result. Il modello riformula per il cliente finale: ho preparato la bozza 2026/0458 per il cliente Rossi Srl, 800 euro più 22% di IVA, data 23 aprile 2026, metodo bonifico. La bozza resta in attesa della tua conferma nel pannello Fattura24. Vuoi che aggiunga una nota in fattura?
Il cliente non ha mai aperto il gestionale. Il commercialista, appena torna alla scrivania, trova la bozza pronta, la controlla in dieci secondi e la invia.
I guardrail quando l’AI agisce su dati reali
Qui sta la parte seria del discorso. Function calling senza guardrail è un incidente che aspetta di accadere. In TrueReply applichiamo cinque livelli di protezione su ogni tool custom.
Primo livello, enum e vincoli nello schema. Le aliquote IVA sono un enum fisso, non stringa libera. Le quantità hanno un minimum. Le date hanno un pattern. Il modello non può inventare valori fuori range.
Secondo livello, conferma umana esplicita per operazioni irreversibili. Se la funzione è create_record su tabella contabile o aggiorna_stato su un ordine già spedito, l’agente AI chiede al cliente una conferma testuale prima di invocarla. Confermi che devo procedere, sì o no? Solo su sì esplicito il runtime procede.
Terzo livello, bozza e non finalizzato. Dove possibile, l’AI crea sempre in stato draft. La finalizzazione resta umana. Vale per fatture, preventivi ufficiali, contratti. Vale anche per invii di SMS massivi o email a liste.
Quarto livello, rate limiting per tool. Se create_record viene chiamata più di tre volte in sessione dallo stesso utente, il runtime blocca e segnala. L’AI non può ciclare.
Quinto livello, audit log immutabile. Ogni tool call viene loggata con timestamp, utente, parametri, risposta. In caso di contestazione sai esattamente cosa ha fatto il chatbot, quando, e su istruzione di chi.
Questa architettura la chiamiamo security by design. Non è una feature accessoria, è parte dell’orchestratore stesso. Linea standard o Custom non cambia nulla da questo punto di vista: le stesse protezioni valgono per entrambi.
I gestionali italiani e il loro livello di API
Non tutti i gestionali italiani sono uguali quando si tratta di integrazione via function calling. Alcuni hanno API REST moderne e documentate, altri hanno endpoint SOAP legacy ma funzionanti, altri ancora espongono solo servizi web parziali o richiedono moduli aggiuntivi a pagamento. Qui sotto una mappa sintetica che costruiamo insieme al cliente prima di ogni progetto.
| Gestionale | Tipo API | Copertura | Compatibilità TrueReply |
|---|---|---|---|
| Fattura24 | REST JSON con apiKey | alta, documenti e anagrafiche | Linea standard con tool HTTP |
| TeamSystem Enterprise | Docs for Developers, REST | alta su moduli recenti | Linea standard o Custom |
| Zucchetti Cloud | API REST su ZConnect | media-alta, variabile per modulo | Linea standard o Custom |
| Sistemi eSolver | servizi web SOAP e REST | media, bene su anagrafica e vendite | Custom |
| Passepartout Mexal | Mexal API REST | alta, gestionale completo | Custom |
| Danea Easyfatt | import/export CSV e XML | bassa come API realtime | Custom con sync periodico |
| Scrigno PMS | API proprietaria | media, focus booking | Custom |
| Ericsoft Hotel | API REST documentata | alta, completa sul PMS | Linea standard o Custom |
| 5stelle PMS | API REST | alta, ben documentata | Linea standard |
| Octorate channel manager | API REST | alta | Linea standard |
| MioDottore PRO | API gestione agenda | media-alta sugli appuntamenti | Linea standard |
| AlfaDocs | API REST per studi dentistici | media | Custom |
| GipoNext | API su richiesta | variabile | Custom |
| Iusnet avvocati | API limitate | bassa | Custom con RPA o workaround |
| Kleos studi legali | API documentate | media | Custom |
La colonna compatibilità TrueReply indica cosa è realistico. Linea standard quando il gestionale ha API REST documentate e possiamo collegarle con i tool HTTP custom inclusi. Custom quando l’integrazione richiede lavoro di analisi, wrapping o sviluppo di adapter intermedi perché l’API è parziale, non standard o non documentata pubblicamente.
Function calling su Fattura24, esempio end to end
Proviamo a mettere insieme il caso del commercialista di Brescia. Lo studio riceve via chatbot sul sito richieste di preventivo e richieste di fattura pro forma. La configurazione che gira in produzione prevede tre funzioni.
La prima, lookup_cliente, cerca per partita IVA o codice fiscale dentro l’anagrafica Fattura24 e restituisce id e dati principali. La seconda, cerca_prestazione, attinge a un piccolo catalogo di prestazioni standard dello studio con i relativi importi. La terza, crea_bozza_fattura, è lo schema che abbiamo visto prima.
Il cliente scrive: ciao, sono Mario Rossi della Rossi Srl, partita IVA 01234567890, potete farmi una pro forma per la consulenza fiscale del mese scorso? Il modello capisce che servono tre step. Primo, lookup_cliente con piva 01234567890. Secondo, cerca_prestazione con keyword consulenza fiscale mensile. Terzo, crea_bozza_fattura con cliente_id restituito dal primo step e righe costruite dal secondo.
Tutto questo succede in meno di dieci secondi, mentre il sistema tiene il cliente occupato con un messaggio tipo sto controllando la tua posizione in contabilità, un attimo. Il commercialista riceve una notifica sul suo pannello Fattura24 e una email con il riepilogo.
PMS hotel e function calling
Per un hotel il pattern cambia, ma la struttura regge. Abbiamo tre funzioni principali: check_disponibilita, crea_prenotazione_opzionale, invia_preventivo. La prima interroga il PMS (5stelle, Scrigno, Ericsoft) per verificare le camere libere nelle date richieste. La seconda crea una prenotazione in stato opzione, bloccata per 24 ore, senza finalizzare. La terza invia al cliente via email o WhatsApp un link con riepilogo e pulsante di conferma.
La parte interessante è che la finalizzazione della prenotazione, quindi il passaggio da opzione a confermata, richiede di solito l’inserimento della carta di credito come garanzia. In questo caso l’assistente passa la palla a un link sicuro del PMS che gestisce PCI compliance. L’AI non tocca mai dati di pagamento. Mai. Questo è un sesto guardrail implicito.
Abbiamo approfondito lo scenario hotel nel pezzo dedicato ai PMS italiani e a chi sta costruendo front desk AI in hotel, e la spina dorsale tecnica è la stessa che descriviamo qui.
Structured output e JSON schema enforcement
Un tema che merita una sezione dedicata è come garantiamo che il modello rispetti davvero lo schema JSON. I modelli moderni hanno due meccanismi. Il primo è il JSON mode, dove il modello viene vincolato dal decoder a produrre solo output che parsi come JSON valido. Il secondo, più forte, è lo structured output con schema enforcement, dove il modello emette output che non solo è JSON valido ma rispetta esattamente i vincoli dello schema (tipi, enum, required, pattern).
Nel nostro stack, ogni tool HTTP custom definito dal cliente viene passato al modello con uno schema JSON rigoroso. Se il cliente specifica che aliquota_iva è un enum [22, 10, 5, 4, 0], il modello non può inventare 23. Se specifica che data_documento è una stringa che matcha un pattern ISO, il modello non può scrivere 23 aprile. Se sbaglia, il dispatcher rifiuta la chiamata e la rimanda al modello con un messaggio di errore. Il modello corregge e riprova, massimo tre tentativi. Dopo tre fallimenti la conversazione degrada elegantemente chiedendo al cliente di riformulare o lasciando un handoff all’umano.
Function calling sulle linee standard, o Custom per i proprietari
La domanda pratica che ci arriva sempre è: basta una linea standard o serve Custom? La risposta dipende da due variabili: quanto è documentata l’API del gestionale e quanto è strategica l’integrazione.
Sulle linee standard includiamo tool HTTP custom configurabili. Il cliente, o il suo IT, fornisce l’endpoint, l’autenticazione e lo schema dei parametri. Noi lo registriamo come funzione invocabile dal modello. Questo funziona benissimo per gestionali con REST API pulite: Fattura24, 5stelle, Ericsoft, Octorate, MioDottore PRO, le parti REST di TeamSystem e Zucchetti. L’attivazione in genere richiede dai tre ai sette giorni lavorativi.
Quando invece il gestionale è proprietario, non espone API pubbliche, richiede SOAP, ha un middleware intermedio, o necessita di logica di business non banale (es. calcoli tariffa dinamici, validazioni regolatorie specifiche), passiamo al piano Custom. Qui progettiamo e sviluppiamo adapter intermedi, agenti AI su misura (vedi anche agente AI custom) e webhook firmati bidirezionali. Questo include anche pattern asincroni in stile chatbot e-commerce con webhook dove il gestionale notifica eventi a TrueReply e viceversa.
Il piano Custom è a preventivo perché la complessità varia. Abbiamo fatto integrazioni chiuse in tre settimane su gestionali medici italiani e integrazioni più complesse con ERP di gruppi industriali che hanno richiesto due mesi e mezzo di lavoro congiunto con l’IT interno.
Timeline tipica di 21 giorni
Per un’integrazione standard su un gestionale con API REST documentate, la timeline che proponiamo è questa.
Giorno 1-3. Kickoff tecnico. Raccolta delle credenziali dell’ambiente di staging del gestionale. Analisi endpoint, scopi, limiti. Definizione delle funzioni da esporre al modello (tipicamente fra tre e sei funzioni).
Giorno 4-8. Scrittura degli schemi JSON e dei prompt di sistema. Setup del dispatcher con autenticazione, retry, rate limit. Implementazione dei guardrail di conferma umana per le operazioni irreversibili.
Giorno 9-14. Test in staging. Simulazione di conversazioni reali su corpus di domande tipiche raccolte dal cliente. Verifica di ogni tool call con log completi. Affinamento degli schemi e delle descrizioni delle funzioni (qui si gioca la qualità: una descrizione chiara riduce drasticamente le chiamate sbagliate).
Giorno 15-18. Review con il cliente. Revisione dei log di staging insieme a chi usa quotidianamente il gestionale. Identificazione edge case dimenticati.
Giorno 19-21. Cutover in produzione. Switch delle credenziali da staging a produzione. Monitoring intensivo delle prime 48 ore. Abilitazione progressiva (prima solo lettura, poi scrittura su bozze, poi scrittura piena) per ridurre il rischio.
Questo schema a 21 giorni si rispetta quando l’API è pulita e il cliente risponde in tempi ragionevoli alle richieste. Quando il gestionale è più complesso, la parte 4-8 può allungarsi e si passa a un piano progetto di sei-otto settimane.
Test e staging, perché non si scherza
Un principio che ripetiamo ai clienti: non si collega mai l’AI a un gestionale di produzione senza avere almeno due settimane di staging reale alle spalle. I gestionali italiani seri (TeamSystem, Zucchetti, Passepartout, Fattura24) offrono tutti ambienti sandbox o account di test. Il nostro sviluppo avviene lì. Il cliente stesso fa testing dalla sua UI dello strumento pointando allo staging.
Il cutover in produzione avviene solo quando abbiamo logs puliti su almeno un centinaio di conversazioni di staging, zero chiamate con parametri invalidi, zero escalation fallite. Questa disciplina è quello che distingue un progetto che resta in piedi da uno che implode al primo weekend con conversazioni strane.
Cosa guardare nelle metriche dopo il go live
Post cutover le metriche che monitoriamo sono cinque. La tool call success rate, cioè la percentuale di chiamate a funzione che tornano successo applicativo dal gestionale, deve stare sopra il 95%. La tool call accuracy, cioè la percentuale di chiamate fatte con parametri sensati rispetto al contesto conversazionale, deve stare sopra il 98%. Il tempo medio di risposta al cliente, compreso il tool round trip, sotto i 6 secondi nel 90% dei casi. Il tasso di escalation a umano, ovvero quante conversazioni finiscono in handoff a operatore, sotto il 15% quando il caso d’uso è ben definito. E infine il tasso di azioni completate senza intervento umano, che è la metrica commercialmente più importante: nei nostri clienti sta fra il 60% e l’80% a seconda del verticale.
Un punto che facciamo sempre
Il function calling non è magia. Un assistente AI con tool calling mal progettati farà danni più velocemente di uno mal progettato che risponde solo. La qualità dei guardrail, la pulizia degli schemi, la disciplina di staging, il monitoring post go live: sono queste le cose che fanno funzionare il sistema. La tecnologia sottostante ormai è matura, il valore aggiunto sta nell’ingegneria che ci costruiamo intorno.
Quando parliamo di ownership su Custom intendiamo esattamente questo: il cliente ha visibilità completa sui prompt, sugli schemi, sui log, sulle metriche. Non è una black box. Su gestionali italiani specifici offriamo anche supporto italiano dedicato, con interlocuzione tecnica diretta fra il nostro team e l’IT del cliente, senza ticket di primo livello che rimbalzano in call center.
Per cominciare
Se state valutando un assistente AI che agisce davvero sul vostro gestionale italiano, e il vostro gestionale ha API REST documentate, una linea standard è il punto di partenza naturale. Se invece avete un gestionale proprietario, un ERP custom, un verticale con API parziali, il progetto va su integrazioni custom a preventivo. In entrambi i casi il meccanismo sotto il cofano è lo stesso function calling che abbiamo descritto, con gli stessi guardrail.
Per un preventivo Custom su gestionale proprietario, la strada più veloce è scrivere dal form di contatto indicando il gestionale di riferimento, i casi d’uso principali e una stima del volume conversazioni mese. Torniamo con un piano di lavoro e timeline entro due giorni lavorativi.



