Il Contesto
Questo e un progetto interno / R&D: nessun vincolo di riservatezza, piena liberta nel raccontarne metodo e architettura. Nasce da un problema che chiunque lavori in HR e recruitment conosce: i CV arrivano in formati eterogenei (PDF impaginati, Word, export da LinkedIn, scansioni) e ogni candidato organizza le proprie informazioni a modo suo. Confrontare venti profili per la stessa posizione significa, di fatto, rileggere venti documenti diversi e ricopiarne i dati a mano.
L'obiettivo del progetto era costruire un servizio che trasformasse quel materiale disordinato in un formato unico e standardizzato, così da rendere lo screening dei candidati confrontabile, filtrabile e — dove serve — automatizzabile a valle.
Il Problema
Lo screening manuale dei CV presenta tre criticita strutturali, indipendenti dal volume:
- Tempo lineare sul numero di candidati: leggere, interpretare e normalizzare a mano ogni CV richiede minuti per profilo. Su una shortlist di decine di candidati il costo cumulato e significativo e si ripete a ogni nuova posizione aperta.
- Dati non confrontabili: senza una struttura comune, due CV con le stesse competenze appaiono diversi. Non e possibile ordinare, filtrare o fare query ("chi ha 5+ anni su backend Node?") perché l'informazione resta prosa libera.
- Errori e bias di trascrizione: quando i dati vengono ricopiati a mano in un foglio o in un ATS, si perdono dettagli, si introducono refusi e l'attenzione cala dopo i primi profili.
Il parsing dei CV con sistemi a regole o regex e un approccio classico ma fragile: basta un layout a due colonne, una sezione rinominata o una data scritta in modo diverso per mandarlo fuori strada. Serviva un livello di comprensione semantica, non sintattica.
La Soluzione
L'architettura, ad alto livello, e una pipeline a tre stadi con un frontend di revisione, interamente containerizzata via Docker / docker-compose per avere lo stesso ambiente in sviluppo e in esecuzione.
1. Ingestione e normalizzazione del testo
Il backend NestJS riceve il file caricato, ne estrae il testo grezzo e lo ripulisce (rimozione di header/footer ripetuti, normalizzazione degli spazi e degli encoding). Questo stadio rende il documento agnostico rispetto al formato di origine prima che entri nel modello.
2. Estrazione semantica via LLM
Il cuore del sistema chiama la OpenAI API con un prompt che impone uno schema JSON rigido come output: anagrafica, esperienze (azienda, ruolo, periodo, descrizione), competenze, formazione, lingue. Il modello non riassume il CV: lo mappa sullo schema, popolando solo i campi effettivamente presenti e lasciando esplicitamente vuoti quelli mancanti, così da non inventare dati.
3. Validazione e persistenza dell'output strutturato
L'output del modello viene validato contro lo schema atteso prima di essere accettato: tipi corretti, campi obbligatori presenti, struttura conforme. Solo a quel punto diventa un record pulito, pronto per il confronto tra candidati.
4. Frontend di revisione
L'interfaccia React mostra l'estrazione in forma tabellare e affianca, dove serve, il testo originale: il recruiter resta nel loop, puo correggere un campo al volo e validare il profilo. L'AI accelera il lavoro, non lo sostituisce alla cieca.
Tecnologie Chiave
Stack volutamente essenziale: poche tecnologie mature, ognuna con un ruolo netto nella pipeline.
Backend dell'API: orchestra ingestione, chiamata al modello e validazione dell'output strutturato.
Frontend di revisione: visualizza l'estrazione e tiene il recruiter nel loop per correzioni rapide.
Motore di estrazione semantica: mappa il testo libero del CV su uno schema JSON rigido.
Containerizzazione del servizio per parita tra ambiente di sviluppo ed esecuzione.
Orchestrazione locale di backend e frontend con un singolo comando, riproducibile.
Il Risultato
Lo screening passa dalla lettura sequenziale di documenti eterogenei al confronto di record strutturati e omogenei.
Tempo screening CV (stima)
Output standardizzato
Estrazione semantica
Le metriche sono indicative e stimate sulla base dell'esperienza di sviluppo: trattandosi di un progetto R&D interno non rappresentano misurazioni certificate su un deployment di produzione.
Sfide Tecniche
Forzare un output deterministico da un modello generativo
Il rischio principale di un LLM applicato all'estrazione e che inventi dati plausibili o restituisca JSON malformato. La sfida e stata vincolare il modello a uno schema rigido e gestire ogni risposta come non affidabile finché non e validata: l'output viene parsato e controllato campo per campo, e ai campi non presenti nel CV corrisponde un valore vuoto esplicito invece di un'allucinazione. La validazione a valle e la rete di sicurezza che rende l'output utilizzabile a programma.
Layout e formati eterogenei in ingresso
CV a due colonne, sezioni rinominate, date scritte in dieci modi diversi: un parser a regole si rompe a ogni eccezione. La soluzione e stata spostare il problema dal livello sintattico a quello semantico, normalizzando prima il testo in una forma neutra e delegando al modello la comprensione del contenuto, non della sua impaginazione. Così il sistema regge formati mai visti prima senza nuove regole ad-hoc.
Per il profilo professionale ed esperienza in applicazioni AI e LLM vedi la pagina Chi sono; per altri progetti realizzati vedi il portfolio completo.