🚀 Un mini chatbot che “capisce” le tue richieste di volo: come funziona e perché è importante
- texservice13
- 24 giu
- Tempo di lettura: 5 min
Aggiornamento: 26 giu
Hai mai provato a scrivere a un assistente virtuale “Vorrei annullare il mio biglietto” e, invece di capire subito, ti ha chiesto di spiegare tutto di nuovo?Il Proof of Concept (PoC) che ti presento è stato costruito proprio per evitare questi fraintendimenti, ma solo per le prenotazioni aeree.
In questo post scopriremo:
Cosa fa il PoC (e in che modo lo fa).
Come utilizza spaCy per la ricerca semantica.
I pro e i contro di un sistema hard‑coded e deterministico.
Un demo live (in Python) per vedere il risultato con un paio di esempi.
1. Che cos’è la “ricerca semantica” e perché serve?
Concetto | Spiegazione in 3 parole | Esempio pratico |
Ricerca | Trova parole | “cerca volo” |
Semantica | Significato vero | “cancella” = “annulla” = “revoca” |
Semantica + Ricerca | Capire l’intento | “Vorrei revocare la mia prenotazione” → cancellazione |
In parole povere, non basta guardare le parole esatte che scrivi, ma bisogna capire cosa vuoi davvero. La ricerca semantica fa proprio questo: analizza i verbi, i sostantivi e le frasi per riconoscere l’intento cancellare o prenotare anche se lo esprimi in modi diversi.
2. Il PoC in azione: prenotazioni e cancellazioni aeree
2.1. Qual è l’obiettivo?
Il sistema deve gestire due operazioni:
Prenotare un volo.
Cancellare una prenotazione già esistente.
Tutto il resto (date, orari, numeri di volo, aeroporti) è estratto automaticamente dal testo dell’utente.
2.2. Come è stato costruito?
Libreria: spaCy (modello italiano “it_core_news_lg” o “sm”).
Logica: hard‑coded → regole fisse, nessun modello generativo (come un LLM).
Tecnica di elaborazione: ACON (Algoritmo Deterministico di Controllo).
Deterministico = prevedibile: per la stessa frase ottieni sempre la stessa risposta.
3. Passo per passo: cosa succede quando scrivi qualcosa?
3.1. Analisi dell’input
- Raccoglie *verbi* e *sostantivi* (es. “cancellare”, “volo”).
- Unisce tutti i termini per facilitare il confronto.
# Carica il modello spaCy (usa sm se lg non è disponibile)
try:
nlp = spacy.load("it_core_news_lg")
except:
nlp = spacy.load("it_core_news_sm")
# Parole semanticamente importanti
parole_cancellazione = [
"cancellare", "cancellazione", "eliminare", "eliminazione",
"annullare", "annullamento", "rimuovere", "rimozione",
"disdire", "disdetta", "revocare", "revoca"
]
parole_prenotazione = [
"prenotare", "prenotazione", "riservare", "riserva",
"prendere", "acquistare", "acquisto", "prenotarmi"
]
# Cerca verbi e sostantivi significativi
verbi_trovati = []
sostantivi_trovati = []
doc = nlp(testo_input.lower())
verbi = [t.lemma_ for t in doc if t.pos_ == "VERB"]
sostantivi = [t.lemma_ for t in doc if t.pos_ == "NOUN"]
tutti_i_termini = verbi + sostantivi + testo_input.lower().split()
3.2. Riconoscimento dell’intento
if any(parola in termine for termine in tutti_i_termini
for parola in parole_cancellazione):
cancellazione_trovata = True
elif any(parola in termine for termine in tutti_i_termini
for parola in parole_prenotazione):
prenotazione_trovata = True
in questo PoC si dà **Priorità** a *cancellazione*: se trovi parole come “cancellare”, “annullare”, ecc., il sistema risponde subito con “Hai chiesto una cancellazione”.
3.3. Estrarre le informazioni indispensabili
Tipo di dato | Funzione Python | Esempio di espressione che riconosce |
Numero volo | `cerca_numero_volo()` | `AZ123`, `LH4567`, `volo 1234` |
Data | `cerca_data()` | `15 luglio`, `10 agosto` |
Ora | `cerca_ora()` | `16:30`, `alle 14` |
Luogo (da…a…) | `cerca_luoghi()` | `da Roma a Milano` |
Se manca qualcosa, il bot chiede all’utente di specificare il dato mancante (es. “Non ho trovato la data. Potresti specificarla?”).
# Se trova cancellazione, ha priorità
if cancellazione_trovata:
print("Hai chiesto una cancellazione.")
print("Per favore, inserisci il codice di prenotazione:")
return "cancellazione"
# Altrimenti è una prenotazione
elif prenotazione_trovata:
print("Hai chiesto una prenotazione.")
# Cerca numero del volo, data, ora e luoghi
numero_volo = cerca_numero_volo(testo_input)
data_trovata = cerca_data(testo_input)
ora_trovata = cerca_ora(testo_input)
da, a = cerca_luoghi(testo_input)
if numero_volo:
print(f"Numero volo trovato: {numero_volo}")
else:
print("Non ho trovato il numero del volo. Potresti specificarlo?")
if data_trovata:
print(f"Data trovata: {data_trovata}")
else:
print("Non ho trovato la data. Potresti specificarla?")
if ora_trovata:
print(f"Ora trovata: {ora_trovata}")
else:
print("Non ho trovato l'ora. Potresti specificarla?")
if da and a:
print(f"Percorso: da {da} a {a}")
elif da:
print(f"Partenza da: {da}")
elif a:
print(f"Destinazione: {a}")
else:
print("Non ho trovato i luoghi. Potresti specificare da dove a dove?")
return "prenotazione"
else:
print("Non ho capito cosa vuoi fare. Posso aiutarti con prenotazioni o cancellazioni.")
return "sconosciuto"
def cerca_luoghi(testo):
"""Cerca 'da ... a ...' """
match = re.search(r"da\s+(\w+)\s+a\s+(\w+)", testo, re.IGNORECASE)
if match:
return match.group(1), match.group(2)
return None, None
def cerca_data(testo):
"""Cerca date nel formato '15 luglio', '10 agosto', ecc."""
mesi = ["gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno",
"luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre"]
pattern = r"\b\d{1,2}\s+(" + "|".join(mesi) + r")\b"
match = re.search(pattern, testo, re.IGNORECASE)
return match.group() if match else None
def cerca_ora(testo):
"""Cerca ore nel formato '16:30', 'alle 14', ecc."""
pattern1 = r"\b\d{1,2}[:.]\d{2}\b"
pattern2 = r"alle\s+\d{1,2}"
match1 = re.search(pattern1, testo)
match2 = re.search(pattern2, testo)
if match1:
return match1.group()
elif match2:
return match2.group()
return None
def cerca_numero_volo(testo):
"""Cerca numeri di volo nel formato XY123, AZ789, ecc."""
# Pattern per codici volo: 2 lettere + numeri o lettere mescolate
pattern = r"\b[A-Z]{2}\d+[A-Z]*\b"
match = re.search(pattern, testo, re.IGNORECASE)
if match:
return match.group().upper()
# Pattern alternativo: solo numeri (es. volo 1234)
pattern2 = r"\b(?:volo\s+)?(\d{2,6})\b"
match2 = re.search(pattern2, testo, re.IGNORECASE)
if match2:
return match2.group(1) if match2.group(1) else match2.group()
return None
3.4. Output finale
- **Cancellazione**: stampa “Hai chiesto una cancellazione” + richiede il codice di prenotazione.
- **Prenotazione**: stampa tutti i dati trovati o richiede quelli mancanti, quindi conferma la prenotazione.
# Funzione principale di interazione
def chatbot_interattivo():
print("🤖 Come posso esserti utile?")
while True:
user_input = input("\n💬 Scrivi il tuo messaggio (o 'esci' per uscire): ")
if user_input.lower() in ['esci', 'exit', 'quit']:
print(" Arrivederci!")
break
# Analizza e guida l'utente
tipo_richiesta = analizza_stringa_e_guida_utente(user_input)
# Se è una cancellazione, chiedi il codice
if tipo_richiesta == "cancellazione":
codice = input("🔢 Inserisci il codice di prenotazione: ")
if codice:
print(f" Sto cercando la prenotazione con codice: {codice}")
# Qui andrebbe la logica di cancellazione reale
print("✅ Cancellazione completata con successo!")
# Esempio di utilizzo
if __name__ == "__main__":
chatbot_interattivo() 4. Pro & Contro di un approccio **hard‑coded**
✅ Vantaggi (i “pro”)
- **Determinismo**: ogni volta lo stesso input produce lo stesso output. Perfetto per ambienti dove la prevedibilità è obbligatoria (es. test di sistema, contesti regolamentati).
- **Controllo totale**: puoi aggiungere, rimuovere o modificare le regole a piacere.
- **Nessun costo di “training”**: non serve un’enorme quantità di dati né GPU per addestrare un modello.
❌ Limiti (i “contro”)
Limite | Perché è un problema |
Zero intelligenza contestuale | Se l’utente scrive “Mi potresti dare un volo per domani?” il bot non capisce. |
Rigidità | Non si adatta a formulazioni nuove o slang giovanile. |
Scalabilità limitata | Aggiungere nuove funzionalità richiede più codice “hard‑coded”. |
Gestione ambiguità | Se la frase è poco chiara (es. “cancella il volo 123”, ma non è chiaro il numero di prenotazione), il bot può fallire. |
> **In pratica:** il PoC è ottimo per dimostrare *come* funziona la ricerca semantica, ma in un’app reale vorresti un mix tra regole fisse e un modello più flessibile.
5. Cosa potresti migliorare?
1. **Aggiungere un livello di “fallback”** con un piccolo modello di Language Model che gestisca le frasi non riconosciute.
2. **Gestire sinonimi** più complessi (es. “volare verso”) usando WordNet o i vectori di spaCy.
3. **Implementare un’interfaccia grafica** (web o mobile come Gradio) per rendere l’interazione più user‑friendly.
4. **Logging intelligente**: salvare le frasi non capite per analizzarle e perfezionare le regole.
6. Conclusioni
Il PoC che ho mostrato è un **esempio concreto di come la ricerca semantica possa trasformare una semplice frase in una serie di azioni automatiche**, tutto senza l’uso di grandi modelli di intelligenza artificiale.
Se sei uno studente curioso o un giovane sviluppatore, prova a **modificare le liste di parole chiave** (`parole_cancellazione`, `parole_prenotazione`) o a **estendere le regex** per date/ore. Scoprirai quanto è divertente “insegnare” al computer a capire il linguaggio umano, passo dopo passo.
Buon coding e buona “volata” nel mondo della **NLU (Natural Language Understanding)**! ✈️💬
🎓 Risorse consigliate
Risorsa | Perché è utile |
Guida ai modelli italiani (lg vs sm). | |
Tutorial pratico su spaCy per principianti. | |
Dove scaricare i modelli se il tuo PC non li ha. |
> **Divertiti a sperimentare!** Se ti va, condividi i tuoi miglioramenti su GitHub o nei commenti qui sotto...




Commenti