Da Cognitor a porusski.it: quando l'assistente deve anche tradurre
Il contesto di porusski.it prevede che, quando un utente richiede una traduzione, Cognitor identifichi l’intento (“voglio una traduzione”) ed estragga le entità rilevanti, come il testo da tradurre. Tuttavia, la pipeline standard di Cognitor non è progettata per produrre una traduzione italiano‑russo; serve un modello di Neural Machine Translation (NMT) specifico per gestire la generazione del testo target. Per questa ragione, l’intent di traduzione richiama un secondo modello, un Transformer encoder‑decoder personalizzato, totalmente indipendente dall’architettura BiGRU+CRF che alimenta il resto del bot.
In questo articolo approfondiamo l’intero flusso: dalla problematica iniziale alla definizione dell’architettura Transformer, dalla difficoltà con i nomi propri alla soluzione basata su NER e regole fonetiche, fino a come i due modelli coesistono senza conflitti e quali insegnamenti si possono trarre da questa integrazione. Scoprirete le scelte tecniche, le sfide superate e le potenzialità future di un sistema NLU realmente modulare.
Il problema: un intent, ma non basta un modello solo
Su porusski.it, la richiesta di traduzione attiva l’intento “voglio una traduzione” e consente a Cognitor di estrarre le entità chiave, tipicamente il testo da tradurre. Questa fase di riconoscimento è gestita perfettamente dal motore NLU, ma la pipeline smette di funzionare non appena è necessario produrre una frase in russo. La generazione di una traduzione italiano‑russo non è un compito di classificazione o di Named Entity Recognition (NER), ma richiede un modello di generazione linguistica avanzato.
Il modello di traduzione deve quindi essere separato dall’architettura principale basata su BiGRU+CRF, perché i requisiti di apprendimento e di capacità di generalizzazione sono diversi. Per questa ragione, l’intent di traduzione richiama un Transformer encoder‑decoder di Neural Machine Translation (NMT) custom, studiato esclusivamente per la coppia di lingue italiano‑russo. Questo approccio consente di mantenere intatta la struttura di Cognitor, aggiungendo solo un componente specializzato quando necessario.
L’integrazione di due architetture distinte – la rete BiGRU+CRF per il dialogo e il Transformer NMT per la traduzione – rappresenta un esempio di modularità che permette di scalare il sistema senza dover ricostruire l’intero workflow. Tale separazione facilita il controllo, la manutenzione e l’ottimizzazione di ciascuna parte in modo indipendente, migliorando al contempo le performance complessive dell’assistente.
L'architettura del Transformer
Il modello utilizzato, denominato RussianTransformer, è una realizzazione nativa in PyTorch della famosa architettura “Attention is all you need”. Il design prevede tre livelli di encoder e tre di decoder, otto attention head, una dimensione di modello (d_model) pari a 512 e una rete feed‑forward a 2048 unità. Il positional encoding è sinusoidale, garantendo così una corretta rappresentazione della posizione dei token nella sequenza. Complessivamente, il modello conta circa 176 milioni di parametri, sufficienti a catturare le complessità linguistiche della traduzione italiano‑russo.
Il vocabolario è condiviso tra le due lingue e comprende 100.000 subword tokenizzati con SentencePiece. Questa scelta riduce drasticamente il problema dell’out‑of‑vocabulary, poiché anche parole mai viste durante l’addestramento possono essere ricostruite a partire da subword conosciuti. Il training avviene con cross‑entropy e label smoothing 0.1, evitando l’over‑confidence su una singola traduzione corretta e favorendo la flessibilità quando sono possibili più traduzioni valide.
Il dataset di addestramento è stato creato su misura per le esigenze di Cognitor, includendo circa 76.000 coppie di frasi allineate. Dopo il training, il checkpoint (circa 680 MB) viene convertito in TorchScript tramite tracing, rendendo possibile l’inferenza in produzione senza dipendere dal codice Python del modello. La generazione avviene in modalità autoregressiva greedy: a ogni passo il decoder emette il token più probabile (argmax) fino al token di fine frase o a un limite di lunghezza, evitando la complessità del beam search per un dominio di frasi brevi e strutturate.
Il vero problema: non tradurre i nomi propri, trascriverli
La traduzione italiano‑russo presenta una difficoltà specifica legata ai nomi propri e cognomi: il passaggio dall’alfabeto latino a quello cirilico non è una traduzione semantica, ma una trascrizione fonetica. Nei test iniziali, il modello traduceva correttamente i nomi di battesimo più comuni (es. “Luca” → “Лука”), ma ometteva sistematicamente i cognomi poco frequenti o mai presenti nel training, producendo output incompleti:
Luca Smorti sta lavorando → Лука работает (il cognome sparisce)
Luca Pasquini → Лука. (idem)Questo comportamento è strutturale: il modello apprende la trascrizione dei nomi per memorizzazione statistica, ma i cognomi rappresentano un insieme aperto, impossibile da coprire interamente con dati di training. Anche l’aggiunta di nuovi batch introduce solo una piccola quantità di cognomi nuovi, lasciando sempre scoperti molti casi. Le due soluzioni provate – uno schema di tag grammaticali e un copy mechanism in stile Pointer‑Generator – sono state abbandonate perché non risolvevano il problema della conversione fonetica, ma solo quello della preservazione dei token originali.
La soluzione: NER + regole fonetiche, fuori dal modello
La strategia adottata non modifica il Transformer, ma introduce una pipeline deterministica di pre‑ e post‑processing attorno al modello di traduzione. Il primo passo prevede un NER reale (spaCy, modello it_core_news_sm) in grado di identificare i nomi di persona nella frase italiana, anche quando si tratta di cognomi mai visti. Una volta individuati, si applica una fase di traslitterazione che consulta prima un dizionario di cognomi verificati manualmente, poi utilizza un motore di regole fonetiche per convertire l’italiano in cirilico (gestione di c/g davanti a e/i, sch, gli, gn, zz, qu, raddoppiamenti).
Infine, una fase di riparazione post‑hoc confronta i nomi trovati nella frase sorgente con l’output del modello. Se un cognome è stato omesso, viene reinserito accanto al nome di battesimo corrispondente, senza alterare le parti già tradotte correttamente. Il risultato sui casi di esempio è notevolmente migliorato:
Luca Smorti sta lavorando → Лука Сморти работает
Luca Pasquini → Лука Пасквини.Nonostante l’alta accuratezza (~95 %) su test specifici, rimangono limiti nella gestione della declinazione grammaticale russa dei cognomi nuovi e nelle situazioni con più persone nello stesso soggetto, dove la riparazione utilizza un’euristica meno elegante. Queste sfide evidenziano la necessità di dati di addestramento più completi, ma la soluzione attuale dimostra quanto una combinazione di NER e regole fonetiche possa colmare lacune che un modello generativo da solo non riesce a superare.
Come i due modelli convivono nella stessa conversazione
Dal punto di vista dell’architettura di Cognitor, la bellezza dell’integrazione risiede nella Operations Manager, progettata per l’auto‑discovery di operazioni personalizzate. Questa componente ha permesso di agganciare il Transformer NMT, con la sua pipeline di trascrizione dei nomi, come una nuova operazione invocabile dall’intent di traduzione attraverso il motore di regole YAML. Il flusso rimane così lineare: classificazione dell’intento, gestione dello slot con il testo da tradurre, chiamata al modello di traduzione, e infine risposta all’utente.
La coexistence dei due modelli – BiGRU+Attention+CRF per la gestione del dialogo e Transformer encoder‑decoder per la traduzione – non ha richiesto una riprogettazione dell’intero sistema. Al contrario, il design modulare ha consentito di aggiungere funzionalità complesse mantenendo la stabilità e la coerenza dell’esperienza conversazionale. Questo approccio evidenzia come la separazione delle responsabilità tra componenti specializzate possa migliorare l’efficienza operativa e facilitare futuri ampliamenti.
In pratica, ogni volta che l’utente richiede una traduzione, Cognitor passa fluidamente dal riconoscimento dell’intento alla chiamata del modello NMT, integrando la trascrizione dei nomi attraverso le regole fonetiche. Il risultato è una risposta coerente, rapida e linguisticamente accurata, senza alcuna interruzione percepita dall’utente finale.
La lezione di fondo
Il caso di studio dimostra che non tutti i problemi linguistici sono equivalenti: la comprensione di un’intenzione richiede un’architettura, mentre la generazione di una traduzione ne richiede un’altra. Anche all’interno dello stesso task di traduzione, un sotto‑caso apparentemente simile – la gestione dei nomi propri – può richiedere soluzioni diverse dal tipico copy mechanism, poiché l’obiettivo è trascrivere tra alfabeti, non semplicemente preservare i token originali.
La chiave del successo è la modularità: separare le componenti in blocchi indipendenti consente di combinare le migliori tecnologie disponibili senza creare conflitti. Inoltre, riconoscere quando una soluzione “manuale” – come le regole fonetiche basate su NER – è più efficace di un approccio puramente data‑driven è fondamentale per una progettazione intelligente. Per chi desidera sperimentare, il risultato è disponibile su porusski.it, mentre la documentazione tecnica di Cognitor può essere consultata su cognitor.programmato.it.