Perché non deduplichiamo i fatti di conformità tramite similarità di embedding
Nella nostra valutazione di deduplicazione della memoria, le contraddizioni avevano una media di 0.938 cosine rispetto al fatto memorizzato più vicino, mentre i duplicati veri avevano una media di 0.940. Nessun singolo threshold separava chiaramente le coppie che non dovevano essere fuse da quelle che dovevano esserlo. Quindi, il cosine non viene mai utilizzato per decidere la fusione nel nostro pipeline.

Un punteggio di similarità generico risponde bene a una domanda: queste due affermazioni si riferiscono alla stessa cosa? Sul modello che abbiamo misurato, non ha risposto alla domanda che una memoria di fatti di conformità deve invece affrontare: queste due affermazioni sono d'accordo? Abbiamo misurato lo scarto sui nostri dati, e non è un margine che si può risolvere con un aggiustamento. Nella nostra valutazione di deduplicazione della memoria, i duplicati veri avevano una media di 0.940 cosine rispetto al fatto memorizzato più vicino, mentre le contraddizioni dirette avevano una media di 0.938, e nessun singolo threshold globale in quei dati separava chiaramente le riformulazioni che volevamo sopprimere dalle contraddizioni che non potevamo. Chiamiamo questo il trabocchetto dell'argomento (aboutness trap), ed è il motivo per cui, nel nostro pipeline, il cosine non viene mai utilizzato per decidere la fusione.
Il fallimento è silenzioso e unidirezionale. Una deduplicazione mancata lascia una riga ridondante, che è un problema estetico. Una fusione falsa sopprime uno dei due fatti che non concordano, e se il fatto soppresso è "L'autenticazione a più fattori (MFA) non è applicata a tutti gli utenti", un assistente per audit ora detiene l'opposto della verità. Trattiamo questi due errori come categoricamente diversi, e l'intero design deriva da questa asimmetria.
La misurazione
La valutazione esegue il percorso decisionale reale del backend (lo stesso evaluateCandidate utilizzato dal pipeline) su un dataset avversario, sintetico e privo di PII di coppie di affermazioni GRC. Ogni coppia è etichettata con la sua relazione: un duplicato riformulato che deve essere soppresso, o una delle tre tipologie che non devono essere fuse, un fatto distinto che differisce per un solo token, una contraddizione diretta o un raffinamento di ambito. Risultato della misurazione: 2026-06-25, mistral-embed (il modello v23.12 dietro l'alias) per i vettori e un piccolo giudice Mistral (mistral-small-2603, temperatura 0) per la decisione, 261 coppie, 522 chiamate al modello, circa $0.036.
Lo studio sugli embedding è la parte che merita attenzione. Media del cosine del candidato rispetto al fatto memorizzato più vicino, per relazione (mistral-embed v23.12, misurazione 2026-06-25):
| relazione | cosine medio | n |
|---|---|---|
| duplicato | 0.940 | 10 |
| contraddizione | 0.938 | 7 |
| non-duplicato (un-token) | 0.902 | 239 |
| raffinamento | 0.847 | 5 |
Leggete le prime due righe. La media delle contraddizioni si trova 0.002 sotto la media delle riformulazioni dello stesso fatto. La singola parola che inverte il valore di verità ("non") sposta a malapena il vettore, perché entrambe le frasi trattano in modo schiacciante dell'applicazione del MFA, e su questo modello, la vicinanza traccia l'argomento condiviso molto più di quanto non tracci la negazione.
I fatti distinti a un solo token sono quasi altrettanto vicini. "Abbiamo completato un rapporto SOC 2 Type 1" rispetto a "Type 2" non è una pedanteria: un rapporto Type 1 attesta l'adeguatezza della progettazione dei controlli a una data specifica, mentre un rapporto Type 2 attesta anche l'efficacia operativa nel corso di un periodo specificato (Guida AICPA sui rapporti SOC 2). Fondere questi due fatti comunica a un team di sicurezza di un prospect che possediamo una prova che in realtà non abbiamo. In un test smoke end-to-end contro i moduli reali, "SOC 2 Type 1" e "Type 2" hanno ottenuto un embedding con cosine di 0.961, superiore alla media dei duplicati veri nella tabella. Quell'unica istanza è quella importante: una coppia che non deve mai essere fusa, con un punteggio superiore alla media delle coppie che dovrebbero esserlo. La classe dei non-duplicati nel complesso aveva una media di 0.902.
Perché un singolo threshold non li separa
L'istinto, una volta visto un punteggio di duplicato alto, è impostare un threshold di fusione appena sotto di esso. I nostri dati lo sconsigliano in due modi. Le medie delle classi non si separano: 0.940 per i duplicati e 0.938 per le contraddizioni sono, ai fini del thresholding, lo stesso numero. E abbiamo un controesempio concreto sopra quel numero, la coppia Type 1 vs Type 2 a 0.961, un caso che non deve essere fuso che supera la media dei duplicati veri. Un taglio globale sufficientemente basso da sopprimere le comuni riformulazioni, in questi dati, sopprimerebbe anche fatti che abbiamo misurato e che devono essere tenuti separati. Non stiamo affermando di aver dimostrato che nessun confine separatore può esistere per qualsiasi dataset o modello. Stiamo riportando che, su questo dataset GRC avversario, con questo modello di embedding, nessun singolo threshold globale di cosine separava le coppie sicure da fondere da quelle letali da fondere.
Quindi, gli embedding svolgono un solo compito nel nostro pipeline: il retrieval. Il limite inferiore del cosine è 0.55, deliberatamente basso, e esiste solo per scegliere quale fatto memorizzato vale la pena confrontare con il candidato. Non decide se fondere. Una volta che il vicino più prossimo è stato recuperato, la decisione viene presa da un meccanismo che analizza i token che il cosine sottovaluta.
L'architettura che mantiene separate le contraddizioni
Due livelli, e quello deterministico è autorevole.
Primo, un controllo deterministico dei token protetti. Confrontiamo il candidato con il vicino recuperato alla ricerca dei token che trasportano significato di conformità: negazioni ("non", "non più"), quantificatori e ambiti ("tutti", "solo", "amministratori"), giurisdizioni e regioni, versioni del framework, tipi di SOC 2, numeri e unità. Una differenza unilaterale in qualsiasi classe protetta blocca la fusione e sovrascrive il giudizio indipendentemente da ciò che il giudice restituisce. "Il MFA è applicato" rispetto a "Il MFA non è applicato" viene bloccato dalla regola della negazione, indipendentemente da quanto simili appaiano le due frasi.
Secondo, un giudice conservativo. Il modello deve raggiungere un livello di confidenza di 0.8 per sopprimere un candidato come duplicato; al di sotto di quel valore, mantiene entrambe le righe. È orientato a mantenere, perché le due direzioni di errore non sono simmetriche: un duplicato mantenuto è un problema estetico, una contraddizione fusa è una corruzione.
Il traguardo che il sistema deve raggiungere: zero fusioni false sulle 251 coppie che non devono essere fuse. Ce l'ha fatta, zero fusioni false osservate. Come regola empirica, 3/251 è circa l'1.2%, ma su un set fisso e curato si tratta di un'euristica, non di un limite di confidenza reale né di una garanzia di produzione. La proprietà su cui facciamo effettivamente affidamento è più ristretta e solida: il controllo deterministico da solo, senza alcun modello nel loop, ha bloccato tutte le 251, quindi il limite è garantito da un codice che si può leggere piuttosto che da un modello di cui ci si deve fidare.
Cosa ha ingannato il giudice
La parte onesta. Una valutazione di pulizia compagna due giorni dopo, il 2026-06-27, ha rilevato una fusione falsa che una versione precedente del controllo aveva mancato: "L'SSO è disponibile per i clienti enterprise" rispetto a "L'SSO è disponibile per tutti i clienti". Il modello ha giudicato l'affermazione più ampia una raffinazione innocua di quella più ristretta e l'ha fusa. È il trabocchetto dell'argomento (aboutness trap) a un livello superiore: le due frasi trattano quasi esclusivamente della disponibilità dell'SSO, e il giudice, come l'embedding, sottovaluta il quantificatore che cambia a chi si applica il fatto. La soluzione è stata spostare un cambiamento unilaterale in una classe portatrice di ambito (quantificatori, soggetti, negazione, modalità) nel controllo deterministico piuttosto che lasciarlo al giudizio, oltre a una regola esplicita di ambito di applicabilità nel prompt del giudice come difesa in profondità. Dopo la correzione, quella valutazione ha mostrato zero fusioni false, 18 delle 18 coppie distinte tenute separate e 8 delle 8 duplicati veri recuperati.
Il pattern si ripete tra i livelli. L'embedding sottovaluta strutturalmente la negazione e l'ambito, su questo modello. Il giudice li sottovaluta in modo soft. Il livello che ha catturato in modo affidabile questi casi nei nostri test è quello che nomina i token esatti che invertono un fatto di conformità, e quel livello è un codice deterministico, non un altro modello chiamato a essere attento.
Limiti
Questa è una porta di qualità decisionale su coppie etichettate, un candidato contro il suo vicino abbinato, non un test di carico di retrieval per magazzini grandi, e le classi delle contraddizioni e dei raffinamenti sono piccole (7 e 5 coppie), quindi le loro medie sono indicative, non stime precise. I valori di cosine sono specifici per mistral-embed v23.12 su queste frasi GRC; un modello di embedding diverso li sposterebbe, e l'insensibilità alla negazione che abbiamo osservato è specifica del modello che abbiamo misurato, non una legge degli embedding di similarità. I modelli addestrati in modo contrastivo possono essere sintonizzati per allontanare le contraddizioni, utilizzandole come negativi duri (SimCSE, EMNLP 2021), quindi la lettura corretta è "misurate il vostro modello", non "gli embedding non potranno mai fare questo". Il recupero dei duplicati nella corsa di deduplicazione era 0.5, cinque dei dieci duplicati veri soppressi. Questo è il prezzo che abbiamo scelto: il giudice mantiene entrambe le righe ogni volta che non è sicuro, quindi il recupero è il parametro che regoliamo mentre il conteggio delle fusioni false osservate rimane a zero. Preferiamo portare con noi alcune righe di fatti veri ridondanti piuttosto che fondere mai due che non concordano.
Il trabocchetto dell'argomento (aboutness trap) e una checklist
L'idea da portare a casa da questo articolo: sul modello che abbiamo misurato, un punteggio di similarità elevato significava che due affermazioni trattavano della stessa cosa, non che concordavano, e la deduplicazione richiede accordo. Quando una tale memoria è un'informazione documentata su cui si basa un ISMS, la ISO/IEC 27001:2022, Clausola 7.5.3, richiede che sia protetta dalla perdita di integrità (ISO/IEC 27001:2022, Clausola 7.5.3, edizione 2022-10); se una fusione silenziosa rende un registro richiesto inaccurato, si tratta di una perdita di integrità in quel senso. Se state costruendo una memoria o uno strato di conoscenza con deduplicazione semantica, eseguite questa verifica su di esso:
- Misurate la distribuzione, non fate supposizioni. Eseguite embedding su coppie duplicate, contraddittorie e quasi-distinte etichettate dal vostro dominio, sul vostro modello, e osservate il cosine per relazione. Se i punteggi delle contraddizioni si sovrappongono con quelli dei duplicati, nessun threshold su quel punteggio li separerà.
- Usate gli embedding per il retrieval, non per la decisione di fusione. Un limite inferiore di cosine basso per scegliere un vicino di confronto è accettabile. Usare lo stesso punteggio per decidere una fusione è il modo in cui una contraddizione viene silenziosamente rimossa.
- Inserite un controllo deterministico prima della fusione. Elencate i token che invertono il significato nel vostro dominio (negazioni, quantificatori, ambiti, versioni, giurisdizioni, unità) e lasciate che un cambiamento unilaterale in una di queste classi sovrascriva il modello.
- Rendete il giudice conservativo e asimmetrico. Orientatelo a mantenere entrambe le righe. Decidete quale errore è estetico e quale è corruzione, e non lasciate che il modello scambi il secondo per evitare il primo.
- Impostate a zero l'errore fatale come traguardo, regolate separatamente il recupero. Mantenete le fusioni false a zero come traguardo; migliorate il recupero dei duplicati senza spostare quel limite.
- Inserite le quasi-mancate nel vostro dataset. La coppia che amplia l'ambito e sembra una raffinazione è quella che viene fusa. Numeri scritti per esteso, acronimi in minuscolo e scambi di quantificatori sono i punti in cui un giudice fallisce silenziosamente.
Tutti i dati sopra riportati sono misurazioni effettuate sui nostri dataset sintetici GRC, con mistral-embed v23.12 e mistral-small-2603 a temperatura 0, datati 2026-06-25 e 2026-06-27. Il dataset non contiene dati di clienti.
Articoli correlati

Il test di simmetria: distribuire una correzione del prompt che non puoi riprodurre
Quando un bug di produzione non si riproduce offline, non puoi validare una correzione del prompt facendola avere successo. Puoi validarla verificando se la tua modifica sposta l'output in una direzione coerente o aggiunge semplicemente rumore variabile del modello. Ecco il test che abbiamo eseguito su 126 coppie A/B alla cieca.

La lotteria dell'ID del modello: stessa richiesta, estrazione diversa
Dietro una porta di accesso multi-provider, lo stesso ID del modello ha prodotto il suo primo token con una mediana di 312 ms senza output di reasoning un giorno, e a 3.073 ms con 2.627 caratteri di reasoning giorni dopo. La flag di instradamento che ci aspettavamo di prevenire questo non l'ha fatto.

La collisione del vocabolario: quando un classificatore di sicurezza blocca l'intero dominio
Un classificatore di moderazione generico ha erroneamente segnalato 15 messaggi su 15 in un arco di 17 giorni nel nostro prodotto di compliance. I nostri utenti, infatti, discutono di minacce per lavoro. La soluzione adottata ha spostato il rischio senza eliminarlo.
