Come innestare un'IA su un magazzino che gira già, con la scrittura diretta esclusa per architettura, una soglia che decide da sola cosa applicare e cosa manda in revisione, e il registro che rende ogni suggerimento verificabile dopo il fatto.
di Nadia Maar ·
La domanda che arriva più spesso non è «possiamo usare l'IA per il magazzino», è «possiamo usarla senza che rompa quello che già funziona». Sono due domande diverse, e la seconda è quella giusta: un gestionale che gira da anni ha vincoli che nessuno ha scritto in un manuale — un fornitore che accetta ordini solo il martedì, uno sconto quantità che scatta a soglie precise, un margine minimo sotto cui un prodotto non si riordina mai. Un modello linguistico non conosce niente di tutto questo, e la tentazione di dargli accesso diretto al database «tanto capisce il contesto» è la stessa tentazione che ha già causato incidenti in altri sistemi, solo con un nome più nuovo.
La soluzione non è evitare l'IA, è metterla nel punto giusto della catena: propone, non decide. Il modello legge dati strutturati attraverso funzioni con uno schema preciso, mai una query libera; ogni proposta passa da una soglia di rischio che decide da sola se applicarla o mandarla a una persona; e ogni cosa — proposta, decisione, esito — resta scritta in un registro che si può controllare mesi dopo.
Questo pezzo è quell'architettura: il codice della funzione che il modello può chiamare e di quella che non può, la soglia che smista automatico da manuale, e perché il registro non è una formalità ma la differenza fra un sistema che si può fidare e uno che si spera funzioni.
Un modello linguistico non sbaglia come sbaglia il codice tradizionale — con un errore che si ripete uguale finché non lo si corregge. Sbaglia in modo diverso ogni volta, in un modo che dipende dalla formulazione della domanda, dal contesto fornito, da un aggiornamento del modello che nessuno ha chiesto. Dargli accesso a un `UPDATE` diretto su una tabella di magazzino significa accettare che, una volta su qualche migliaio, quell'`UPDATE` sia sbagliato in un modo che nessun test ha previsto perché nessun test può prevedere tutte le formulazioni possibili di una richiesta in linguaggio naturale.
«Che cosa succede se il modello si sbaglia?» Se la risposta descrive un log da controllare dopo, la scrittura sta già succedendo prima del controllo. La risposta giusta descrive un passo che DEVE succedere prima che qualcosa cambi — non una rete di sicurezza sotto un errore già avvenuto.
Lo schema qui sotto è quello che si passa al modello come «funzione disponibile». Non è documentazione: è un contratto — il modello può popolare solo questi campi, con questi tipi, e la funzione che riceve la chiamata rifiuta tutto quello che non rispetta lo schema prima ancora di guardare il contenuto.
const proponiRiordino = {
nome: "proponi_riordino",
descrizione: "Propone il riordino di un prodotto sotto scorta minima. " +
"Non esegue nulla: la proposta entra in coda di approvazione.",
parametri: {
type: "object",
properties: {
codiceProdotto: { type: "string", pattern: "^[A-Z]{2}-[0-9]{4,6}quot; }, quantita: { type: "integer", minimum: 1, maximum: 5000 }, fornitorePreferito: { type: "string" }, motivazione: { type: "string", maxLength: 400 }, }, required: ["codiceProdotto", "quantita", "motivazione"], additionalProperties: false, // il modello non può aggiungere campi // non previsti, nemmeno per "essere utile" }, } as const async function eseguiProponiRiordino(argomenti: unknown) { // Prima convalida: lo schema. Seconda convalida: le regole di dominio // che nessuno schema JSON può esprimere. const dati = SchemaRiordino.parse(argomenti) // lancia se non valido const prodotto = await getProdotto(dati.codiceProdotto) if (!prodotto) throw new Error("Prodotto inesistente: proposta scartata") const costoStimato = dati.quantita * prodotto.costoUnitario if (costoStimato > prodotto.budgetRiordinoMassimo) { // Il modello può proporre più del budget: la funzione non lo esegue, // lo declassa automaticamente a revisione manuale invece di rifiutarlo // in silenzio — la sezione 3 spiega perché la differenza conta. return accodaPerRevisione(dati, "supera il budget di riordino") } return valutaSoglia(dati, prodotto) }
additionalProperties: false è la riga che impedisce al modello di «essere creativo» aggiungendo un campo non previsto — per esempio uno sconto che decide di applicare di sua iniziativa. Senza quella riga, uno schema JSON accetta comunque campi extra per default.
Non tutte le proposte hanno lo stesso rischio. Riordinare 40 pezzi di un prodotto che si vende regolarmente, dentro il budget previsto, da un fornitore abituale, è una decisione che un magazziniere approverebbe in tre secondi senza pensarci — automatizzarla non toglie controllo, toglie lavoro ripetitivo. Riordinare 3.000 pezzi di qualcosa che non si muove da due mesi è una decisione che merita gli occhi di una persona, qualunque cosa dica il modello.
23 proposte di riordino in una giornata
20 restano sotto soglia; 3 revisione manuale.
Tre proposte superano il budget di riordino o la quantità massima per quel prodotto. Non vengono rifiutate: vengono declassate a revisione, con la motivazione del modello a fianco. La differenza conta — un rifiuto silenzioso avrebbe fatto sparire l'analisi che il modello ha comunque svolto.
18 restano sotto soglia; 2 revisione manuale.
Due proposte riguardano un fornitore mai usato prima o un prodotto fermo da settimane. Sono esattamente i casi in cui il modello ha meno contesto storico su cui basarsi, e in cui una persona decide meglio in trenta secondi di quanto qualunque soglia automatica possa fare.
Circa il 78%: riordini di routine che rispettano ogni vincolo, generati nel gestionale con la proposta dell'IA come motivazione registrata, e reversibili finché il fornitore accetta modifiche. Il tempo di una persona si concentra sulle cinque che contano davvero, invece di spalmarsi uguale su tutte e ventitré.
Sei mesi dopo, qualcuno chiederà perché il magazzino ha 400 pezzi di un prodotto che non si vende. Se la risposta è «non lo sappiamo, l'ha deciso il sistema», l'IA smette di essere uno strumento e diventa un sospetto permanente. Il registro esiste per rispondere con precisione: chi ha proposto che cosa, con quale motivazione, chi ha approvato o corretto, e quando.
| 08:14 | Sistema | Proposto riordino EK-4471 · 120 pz · sotto soglia budget | auto |
| 08:14 | Sistema | Applicato automaticamente — ordine generato verso fornitore abituale | auto |
| 09:02 | Sistema | Proposto riordino TK-1182 · 2.400 pz · supera soglia quantità | coda |
| 10:41 | M. Ferretti | Corretto a 800 pz, motivazione: promozione terminata la settimana scorsa | revisione |
| 11:15 | M. Ferretti | Approvato con correzione — ordine generato per 800 pz | manuale |
| 14:30 | Sistema | Proposto riordino QZ-0093 · fornitore nuovo, mai ordinato prima | coda |
| 16:02 | M. Ferretti | Respinto — fornitore non ancora qualificato dall'ufficio acquisti | revisione |
23 proposte generate, 18 applicate in automatico, 5 in revisione
Non è un tasso d'errore da minimizzare: è la prova che la soglia funziona. Se scendesse a zero, vorrebbe dire che la soglia sta lasciando passare tutto in automatico — non che il modello è diventato perfetto. Un sistema onesto con sé stesso manda in revisione una parte del proprio lavoro ogni giorno, per costruzione.
Se avete un processo ripetitivo che vorreste alleggerire con l'IA — riordini, controlli, smistamento — portate un esempio reale di dieci decisioni passate. In mezz'ora vediamo quante rientrerebbero sotto una soglia automatica e quante meriterebbero comunque una persona.
Se il vostro processo cambia raramente e ha meno di una decina di casi eccezionali all'anno, ve lo dico: probabilmente non vi serve un modello linguistico, vi bastano delle regole scritte a mano — più prevedibili, più economiche da mantenere, e altrettanto automatiche.
Sviluppo agenti AI per aziende
Non con un accesso diretto in scrittura. L'architettura sicura limita il modello a un elenco chiuso di funzioni tipizzate — «proponi un riordino», mai «esegui questa query» — ognuna delle quali valida i propri argomenti secondo le regole di dominio prima di fare qualunque cosa. Il modello genera argomenti per funzioni scritte da altri, non codice eseguibile.
Con una soglia di rischio su più criteri insieme — quantità, costo, affidabilità del fornitore, storico del prodotto. Su un magazzino con vendite stabili, la maggioranza delle proposte di routine passa la soglia ed è automatica; qualunque criterio fuori soglia manda la proposta in coda di revisione con la motivazione del modello a fianco.
Con un registro che scrive ogni proposta, applicata o no: chi l'ha generata, con quale motivazione, chi l'ha approvata o corretta, e quando. Senza questo registro, ogni domanda su una decisione passata resta senza risposta verificabile — e l'IA smette di essere uno strumento per diventare un sospetto permanente.
No, ed è la differenza principale col software tradizionale: un modello linguistico sbaglia in modo diverso a seconda della formulazione della richiesta e del contesto, non con un errore ripetibile. Per questo il controllo non può essere «correggere il bug dopo averlo trovato»: deve essere una soglia che impedisce l'esecuzione prima che l'errore, qualunque forma prenda, tocchi i dati veri.