Hai mai insegnato a un cane a dare la zampa? Non gli hai mostrato un dataset di diecimila foto di zampe etichettate «giusto» e «sbagliato». Hai aspettato che per caso alzasse la zampa, gli hai dato un biscotto, e lui ha collegato i puntini: quella mossa, in quella situazione, porta biscotti. Poi ha riprovato, sempre più spesso, sempre meglio. Congratulazioni: hai già fatto reinforcement learning, solo senza Python.
Agente, ambiente e ricompensa, il dilemma esplorazione–sfruttamento e le tappe che hanno fatto la storia: nel libro.
Leggi «Reinforcement Learning: imparare per tentativi» nel libro →
Oggi costruiamo il vocabolario fondamentale — agente, ambiente, stato, azione, ricompensa, policy — e lo mettiamo subito alla prova implementando da zero un algoritmo di Q-learning su una piccola griglia. Ti serve solo Python 3.12 e NumPy (in un progetto nuovo: uv init && uv add numpy, oppure il classico venv + pip). Se non ricordi cos’è un array NumPy, ti basta sapere che è una tabella di numeri su cui si fanno operazioni veloci senza scrivere cicli.
Il terzo paradigma dell’apprendimento
Nel supervised learning qualcuno ti consegna le risposte giuste: ecco mille email, ecco quali sono spam, impara la corrispondenza. Nell’unsupervised nessuno ti dà risposte e cerchi strutture nascoste. Il reinforcement learning è una terza via, più simile alla vita: nessuno ti dice qual è l’azione giusta, ma dopo ogni azione l’ambiente ti dà un voto — la ricompensa (reward). Positiva, negativa o nulla. Sta a te capire, per tentativi, quale sequenza di azioni massimizza i voti accumulati nel tempo.
È la differenza tra imparare a guidare con un istruttore che ti corregge ogni singola manovra (supervised) e imparare ad andare in bicicletta: nessuno può spiegarti a parole come stare in equilibrio, ma ogni sbandata e ogni metro percorso senza cadere ti danno un feedback inequivocabile.
Il loop agente-ambiente: il motore di tutto
Tutto il RL, da un termostato intelligente ad AlphaGo, gira sullo stesso ciclo. L’agente (chi decide) osserva lo stato dell’ambiente (dove si trova, cosa vede), sceglie un’azione, e l’ambiente risponde con due cose: un nuovo stato e una ricompensa. Il ciclo ricomincia, migliaia o milioni di volte.
Il loop agente-ambiente: l’agente agisce, l’ambiente risponde con nuovo stato e ricompensa. Tutto il reinforcement learning — dal termostato ad AlphaGo — è una variazione su questo ciclo.
Il vocabolario minimo, con l’analogia del cane sempre a portata di mano:
- Stato (s): la situazione attuale. Per il cane: «il padrone ha detto zampa e ha la mano tesa».
- Azione (a): una delle mosse possibili. Alzare la zampa, abbaiare, sdraiarsi.
- Ricompensa (r): il voto immediato. Biscotto = +1, niente = 0.
- Policy (π): la strategia dell’agente, la mappa «in questo stato faccio questa azione». È ciò che l’apprendimento deve migliorare.
- Valore Q(s, a): quanto «rende» in prospettiva fare l’azione a nello stato s — non solo il biscotto immediato, ma tutti quelli futuri che quella mossa sblocca.
Il reinforcement learning non impara le risposte giuste: impara quali azioni, alla lunga, portano più biscotti.
Esplorare o sfruttare? Il dilemma del ristorante
C’è una tensione inevitabile in tutto questo. Il sabato sera vai nel solito ristorante che sai essere buono (sfruttamento: incassi una ricompensa sicura) o provi quello nuovo dietro l’angolo (esplorazione: rischi una cena mediocre, ma potresti scoprire il tuo nuovo preferito)? Un agente che sfrutta e basta resta incastrato nella prima strategia decente che trova; uno che esplora e basta non capitalizza mai ciò che ha imparato.
La soluzione più semplice si chiama epsilon-greedy: con probabilità ε (per esempio il 10%) scegli un’azione a caso, altrimenti la migliore che conosci. Nel codice qui sotto la vedrai in due righe.
Q-learning su una griglia, da zero
Mettiamo tutto insieme. L’ambiente è una griglia 4×4: l’agente parte in alto a sinistra e deve raggiungere il tesoro in basso a destra, evitando una trappola. Ogni passo costa −1 (per spingerlo a fare in fretta), la trappola vale −20, il tesoro +30. L’agente impara aggiornando una tabella Q con la regola di Bellman: «il valore di questa mossa è la ricompensa immediata più il meglio che potrò fare dopo, un po’ scontato».
# Python 3.12 — dipendenza: numpy
import numpy as np
rng = np.random.default_rng(0)
# --- L'ambiente: griglia 4x4 ---
LATO = 4
PARTENZA, TESORO, TRAPPOLA = 0, 15, 9 # celle numerate da 0 a 15
AZIONI = [-LATO, +LATO, -1, +1] # su, giù, sinistra, destra
def passo(stato, azione):
"""Applica un'azione: restituisce (nuovo_stato, ricompensa, finito)."""
r, c = divmod(stato, LATO)
# se la mossa esce dalla griglia, l'agente resta fermo (muro)
if (azione == -LATO and r == 0) or (azione == +LATO and r == LATO - 1) \
or (azione == -1 and c == 0) or (azione == +1 and c == LATO - 1):
nuovo = stato
else:
nuovo = stato + azione
if nuovo == TESORO: return nuovo, +30, True # obiettivo raggiunto
if nuovo == TRAPPOLA: return nuovo, -20, True # episodio fallito
return nuovo, -1, False # costo del passo
# --- L'agente: tabella Q (16 stati x 4 azioni), tutta a zero ---
Q = np.zeros((LATO * LATO, 4))
alpha, gamma, eps = 0.1, 0.9, 0.1
# alpha: quanto fidarsi della nuova esperienza (tasso di apprendimento)
# gamma: quanto pesano le ricompense future (0.9 = lungimirante)
# eps: quota di mosse esplorative a caso (epsilon-greedy)
for episodio in range(2000):
stato, finito = PARTENZA, False
while not finito:
# epsilon-greedy: a volte esplora, di solito sfrutta
if rng.random() < eps:
a = rng.integers(4) # esplora: mossa a caso
else:
a = int(np.argmax(Q[stato])) # sfrutta: la mossa migliore nota
nuovo, ricompensa, finito = passo(stato, AZIONI[a])
# Regola di Bellman: reward immediato + miglior futuro scontato
obiettivo = ricompensa + gamma * np.max(Q[nuovo]) * (not finito)
Q[stato, a] += alpha * (obiettivo - Q[stato, a])
stato = nuovo
# --- La policy imparata: una freccia per ogni cella ---
frecce = np.array(["↑", "↓", "←", "→"])
mappa = frecce[np.argmax(Q, axis=1)].reshape(LATO, LATO)
mappa[divmod(TESORO, LATO)] = "★"
mappa[divmod(TRAPPOLA, LATO)] = "✖"
for riga in mappa:
print(" ".join(riga))
Esegui lo script: vedrai una griglia di frecce che aggirano la trappola e convergono sul tesoro. Nessuno ha mai detto all’agente «gira a destra alla terza cella»: la strategia è emersa da duemila episodi di tentativi, errori e biscotti. Prova a rieseguire con eps = 0 (niente esplorazione): spesso la policy resterà mediocre, perché l’agente si fossilizza sulla prima strada che gli è andata bene — il ristorante di cui sopra.
Quando il RL non ti serve (cioè quasi sempre)
Doccia fredda, per onestà: nella maggior parte dei problemi aziendali il reinforcement learning è la risposta sbagliata. Se hai dati storici etichettati, il supervised learning è più semplice, più stabile e più economico. Il RL brilla solo quando le decisioni sono sequenziali (ogni azione cambia le situazioni future), il feedback arriva in ritardo, e hai un simulatore o la possibilità di sperimentare senza danni: giochi, robotica, controllo di sistemi, ottimizzazione di risorse. È anche notoriamente instabile e affamato di esperienza — il nostro agente ha avuto bisogno di duemila tentativi per una griglia 4×4. Detto questo, il vocabolario che hai imparato oggi ti serve comunque: il fine-tuning con feedback umano dei modelli linguistici (RLHF) parla esattamente questa lingua — stati, azioni, ricompense, policy.
Prova tu: aggiungi una seconda trappola nella cella 6 e un «vento» che con probabilità 0,2 sposta l’agente di una cella a destra dopo ogni mossa (ambiente stocastico). L’agente impara ancora ad arrivare al tesoro? Quanti episodi servono in più? Poi sperimenta con gamma = 0.5: cosa succede a una policy «miope»?
Per approfondire: il riferimento assoluto è Reinforcement Learning: An Introduction di Sutton e Barto (seconda edizione, gratuita online sul sito degli autori) — i capitoli 1, 3 e 6 coprono esattamente il percorso di questo tutorial. Per sperimentare con ambienti già pronti, guarda la libreria Gymnasium della Farama Foundation.

I commenti sono riservati agli iscritti.
Accedi per commentare