Vai al contenuto
EuroVPSEuroVPS

Cercare in decenni di email: prima le parole chiave, poi il significato

Cercare in un archivio email funziona se i dati sono puliti: dedup, thread, testo citato separato, due indici combinati e una citazione per ogni risposta.

Di EuroVPS Engineering

5 min di lettura
Searching decades of email: keywords first, meaning second

Puntare un modello linguistico su una casella di posta e fargli domande sembra un progetto da fine settimana. Poi vi dice con sicurezza la data di contratto sbagliata, perché ha letto una copia citata di una vecchia email dentro una risposta più recente, oppure non trova la fattura 10442 perché il numero non ha alcun «significato» a cui una ricerca vettoriale possa aggrapparsi. Una buona ricerca su un archivio di posta per lo più non riguarda il modello. Riguarda i dati che gli date in pasto e il modo in cui recuperate. Ecco come la affrontiamo.

L'email è più disordinata di quanto sembri

Un archivio di posta che copre anni, diversi sistemi di posta e qualche migrazione ha problemi che rovinano la ricerca prima che qualsiasi AI entri in gioco:

  • Duplicati. Lo stesso messaggio sta nella Posta in arrivo, in una cartella di progetto e in un vecchio export. La ricerca lo restituisce tre volte; un'AI lo conta come tre fonti concordi.
  • Storico citato. Ogni risposta porta sotto di sé l'intero thread. Indicizzatelo ingenuamente e l'email più vecchia di un thread compare in ogni risposta, fuori contesto e con la data sbagliata.
  • Codifiche. La posta più vecchia è piena di set di caratteri legacy, header codificati e parti etichettate male. Decodificatela male e nomi e testo non inglese diventano spazzatura.
  • Allegati. Il contratto è il PDF, non l'email che dice «in allegato». Se non estraete il testo degli allegati, non potete trovare i documenti più importanti.
  • Cancellazioni. La posta cancellata dalla casella per motivi di conservazione deve sparire anche da ogni indice.

Pulite prima di indicizzare

Deduplicate sul Message-ID, ripiegando su un hash degli header principali e del corpo quando manca. Conservate un documento per messaggio e tenete come metadato l'elenco delle cartelle in cui compariva.

Raggruppate in thread su References e In-Reply-To, non sugli oggetti. Gli oggetti cambiano e «Re: fattura» non è univoco. Con un threading corretto potete mostrare un'intera conversazione in ordine e lasciare che il passo di recupero riunisca un thread invece di singoli frammenti.

Separate il testo nuovo dal testo citato. Per ogni messaggio, indicizzate il corpo completo per la ricerca per parole chiave, ma create l'embedding solo della parte che l'autore ha davvero scritto. Un punto di partenza semplice:

import re
from email import policy
from email.parser import BytesParser

QUOTE_MARKERS = [
    re.compile(r"^On .+ wrote:$", re.M),
    re.compile(r"^-{2,}\s*Original Message\s*-{2,}", re.M | re.I),
    re.compile(r"^From: .+\nSent: .+", re.M),
]

def new_text(raw: bytes) -> str:
    msg = BytesParser(policy=policy.default).parsebytes(raw)
    part = msg.get_body(preferencelist=("plain", "html"))
    text = part.get_content() if part else ""
    cut = len(text)
    for rx in QUOTE_MARKERS:
        m = rx.search(text)
        if m:
            cut = min(cut, m.start())
    lines = [l for l in text[:cut].splitlines() if not l.startswith(">")]
    return "\n".join(lines).strip()

La posta reale ha bisogno di più marcatori di questi, in ogni lingua in cui scrive la vostra azienda, ma il principio regge: il modello dovrebbe leggere ciò che ogni persona ha detto, una volta, con la data e il mittente giusti.

Estraete il testo degli allegati con strumenti standard (pdftotext per i PDF, parser di libreria per i formati office) e indicizzatelo come parte del messaggio, mantenendo un collegamento al file originale.

Due indici, perché rispondono a domande diverse

Un indice full text risponde a domande con riferimenti esatti: un mittente, un dominio, un intervallo di date, un numero di fattura, una frase, «ha un PDF». È veloce, preciso e spiegabile. Usatene uno con stemming consapevole della lingua, così «fatture» trova «fattura», e con sinonimi tra le lingue che la vostra azienda usa, così una ricerca in una lingua trova la posta scritta nell'altra.

Un indice vettoriale risponde a domande sul significato: «quando il fornitore ha contestato per la prima volta il calendario di consegna?». Potrebbe non esserci una sola parola chiave per questo. Un modello di embedding trasforma ogni messaggio pulito in un vettore, e la ricerca trova i messaggi vicini per significato alla domanda.

Nessuno dei due basta da solo. I vettori sono deboli con identificatori e numeri; le parole chiave sono deboli con le parafrasi. Eseguite entrambi, e combinate:

  • Estraete prima i filtri dalla domanda: persone, domini, date, «con allegato».
  • Applicate quei filtri a entrambe le ricerche, così la ricerca vettoriale non vaga mai fuori dal periodo o dalle persone di cui parla la domanda.
  • Unite le due liste di risultati. La reciprocal rank fusion è semplice e funziona bene: assegnate a ogni messaggio un punteggio pari alla somma di 1 / (k + rank) sulle due liste.
  • Espandete i primi risultati ai loro thread, così il modello legge conversazioni, non frammenti.

Fate mostrare al modello il suo lavoro

Solo a questo punto entra in gioco il modello linguistico. Dategli i messaggi recuperati, ciascuno con ID, data e mittente, e istruitelo a rispondere solo a partire da essi e a citare l'ID per ogni affermazione. Nell'interfaccia, trasformate ogni citazione in un link che apre l'email originale.

Le citazioni fanno due lavori. L'utente può verificare ogni affermazione con un clic, che è l'unico modo responsabile di usare un modello su documenti aziendali. E potete vedere immediatamente quando il recupero ha fallito: una risposta che cita i messaggi sbagliati è un problema di recupero, non del modello, e vi dice dove guardare.

Dite chiaramente agli utenti che un modello può fraintendere. Con le fonti a un clic di distanza, è un rischio gestibile.

Tenete i dati in casa

Ogni componente di questo design gira comodamente sul vostro hardware: l'indice full text su server ordinari, il database vettoriale accanto, e il modello di embedding e il modello linguistico su server GPU che controllate voi. La posta, le domande e le risposte non devono mai lasciare la vostra rete.

Testatelo come un sistema, non come una demo

Prima di fidarvi, costruite un piccolo insieme di domande con risposte note: una fattura specifica, la prima email di una disputa nota, un messaggio scritto nella vostra seconda lingua, un messaggio cancellato il mese scorso (non dovrebbe essere trovato). Eseguitele dopo ogni modifica alla pulizia, all'indicizzazione o ai prompt, e conservate i risultati. Se una modifica peggiora le domande note, lo vedrete.

E sorvegliate la pipeline stessa. Una sincronizzazione che si è fermata in silenzio, un indice che non si è messo al passo, o un arretrato di vettori dopo un riavvio sembrano tutti «la ricerca funziona» finché qualcuno non ha bisogno della posta della settimana scorsa. Controllate l'intera catena end to end, a calendario, e allertate quando una qualsiasi fase resta indietro.

In breve

  • Deduplicate, raggruppate in thread, decodificate e togliete il testo citato prima di indicizzare qualsiasi cosa.
  • Indicizzate gli allegati; è lì che stanno i contratti.
  • Eseguite insieme ricerca per parole chiave e vettoriale, con i filtri applicati a entrambe.
  • Rispondete solo dalla posta recuperata, con una citazione su ogni affermazione.
  • Tenete ogni componente su hardware che controllate, e testate con domande note.

Costruiamo archivi di posta privati così, con l'AI che gira sulle vostre GPU private. Se ne state pianificando uno, saremo lieti di aiutarvi.

Parla con un ingegnere

Related (rows[1])

Correlati: Archivio email privato con ricerca AI locale · Documenti office gestiti su Nextcloud

Pubblicato il 15 ottobre 2026.

Tutte le note dal campo