Gli embeddings sono la base tecnica di ogni soluzione di RAG (Retrieval-Augmented Generation) su Azure. Un modello di embedding trasforma testo (o immagini) in un vettore denso di numeri in virgola mobile, dove la posizione nello spazio cattura il significato semantico: frasi con contenuto simile finiscono vicine, anche se non condividono le stesse parole. Questa è la differenza chiave rispetto alla ricerca keyword/BM25, che confronta i token letterali.

Modelli di embedding e dimensione del vettore

Su Azure OpenAI (in Azure AI Foundry) i modelli tipici sono text-embedding-3-small e text-embedding-3-large. Le scelte architetturali principali:

  • text-embedding-3-small: 1536 dimensioni di default, ottimo rapporto costo/qualità per gran parte degli scenari.
  • text-embedding-3-large: 3072 dimensioni, recall più alto su corpus complessi/multilingua, ma più costoso in storage e latenza.
  • I modelli v3 supportano il parametro dimensions per ridurre la lunghezza del vettore (es. large a 1024) mantenendo buona qualità: utile per contenere costo e footprint dell’indice.

Il punto architetturale da fissare: il numero di dimensioni del campo vettoriale nell’indice deve corrispondere esattamente all’output del modello scelto. Se generi gli embeddings con large a 3072 ma dichiari un campo a 1536, l’indicizzazione fallisce.

Similarità e metriche

La misura più usata è la cosine similarity, che confronta l’angolo tra due vettori ignorando la loro magnitudine: è la metrica corretta per gli embeddings OpenAI, già normalizzati. Alternative configurabili sono dotProduct (equivalente al coseno solo su vettori normalizzati) ed euclidean (L2). In pratica, per i modelli text-embedding-3 si lascia cosine.

In Azure AI Search un campo vettoriale si definisce con:

  • tipo Collection(Edm.Single),
  • dimensions allineato al modello,
  • un vectorSearchProfile che lega il campo a un algoritmo e a un eventuale vectorizer.
{ "name": "contentVector", "type": "Collection(Edm.Single)",
  "dimensions": 1536, "vectorSearchProfile": "hnsw-profile" }

HNSW vs exhaustive KNN

La scelta dell’algoritmo è tipicamente d’esame:

  • HNSW (Hierarchical Navigable Small World): indice a grafo, ricerca ANN (Approximate Nearest Neighbor). Bassa latenza su indici grandi, ma recall approssimato; si regola con parametri come m, efConstruction ed efSearch.
  • exhaustiveKnn: scansione completa, recall esatto ma costo lineare col numero di documenti. Adatto a dataset piccoli o come ground truth per valutare il recall di HNSW.

Un pattern comune è indicizzare in HNSW ma consentire query exhaustive ad hoc. Per massimizzare la qualità si usa poi la hybrid search (vettoriale + keyword) con semantic ranker che riordina i risultati con un modello di re-ranking L2.

Chunking e integrated vectorization

I documenti lunghi vanno spezzati in chunk prima dell’embedding, perché i modelli hanno un limite di token e perché il retrieval deve restituire passaggi mirati, non interi PDF.

  • Chunk troppo grandi: diluiscono il significato in un solo vettore, abbassano la precisione e rischiano di sforare la context window del modello generativo.
  • Chunk troppo piccoli: frammentano il contesto, riducono il recall e costringono a recuperare più chunk per rispondere.
  • Regola pratica: chunk di alcune centinaia di token con overlap (es. 10-25%) per non tagliare frasi a metà.

L’integrated vectorization automatizza la pipeline dentro Azure AI Search: uno skillset con SplitSkill (chunking) e AzureOpenAIEmbeddingSkill genera i vettori in fase di indexing, mentre un vectorizer nel profilo consente le query in testo naturale (Search converte a runtime la query in vettore usando lo stesso modello). Così eviti di scrivere codice di embedding lato client e garantisci coerenza modello indexing/query.

Trappole tipiche d’esame

  • Scenario: hai cambiato modello da small a large ma le ricerche danno errore in indicizzazione → la dimensione del campo vettoriale deve corrispondere al modello (1536 vs 3072); ricrea l’indice con le dimensioni corrette.
  • Scenario: milioni di documenti, serve bassa latenza tollerando lieve perdita di recall → scegli HNSW, non exhaustive KNN.
  • Scenario: dataset piccolo dove serve recall esatto o baseline di valutazione → exhaustiveKnn.
  • Scenario: le risposte RAG sono generiche o incomplete → probabile chunking errato; riduci la dimensione dei chunk e aggiungi overlap.
  • Scenario: vuoi query in testo naturale senza generare embeddings nel codice → configura un vectorizer/integrated vectorization con lo stesso modello usato in indexing.