Puntata 240
Puntata 240 — Embeddings: scegliere, valutare, mixare
Livello: 🧙 Maestro Yoda · Capitolo 22 · Agenti, tool use, RAG
Hai puntato tutto sul “vector DB più cool”, ma poi le risposte fanno schifo. 9 volte su 10 il colpevole non è il DB: è l’embedding model. Scegliere bene un embedding fa più differenza per la retrieval quality di qualsiasi altra ottimizzazione. Nel 2026 ci sono opzioni eccellenti gratis. Il difficile è sapere quale.
Cos’è un embedding (in 3 righe)
Un embedding model è una rete neurale (di solito un encoder transformer come BERT) che mappa un testo (o immagine, audio) a un vettore denso fisso, tipo [0.12, -0.78, ..., 0.31] di lunghezza 256-4096.
Proprietà: testi semanticamente simili producono vettori vicini (per cosine similarity). Testi non correlati: vettori lontani.
Per RAG: sia i documenti che le query passano per lo stesso embedding model. Il “match” diventa una k-NN search nel vector DB (puntata 239).
Cosa cambia tra embedding model
Cinque dimensioni di scelta:
1. Lingue supportate
- Solo inglese:
text-embedding-ada-002(legacy),all-MiniLM-L6-v2. Veloci, leggeri, scarsi in italiano. - Multilingua:
BAAI/bge-m3,intfloat/multilingual-e5-large,text-embedding-3-large(OpenAI),voyage-3(Voyage AI). Necessari per il mercato italiano.
2. Dimensione del vettore
- 384-768: leggero, basso footprint storage e RAM, qualità decente.
- 1024-1536: standard, ottimo trade-off.
- 2048-4096: stato dell’arte, ma 2× storage e RAM rispetto a 1024.
3. Modello aperto vs API
- API managed: OpenAI, Cohere, Voyage, Anthropic. Pay-per-token. Niente infra.
- Open self-hosted: BAAI, Nomic, Sentence Transformers, JinaAI (con caveat license). Gratis ma serve GPU/CPU.
4. Specializzazione di dominio
- Generico: tutti i sopra.
- Specializzato: code-search (
jina-embeddings-v2-code,voyage-code-2), legal, finance, medical (alcuni Cohere, alcuni Voyage). Migliore su dominio.
5. Late vs early interaction
- Bi-encoder (standard): un vettore per documento, k-NN. Veloce.
- Late interaction (ColBERT, ColBERT v2): N vettori per documento (uno per token), interaction più ricca. Più accurato ma 10× storage e più lento. Buona seconda stage.
I top embedding model 2026
Per uso multilingua (incluso italiano)
| Modello | Provider | Dim | Note |
|---|---|---|---|
| multilingual-e5-large-instruct | Microsoft/HF | 1024 | Open MIT. Ottimo italiano. Standard de facto open. |
| BAAI/bge-m3 | BAAI | 1024 | Open MIT. Multi-functionality (dense + sparse + multi-vector). |
| NV-Embed-v2 | Nvidia | 4096 | Top MTEB nel 2024. License restrittiva (no commercial). |
| text-embedding-3-large | OpenAI | 3072 (riducibile) | API. $0.13/1M token. Ottimo italiano. |
| voyage-3 / voyage-3-large | Voyage AI | 1024 | API. $0.12/1M token. Top performance 2025-26. |
| embed-multilingual-v3.0 | Cohere | 1024 | API. $0.10/1M token. Buono. |
| jina-embeddings-v3 | JinaAI | 1024 | Open CC-BY-NC (non-commercial) — attento! |
Per inglese (se non serve multilingua)
- OpenAI text-embedding-3-small ($0.02/1M, default rapido).
- bge-large-en-v1.5 (open).
- mxbai-embed-large-v1 (open MIT).
Per codice
- voyage-code-3 (API, ottimo).
- jina-embeddings-v2-code (open).
- text-embedding-3-large (decente).
MTEB: il benchmark di riferimento
MTEB (Massive Text Embedding Benchmark) di HuggingFace + Cohere. 56 task in 112 lingue. Misura:
- Classification, Clustering, Pair Classification, Reranking, Retrieval, STS, Summarization.
Leaderboard sempre aggiornata: huggingface.co/spaces/mteb/leaderboard.
Caveat:
- Contamination: alcuni modelli sono fine-tuned su dataset MTEB → score gonfiati.
- Domain mismatch: il tuo dominio (legale italiano, medico cinese) non è in MTEB. Score MTEB ≠ score tuo.
- Task mismatch: se ti serve retrieval, guarda la categoria “Retrieval”, non l’average.
Regola: usa MTEB per screening (escludere le opzioni chiaramente peggiori), poi valuta sul tuo dataset.
Come valutare embedding model sul tuo use case
Setup minimo:
- Costruisci un eval set di 50-500 coppie (query, chunk_giusto).
- Per ogni embedding candidato:
- Embed tutto il corpus (chunk).
- Embed le query.
- Per ogni query: top-10 cosine similarity.
- Calcola Recall@5 (% query in cui il chunk giusto è nei top-5).
- Compara modelli.
Esempio risultato realistico (legale italiano, 5,000 chunk):
| Modello | Recall@5 | Cost / 1M token |
|---|---|---|
| OpenAI text-embedding-3-small | 0.74 | $0.02 |
| multilingual-e5-large-instruct | 0.81 | free (self-host) |
| bge-m3 | 0.83 | free |
| voyage-3 | 0.85 | $0.12 |
| OpenAI text-embedding-3-large | 0.86 | $0.13 |
A questo punto la scelta è economica + operativa: bge-m3 self-hosted vince in molti casi business (free + 0.83 recall accettabile).
Trick per migliorare recall (a parità di modello)
Instruction prefixing (per modelli “-instruct”)
Modelli E5, BGE-instruct, Jina-v3: aspettano un prefisso per query e/o documenti.
query: "Cosa dice il GDPR sul consenso?"
passage: "Articolo 7 GDPR — Condizioni per il consenso..."
Saltarlo = -10-15% recall. Sempre leggere la model card.
Pooling strategy
Alcuni encoder permettono CLS pooling, mean pooling, last token pooling. La default di HuggingFace è mean pooling — di solito ok ma controlla.
Normalization
Cosine similarity vuole vettori normalizzati a L2 = 1. Quasi tutti gli embedding model lo fanno; controlla.
Matryoshka embeddings
Modelli moderni (text-embedding-3, NV-Embed) producono vettori “annidati”: puoi troncare le ultime dimensioni e mantenere buona quality. Es. 3072 → 1024 con minima perdita. Usalo per ridurre footprint.
Hybrid search: dense + sparse
Combinare dense embeddings (semantic) con sparse retrievers (BM25, SPLADE) migliora recall del 10-30%.
BM25 (sparse classico)
Pesa termini esatti, ottimo per nomi propri, codici, acronimi.
- “DPIA” come query: BM25 trova chunk con “DPIA” letterale; dense può perderlo se il concept non è ben rappresentato.
SPLADE / sparse neural
Sparse ma con weight neuronali. Compromesso interessante. Più complesso da setup.
Reciprocal Rank Fusion (RRF)
Fonde i ranking di dense e sparse:
score(doc) = sum_per_retriever( 1 / (60 + rank(doc, retriever)) )
Robusto, parameter-free, standard.
Tool che supportano hybrid out-of-the-box: Weaviate, Qdrant, Vespa, Elasticsearch + dense_vector.
Multi-vector e late interaction
ColBERT v2 (Stanford) emette N vettori per documento (uno per token), ognuno ~128 dim. Al match: MaxSim per ogni query token, somma.
Pro: 10-30% migliore recall di bi-encoder a parità di modello base. Contro: 10-50× più storage, query 5-10× più lente.
Usato come reranker stage 2: dense bi-encoder fa top-100, ColBERT riordina i top-10.
Reranker (stage 2 essenziale)
Pattern di alta qualità:
- Stage 1 — retrieval: bi-encoder dense, top-50.
- Stage 2 — rerank: cross-encoder o ColBERT, riordina top-10.
Cross-encoder popolari:
- BAAI/bge-reranker-large (open).
- mixedbread-ai/mxbai-rerank-large-v1 (open).
- Cohere Rerank 3 (API, $1/1k searches).
- jina-reranker-v2 (open con caveat).
Reranker costa 10-100× per item rispetto al retrieval, ma processi solo top-50 (non tutto il corpus). Migliora order top-5 in modo drastico.
Costi: ordini di grandezza
Per indicizzare 1M chunk × 400 token medi = 400M token:
| Soluzione | Costo embedding |
|---|---|
| OpenAI text-embedding-3-small | $8 |
| OpenAI text-embedding-3-large | $52 |
| Voyage-3 | $48 |
| Cohere embed-multilingual-v3 | $40 |
| Self-hosted bge-m3 su 1 GPU spot (4h) | $3-8 |
| Self-hosted bge-m3 su CPU (1 giorno) | gratis |
Per query online: ognuna è 1 embedding (~500 token query medio):
- API: $0.00001-0.00007 per query.
- Self-hosted: ~5-50 ms latency, gratis.
A scala (milioni di query/giorno) self-hosted vince economicamente di 10-100×.
Cosa NON fare con gli embedding
- Mixing diversi modelli nello stesso DB: vettori non comparabili. Re-indicizzi tutto se cambi modello.
- Ignorare la lingua: usare un modello inglese-only su corpus italiano = -30-50% recall.
- Skippare la normalizzazione: cosine ≠ dot product senza normalize.
- Saltare reranking: stage 2 quasi sempre vale i 50-200ms extra.
- No eval set: scegli sul MTEB, ti fidi, non valuti. Risultato: in produzione fa peggio del previsto.
- Embedding troppo lunghi (>8k token per chunk): la maggior parte dei modelli ha context limit 512-8192. Sopra, devono troncare.
Glossario lampo
- Bi-encoder — embedding model che produce un vettore singolo per testo. Standard per retrieval.
- Cross-encoder — modello che prende coppia (query, doc) insieme e produce uno score. Usato come reranker.
- MTEB — Massive Text Embedding Benchmark, 56 task in 112 lingue. Leaderboard HF.
- Matryoshka embeddings — vettori “annidati” troncabili senza riaddestramento. Riduce footprint mantenendo quality.
- RRF (Reciprocal Rank Fusion) — formula per combinare ranking di retriever multipli (es. dense + sparse).
- Instruction prefixing — prefisso testuale richiesto da modelli “instruct” prima di query/passage. Saltarlo degrada drasticamente.
Take-away
La scelta dell’embedding model è il singolo factor più alto-leva nella retrieval quality di un sistema RAG. Per italiano + open + commerciale: bge-m3 o multilingual-e5-large-instruct sono le scelte sicure nel 2026. Per chi vuole API premium: voyage-3 e text-embedding-3-large dominano. Misura sempre sul tuo eval set: i benchmark MTEB orientano, non decidono. E aggiungi un reranker — è il miglior ROI in 5 minuti di codice.
➡️ Prossima puntata: chunking strategies — l’arte sottile di spezzettare i documenti.