Mario Marino

progettista e sviluppatore di applicativi gestionali e sistemi basati su LLM

Sistema RAG a tre livelli di conoscenza

Un motore di risposta ancorato ai documenti, alle sintesi curate e ai dati aziendali

Periodo
dal 2025
Ruolo
progettazione, sviluppo e test
Tecnologie
Python · Django REST Framework · PostgreSQL · pgvector · OpenAI · Anthropic · Claude Agent SDK
Stato
in produzione

Nel contesto di un sistema LLM aziendale che risponde in modo competente ed esperto alle domande di collaboratori e professionisti, la documentazione su cui il sistema lavora è tanta e cambia: analisi di mercato, normativa dei bandi, relazioni, dati dei progetti in corso. La risposta a una domanda precisa sta quasi sempre dentro un documento che bisogna però prima individuare, e trovarlo è un lavoro che ricomincia da capo a ogni domanda.

Questo servizio risponde a domande in linguaggio naturale su quella conoscenza. Recupera i pezzi di documentazione pertinenti e li passa a un modello linguistico, che scrive la risposta su quei pezzi e non sulla propria memoria: è il metodo che va sotto il nome di RAG (retrieval-augmented generation). La conseguenza pratica è che la conoscenza resta fuori dal modello — si aggiorna cambiando i documenti, e ogni risposta si può verificare risalendo alle fonti da cui proviene.

Un modello linguistico da solo non potrebbe farlo: non conosce i documenti dell'azienda, è fermo alla data in cui è stato addestrato, e di ciò che afferma non permette di risalire alla fonte. Spostare la conoscenza fuori dal modello la rende aggiornabile senza riaddestrare niente, e verificabile da chi legge la risposta.

Il lavoro presente l'ho costruito per l'uso interno dell'azienda in cui lavoro, pensando ad un sistema flessibile, scalabile e facilmente manutenibile.

Le fonti — i documenti grezzi e il wiki curato — confluiscono in un solo indice. Una domanda viene instradata, verso il testo o verso i numeri, recuperata da quell'indice oppure interrogata sullo store analitico, e trasformata in risposta dal modello. Le modalità sono due: sincrona, immediata, e analisi approfondita, affidata a un agente per i casi complessi.

il problema difficile

Recuperare del testo e farne una risposta è la parte facile. La parte difficile è che chi legge non ha modo di accorgersi quando la risposta è sbagliata. E i modelli LLM per loro natura tendono a rispondere comunque in modo assertivo e non dubitativo, anche quando i dati di riferimenti sono incerti.

Due casi reali che ho incontrato erano tutti e due invisibili a chi faceva la domanda. Nel primo il servizio rispondeva «non ho trovato nulla» mentre la conoscenza c'era, e sembrava un'assenza di dati invece che un errore di ricerca. Nel secondo riportava con piena sicurezza un dato che la fonte stessa dichiarava inaffidabile.

Quasi tutto quello che segue serve a una cosa sola: fare in modo che il sistema sbagli in modo visibile. È anche il criterio con cui ho scelto fra le alternative, quando la misura non bastava a decidere.

tre livelli di conoscenza

Domande diverse chiedono conoscenza diversa, e tenerla tutta in un posto solo limita la qualità della risposta. Per tale ragione il motore, che risponde in linguaggio naturale ancorando ogni risposta alla conoscenza aziendale, combina tre livelli:

  1. il testo grezzo dei documenti segmentato in chunk attraverso il processo di embedding
  2. il wiki curato
  3. i dati gestionali ricavati da query SQL su un clone dei DB dei gestionali aziendali
documenti wiki curato dati del gestionale un solo indice store analitico docx e pdf, spezzati in git, pagine di sintesi copia notturna, di sola lettura livelli 1 e 2 nella stessa tabella vettori a 1536 dimensioni ricerca per distanza coseno livello 3, tenuto separato solo query già scritte e provate il modello non scrive SQL competono per pertinenza numeri esatti
I livelli 1 e 2 due vivono nello stesso indice vettoriale e competono per pertinenza; il terzo sta fuori, perché la ricerca per somiglianza non sa contare e **su un numero, una risposta quasi giusta è una risposta sbagliata**.

Il primo livello è il RAG, ovvero il testo dei documenti così com'è, spezzato in frammenti e trasformato in vettori numerici che ne rappresentano il significato, così che la ricerca avvenga per somiglianza di senso invece che per parole esatte. È l'ancoraggio ai fatti come sono scritti nella fonte.

Il secondo è un wiki in markdown curato a mano, dove pagine di sintesi organizzano un dominio, per esempio una pagina per ogni mercato. Le pagine rimandano ai documenti anziché ricopiarli, e dichiarano nel frontmatter il canale che ereditano e il documento a cui si riferiscono. Vengono indicizzate negli stessi vettori del primo livello: sintesi e testo grezzo competono insieme per pertinenza, e il ranking non sa quale delle due sta guardando.

Il terzo è uno store analitico, per le domande numeriche basato su query SQL: quanti progetti attivi, quanto è stato speso su un mercato, quanto resta di un budget. È una copia di sola lettura del database dei nostri sistemi gestionali, rigenerate ogni notte, e si interrogano soltanto con query già scritte e provate. Il modello riconosce la domanda numerica, sceglie la query da un catalogo e ne estrae i parametri; non scrive SQL. Se nessuna query del catalogo risponde, il servizio lo dichiara invece di produrre un numero.

il pavimento del verbatim

I tre livelli concorrono alla stessa risposta, e questo crea un problema di equilibrio. Le sintesi curate sono dense e mirate, quindi tendono a vincere il confronto di pertinenza e finirebbero per far sparire il testo grezzo dai risultati.

La leva ovvia sarebbe pesare i due tipi di frammento in modo diverso, premiando il curato. L'ho provata e misurata, e il risultato è stato negativo: premiare le sintesi promuove anche quelle fuori tema, e il guadagno netto sta sotto zero. La leva che funziona è un pavimento — un minimo di frammenti grezzi garantiti in ogni risultato — tenuto separato dal peso, così che ciascuna regoli una cosa sola. In produzione il peso è a zero e il pavimento a un frammento. Era a due, ed è stato abbassato dopo che una revisione del modo di spezzare i documenti ha reso i frammenti grezzi più densi: il secondo, forzato, non aggiungeva niente e a volte toglieva spazio a qualcosa di migliore.

Un esempio. Alla domanda sul posizionamento del vino italiano nel mercato giapponese il servizio recupera cinque frammenti: tre dalla pagina curata di quel mercato, che risultano i più pertinenti, e due dai documenti originali, garantiti dal pavimento. La risposta prende l'impianto dai primi e l'ancoraggio dai secondi.

il percorso di una domanda

Una domanda non va dritta all'indice. Prima si decide di che natura è, poi dove cercare, poi si restringe il campo; la ricerca per somiglianza è l'ultimo passo, non il primo.

domanda instradamento a tre vie scelta del canale pre-filtro ricerca per somiglianza pavimento di onestà risposta, con le fonti query di catalogo store analitico testo, numeri, o niente per somiglianza di significato cinque filtri, una sola WHERE istruzioni non rimuovibili parametri estratti sola lettura, con la data
La colonna centrale è il percorso testuale. Tratteggiato il ramo numerico, che salta la ricerca semantica e rientra nel contesto prima del modello. Il pavimento di onestà si applica su tutti e due i rami.

Il primo bivio è più grosso di quanto sembri: distingue le domande di testo da quelle di numeri. Lo decide il modello stesso, con una sola chiamata, scegliendo fra le query del catalogo e una funzione di ripiego che dichiara «questa non è una domanda da store». Nel caso comune non costa niente in più, perché quella chiamata la si faceva comunque. Se la domanda è numerica ma nessuna query del catalogo la copre, il modello sceglie il ripiego e si finisce sul percorso testuale, dove il servizio dichiara di non avere il dato invece di inventarlo.

scegliere dove cercare

L'indice è partizionato in canali tematici, e prima di cercare bisogna decidere in quale guardare. La qualità del recupero è vincolata da questa scelta: sbagliare canale significa cercare bene nel posto sbagliato.

All'inizio lo decideva un elenco di parole chiave, fragile per costruzione. Bastava un plurale — «mercati» non contiene «mercato» — o una domanda formulata in modo naturale per non attivare nessun canale, e la risposta diventava «non ho trovato nulla» mentre la conoscenza c'era. In più il primo termine che agganciava vinceva, anche quando puntava al canale sbagliato.

Ora la scelta si fa per somiglianza di significato. Ogni canale è descritto da poche domande-esempio curate; la domanda reale viene confrontata con quelle, con lo stesso meccanismo della ricerca, e vince il canale più vicino se supera una soglia di confidenza. Sotto la soglia il servizio cerca su tutti i canali e lascia decidere la pertinenza.

Tre cose di questa scelta valgono più del meccanismo:

Costa una chiamata di embedding in più per domanda, e nessuna chiamata al modello: gli esempi sono vettorializzati una volta e tenuti in memoria, con l'impronta dei testi a decidere quando vanno rifatti.

restringere prima di cercare

Accanto al canale ci sono altri filtri. Tutti insieme formano una sola condizione applicata prima del calcolo di somiglianza: nessuno lavora a valle, e nessun meccanismo a valle può ripescare ciò che è stato escluso a monte.

La domanda che si ripete, ogni volta che qualcuno legge il percorso, è se il passo probabilistico filtri i documenti. Non lo fa: sceglie un parametro — il canale — e solo quando chi chiama non ne ha dichiarato uno valido. Il passo incerto può quindi sbagliare dove si cerca, mai se un filtro viene applicato. Tenere quella riga netta è ciò che rende il sistema spiegabile a chi lo integra.

I filtri sono cinque e, dopo una revisione che ne ha rimossi tre che non filtravano nulla, sono tutti attributi del documento: nessuno agisce sul singolo frammento. Non è una potatura, è un'invariante — un filtro sul frammento oggi richiederebbe una giustificazione esplicita. Quello che conta però non è l'elenco, è come ciascuno si comporta quando manca:

Filtro Se manca o non si applica
Il committente non allarga mai: vale il valore di default, e una risposta vive dentro un committente solo
Il canale tematico allarga: la ricerca diventa multi-canale, mai un risultato vuoto
L'anno aperto sull'assenza: un documento senza anno non viene escluso da una domanda per anno
Il mercato chiuso: confronto esatto, senza distinzione di maiuscole
Le etichette dichiarate come confine di riservatezza stringono: una domanda che non le dichiara non vede quei documenti

Il degrado allarga sul tema e stringe sulla riservatezza. È la stessa regola scritta due volte: dove sbagliare costa poco si preferisce cercare troppo, dove costa molto si preferisce non trovare. Sulle etichette il fallimento è chiuso da entrambi i lati — un'etichetta dimenticata su un documento lo fa sparire dalle risposte, non lo fa trapelare — con un limite che va detto: il servizio non può verificare chi sta chiedendo, conosce il sistema chiamante e non la persona. Ruoli e permessi restano nell'applicazione che chiama.

Solo le etichette hanno un vocabolario governato, condiviso fra chi indicizza e chi interroga. Le altre no, e la conseguenza è che un valore sbagliato da chi chiama non è un errore: è zero risultati in silenzio. Si cura verificando i dati con un comando dedicato, non cambiando meccanismo.

Una nota sul caso che ho sbagliato, perché è il più istruttivo di tutti. Le etichette non erano nell'elenco dei parametri ammessi in ingresso, quindi venivano scartate prima di raggiungere il motore di ricerca: il filtro compariva nella richiesta e non veniva applicato. È sopravvissuto per mesi perché ogni test partiva dal motore in giù, cioè a valle del tratto rotto. La copertura adesso parte da dove chi chiama esprime la sua intenzione, e l'elenco dei parametri ammessi è derivato per introspezione dalla firma della ricerca, così esiste letteralmente in un posto solo: prima era scritto a mano in due, e due elenchi a mano divergono.

i numeri non si recuperano, si calcolano

La ricerca per somiglianza non sa contare né sommare, e su un numero una risposta quasi giusta è una risposta sbagliata. Il terzo livello è quindi costruito con criteri opposti a quelli degli altri due: niente ricerca semantica, niente generazione libera.

C'è anche un ponte fra il terzo livello e il secondo: una pagina di metriche viene rigenerata ogni notte dallo store e messa nel wiki, ma esclusa dall'indice. Serve a chi cura le pagine per avere i numeri sotto mano; nell'indice non entra, perché dati strutturati dentro la ricerca semantica sono esattamente ciò che questo livello esiste per evitare.

il dubbio che arriva fino alla risposta

Questa è la parte del sistema di cui vado più fiero, e nasce da un difetto trovato in produzione.

Chi cura una pagina del wiki, quando trova un dato che non torna — un numero gonfiato da un'anomalia, due elenchi normativi che si contraddicono — non lo cancella e non lo aggiusta di nascosto: lo dichiara con un'avvertenza. È il valore che il secondo livello aggiunge e che il primo non può restituire, perché nasce dal confronto fra fonti, che è lavoro umano e non sta scritto in nessun documento.

Il servizio però recupera frammenti, non pagine intere. Le avvertenze stavano in fondo alla pagina, in una sezione dedicata, e l'affermazione dubbia altrove: veniva pescato il frammento con l'affermazione e mai quello con l'avvertenza. Peggio, la sezione delle avvertenze è scritta con vocabolario metodologico — tabella, serie, valore anomalo — che non somiglia a nessuna domanda che un utente farebbe davvero, quindi non veniva pescata nemmeno per caso.

Su una pagina la crescita di un mercato era data al 53% annuo, e più sotto era scritto che quel numero è gonfiato da un'anomalia e che il valore realistico è intorno al 3,5%. Alla domanda su quanto cresce quel mercato, il servizio rispondeva 53%.

sezione: «cresce del 53%» sezione pescata dalla ricerca ⚠ il 53% è gonfiato: il valore vero è 3,5% un frammento il vettore il contenuto = una sezione della pagina solo il testo della sezione: la ricerca non cambia la sezione più le avvertenze della pagina: il dubbio arriva anche a chi non lo cercava la pagina curata
Il testo con cui un frammento viene cercato e il testo che il modello legge sono due cose distinte. Le avvertenze viaggiano solo nel secondo: il dubbio arriva a destinazione e la precisione della ricerca resta quella di prima.

La correzione sfrutta una separazione che era già nel codice e che nessuno aveva avuto motivo di usare: il testo con cui un frammento viene cercato e il testo che il modello legge sono due argomenti diversi della stessa funzione. Le avvertenze di una pagina viaggiano ora con ogni suo frammento, ma solo nel secondo. Il vettore resta invariato, quindi la ricerca non peggiora di un punto; e il frammento che ospita l'avvertenza non se la ritrova duplicata.

Sopra c'è un secondo strato, che chiamo pavimento di onestà: quando ha fatto una ricerca, il servizio appende alle istruzioni del chiamante alcune righe che il chiamante non può rimuovere, e che coprono tre stati distinti — riporta le avvertenze senza attenuarle; se non hai trovato niente dichiaralo; se le evidenze sono state scartate per limiti di spazio, dichiara anche quello. Si applica solo dove il recupero è stato eseguito: sulle chiamate che non passano dal corpus le istruzioni restano esattamente quelle di chi chiama.

Scoprire dove metterlo è stato metà del lavoro. Il servizio non aveva un prompt di sistema proprio — passava al modello quello del chiamante senza toccarlo — e il punto giusto è risultato essere dopo la compressione del contesto, perché solo lì si sa se le evidenze sono sopravvissute. Nella prova in cui le istruzioni di chi interrogava chiedevano uno stile «sintetico e assertivo», la risposta ha riportato lo stesso il dubbio e scartato il 53%.

Conta perché porta il non-sapere dentro la risposta: il sistema restituisce il problema invece di una soluzione errata. Ed è la proprietà che rende praticabile curare un dominio che non si padroneggia, perché un dubbio irrisolto non svanisce, arriva a chi legge.

Il costo è misurato e l'ho accettato consapevolmente. Il meccanismo è ottuso: attacca tutte le avvertenze di una pagina a tutti i suoi frammenti, anche a quelli che non c'entrano. I frammenti passano da circa 880 a 2.400 caratteri, con un caso peggiore di sei volte, e il costo cresce insieme alla curatela — le pagine con avvertenze erano quattordici quando ho fatto la modifica, diciassette una settimana dopo. Alta copertura, bassa precisione, per scelta: garantisce che il dubbio non si perda, non che sia mirato.

come entra un documento

La qualità dell'indice dipende da come i documenti vengono divisi, e questo è il punto in cui i sistemi RAG si assomigliano tutti in superficie e si distinguono nei risultati.

Prima ancora, però, c'è una decisione che riguarda se un documento debba entrare. Ogni documento passa da un albero chiuso a tre esiti: non entra affatto se non è conoscenza — modulistica, ricevute, email di trasmissione; entra nell'indice così com'è; oppure, se cambia o contraddice una pagina del wiki, passa dalla curatela umana invece che dal testo grezzo, altrimenti il servizio si troverebbe a servire due verità in conflitto sulla stessa domanda.

Il ramo della curatela ha un limite che non è tecnico: regge finché chi cura padroneggia la materia. Sui temi in cui non la padroneggia ho aggiunto un questionario per l'esperto di dominio — un file markdown, non uno strumento — che porta già scritta la formulazione proposta, perché chi è impegnato corregge un testo mentre davanti a un foglio bianco risponde a monosillabi. Tre dettagli che ne fanno un meccanismo invece che un buon proposito: il file sta fuori dalla cartella indicizzata, così una formulazione proposta e poi respinta non può finire fra le risposte per costruzione anziché per una regola da ricordare; la curatela non si ferma ad aspettare, perché la pagina entra con la sua avvertenza, che il pavimento porta già fino a chi interroga; e al ritorno è il grado di sicurezza dichiarato dall'esperto a decidere se l'avvertenza cade, resta più precisa, o la pagina non cambia affatto.

Sul come vengono spezzati, il primo impianto usava come frammento quello che l'estrattore restituiva, e il 33% dei frammenti erano titoli di sezione da una riga: esche vuote per la ricerca per somiglianza, che prendono punteggi alti e non portano informazione. Ora i blocchi vengono impacchettati fra 200 e 1.800 caratteri con una sovrapposizione fra l'uno e l'altro, le tabelle non si spezzano mai, e i PDF si impacchettano dentro la pagina, così il riferimento alla posizione resta esatto. Sui file veri: da 57 frammenti a 19, e nessuno sotto i 100 caratteri.

Le forme che non stanno in questo schema hanno una strategia dichiarata sul file, non indovinata: i documenti a domanda e risposta si spezzano per coppia, ignorando i salti di pagina che altrimenti taglierebbero a metà una risposta; i fogli di calcolo diventano tabelle in markdown invece di una riga per frammento. E se il documento non contiene i marcatori attesi, la strategia produce zero frammenti e lo dice, invece di riuscire in silenzio.

Sul silenzio ho pagato una lezione che vale la pena raccontare. La reindicizzazione di massa inghiottiva le eccezioni: un giro su sorgenti non più raggiungibili ha portato l'indice da 1.595 frammenti a 6, riportando «tutto ok». Ora l'estrazione avviene prima della cancellazione, gli errori interrompono il lavoro, e i frammenti vecchi sopravvivono a un'estrazione fallita.

come si aggiorna la conoscenza

Il wiki curato vive in git, e il ciclo è deliberatamente banale: si scrive in un clone locale, si pubblica, il server si riallinea e reindicizza solo le pagine cambiate. Il servizio consuma una copia in sola lettura: sul server non si scrive mai.

si cura si pubblica si allinea si indicizza nel clone locale sul repo remoto la copia sul server le pagine cambiate se l'allineamento fallisce, l'indicizzazione non parte indicizzare uno stato vecchio dichiarandolo aggiornato produce un corpus che sembra fresco: è la falsa conferma a non farsi notare, non il mancato aggiornamento
L'ordine dei due passi è un'invariante, non un dettaglio di implementazione: per questo vivono dentro una funzione sola, chiamata sia dal comando sia dal bottone in interfaccia.

L'invariante è costata mezza giornata per essere capita: un aggiornamento eseguito saltando l'allineamento aveva lasciato tre persone a discutere di quale versione della conoscenza fosse quella buona. Prima i due passi erano separati per costruzione — uno nello script, uno nel comando — e chi ne usava metà saltava l'altra senza che nulla protestasse.

Attorno a questo ci sono tre scelte che valgono più del meccanismo:

C'è infine una trappola che ho scoperto pagandola. Il salto delle pagine invariate confronta l'impronta del testo, quindi rileva le modifiche al wiki ma non i cambi alla logica di indicizzazione: si rilascia una modifica al modo di spezzare le pagine, si lancia l'aggiornamento normale, e si ottiene «nessuna pagina cambiata» — nessun errore, nessun avviso, indicizzazione vecchia. Serve un'opzione esplicita che rigeneri tutto, e la prova che il rilascio sia atterrato è un contatore a zero nel rapporto.

Le sorgenti curate oggi sono più d'una, e non sono due copie della stessa cosa: una è un archivio che esiste per essere conoscenza, l'altra è la documentazione d'uso di un'applicazione, che vive nel repository di quell'applicazione accanto al codice che descrive. Da qui la forma dell'impianto, che è la conseguenza da ricordare: è il servizio a descrivere la sorgente — dove sta, con quale dialetto di intestazioni, quale canale eredita, se attendersi un anno — non la sorgente ad adeguarsi al servizio. Una sorgente nuova non chiede di riscrivere il repository che la ospita: si dichiara e basta.

le identità non escono in chiaro

Fino a un certo punto della storia del servizio, niente di ciò che usciva passava da un filtro: domande, evidenze recuperate e righe dello store arrivavano ai fornitori dei modelli esattamente come stavano. Era un rischio teorico finché il corpus era normativa: una misura sul corpus non ha trovato un solo codice fiscale, partita IVA o IBAN in oltre duemila frammenti. Due cose arrivate insieme lo hanno reso concreto — un quarto fornitore di modelli, fuori dall'Unione Europea, e il ramo numerico, che manda al modello righe dove le ragioni sociali stanno accanto agli importi. Da quel momento quale modello uso e quali dati escono erano la stessa decisione, e non dovevano esserlo.

Il modulo che ho aggiunto sostituisce identità con segnaposto tipizzati prima che qualcosa raggiunga un modello. Le scelte che lo rendono utile invece che rassicurante:

Due limiti dichiarati, perché senza di essi il meccanismo prometterebbe più di quanto mantiene. Il primo: il ramo di esplorazione libera dell'agente esegue una query scritta dal modello, e le condizioni girano sui dati veri — il mascheramento avviene dopo, sulle righe che tornano. Il valore è protetto, la domanda sul valore no: un modello che lo voglia può ricostruire un nome per tentativi, senza che nessun nome compaia mai in uscita. Non è correggibile spostando una riga, perché è il limite del mascherare in uscita contro uno strumento che sa calcolare in ingresso; si accetta perché quel ramo è raggiungibile solo da chi lancia un'analisi sui propri dati, ma va scritto. Il secondo: la domanda dell'utente arriva al modello prima che il percorso si biforchi, e mascherarla romperebbe l'instradamento, perché i parametri estratti dalla domanda servono a filtrare i dati veri.

Tutto il meccanismo sta dietro tre metodi e un interruttore. Con l'interruttore spento viene iniettato un oggetto che non fa nulla, e gli agganci non contengono un solo if: il comportamento torna identico a prima che il modulo esistesse, e cancellare la cartella riporterebbe il sistema allo stato precedente anche fisicamente. È la ragione per cui il giorno in cui il servizio parlerà con un modello ospitato in casa, la pseudonimizzazione si potrà spegnere senza smontare niente.

la risposta dichiara le sue fonti

Per molto tempo l'informazione su quali documenti avessero prodotto una risposta è esistita solo dentro il blocco diagnostico, e non era quella giusta per essere mostrata a un utente: compariva solo con la diagnostica accesa, veniva troncata ai primi frammenti, e portava il nome del file invece del titolo leggibile.

Ora la risposta ha un campo suo, con il titolo da mostrare e l'identificatore con cui risalire al documento, ordinato dalla fonte più vicina alla domanda. Distanze, posizioni e conteggi restano nella diagnostica: sono diagnosi, non attribuzione, e ammetterli lì avrebbe prodotto un secondo blocco diagnostico con le stesse ambiguità del primo.

La parte che mi interessa di più è un'altra: la presenza del campo è essa stessa informazione. Esce solo dove il recupero è stato tentato, e lì esce sempre, lista vuota compresa. Così «non ho cercato nel corpus» e «ho cercato e non ho trovato nulla» sono due stati distinguibili da chi integra il servizio, invece di due frasi da dedurre leggendo il testo della risposta. È la stessa distinzione che il pavimento di onestà dichiara al modello, resa leggibile anche al programma che chiama.

L'aggregazione — un documento vale una fonte, ordinate per vicinanza — vive in un posto solo, condiviso con il banco di prova interno. Una seconda copia sarebbe divergiata in silenzio, e il sintomo sarebbe stato un banco di prova che mostra fonti diverse da quelle che il servizio dichiara: cioè un banco di prova inutile.

l'analisi approfondita

La risposta sincrona arriva in pochi secondi e copre la maggior parte delle domande. Accanto c'è un agente asincrono, per le richieste che valgono più passi: una sintesi che attraversa più mercati, un confronto fra fonti. Naviga il wiki, incrocia più pagine, interroga lo store, procede per passi e cita le fonti.

Un confronto misurato dice che l'agente vince su copertura e citazioni nelle domande di sintesi, mentre la risposta immediata è pari o migliore, e più prevedibile, sulle ricerche puntuali nella normativa. La differenza di costo e di tempo — centesimi e secondi contro qualche decina di centesimi e minuti — fa sì che l'uso si instradi da sé, senza doverlo regolare.

perché non un modello da solo

È la domanda che si fa chiunque guardi un sistema del genere oggi, quando i modelli hanno finestre di contesto enormi e si potrebbe pensare di passargli tutto.

un modello da solo questo servizio
Da dove viene la risposta memoria del modello, opaca documenti e sintesi dell'azienda, tracciabili
Dati proprietari non li conosce indicizzati e recuperabili
Aggiornamento fermo alla data di addestramento si cambiano i documenti, cambiano le risposte
Verificabilità difficile risalire alla fonte ogni risposta dichiara i documenti da cui viene
Numeri plausibili esatti, dal catalogo di query, con la loro data
Incertezza la smussa: risponde sicuro anche sul contestato i dubbi della curatela arrivano alla risposta
Costo di evoluzione riaddestramento scrittura di testo e un aggiornamento

In breve: mettere la conoscenza dentro il modello la rende rigida, costosa e non tracciabile; tenerla accanto al modello la lascia viva, verificabile e curabile a mano. Per una conoscenza aziendale che cambia e che va giustificata, la seconda vince.

come si misura

Un insieme di domande di riferimento, con la risposta attesa, si esegue prima di ogni rilascio. Ha due livelli, e la distinzione è ciò che rende utile il risultato: uno isola il recupero — sono stati pescati i frammenti giusti? — e l'altro giudica la risposta finale. Quando qualcosa peggiora, i due livelli dicono se la colpa è del corpus o della curatela, che è la domanda che serve per sapere dove mettere le mani.

Un secondo comando verifica i dati dove il primo verifica il codice: che ogni filtro dichiarato abbia documenti da agganciare, e che i valori presenti nel corpus stiano nel vocabolario del registro. È il controllo che intercetta il caso più silenzioso di tutti — un filtro corretto che non seleziona nulla perché nessuno ha mai etichettato i documenti.

Due pratiche contano più degli strumenti:

C'è infine un anello che chiude il ciclo: da una risposta scadente registrata in produzione si genera la voce pronta da aggiungere all'insieme di riferimento. Serve a evitare che una regressione osservata resti un aneddoto.

limiti dichiarati

Le cose aperte le tengo scritte, ed è parte del metodo: un sistema che risponde a domande deve dichiarare dove non arriva.

stato

In produzione, con i tre livelli attivi e le due modalità disponibili. È uno strumento interno: l'indirizzo non è pubblico e non c'è niente da visitare.