Embeddings: Come l'AI Capisce che 'Cane' e 'Cucciolo' Sono Simili
Come funzionano gli embedding moderni? Cosine similarity, BERT, vector database e RAG: tutto quello che serve per capire come l'AI vede il significato.
Alessandro Saiani
Human in the Loop

Nell'articolo su Word2Vec abbiamo visto l'idea fondamentale: trasformare le parole in vettori di numeri dove la distanza rappresenta il significato. "Re - uomo + donna = regina" — matematica con le parole.
Ma Word2Vec ha un problema serio: ogni parola ha un solo vettore, fisso per sempre. "Pesca" è un unico punto nello spazio — che tu stia parlando del frutto o dell'attività al lago. E non sa nulla di frasi intere: "il cane morde l'uomo" e "l'uomo morde il cane" producono gli stessi vettori.
Gli embeddings moderni risolvono tutto questo. Cambiano in base al contesto. Rappresentano frasi intere. E sono il motore invisibile dietro la ricerca semantica, il RAG, i vector database, e ogni volta che Claude "capisce" cosa intendi.
Questo articolo parte dove Word2Vec si ferma.
Come Si Misura la Similitudine: Cosine Similarity
Prima di parlare di modelli, serve capire come si confrontano due vettori. Perché dire "gatto e cane sono vicini" richiede una definizione matematica di "vicino".
Il Problema della Distanza Euclidea
La prima idea sarebbe la distanza classica — la linea retta tra due punti (distanza euclidea). Ma ha un difetto: dipende dalla lunghezza del vettore, non solo dalla direzione.
Immagina due testi sullo stesso argomento. Uno è lungo (tanti token, vettore "grande"), l'altro breve. La distanza euclidea li vedrebbe lontani — ma il significato è lo stesso.
Cosine Similarity: Conta Solo la Direzione
La cosine similarity misura l'angolo tra due vettori, ignorando la lunghezza. Il valore va da -1 a +1:
cos(θ) = (A · B) / (|A| × |B|)
- +1.0: vettori nella stessa direzione → significato identico
- 0.0: vettori perpendicolari → nessuna relazione
- -1.0: direzioni opposte → significato opposto
In pratica:
similarity("cane", "cucciolo") = 0.92 → molto simili
similarity("cane", "gatto") = 0.85 → simili (entrambi animali)
similarity("cane", "automobile") = 0.15 → poco in comune
similarity("cane", "felicità") = 0.08 → quasi nessuna relazione
Perché funziona? Perché nel vettore di un embedding, la direzione codifica il significato e la lunghezza dipende da fattori come la frequenza della parola o la lunghezza del testo. La cosine similarity cattura il primo e ignora il secondo.
Nella Pratica Quotidiana
Ogni volta che usi la ricerca semantica, il RAG, o un vector database, dietro c'è una cosine similarity. Scrivi "come faccio a autenticarmi?" e il sistema trova un documento intitolato "Guida alla Login" — perché i due embedding puntano nella stessa direzione, anche se non condividono nessuna parola.
Da Statici a Contestuali: Il Salto Fondamentale
Word2Vec, GloVe e FastText producono embedding statici: un vettore per parola, calcolato una volta, uguale per sempre. Nel 2018 è cambiato tutto.
ELMo: Il Primo Embedding Contestuale (2018)
ELMo (Embeddings from Language Models) di Allen NLP è stato il primo a generare vettori diversi per la stessa parola in contesti diversi. Usava una rete LSTM bidirezionale: leggeva la frase da sinistra a destra e da destra a sinistra, poi combinava i risultati.
"Andiamo a pesca al lago" → vec("pesca") = [0.21, -0.45, 0.83, ...] (attività)
"La pesca è un frutto dolce" → vec("pesca") = [-0.12, 0.67, 0.31, ...] (frutto)
Stesso token, vettori diversi. Il contesto cambia la rappresentazione. È il principio che poi BERT e GPT porteranno alle estreme conseguenze.
BERT: L'Attention Cambia Tutto (2018)
BERT (Google) ha sostituito le LSTM con il meccanismo di self-attention dei Transformer. Ogni token "guarda" tutti gli altri token della frase contemporaneamente — non sequenzialmente.
Il risultato: embedding che catturano relazioni a lunga distanza. In "il programmatore che ha scritto il codice ieri ha trovato un bug", BERT collega "bug" a "programmatore" e "codice" anche se sono distanti nella frase.
BERT è bidirezionale: legge il contesto in entrambe le direzioni. GPT è unidirezionale: legge solo da sinistra a destra (perché genera token uno alla volta). Entrambi producono embedding contestuali, ma con caratteristiche diverse.
Cosa Cambia in Pratica
| Aspetto | Embedding Statico | Embedding Contestuale |
|---|---|---|
| Polisemia | Un vettore per "banco" | Vettore diverso per "banco di scuola" vs "banco di nebbia" |
| Negazione | "buono" ≈ "non buono" | "buono" ≠ "non buono" |
| Ordine parole | Ignorato | Considerato |
| Calcolo | Lookup in tabella | Forward pass di un modello |
| Dimensione | 50-300 | 768-4096+ |
| Uso tipico | Feature per modelli ML | Ricerca semantica, RAG, classificazione |
Il prezzo: un embedding statico è un lookup istantaneo. Un embedding contestuale richiede un forward pass dell'intero modello — millisecondi per frase, che diventano ore su milioni di documenti.
Embedding di Frasi: SBERT e il Problema del Cross-Encoding
BERT produce un vettore per ogni token. Ma cosa fai se ti serve un vettore per un'intera frase o un paragrafo?
Il Problema: BERT È Lento per la Ricerca
Il modo "diretto" di usare BERT per la similarità tra frasi è il cross-encoding: dai in input entrambe le frasi al modello, che produce un punteggio di similarità.
Funziona bene. Ma è O(n²): per confrontare una query con 10.000 documenti, servono 10.000 forward pass di BERT. Con un milione di documenti, diventa impraticabile.
SBERT: Un Vettore per Frase
Sentence-BERT (2019) ha risolto il problema con un'idea semplice: fare fine-tuning di BERT per produrre un singolo vettore che rappresenta l'intera frase. Due frasi simili hanno vettori vicini.
Come funziona:
- Passa la frase nel modello BERT
- Prendi il vettore del token
[CLS]o la media di tutti i token (mean pooling) - Usa quel vettore come embedding della frase
Il vantaggio: calcoli l'embedding di ogni documento una volta sola, lo salvi, e poi confronti le query con una cosine similarity — operazione quasi istantanea. Da O(n²) a O(n).
SBERT è stato il modello che ha reso la ricerca semantica praticabile su larga scala. Prima di SBERT, la ricerca full-text con keyword era l'unica opzione per milioni di documenti.
I Modelli di Embedding Moderni
Dal 2023 in poi, le aziende AI hanno rilasciato modelli di embedding specializzati — più potenti di SBERT e ottimizzati per casi d'uso specifici.
OpenAI: text-embedding-3
Il modello più usato nell'ecosistema commerciale.
- text-embedding-3-small: 1536 dimensioni, $0.02/1M token — il workhorse
- text-embedding-3-large: 3072 dimensioni, $0.13/1M token — il più preciso
Innovazione chiave: Matryoshka embeddings. Puoi troncare il vettore a dimensioni inferiori (es. 256 invece di 3072) perdendo poco in qualità ma risparmiando spazio e velocità. Come le matrioske russe: le informazioni più importanti stanno nelle prime dimensioni.
Dimensione 3072: accuracy 100% (baseline)
Dimensione 1024: accuracy ~99%
Dimensione 256: accuracy ~95%
Cohere: Embed v4
Primo modello mainstream a supportare embedding multimodali: testo e immagini nello stesso spazio vettoriale. Una foto di un gatto e la frase "gatto che dorme" producono vettori vicini.
Supporta 100+ lingue — rilevante per l'italiano — e ha un punteggio alto sul benchmark MTEB.
Voyage AI: Modelli Verticali
Voyage ha scommesso sulla specializzazione:
- voyage-3: general-purpose, top su MTEB
- voyage-code-3: ottimizzato per codice — cerca per significato, non per syntax match
- voyage-finance-2: ottimizzato per documenti finanziari
- voyage-law-2: ottimizzato per testi legali
Il vantaggio dei modelli verticali: un embedding generico potrebbe non distinguere "derivative" (derivata matematica) da "derivative" (strumento finanziario). Uno specializzato sì.
Google: Gemini Embedding
Integrato nativamente nell'ecosistema Google Cloud, supporta fino a 8192 token di input — molto più della media. Multilingua.
Jina AI: jina-embeddings-v3
Modello open-weight (Apache 2.0) con un'idea interessante: task-specific adapters. Lo stesso modello base può essere indirizzato verso retrieval, classificazione o similarità con un parametro.
MTEB: Come Si Misurano gli Embedding
Il Massive Text Embedding Benchmark (MTEB) è il benchmark standard per valutare i modelli di embedding. Copre 8 task diversi su 58 dataset:
| Task | Cosa Misura | Esempio |
|---|---|---|
| Retrieval | Trovare documenti rilevanti | Ricerca semantica |
| STS | Similarità tra frasi | "Il cane corre" ≈ "Il cucciolo scappa" |
| Classification | Classificare testi | Sentiment, topic |
| Clustering | Raggruppare testi simili | Organizzare ticket di supporto |
| Reranking | Riordinare risultati | Migliorare risultati di ricerca |
| Pair Classification | Relazione tra coppie | Paraphrase detection |
| Summarization | Qualità dei riassunti | Embedding del riassunto vs originale |
| BitextMining | Allineamento traduzioni | Trovare frasi corrispondenti |
Perché serve un benchmark così ampio? Perché un modello eccellente in retrieval potrebbe essere mediocre in clustering. MTEB dà una visione completa. La classifica aggiornata è pubblica su Hugging Face.
Embedding per il Codice
Se lavori con il codice, gli embedding aprono possibilità che la ricerca testuale non può raggiungere.
Il Problema della Ricerca Sintattica
Cerchi "autenticazione utente" nel codebase. La ricerca testuale trova file che contengono quelle parole esatte. Non trova validateUserCredentials(), checkJWTToken() o passport.authenticate() — che fanno esattamente la cosa che cerchi.
Come Funzionano gli Embedding per il Codice
Un modello di code embedding trasforma funzioni, classi e snippet in vettori dove la distanza rappresenta la similarità funzionale, non lessicale.
embedding("function login(email, password) { ... }")
≈
embedding("def authenticate_user(credentials): ...")
Stessa funzionalità, linguaggi diversi, nomi diversi — ma vettori vicini.
Modelli specializzati:
- Voyage-code-3: stato dell'arte nel code retrieval
- Qodo-Embed-1: ottimizzato per comprensione semantica del codice
- CodeBERT: il BERT del codice, fine-tunato su coppie NL-Code
Casi d'uso reali:
- Code search: "trova dove gestiamo il rate limiting" → trova il middleware corretto
- Deduplicazione: identificare funzioni duplicate o quasi-duplicate in codebase grandi
- Code review: trovare pattern simili a bug noti
- Documentation matching: collegare codice alla documentazione rilevante
CLIP: Quando Testo e Immagini Condividono lo Spazio
Abbiamo visto che Cohere Embed v4 supporta embedding multimodali. Ma l'idea di mettere testo e immagini nello stesso spazio vettoriale non nasce lì — nasce con CLIP.
CLIP (Contrastive Language-Image Pre-training, OpenAI 2021) è il modello che ha aperto la strada. L'idea: se una foto e una didascalia descrivono la stessa cosa, i loro vettori devono essere vicini.
Come è stato addestrato:
- Prendi 400 milioni di coppie (immagine, testo) dal web
- Per ogni coppia, avvicina i vettori dell'immagine e del testo corrispondente
- Allontana i vettori delle coppie non corrispondenti
Il risultato: puoi cercare immagini con testo e testo con immagini — senza mai aver visto quella specifica combinazione in training.
query_text = "tramonto sul mare con barca a vela"
→ trova foto di tramonti con barche, anche se nessuna aveva quella didascalia
CLIP è la base di:
- Stable Diffusion: il text encoder che trasforma il prompt in un vettore che guida la generazione
- Google Lens: ricerca visuale
- Ricerca multimodale: cercare in database misti di testo, immagini e video
Vector Database: Dove Vivono gli Embedding
Produrre embedding è metà del lavoro. L'altra metà è salvare e cercare tra milioni (o miliardi) di vettori in modo efficiente.
Il Problema: Nearest Neighbor è Lento
Data una query, trovare il vettore più vicino tra N vettori richiede N confronti — una cosine similarity per ognuno. Con un milione di vettori da 1536 dimensioni, è già lento. Con un miliardo, è impossibile.
ANN: Approximate Nearest Neighbor
La soluzione: non cercare il più vicino, ma uno abbastanza vicino. Gli algoritmi ANN (Approximate Nearest Neighbor) sacrificano una precisione minima per un guadagno enorme in velocità.
Le tecniche principali:
HNSW (Hierarchical Navigable Small World): costruisce un grafo multi-livello dove i nodi sono i vettori. La ricerca parte dai livelli alti (pochi nodi, ricerca grossa) e scende ai livelli bassi (molti nodi, ricerca fine). È come cercare un indirizzo: prima la città, poi il quartiere, poi la via.
IVF (Inverted File Index): divide lo spazio in cluster. Prima trova il cluster più vicino alla query, poi cerca solo dentro quel cluster.
Product Quantization: comprime i vettori per ridurre memoria e accelerare i confronti.
I Database Specializzati
| Database | Tipo | Punto di forza |
|---|---|---|
| Pinecone | Cloud managed | Zero-ops, scala automaticamente |
| Weaviate | Open source | Supporto nativo per moduli ML |
| Qdrant | Open source (Rust) | Performance raw |
| Milvus/Zilliz | Open source / Cloud | Scalabilità enterprise (miliardi di vettori) |
| Chroma | Open source | Semplicità, ottimo per prototyping |
| pgvector | Estensione PostgreSQL | Nessun database aggiuntivo |
pgvector merita una menzione speciale: è un'estensione di PostgreSQL che aggiunge il tipo vector e operatori di similarità. Se hai già Postgres, puoi fare ricerca vettoriale senza aggiungere infrastruttura. Per meno di qualche milione di vettori, è spesso sufficiente.
Dimensioni: Quante Ne Servono?
I modelli di embedding producono vettori di dimensione variabile: da 384 a 4096. Più dimensioni = più informazione = più spazio e più tempo di ricerca.
| Modello | Dimensioni | Note |
|---|---|---|
| MiniLM-L6-v2 | 384 | Veloce, buono per prototyping |
| text-embedding-3-small | 1536 | Standard OpenAI |
| text-embedding-3-large | 3072 | Max qualità OpenAI |
| Cohere Embed v4 | 1024 | Multimodale |
| Voyage-3 | 1024 | Top MTEB |
| jina-embeddings-v3 | 1024 | Open source |
Matryoshka Representation Learning
L'innovazione più pratica degli ultimi anni. L'idea: durante il training, il modello viene ottimizzato per produrre vettori dove le prime N dimensioni contengono le informazioni più importanti.
Puoi quindi troncare il vettore a dimensioni inferiori senza ri-addestrare il modello:
Vettore completo (3072 dim): massima qualità
Troncato a 1024 dim: ~99% della qualità
Troncato a 256 dim: ~95% della qualità
Troncato a 64 dim: ~85% della qualità
Perché è utile? Perché lo spazio di storage e la velocità di ricerca dipendono dalla dimensione del vettore. Se stai indicizzando 100 milioni di documenti, passare da 3072 a 256 dimensioni riduce lo storage di 12 volte — e la ricerca è proporzionalmente più veloce.
text-embedding-3 di OpenAI e jina-embeddings-v3 supportano nativamente Matryoshka.
Visualizzare gli Embedding: t-SNE e UMAP
I vettori di embedding vivono in spazi a centinaia di dimensioni — impossibili da visualizzare. Ma possiamo proiettarli in 2D per "vedere" la struttura.
t-SNE
t-SNE (t-distributed Stochastic Neighbor Embedding) proietta vettori ad alta dimensionalità in 2D/3D preservando le relazioni di vicinanza locale: punti vicini nello spazio originale restano vicini nella proiezione.
Il risultato sono mappe dove i cluster emergono visivamente: le parole sugli animali formano un gruppo, quelle sulla tecnologia un altro, quelle sulle emozioni un altro ancora.
Limiti: t-SNE è lento su grandi dataset, non preserva le distanze globali (due cluster lontani nella mappa potrebbero non esserlo nello spazio reale), e il risultato cambia con i parametri (perplexity).
UMAP
UMAP (Uniform Manifold Approximation and Projection) è l'alternativa più moderna: più veloce, preserva meglio la struttura globale, e i risultati sono più riproducibili.
Per uso pratico: se devi visualizzare embedding per debug o presentazione, UMAP è la scelta standard nel 2026.
Un Esempio Concreto: Come Funziona il RAG
Mettiamo tutto insieme. Il RAG (Retrieval-Augmented Generation) è il caso d'uso killer degli embedding — e usa ogni concetto che abbiamo visto.
Il Flusso Completo
Fase 1 — Indicizzazione (una tantum):
- Prendi i tuoi documenti (documentazione, wiki, codebase)
- Spezzali in chunk di 200-500 token
- Passa ogni chunk nel modello di embedding → ottieni un vettore
- Salva i vettori nel vector database (con il testo originale come metadata)
Fase 2 — Query (in tempo reale):
- L'utente fa una domanda: "Come configuro l'autenticazione JWT?"
- La domanda passa nello stesso modello di embedding → vettore della query
- Il vector database trova i 5 chunk con vettori più vicini (ANN + cosine similarity)
- I chunk recuperati vengono aggiunti al prompt di Claude come contesto
- Claude genera una risposta basata solo sui documenti rilevanti
Perché funziona: la domanda "Come configuro l'autenticazione JWT?" e il chunk "### Setup JWT: Installa il pacchetto jsonwebtoken..." hanno embedding vicini — anche se non condividono le stesse parole. La cosine similarity cattura la relazione semantica.
Perché è meglio della ricerca keyword: "autenticazione JWT" non troverebbe un documento che parla di "token di accesso con firma crittografica" — ma gli embedding sì.
Cosa Viene Dopo
Questo articolo ha coperto l'evoluzione da vettori statici a contestuali, la cosine similarity, i modelli moderni, il codice, il multimodale, i vector database, e come tutto questo si connette nel RAG.
Ma c'è un livello ancora più profondo. I prossimi articoli della serie copriranno:
- BPE: come funziona l'algoritmo che taglia le parole in token prima che diventino embedding
- Pre-training: come un modello impara a generare embedding contestuali leggendo internet
- RLHF/DPO: come si insegna al modello a produrre output utili e sicuri
Ogni volta che Claude legge il tuo messaggio, la prima operazione è un embedding lookup — esattamente come Word2Vec, solo con contesto, attenzione multi-head, e miliardi di parametri. Il principio di Firth del 1957 — "conoscerai una parola dalla compagnia che tiene" — è ancora lì, alla base di tutto.
Solo che oggi la "compagnia" non è una finestra di 4 parole. È un milione di token di contesto.
Fonti
- Reimers & Gurevych — Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks (2019) — Il paper che ha reso la ricerca semantica praticabile
- Radford et al. — Learning Transferable Visual Models From Natural Language Supervision (CLIP, 2021) — Embedding multimodali testo-immagine
- Kusupati et al. — Matryoshka Representation Learning (2022) — Embedding troncabili a dimensionalità variabile
- MTEB Leaderboard — Hugging Face — Benchmark aggiornato dei modelli di embedding
- OpenAI — text-embedding-3 Documentation — Guida ai modelli embedding OpenAI
- Pinecone — What Are Vector Embeddings? — Introduzione pratica con esempi
- Voyage AI — Embedding Models — Documentazione modelli specializzati
- Jina AI — jina-embeddings-v3 — Modello open-weight con task adapters
- Cohere — Embed v4 — Primo embedding multimodale mainstream
- Weaviate — ANN Algorithms Explained — Spiegazione HNSW e Product Quantization
- Lilian Weng — Some Math behind Neural Tangent Kernels — Deep dive tecnico su embedding