🧙 Maestro Yoda Cap. 22 · Agenti, tool use, RAG

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.

una mappa concettuale enorme con migliaia di parole/frasi distribuite in 3D. “Cane” e “gatto” sono vicini. “Cane” e “vacanza” lontani. “Pasta al ragù” e “ricetta bolognese” sono accanto. Sotto: “se questa mappa è ben fatta, il retrieval va liscio. Se è male fatta, raccogli spazzatura”

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)

ModelloProviderDimNote
multilingual-e5-large-instructMicrosoft/HF1024Open MIT. Ottimo italiano. Standard de facto open.
BAAI/bge-m3BAAI1024Open MIT. Multi-functionality (dense + sparse + multi-vector).
NV-Embed-v2Nvidia4096Top MTEB nel 2024. License restrittiva (no commercial).
text-embedding-3-largeOpenAI3072 (riducibile)API. $0.13/1M token. Ottimo italiano.
voyage-3 / voyage-3-largeVoyage AI1024API. $0.12/1M token. Top performance 2025-26.
embed-multilingual-v3.0Cohere1024API. $0.10/1M token. Buono.
jina-embeddings-v3JinaAI1024Open 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:

  1. Costruisci un eval set di 50-500 coppie (query, chunk_giusto).
  2. 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).
  3. Compara modelli.

Esempio risultato realistico (legale italiano, 5,000 chunk):

ModelloRecall@5Cost / 1M token
OpenAI text-embedding-3-small0.74$0.02
multilingual-e5-large-instruct0.81free (self-host)
bge-m30.83free
voyage-30.85$0.12
OpenAI text-embedding-3-large0.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à:

  1. Stage 1 — retrieval: bi-encoder dense, top-50.
  2. 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:

SoluzioneCosto 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

  1. Mixing diversi modelli nello stesso DB: vettori non comparabili. Re-indicizzi tutto se cambi modello.
  2. Ignorare la lingua: usare un modello inglese-only su corpus italiano = -30-50% recall.
  3. Skippare la normalizzazione: cosine ≠ dot product senza normalize.
  4. Saltare reranking: stage 2 quasi sempre vale i 50-200ms extra.
  5. No eval set: scegli sul MTEB, ti fidi, non valuti. Risultato: in produzione fa peggio del previsto.
  6. 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.