<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Topics tagged with machinelearning]]></title><description><![CDATA[A list of topics that have been tagged with machinelearning]]></description><link>https://forum.androidiani.net/tags/machinelearning</link><generator>RSS for Node</generator><lastBuildDate>Fri, 01 May 2026 02:08:31 GMT</lastBuildDate><atom:link href="https://forum.androidiani.net/tags/machinelearning.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 21 Apr 2026 07:55:23 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[RAG in .NET con Semantic Kernel: le insidie che i tutorial non ti dicono]]></title><description><![CDATA[RAG — Retrieval-Augmented Generation — è diventato il pattern dominante per integrare conoscenza dominio-specifica nei modelli linguistici. Ma tra un tutorial “hello world” e un sistema RAG che funziona davvero in produzione c’è un abisso. Questo articolo esplora le insidie reali che i tutorial non affrontano, partendo da un’implementazione in .NET con Semantic Kernel.Il pipeline RAG in cinque fasiPrima di entrare nei dettagli critici, è utile avere una mappa mentale del pipeline completo. Un sistema RAG ben strutturato si articola in cinque fasi sequenziali:Ingestion — caricamento dei documenti sorgenteChunking — suddivisione in segmenti adatti all’embeddingEmbedding — conversione dei chunk in vettori numericiStorage — persistenza dei vettori in un vector storeRetrieval + Generation — ricerca dei chunk rilevanti e generazione della rispostaOgni fase nasconde decisioni non banali. Vediamo quelle che fanno davvero la differenza.Il chunking è la variabile più sottovalutataLa qualità del chunking influenza il retrieval più di qualsiasi altra scelta, incluso il modello di embedding. La maggior parte dei tutorial usa split naive basati su caratteri o token fissi, ignorando la struttura semantica del documento.Con Semantic Kernel, la scelta corretta per documenti Markdown è TextChunker.SplitMarkdownParagraphs(), che rispetta i confini dei paragrafi:var chunks = TextChunker.SplitMarkdownParagraphs(
    lines: markdownContent.Split('\n').ToList(),
    maxTokensPerParagraph: 512,
    overlapTokens: 50
);Due parametri critici spesso ignorati:overlapTokens: senza sovrapposizione, le frasi che cadono al confine tra due chunk vengono perse. Una sovrapposizione del 10-15% (qui 50 token su 512) risolve il problema.Pre-processing HTML→Markdown: se i sorgenti sono pagine web, convertire in Markdown prima del chunking (con librerie come HtmlAgilityPack) elimina tag irrilevanti che degradano la qualità dell’embedding.Un’altra best practice avanzata: separare i blocchi di codice dalla prosa e taggare ogni chunk con metadati (tipo di contenuto, sezione, sorgente) per poter filtrare durante il retrieval.Le soglie di rilevanza non sono universaliI tutorial usano tipicamente soglie di similarità coseno tra 0.75 e 0.80. Questo valore è quasi sempre sbagliato per il tuo corpus specifico. La soglia ottimale dipende da: qualità dell’embedding model, distribuzione semantica del corpus, tipologia delle query.L’approccio corretto:Costruire manualmente un set di valutazione di 20-30 coppie query/risposta attesaPartire da 0.70 e iterare misurando Context RecallNon affidarsi mai ai default senza validazione corpus-specificaScegliere il vector store giustoSemantic Kernel supporta diversi backend. La scelta sbagliata genera complessità inutile o performance inadeguate:VolatileMemoryStore — solo per demo, dati persi al restartSqliteMemoryStore — sviluppo locale e prime versioni production: zero infrastruttura, persistenza garantitaElasticsearch — stack esistenti con ricerca ibrida (full-text + vettoriale)Azure AI Search — produzione su Azure, gestione scalabilità automaticaQdrant / Pinecone — carichi vettoriali dedicati ad alta scalaPer molte applicazioni aziendali, SQLite è la scelta razionale fino a migliaia di documenti. Aggiungere infrastruttura vettoriale dedicata ha senso solo con volumi e requisiti di latenza che lo giustificano effettivamente.Evitare il re-embedding a ogni avvioUno degli errori più costosi (in termini economici e di latenza) è re-embeddare l’intero corpus a ogni riavvio dell’applicazione. La soluzione è semplice: verificare l’esistenza della collection prima di procedere all’ingestion:var collections = await sqliteStore.GetCollectionsAsync().ToListAsync();
if (!collections.Contains(CollectionName))
{
    await ragService.IngestDocumentsAsync(documents, CollectionName);
}Con Azure AI Search o Qdrant, la logica è analoga ma si basa sulle API specifiche del provider.Il prompt di grounding non è opzionaleLa costruzione del prompt è la difesa principale contro le allucinazioni. C’è una differenza sostanziale tra queste due istruzioni:“Usa il contesto seguente per rispondere” — il modello può integrare con la sua conoscenza generale“Rispondi SOLO usando il contesto seguente. Se la risposta non è nel contesto, dillo esplicitamente.” — vincolo semantico forteLa parola “SOLO” cambia radicalmente il comportamento del modello. In produzione, il prompt di sistema deve essere esplicito e non ambiguo.Semantic caching per ridurre latenza e costiUn ottimizzazione ad alto impatto spesso ignorata: se una query è semanticamente simile a una già elaborata, si può restituire la risposta cached senza chiamare il vector store né il modello:var cachedAnswer = await cacheService.FindSimilarAsync(query, threshold: 0.92f);
if (cachedAnswer != null)
{
    return cachedAnswer.Answer;
}Con una soglia alta (0.90-0.95), il cache serve solo query davvero simili, evitando risposte errate. Per sistemi con pattern di query ripetitivi (FAQ, assistenti documentali), questo ottimizzazione può ridurre i costi LLM del 40-60%.Osservabilità: cosa monitorareUn sistema RAG senza osservabilità è un sistema cieco. I KPI da tracciare per ogni richiesta:TopChunkScore: se costantemente sotto 0.75, il retrieval fatica. Rivedere chunking o embedding model.ChunksRetrieved: se raggiunge sempre il limite massimo, espandere la finestra di ricerca.CacheHit: se sempre false con alta latenza, la soglia del cache è troppo restrittiva.Latency: separare la latenza di retrieval da quella LLM per identificare il bottleneck.Valutazione continua e CIIl rischio silenzioso del RAG è la regressione: una modifica al chunking o alla soglia migliora alcune query e ne peggiora altre. La soluzione è integrare un set di valutazione nel pipeline CI con xUnit:Context Recall: i chunk corretti vengono recuperati?Faithfulness: la risposta rimane ancorata al contesto?Answer Correctness: corrisponde alla risposta attesa?Il set di test deve includere query facili, domande che richiedono sintesi multi-documento, e domande a cui il sistema non dovrebbe rispondere (out-of-scope) — queste ultime sono fondamentali per rilevare allucinazioni.ConclusioneCostruire un sistema RAG che funziona nei demo è relativamente semplice con Semantic Kernel. Costruirne uno che funziona in produzione — con costi controllati, latenza accettabile, assenza di allucinazioni e monitoraggio efficace — richiede decisioni architetturali precise. Il chunking con overlap, le soglie calibrate sul corpus reale, il caching semantico e l’osservabilità non sono optional: sono la differenza tra un prototipo e un sistema affidabile.Fonte originale: RAG in .NET: What the Tutorials Don’t Tell You di Jamie Maguire.]]></description><link>https://forum.androidiani.net/topic/e08c285d-52b6-45fa-a447-3192f21f02ee/rag-in-.net-con-semantic-kernel-le-insidie-che-i-tutorial-non-ti-dicono</link><guid isPermaLink="true">https://forum.androidiani.net/topic/e08c285d-52b6-45fa-a447-3192f21f02ee/rag-in-.net-con-semantic-kernel-le-insidie-che-i-tutorial-non-ti-dicono</guid><dc:creator><![CDATA[blog@spcnet.it]]></dc:creator><pubDate>Tue, 21 Apr 2026 07:55:23 GMT</pubDate></item></channel></rss>