Quando un sistema RAG risponde male, l’istinto è cambiare modello o riscrivere il prompt. Quasi sempre è la diagnosi sbagliata: se i passaggi giusti non entrano nel contesto, nessun modello li può inventare, e ogni ora spesa sul prompt è persa. Le leve sul recupero sono tre — come il contenuto viene spezzato, quanto è severo il filtro sulla similarità, quali ricerche vengono combinate — e hanno tutte la stessa natura: sono parametri di configurazione. Da MLOps engineer questo cambia tutto, perché un parametro si versiona, si applica da pipeline e si misura, invece di essere ritoccato a mano nel portale finché «sembra andare meglio».
Il chunk è la vera unità di recupero
Non si recuperano documenti: si recuperano chunk. Spezzare serve prima di tutto a stare sotto il limite di token dei modelli — per text-embedding-3-small l’input massimo documentato è 8.191 token, all’incirca 6.000 parole — ma serve anche quando il documento ci starebbe: una pagina che tratta dieci sotto-argomenti è rappresentata male da un solo vettore.
In Azure AI Search il chunking integrato passa dalla Text Split skill. Il parametro textSplitMode vale pages (predefinito, chunk fatti di più frasi) oppure sentences; con pages si aggiungono maximumPageLength, pageOverlapLength — che deve essere inferiore alla metà della lunghezza massima — e maximumPagesToTake. Come punto di partenza la documentazione indica 2.000 caratteri con 500 di sovrapposizione; ragionando in token suggerisce 512 token con una sovrapposizione iniziale del 25 per cento, cioè 128 token. Per il chunking a dimensione fissa la tabella delle tecniche parla di paragrafi semanticamente sensati, per esempio 200 parole o 600 caratteri, con un 10-15 per cento di sovrapposizione.
{
"@odata.type": "#Microsoft.Skills.Text.SplitSkill",
"textSplitMode": "pages",
"maximumPageLength": 2000,
"pageOverlapLength": 500
}
L’effetto è enorme e misurabile: sullo stesso e-book di prova, 1.000 caratteri senza sovrapposizione producono 172 chunk, 5.000 caratteri con 500 di sovrapposizione ne producono 38, e la modalità sentences ne produce oltre tredicimila. Cambiano il costo degli embedding, la dimensione dell’indice e la granularità delle risposte. Due trappole ricorrenti: una sovrapposizione troppo grande rispetto al contenuto reale può risultare in nessuna sovrapposizione effettiva; e modificare la strategia di chunking obbliga a rigenerare tutti gli embedding e a reindicizzare. Non è un tuning a caldo, è una migrazione — quindi skillset e definizione dell’indice stanno in Git, l’indice nuovo si costruisce accanto al vecchio e si confronta prima di spostare il traffico.
La soglia: k restituisce sempre k
Una vector query restituisce sempre il numero k di vicini richiesti, anche quando i vicini sono pessimi: la documentazione avverte che si possono ottenere risultati anche per query insensate o fuori tema, perché l’algoritmo cerca i più vicini, non i pertinenti. Alzare k quindi non aumenta la precisione, aumenta il rumore che il modello riceve.
I due rimedi documentati sono aggiungere la parte full-text (cioè passare all’ibrido) oppure imporre una soglia minima. La soglia si esprime con il parametro threshold, di tipo vectorSimilarity e con un valore, ed è in anteprima: filtra i risultati sotto soglia prima della fusione fra i set, anche a costo di restituire meno di k elementi. Va scelta guardando i subscore, non copiando un numero letto altrove, perché le scale non sono confrontabili fra loro: BM25 non ha limite superiore, il punteggio vettoriale con metrica coseno sta fra 0,333 e 1,00, e il punteggio RRF ha un massimo che dipende da quante query vengono fuse. Soprattutto: le soglie minime hanno senso su una vector query pura, mentre le query ibride non vi si prestano, perché gli intervalli dell’RRF sono molto più stretti e volatili.
Ricerca ibrida: due liste, una sola classifica
La ricerca ibrida è una sola richiesta che contiene sia search sia vectorQueries: full-text e vettoriale girano in parallelo e i risultati vengono uniti con Reciprocal Rank Fusion. RRF assegna a ogni documento un punteggio pari a 1/(rango + k), con k costante piccola — gli esperimenti indicano 60 — e somma i punteggi ottenuti in ciascuna lista. Attenzione al nome: quella k non è il numero di vicini della vector query. Ogni campo o query in più è un’esecuzione in più (un full-text più una vector query su due campi fanno tre esecuzioni), e il parametro weight sulle vector query, con valore predefinito 1.0, moltiplica il loro contributo.
Il semantic ranker si attiva con queryType impostato a semantic più una configurazione semantica, e agisce dopo la fusione RRF: restituisce @search.rerankerScore su una scala da 0,00 a 4,00 e usa fino a 50 match come input, per cui quando lo si combina con i vettori si imposta k a 50, altrimenti lo si priva di materiale. Da ricordare anche che un orderby esplicito annulla il ranking per rilevanza, e che il lato testuale si ferma a 1.000 match, con maxTextRecallSize a 1.000 come predefinito.
Quando serve l’ibrido? Il vettoriale trova ciò che è concettualmente vicino anche senza corrispondenza testuale; il lessicale è preciso e vince su codici prodotto, gergo altamente specialistico, date e nomi di persona. Microsoft dichiara che i test su dataset reali e di benchmark mostrano benefici significativi di rilevanza per il recupero ibrido con semantic ranker: è il default sensato, mentre la ricerca puramente vettoriale resta ragionevole solo quando il corpus non contiene identificatori esatti da agganciare.
Tarare per prova, non per impressione
Il modo documentato per scegliere questi valori si chiama parameter sweep: si generano risultati di recupero per diverse combinazioni di algoritmo (vettoriale, semantico), di top_k e di dimensione dei chunk, e si usa l’evaluator document_retrieval di Microsoft Foundry per individuare la combinazione con la qualità di recupero migliore. Una leva alla volta, sempre lo stesso set di query, e configurazione registrata insieme al risultato. In una pipeline GitHub Actions questo diventa un job che ricostruisce l’indice candidato, lancia la valutazione e blocca la promozione se le metriche di recupero regrediscono.
Da ricordare per l esame
- Una vector query restituisce sempre
krisultati anche se sono pessimi: si filtra conthresholddi tipovectorSimilarity(anteprima), applicato prima della fusione — ma non sulle query ibride, dove gli intervalli RRF sono stretti e volatili. - La ricerca ibrida unisce BM25 e vettoriale con RRF, punteggio 1/(rango + k) con k costante tipicamente 60; quella k non è il numero di vicini.
- Il semantic ranker gira dopo l’RRF, produce
@search.rerankerScorefra 0,00 e 4,00 e usa fino a 50 match: con i vettori si impostaka 50. - Text Split skill:
textSplitModepagesosentences,maximumPageLength,pageOverlapLengthinferiore alla metà; punto di partenza 2.000 caratteri con 500 di sovrapposizione, oppure 512 token con il 25 per cento. - Cambiare chunking o strategia di indicizzazione impone di rigenerare embedding e reindicizzare: si tratta come una migrazione versionata, non come un parametro da ritoccare in produzione.