La qualità di una risposta ancorata non la decide il modello, la decide quello che il retriever gli mette davanti. Il dominio chiede tre cose: scegliere fra le modalità di ricerca sapendo cosa aggiunge ciascuna, far entrare correttamente i documenti scansionati, collegare il recupero a un flusso o a uno strumento di agente.

Le tre modalità di ricerca, e quando l’ibrida non serve

La ricerca full-text classifica con BM25, pesando i termini della query rispetto al corpus: è imbattibile su codici prodotto, sigle, nomi propri e termini rari, dove un embedding fallisce perché quel token non ha un significato distribuito.

La ricerca vettoriale confronta l’embedding della query con quelli dei documenti. Nell’indice serve un campo Collection(Edm.Single) con dimensions e un vectorSearchProfile, e nella sezione vectorSearch si dichiarano algorithms e profiles: HNSW è approssimato e veloce, con un compromesso sul richiamo, exhaustive KNN è esatto ma costoso e serve da riferimento per misurare il richiamo perso. Le metriche di similarità sono cosine, dotProduct ed euclidean; a query time si passa vectorQueries con kind, k, fields ed eventualmente exhaustive.

La ricerca ibrida esegue le due cose nella stessa richiesta e ne fonde i risultati con Reciprocal Rank Fusion: RRF combina le posizioni nelle due liste, non i punteggi, con una costante k di smorzamento. Conseguenza che vale una domanda: il punteggio risultante non è confrontabile con uno score BM25, quindi le soglie assolute ereditate dalla ricerca testuale vanno buttate.

Sopra si innesta il semantic ranker, un riordino L2 che riclassifica con modelli di linguaggio i primi risultati. Si abilita con queryType semantic più il nome di una semanticConfiguration definita nell’indice (titleField, prioritizedContentFields, prioritizedKeywordsFields), e aggiunge @search.rerankerScore, le caption e le answer. Ha disponibilità legata al tier e fatturazione propria: è una scelta, non un default gratuito.

Il criterio onesto: ibrida più semantic ranker è il punto di partenza per il grounding; la sola vettoriale basta su query che sono sempre parafrasi in linguaggio naturale; la sola testuale quando l’utente cerca identificatori esatti. Sui filtri, preFilter è il default e postFilter può restituire meno di k risultati perché filtra dopo il recupero.

results = client.search(
    search_text="rimborso per volo cancellato",           # BM25
    vector_queries=[VectorizableTextQuery(                # vettoriale
        text="rimborso per volo cancellato",
        k_nearest_neighbors=50, fields="contentVector")],
    query_type="semantic",                                # rerank L2
    semantic_configuration_name="default",
    top=8,
)

Chunking e vettorizzazione: dove si decide la qualità del grounding

Un documento intero non si vettorizza: sfonda il limite di token del modello di embedding e produce un vettore che è la media sfocata di venti argomenti. Si spezza in chunk, a dimensione fissa oppure sui confini di frase, con un overlap che evita di tagliare a metà il passaggio con la risposta.

Con l’integrated vectorization il lavoro sta dentro la pipeline dell’indexer: uno skillset con Text Split più la skill di embedding (resourceUri, deploymentId, modelName, dimensions) e un’index projection che scrive i chunk nell’indice figlio. Lato query si aggiunge all’indice un vectorizer, così il client manda testo e la vettorizzazione la fa il servizio.

L’invariante da non violare: il modello di embedding in indicizzazione e a query time deve essere lo stesso, con le stesse dimensioni. Cambiarlo non è una modifica di configurazione, è una reindicizzazione completa.

OCR e documenti scansionati nella pipeline di ingestione

Un PDF scansionato non ha uno strato di testo: senza OCR l’indexer estrae stringa vuota, e il sintomo tipico è un indice pieno di documenti con il campo di contenuto vuoto, senza errori. Le strade sono due: l’OCR skill dentro lo skillset, che basta quando serve solo il testo, oppure una pre-elaborazione con un’analisi documentale (Document Intelligence o Content Understanding) indicizzando il Markdown che restituisce.

La seconda è quasi sempre migliore per il RAG perché conserva la struttura: intestazioni, tabelle e ordine di lettura sopravvivono, e il chunking può seguire i titoli invece di contare caratteri. Una tabella tagliata a metà da uno split fisso non è un chunk incompleto, è un chunk che mente. Nel chunk conviene portare anche il riferimento all’origine, pagina e span, che diventa la citazione.

Collegare il recupero ai flussi e agli agenti

La via più corta è non scrivere il retriever: il tool Azure AI Search di Foundry Agent Service collega un indice all’agente e produce risposte ancorate con citazioni. Quando serve logica applicativa, per esempio un filtro di sicurezza per utente, si incapsula la query in un tool di function calling, così il filtro resta nel codice e non nel prompt.

Il gradino successivo è l’agentic retrieval di Azure AI Search: una knowledge base raccoglie una o più knowledge source, indicizzate (su un indice del servizio) oppure remote, recuperate a query time da una piattaforma esterna. Un modello scompone la domanda e la storia della conversazione in subquery, le esegue in parallelo, applica il semantic reranking e restituisce contenuto unificato più references e un activity log con le subquery generate — la differenza fra un retriever che puoi solo subire e uno che puoi diagnosticare. Due vincoli: l’indice deve avere una configurazione semantica, e la fatturazione è a token sia sul servizio di ricerca sia sul modello del planning. Il reasoning effort (minimal, low, medium) è la manopola fra profondità e costo; la knowledge base si interroga con la retrieve action o via endpoint MCP, ed è quest’ultima la forma in cui un agente la consuma.

Da ricordare per l’esame

  • L’ibrida esegue BM25 e vettoriale in parallelo e ne fonde le posizioni con RRF: il punteggio risultante non è confrontabile con quello BM25.
  • Il semantic ranker riordina i top risultati e aggiunge @search.rerankerScore, caption e answer; richiede una semanticConfiguration nell’indice.
  • Stesso modello di embedding e stesse dimensioni in indicizzazione e a query time: cambiare modello impone di reindicizzare.
  • Su documenti scansionati serve OCR, ma per il RAG conviene il Markdown di un’analisi documentale, che permette un chunking rispettoso di titoli e tabelle.
  • L’agentic retrieval decompone la domanda in subquery via LLM, richiede la configurazione semantica sull’indice e si paga a token su entrambi i servizi.