🚀 Come far parlare le macchine con pochi token: il caso di ACON e ReAct prompt come co-pilota
Per chi è curioso di capire come i chatbot riescono a capire richieste complesse (prenotare un volo, cancellare una prenotazione…) senza impazzire con i costi di calcolo.
1. Il problema: “troppi token, troppe spese”
Gli LLM (Large Language Model) come ChatGPT o LLaMA sono fantastici, ma ogni parola
che gli mandi (e ogni risposta che ti restituiscono) è trasformata in token.Più token usi, più:
⏱️ Tempo di risposta aumenta.
💸 Costo (soprattutto con le API a consumo) sale.
Immagina di dover elaborare decine di messaggi di supporto clienti ogni secondo: il conto può esplodere.
Per approfondimenti vedi : 🚀 ACON – La “Compressione Semantica” che rende gli AI più smart (e meno stressati!)“
2. ACON: Adaptive Context Optimization and Navigation
ACON è una strategia che parte da due principi:
✅ Cosa fa | 🤔 Perché è importante |
Estrae le parole chiave semantiche (es. volo, Milano, 15 luglio) | Riduce il rumore (frasi di cortesia, errori di battitura) |
Comprime il contesto mantenendo solo le informazioni “critiche” | Diminuite il numero di token da inviare al modello |
Indirizza l’azione corretta tramite un router semantico | Il modello sa subito se devi prenotare o cancellare |
In pratica, ACON è il “co‑pilota” che trasforma una frase lunga in una lista di parole indispensabili prima che l’LLM la legga.
Per approfondimenti vedi:
3. ReAct: Reasoning + Acting (Il cervello del sistema)
Mentre ACON si occupa della compressione, ReAct gestisce il flusso di ragionamento:
Reasoning – il modello analizza l’intento (“Voglio un volo”) e decide quali informazioni cercare.
Acting – chiama gli “strumenti” (funzioni Python) per estrarre data, orario, luogo, numero di volo, …
Ripete il ciclo finché non ha tutti i dati, poi produce la risposta finale.
Nota: Nella demo qui sotto, il ciclo è interamente guidato da GPT‑4 mini: l’LLM sceglie da solo quando usare extract_date, quando extract_locations, ecc.
4. Tecnologie di base
Tecnologia | Ruolo nel progetto |
spaCy (it_core_news_sm / lg) | Riconoscimento di entità (nomi città, date, numeri di volo) |
KeyBERT / BERT / TF‑IDF | Estrarre le keyword più importanti da una frase |
Regex avanzate | Parsing di data, ora, codici di volo (es. AZ1234) |
LLM (GPT‑4, LLaMA, ecc.) | Classificazione dell’intento, decisione di routing, generazione output |
Python | Wrapper che collega tutto (funzioni di estrazione, chiamate API, loop ReAct) |
5. Esempio pratico in azione
Input dell’utente
“Vorrei prenotare un volo da Milano a Roma il 15 luglio pomeriggio, compagnia italiana, posto vicino al finestrino.”
Output “compresso” (grazie ad ACON)
volo Milano Roma 15 luglio pomeriggio compagnia italiana finestrino
Solo le parole che servono a completare la prenotazione rimangono, riducendo drasticamente i token da inviare al modello.
6. Come funziona il co‑pilota intelligente (il codice)
6.1 Funzioni di estrazione (regex)
def cerca_luoghi(testo):
# da Milano a Roma → ('Milano', 'Roma')
match = re.search(r"da\s+(\w+)\s+a\s+(\w+)", testo, re.IGNORECASE)
return (match.group(1), match.group(2)) if match else (None, None)
def cerca_data(testo):
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
> Le funzioni sono **veloci** perché usano solo espressioni regolari, senza dover caricare modelli pesanti.
6.2 Classificazione dell’intento (LLM)
6.2.1 Funzione di Analisi dell'Intento
def analyze_intent(user_input):
prompt = f"""
Classifica l'intento dell'utente tra: 'prenotazione', 'cancellazione' o 'sconosciuto'.
Utente: "{user_input}"
Intenzione:
"""
response = openai.ChatCompletion.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
max_tokens=10,
temperature=0
)
intent = response["choices"][0]["message"]["content"].strip().lower()
if intent in ["prenotazione", "cancellazione"]:
return intent
return "sconosciuto"
6.2.2 Mappa degli Strumenti
tools = {
"analyze_intent": lambda x: analyze_intent(x),
"extract_flight_number": lambda x: cerca_numero_volo(x),
"extract_date": lambda x: cerca_data(x),
"extract_time": lambda x: cerca_ora(x),
"extract_locations": lambda x: cerca_luoghi(x)
}
6.2.3 Funzione per Interrogare GPT-4 Mini
def ask_gpt4_mini(user_prompt):
import requests
import json
import os
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv("OPENAI_API_KEY")
payload = {
"model": "gpt-4.1-nano",
"messages": [
{"role": "user", "content": user_prompt}
],
"temperature": 0.2,
"max_tokens": 512,
"stream": False
}
url = "https://api.openai.com/v1/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}"
}
try:
response = requests.post(url, headers=headers, json=payload, timeout=30)
except requests.exceptions.RequestException as e:
print(f"[ERRORE RETE] {e}")
return None
# Prova a parsare JSON
try:
data = response.json()
except json.JSONDecodeError:
print("[ERRORE] La risposta non è JSON valido")
return None
# Caso 1: errore API (es. chiave sbagliata)
if "error" in data:
print(f"[ERRORE API] {data['error']}")
return None
# Caso 2: struttura inattesa
if "choices" not in data or not data["choices"]:
print(f"[ERRORE] Risposta inattesa: {data}")
return None
return data["choices"][0]["message"]["content"]
6.3 Loop ReAct
def run_react_with_gpt(user_input):
# Prompt iniziale
prompt = f"""
Answer the following questions as best you can. You have access to the following tools:
analyze_intent, extract_flight_number, extract_date, extract_time, extract_locations
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [analyze_intent, extract_flight_number, extract_date, extract_time, extract_locations]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!
Question: {user_input}
"""
print(prompt)
while True:
response = ask_gpt4_mini(prompt)
print(response)
if "Final Answer:" in response:
break
# Estrai azione e input
lines = response.split("\n")
action_line = [line for line in lines if line.startswith("Action:")][0]
action_input_line = [line for line in lines if line.startswith("Action Input:")][0]
action = action_line.replace("Action:", "").strip()
action_input = action_input_line.replace("Action Input:", "").strip()
# Esegui azione
if action in tools:
result = tools[action](action_input)
observation = f"Observation: {result}"
prompt += f"\n{response}\n{observation}\n"
else:
observation = "Observation: Unknown action"
prompt += f"\n{response}\n{observation}\n"✅ Cosa succede?
1. L’LLM legge la domanda dell’utente.
2. Propone un’azione (`extract_locations`, `extract_date`, …).
3. Il bot esegue l’azione in Python, restituisce l’**osservazione**.
4. Il ciclo ricomincia finché il modello dichiara “Final Answer”.
7. Suggerimenti per rendere il tutto più **light**
Area | Come ottimizzare |
Token usage | – Usa ACON per ridurre il testo a <20 token prima di mandarlo al modello. – Imposta `max_tokens` bassi (es. 150) per le risposte. |
Regex vs. spaCy | - Per pattern semplici (date, orari) le regex sono più veloci. - Usa spaCy solo quando ti servono entità complesse o multi‑word (`compagnia italiana`). |
Cache dei risultati | Salva le estrazioni già fatte (es. “Milano → Milano”) in un dict per evitare ripetizioni nella stessa conversazione. |
Batching | Se devi processare più richieste contemporaneamente, raggruppa le chiamate alle funzioni di estrazione in un unico loop Python. |
Modelli più piccoli | Per la classificazione di intenti usa `gpt-4o-mini` o `bert-base-italian` (meno costoso). |
8. Perché questo approccio è **futuro‑ready**
✅ | Caratteristica | Descrizione |
1️⃣ | Flessibilità | Aggiungi una nuova azione (es. “ricerca hotel”) creando una sola nuova funzione Python. L’LLM scoprirà automaticamente come usarla. |
2️⃣ | Robustezza | Anche se l’utente scrive “Rimboccami il volo per domani”, il sistema riconosce l’intento di *cancellazione* grazie al ragionamento LLM, non a regole rigide. |
3️⃣ | Scalabilità | Meno token = minori costi su larga scala, perfetto per chatbot che gestiscono migliaia di utenti al giorno. |
9. In sintesi: i 3 take‑away per te
✅ | Cosa ricorderai |
1️⃣ | ACON trasforma frasi lunghe in una “lista di parole chiave” per risparmiare token. |
2️⃣ | ReAct è il meccanismo di “pensiero + azione” che fa parlare il modello con le tue funzioni Python. |
3️⃣ | Usare regex per dati semplici, spaCy per entità complesse, e LLM per capire cosa l’utente vuole davvero. |
10. Vuoi provare?
Passo | Descrizione |
1️⃣ | Copia il codice qui sopra. |
2️⃣ | Installa le dipendenze: pip install spacy openai python-dotenv. |
3️⃣ | Scarica i modelli spaCy italiani: python -m spacy download it_core_news_sm. |
4️⃣ | Aggiungi la tua chiave API OpenAI in un file .env (OPENAI_API_KEY=…). |
5️⃣ | Lancia lo script e scrivi frasi come “Prenoto un volo da Napoli a Venezia il 3 agosto alle 10:30”. |
> 🎉 Vedrai l’LLM pensare, chiamare le funzioni e restituire la risposta finale, il tutto con **meno di 30 token** inviati al modello!
🎓 Conclusioni
Il mondo dei chatbot sta passando da **regole rigide** a **ragionamento dinamico**.
Tecniche come **ACON** e **ReAct** dimostrano che è possibile mantenere alta la **qualità delle risposte** senza sprecare risorse.
Se sei uno studente appassionato di intelligenza artificiale, sperimentare con queste idee ti darà una marcia in più per capire **come i grandi player costruiscono assistenti virtuali intelligenti e a basso costo**.
> **Prossima sfida:** aggiungi il supporto per *prenotazioni di treni* oppure *ricerca eventi* e vedi come il tuo co‑pilota si adatta automaticamente! 🚂✨
Buon hacking e… **buona chat!**




Commenti