[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"portal-settings:stajic:it":3,"public-menus:all":38,"post:where-does-an-llm-get-its-data-rag-data-sources-in-python:it":205,"related:post:where-does-an-llm-get-its-data-rag-data-sources-in-python:it:1":1407},{"statusCode":4,"data":5,"message":37},200,{"tenantId":6,"lang":7,"defaultLang":8,"siteUrl":9,"contactEmail":10,"brandName":11,"logoUrl":12,"siteName":11,"siteDescription":13,"ogImage":10,"robotsIndex":14,"socialLinks":10,"reservedSlugs":10,"seoPolicy":15},"stajic","it","de","https:\u002F\u002Fstajic.de",null,"Stajic Platform","\u002FLogo_Planet.svg","Stajic Portal",true,{"branding":16,"relatedContent":17,"crossDomainLinks":18},{"logoUrl":12},{"enabled":14},[19,22,25,28,31,34],{"url":20,"label":21,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Ffigure.rocks","figure.rocks",{"url":23,"label":24,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Floving.rocks","loving.rocks",{"url":26,"label":27,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Fbazify.com","bazify.com",{"url":29,"label":30,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Fbazify.de","bazify.de",{"url":32,"label":33,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Fbazify.at","bazify.at",{"url":35,"label":36,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Fbazify.ba","bazify.ba","Portal settings resolved",[39,45],{"id":40,"name":41,"location":42,"isActive":14,"isDefault":43,"items":44},1,"main-navigation","header",false,[],{"id":46,"name":47,"location":48,"isActive":14,"isDefault":14,"items":49},4,"main-menu","sidebar",[50,66,79,93,103,118,133],{"id":51,"title":52,"url":60,"target":61,"icon":62,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":64,"portfolioId":10,"children":65},"item-18",{"de":53,"en":54,"es":55,"fr":56,"it":54,"ru":57,"sr":58,"zh":59},"Startseite","Home","Inicio","Accueil","Главная","Почетна","首页","\u002Ffull-stack-web-developer-munich-performance-seo-and-maintainable-builds","_self","i-lucide-home","page",111,[],{"id":67,"title":68,"url":75,"target":61,"icon":76,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":77,"portfolioId":10,"children":78},"item-22",{"de":69,"en":69,"es":70,"fr":69,"it":71,"ru":72,"sr":73,"zh":74},"Vision","Visión","Visione","Видение","Визија","想象","\u002Fueber-uns-webdesign-muenchen-webaplikation","i-lucide-eye",113,[],{"id":80,"title":81,"url":89,"target":61,"icon":90,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":91,"portfolioId":10,"children":92},"item-19",{"de":82,"en":83,"es":84,"fr":83,"it":85,"ru":86,"sr":87,"zh":88},"Leistungen","Services","Servicios","Servizi","Услуги","Услуге","服务","\u002Fservices-dienstleistungen-muenchen","i-lucide-wrench",116,[],{"id":94,"title":95,"url":99,"target":61,"icon":100,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":101,"portfolioId":10,"children":102},"item-23",{"de":96,"en":96,"es":96,"fr":96,"it":96,"ru":97,"sr":97,"zh":98},"Blog","Блог","博客","\u002Fblog","i-lucide-book-open",112,[],{"id":104,"title":105,"url":114,"target":61,"icon":115,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":116,"portfolioId":10,"children":117},"item-32",{"de":106,"en":107,"es":108,"fr":109,"it":110,"ru":111,"sr":112,"zh":113},"Neue Technologien","New Technologies","Nuevas tecnologías","Nouvelles technologies","Nuove tecnologie","Новые технологии","Нове технологије","新技术！","\u002Fneue-webtechnologien","i-lucide-sparkles",122,[],{"id":119,"title":120,"url":129,"target":61,"icon":130,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":131,"portfolioId":10,"children":132},"item-20",{"de":121,"en":122,"es":123,"fr":124,"it":125,"ru":126,"sr":127,"zh":128},"Kontakt","Contact us!","Contacto","Contact","Contatto","Контакт","Контактирајте нас","联系我们！","\u002Fcontact","i-lucide-mail",115,[],{"id":134,"title":135,"url":144,"target":61,"icon":145,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":146,"portfolioId":10,"children":147},"item-21",{"de":136,"en":137,"es":138,"fr":139,"it":140,"ru":141,"sr":142,"zh":143},"Unsere Arbeit","Our Work","Nuestro trabajo","Nos réalisations","I nostri lavori","Наши работы","Наши радови","文件夹","\u002Fportfolio","i-lucide-briefcase",114,[148,161,175,181,193],{"id":149,"title":150,"url":144,"target":61,"icon":159,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":146,"portfolioId":10,"children":160},"item-24",{"de":151,"en":152,"es":153,"fr":154,"it":155,"ru":156,"sr":157,"zh":158},"Alle Projekte","All Projects","Todos los proyectos","Tous les projets","Tutti i progetti","Все проекты","Сви пројекти","所有项目","i-lucide-grid-3x3",[],{"id":162,"title":163,"url":171,"target":61,"icon":172,"isActive":14,"type":173,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":10,"portfolioId":10,"children":174},"item-29",{"de":164,"en":165,"es":166,"fr":167,"it":168,"ru":169,"sr":170,"zh":143},"Local Roots, Global Reach","Local Roots - Global Reach","Empresa local ","Entreprise locale","Azienda locale","Местная компания","Локално предузеће глобално тржиште","\u002Fportfolio\u002Flocal-roots-global-reach-communication-media-systems-for-modern-business","i-lucide-folder","custom",[],{"id":176,"title":177,"url":179,"target":61,"icon":172,"isActive":14,"type":173,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":10,"portfolioId":10,"children":180},"item-28",{"de":178,"en":178,"es":178,"fr":178,"it":178,"ru":178,"sr":178,"zh":178},"Solr Suggester","\u002Fportfolio\u002Fsolr-fuzzy-suggester-und-solr-infix-suggester-abfrage-ueber-ajax-und-filterung",[],{"id":182,"title":183,"url":191,"target":61,"icon":172,"isActive":14,"type":173,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":10,"portfolioId":10,"children":192},"item-27",{"de":184,"en":185,"es":186,"fr":187,"it":188,"ru":189,"sr":190,"zh":185},"Firmenwebseite SEO","Company Website SEO","Sitio web corporativo SEO","Site web d’entreprise SEO","Sito web aziendale SEO","Корпоративный сайт SEO","Пословна веб-страница SEO","\u002Fportfolio\u002Fseo-sem-branding-mobile-webseite-muenchen",[],{"id":194,"title":195,"url":203,"target":61,"icon":172,"isActive":14,"type":173,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":10,"portfolioId":10,"children":204},"item-31",{"de":196,"en":197,"es":198,"fr":199,"it":200,"ru":201,"sr":202,"zh":197},"Digitalisierungsportal","Digitalization Portal","Portal de digitalización","Portail de numérisation","Portale di digitalizzazione","Портал цифровизации","Портал за дигитализацију","\u002Fportfolio\u002Fdigitalisierungsportal-archiv-museum-bibliothek-ead-lido-mets-mods",[],{"statusCode":4,"data":206,"message":1406},{"id":207,"title":208,"slug":209,"content":210,"contentJson":211,"excerpt":677,"featuredImage":678,"featuredImageAlt":679,"featuredImageCaption":10,"featuredImageTitle":10,"featuredImageCopyright":10,"featuredImageAuthor":10,"featuredImageSourceUrl":10,"featuredImageLicense":10,"featuredImageIsAiGenerated":43,"status":680,"publishedAt":681,"createdAt":682,"updatedAt":683,"seoLocalePaths":684,"categories":693,"author":694,"translations":699},"479","Da dove prende i dati un LLM? Fonti di dati RAG in Python","where-does-an-llm-get-its-data-rag-data-sources-in-python","\u003Cp>L'articolo precedente, \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fit\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">Cos'è il RAG? La spiegazione più semplice di come funziona\u003C\u002Fa>, ha stabilito il modello mentale: l'LLM scrive, il RAG recupera conoscenza utile, l'applicazione possiede lo stato corrente e gli strumenti eseguono azioni. Questo articolo fa il passo successivo: \u003Cb>da dove provengono effettivamente i dati e come appare il recupero in Python?\u003C\u002Fb>\u003C\u002Fp>\n\u003Cp>La sorpresa importante è che una \"fonte dati per LLM\" di solito non è nulla di esotico. Può essere un file di testo, una cartella di documenti Markdown, un database SQL, una risposta API, un catalogo prodotti, un sistema di supporto o un indice vettoriale derivato da quelle fonti. L'IA non conosce magicamente questi sistemi. La tua applicazione deve caricare, interrogare, cercare o recuperare i dati rilevanti e inserire il risultato nel contesto del modello.\u003C\u002Fp>\n\u003Cblockquote class=\"border-l-4 border-gray-300 pl-4 italic\">Fonte dati = dove risiedono le informazioni. Recupero = come l'applicazione trova informazioni utili. Contesto = le informazioni selezionate fornite al modello. LLM = il componente che interpreta quel contesto e genera una risposta.\u003Ccite class=\"block mt-2 text-sm\">— Il modello in quattro parti utilizzato in tutto questo articolo\u003C\u002Fcite>\u003C\u002Fblockquote>\n\u003Ch2 id=\"section-4\">Domanda\u003C\u002Fh2>\n\u003Cp>Come utilizza un LLM dati esterni come file, database o API, e come può un piccolo programma Python implementare i passaggi essenziali del RAG senza nasconderli dietro un framework?\u003C\u002Fp>\n\u003Ch2 id=\"section-6\">Cosa significa realmente\u003C\u002Fh2>\n\u003Cp>Quando gli sviluppatori dicono che un LLM è \"collegato ai dati aziendali\", diverse operazioni differenti possono nascondersi dietro quella frase. Un'applicazione può eseguire SQL. Un'altra può chiamare un'API. Un'altra può eseguire una ricerca full-text. Un'altra può calcolare la similarità degli embedding sui chunk di documenti. Tutte possono fornire informazioni esterne a un LLM, ma non sono lo stesso metodo di recupero e non dovrebbero essere trattate come intercambiabili.\u003C\u002Fp>\n\u003Cp>Questa distinzione è importante perché il miglior metodo di recupero dipende dalla forma della domanda. \"Qual è la nostra politica di rimborso?\" è un problema di recupero di documenti. \"Qual è lo stato attuale dell'ordine 4711?\" è di solito una ricerca in un database strutturato. \"Quale paragrafo discute il recupero dell'account?\" può essere una ricerca per parole chiave o semantica. Il RAG è più utile quando il sistema deve \u003Cb>scoprire conoscenza rilevante prima della generazione\u003C\u002Fb>.\u003C\u002Fp>\n\u003Ch2 id=\"section-9\">Esempio più semplice\u003C\u002Fh2>\n\u003Cp>Inizia con tre stringhe in Python ordinario. Non c'è ancora nessun database vettoriale, nessun framework e nessun LLM. Vogliamo solo rendere visibile il passaggio di recupero.\u003C\u002Fp>\n\u003Cpre class=\"code-block\">\u003Ccode>documents = [\n    &quot;The AKM uses 7.62 mm ammunition.&quot;,\n    &quot;A Med Kit restores health.&quot;,\n    &quot;A 4x scope can be attached to several compatible weapons.&quot;\n]\n\nquestion = &quot;Which ammunition does the AKM use?&quot;\n\nfor document in documents:\n    if &quot;AKM&quot; in document:\n        print(document)\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Il programma stampa la prima frase perché contiene il termine che abbiamo cercato. Questo è un recupero primitivo, ma l'architettura è già visibile: \u003Cb>domanda → ricerca → testo rilevante\u003C\u002Fb>. Il RAG aggiunge un ulteriore passaggio importante: passare il testo recuperato a un modello linguistico insieme alla domanda.\u003C\u002Fp>\n\u003Cp>Una versione leggermente più generale classifica i documenti in base alla sovrapposizione dei termini della query:\u003C\u002Fp>\n\u003Cpre class=\"code-block\">\u003Ccode>import re\n\ndocuments = [\n    {&quot;id&quot;: &quot;weapon-akm&quot;, &quot;text&quot;: &quot;The AKM uses 7.62 mm ammunition.&quot;},\n    {&quot;id&quot;: &quot;healing-medkit&quot;, &quot;text&quot;: &quot;A Med Kit restores health.&quot;},\n    {&quot;id&quot;: &quot;scope-4x&quot;, &quot;text&quot;: &quot;A 4x scope can be attached to several compatible weapons.&quot;},\n]\n\ndef words(text):\n    return set(re.findall(r&quot;[a-zA-Z0-9.]+&quot;, text.lower()))\n\ndef retrieve(question, documents, top_k=2):\n    query_terms = words(question)\n    ranked = []\n\n    for document in documents:\n        score = len(query_terms &amp; words(document[&quot;text&quot;]))\n        if score &gt; 0:\n            ranked.append((score, document))\n\n    ranked.sort(key=lambda item: item[0], reverse=True)\n    return [document for _, document in ranked[:top_k]]\n\nquestion = &quot;Which ammunition does the AKM use?&quot;\nhits = retrieve(question, documents)\n\nfor hit in hits:\n    print(hit[&quot;id&quot;], &quot;-&gt;&quot;, hit[&quot;text&quot;])\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Questo non è un motore di ricerca di produzione. Ignora la morfologia, i sinonimi, le varianti ortografiche, la lunghezza dei documenti e molti segnali di ranking. Il suo valore è educativo: \u003Cb>il RAG non inizia con un database vettoriale. Inizia con il recupero.\u003C\u002Fb>\u003C\u002Fp>\n\u003Ch2 id=\"section-16\">Dove l'esempio smette di funzionare\u003C\u002Fh2>\n\u003Cp>La corrispondenza esatta o lessicale diventa debole quando la domanda e la fonte usano parole diverse. Un documento può dire \"manutenzione del veicolo\", mentre l'utente chiede \"come riparo la mia auto?\" Un retriever lessicale può perdere la relazione anche se un umano la vede immediatamente. Il recupero semantico affronta questo problema rappresentando il testo come vettori e confrontando il significato anziché solo i token esatti.\u003C\u002Fp>\n\u003Cp>I file lunghi creano un altro problema. Cercare un intero manuale di 80 pagine come un'unica unità è troppo grossolano, ma dividere ogni frase può distruggere il contesto utile. I sistemi RAG reali necessitano quindi di decisioni su parsing, chunking, metadati, ranking, freschezza, autorizzazioni e provenienza.\u003C\u002Fp>\n\u003Cp>L'esempio non dice nulla nemmeno sui fatti strutturati in tempo reale. Se l'utente chiede lo stato attuale dell'ordine 4711 e l'applicazione ha già una chiave di database, la ricerca semantica è di solito lo strumento sbagliato come primo approccio. Una query deterministica al database è meglio.\u003C\u002Fp>\n\u003Ch2 id=\"section-20\">Risposta diretta\u003C\u002Fh2>\n\u003Cp>Una fonte di dati per LLM è qualsiasi sistema esterno dal quale un'applicazione può ottenere informazioni per il modello: file, database, API, indici di ricerca, vector store o stato applicativo in tempo reale. RAG è il pattern di \u003Cb>recuperare conoscenza rilevante da tali fonti prima della generazione\u003C\u002Fb>.\u003C\u002Fp>\n\u003Cp>In Python, la pipeline essenziale può essere molto piccola: \u003Cb>caricare i dati → creare unità recuperabili → trovare prove rilevanti → assemblare il contesto → chiamare l'LLM\u003C\u002Fb>. Il metodo di recupero dovrebbe corrispondere alla fonte e alla domanda. Usa SQL per fatti strutturati esatti, ricerca full-text per corrispondenza lessicale, embedding per similarità semantica e recupero ibrido quando diversi segnali sono preziosi.\u003C\u002Fp>\n\u003Ch2 id=\"section-23\">Perché è così\u003C\u002Fh2>\n\u003Cp>Un modello linguistico non riceve automaticamente il contenuto del tuo filesystem, database PostgreSQL, CRM, API privata o documento appena modificato. L'applicazione decide quali informazioni esterne sono accessibili e cosa viene inserito nel contesto corrente del modello.\u003C\u002Fp>\n\u003Cp>Il lavoro originale sulla Retrieval-Augmented Generation di Lewis et al. combinava un modello generativo con memoria esterna non parametrica recuperata da un indice vettoriale denso. L'idea architetturale più ampia sopravvive oltre quella specifica implementazione: le prove esterne possono essere recuperate al momento dell'inferenza invece di aspettarsi che tutta la conoscenza utile sia codificata nei parametri del modello.\u003C\u002Fp>\n\u003Cp>Questo crea una separazione utile delle responsabilità: la fonte memorizza le informazioni, il retriever seleziona le prove, il contesto porta tali prove nella richiesta e il modello le interpreta. Mantenere visibili questi confini rende i fallimenti molto più facili da diagnosticare.\u003C\u002Fp>\n\u003Ch2 id=\"section-27\">Contesto: i principali tipi di fonti di dati\u003C\u002Fh2>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Fonte\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Metodo di recupero tipico\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Adatto per\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">TXT \u002F Markdown \u002F HTML\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Parsing + ricerca lessicale o semantica\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Documentazione, manuali, articoli, note\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">PDF \u002F DOCX\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Estrazione consapevole della struttura + ricerca\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Politiche, report, contratti, manuali\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Database SQL\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Query SQL o recupero filtrato\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Ordini, utenti, prodotti, record strutturati\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">API REST \u002F GraphQL\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Richiesta HTTP con parametri\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Sistemi remoti e dati di servizi in tempo reale\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Indice di ricerca\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">BM25 \u002F full-text \u002F ricerca ibrida\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Grandi collezioni di testo\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Indice vettoriale\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Similarità di embedding\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Recupero semantico di documenti\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Stato applicativo\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Lettura diretta dello stato o chiamata a tool\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Ciò che è vero in questo momento\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>Un indice vettoriale merita un'attenzione particolare. In molte architetture \u003Cb>non è la fonte canonica di verità\u003C\u002Fb>. È un indice di recupero derivato da documenti o record. Il documento autorevole può risiedere in object storage, un CMS, Git, PostgreSQL o un altro sistema, mentre embedding e metadati sono memorizzati separatamente per una ricerca semantica veloce. Alcuni sistemi usano effettivamente un vector store come storage primario, ma questa è una scelta architetturale piuttosto che un requisito del RAG.\u003C\u002Fp>\n\u003Cp>Se il confine tra recupero, memoria persistente, stato corrente e contesto del modello non è ancora chiaro, vedi \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fit\u002Fblog\u002Fai-agent-memory-is-not-rag-how-to-separate-memory-retrieval-state-and-context\">AI Agent Memory Is Not RAG\u003C\u002Fa>. Quegli strati possono usare alcune delle stesse tecnologie di storage pur avendo regole di correttezza diverse.\u003C\u002Fp>\n\u003Ch2 id=\"section-31\">Assunzioni\u003C\u002Fh2>\n\u003Cul>\u003Cli>All'applicazione è consentito accedere alla fonte esterna.\u003C\u002Fli>\u003Cli>La fonte rilevante contiene informazioni sufficienti per rispondere alla domanda.\u003C\u002Fli>\u003Cli>I dati possono essere analizzati o interrogati in una forma che il livello di recupero può utilizzare.\u003C\u002Fli>\u003Cli>Le informazioni recuperate sono abbastanza aggiornate per la decisione richiesta.\u003C\u002Fli>\u003Cli>Il modello riceve le prove selezionate nel suo contesto.\u003C\u002Fli>\u003Cli>L'autorizzazione è applicata prima che le prove protette raggiungano il modello.\u003C\u002Fli>\u003Cli>Il modello di generazione può comunque sbagliare anche quando il recupero è corretto.\u003C\u002Fli>\u003C\u002Ful>\n\u003Cp>Queste assunzioni contano perché il recupero non può compensare prove mancanti, versioni obsolete della fonte, parser rotti o accessi non autorizzati. Una pipeline RAG può essere affidabile solo quanto il percorso delle prove che la alimenta.\u003C\u002Fp>\n\u003Ch2 id=\"section-34\">Variabili\u003C\u002Fh2>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Variabile\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Perché cambia il design\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Struttura della fonte\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Una tabella SQL, un PDF legale e un repository di codice sorgente richiedono strategie di recupero diverse\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Tipo di domanda\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Ricerca esatta, ricerca concettuale e ricerca multi-hop sono compiti diversi\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Requisito di aggiornamento\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Lo stato in tempo reale può richiedere query dirette invece di indici ricostruiti periodicamente\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Dimensione del corpus\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">La ricerca in memoria può funzionare per centinaia di chunk ma non per collezioni molto grandi\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Lingua\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Il recupero multilingue richiede modelli e tokenizzazione adatti alle lingue effettive\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Permessi\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Il recupero deve filtrare in base ai diritti di accesso dell'utente corrente\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Latenza e costo\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Più fasi di recupero possono migliorare la qualità ma aggiungono costo di runtime e infrastruttura\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Necessità di provenienza\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">I sistemi ad alta affidabilità necessitano di ID di origine, versioni e prove tracciabili\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Ch2 id=\"section-36\">Metodo diagnostico \u002F decisionale\u003C\u002Fh2>\n\u003Cp>La prima decisione non è “Quale database vettoriale dovrei installare?” È: \u003Cb>Che tipo di fatto sto cercando di recuperare?\u003C\u002Fb>\u003C\u002Fp>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Tipo di domanda\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Approccio preferito iniziale\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Motivo\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">ID esatto o record corrente\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">SQL \u002F ricerca per chiave \u002F API\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Accesso strutturato deterministico\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Dizione esatta, codici, nomi\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Ricerca full-text o per parole chiave\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Precisione lessicale\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Domanda concettuale sui documenti\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Ricerca semantica vettoriale\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Il significato può differire dalla formulazione\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Conoscenza aziendale mista\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Recupero ibrido + filtri sui metadati\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Combina segnali lessicali e semantici\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Stato corrente dell'applicazione\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Accesso diretto allo stato\u002Fstrumento\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">L'aggiornamento conta più della similarità dei documenti\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>Un test utile è: \u003Cb>So già quale record mi serve, o il sistema deve scoprire quale passaggio è rilevante?\u003C\u002Fb> Se il record è noto, interrogarlo direttamente. Se la rilevanza deve essere scoperta, la ricerca diventa più importante.\u003C\u002Fp>\n\u003Cp>Quando una risposta è sbagliata, diagnosticare la pipeline in ordine invece di cambiare immediatamente l'LLM:\u003C\u002Fp>\n\u003Col>\u003Cli>\u003Cb>1. Copertura delle fonti:\u003C\u002Fb> L'informazione corretta esiste nell'insieme di fonti accessibili?\u003C\u002Fli>\u003Cli>\u003Cb>2. Aggiornamento:\u003C\u002Fb> Quella versione è abbastanza recente per la domanda?\u003C\u002Fli>\u003Cli>\u003Cb>3. Parsing:\u003C\u002Fb> Il contenuto rilevante è stato estratto correttamente?\u003C\u002Fli>\u003Cli>\u003Cb>4. Chunking:\u003C\u002Fb> Le prove sono rimaste insieme alle condizioni che danno loro significato?\u003C\u002Fli>\u003Cli>\u003Cb>5. Recupero:\u003C\u002Fb> Il chunk corretto appare tra i candidati?\u003C\u002Fli>\u003Cli>\u003Cb>6. Ranking:\u003C\u002Fb> Le fonti più forti sono classificate sopra quelle più deboli o in conflitto?\u003C\u002Fli>\u003Cli>\u003Cb>7. Assemblaggio del contesto:\u003C\u002Fb> L'applicazione ha effettivamente inviato le prove selezionate al modello?\u003C\u002Fli>\u003Cli>\u003Cb>8. Generazione:\u003C\u002Fb> L'LLM ha utilizzato fedelmente le prove fornite?\u003C\u002Fli>\u003Cli>\u003Cb>9. Attribuzione:\u003C\u002Fb> Ogni affermazione importante può essere ricondotta a una fonte?\u003C\u002Fli>\u003C\u002Fol>\n\u003Cp>Per un metodo più approfondito di debug in produzione, vedere \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fit\u002Fblog\u002Frag-failed-but-which-layer-actually-failed-a-diagnostic-method\">RAG Failed — But Which Layer Actually Failed? A Diagnostic Method\u003C\u002Fa>, che espande questa catena in livelli di errore testabili indipendentemente.\u003C\u002Fp>\n\u003Ch2 id=\"section-43\">Evidenze\u003C\u002Fh2>\n\u003Cp>Il paper RAG di Lewis et al. ha formalizzato la generazione che si condiziona su una memoria esterna recuperata invece di affidarsi solo ai parametri del modello. Ciò fornisce la base concettuale per separare il generatore da una fonte di conoscenza recuperabile.\u003C\u002Fp>\n\u003Cp>Sentence Transformers documenta la ricerca semantica come l'incorporamento del corpus e della query in uno spazio vettoriale e il recupero di elementi con alta similarità semantica. La sua API attuale distingue anche la codifica della query dalla codifica dei documenti per i compiti di recupero.\u003C\u002Fp>\n\u003Cp>SQLite FTS5 dimostra l'altro lato dello spettro: il recupero full-text maturo può classificare i documenti senza embeddings. Questo è importante perché la ricerca lessicale rimane preziosa per identificatori, terminologia esatta e molti design di recupero ibrido.\u003C\u002Fp>\n\u003Cp>La documentazione sugli embeddings di OpenAI descrive gli embeddings come rappresentazioni vettoriali numeriche utilizzate per la correlazione e la ricerca. Questo è un percorso di implementazione per il recupero semantico, non la definizione di RAG stesso.\u003C\u002Fp>\n\u003Ch2 id=\"section-48\">Esempio reale 1: Una cartella di file di testo\u003C\u002Fh2>\n\u003Cp>Supponiamo che una directory chiamata \u003Ccode>knowledge\u002F\u003C\u002Fcode> contenga normali file di testo. Python può caricarli senza alcuna libreria AI.\u003C\u002Fp>\n\u003Cpre class=\"code-block\">\u003Ccode>from pathlib import Path\n\ndef load_text_files(folder=&quot;knowledge&quot;):\n    documents = []\n\n    for path in Path(folder).glob(&quot;*.txt&quot;):\n        documents.append({\n            &quot;source&quot;: path.name,\n            &quot;text&quot;: path.read_text(encoding=&quot;utf-8&quot;)\n        })\n\n    return documents\n\ndocuments = load_text_files()\n\nfor document in documents:\n    print(document[&quot;source&quot;], len(document[&quot;text&quot;]))\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Il filesystem è la fonte dati. La domanda successiva è quanto testo dovrebbe diventare un'unità recuperabile. Per documenti lunghi, cercare un intero file è spesso troppo grossolano. Ecco perché le pipeline RAG comunemente creano chunk.\u003C\u002Fp>\n\u003Ch3 id=\"section-52\">Un chunker molto semplice\u003C\u002Fh3>\n\u003Cpre class=\"code-block\">\u003Ccode>def chunk_text(text, max_chars=800):\n    paragraphs = [p.strip() for p in text.split(&quot;\\n\\n&quot;) if p.strip()]\n\n    chunks = []\n    current = &quot;&quot;\n\n    for paragraph in paragraphs:\n        candidate = f&quot;{current}\\n\\n{paragraph}&quot;.strip()\n\n        if current and len(candidate) &gt; max_chars:\n            chunks.append(current)\n            current = paragraph\n        else:\n            current = candidate\n\n    if current:\n        chunks.append(current)\n\n    return chunks\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Questo esempio raggruppa i paragrafi fino a raggiungere un limite approssimativo di caratteri. È intenzionalmente comprensibile piuttosto che ottimale. I sistemi di produzione spesso suddividono per token, intestazioni, sezioni, confini di frase o struttura del documento. Tabelle, codice sorgente, contratti e documentazione API possono richiedere strategie diverse.\u003C\u002Fp>\n\u003Ch3 id=\"section-55\">Preservare la provenienza durante il chunking\u003C\u002Fh3>\n\u003Cpre class=\"code-block\">\u003Ccode>def build_chunks(documents):\n    chunks = []\n\n    for document in documents:\n        for index, text in enumerate(chunk_text(document[&quot;text&quot;])):\n            chunks.append({\n                &quot;id&quot;: f&#39;{document[&quot;source&quot;]}:{index}&#39;,\n                &quot;source&quot;: document[&quot;source&quot;],\n                &quot;chunk&quot;: index,\n                &quot;text&quot;: text,\n            })\n\n    return chunks\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Un chunk utile porta con sé più del semplice testo. Nome della fonte, ID del documento, URL, timestamp, versione o sezione possono in seguito supportare citazioni, debug e controlli di aggiornamento. Se la provenienza viene persa durante l'ingestion, diventa molto più difficile spiegare perché è stata prodotta una particolare risposta.\u003C\u002Fp>\n\u003Ch2 id=\"section-58\">Esempio reale 2: Dati strutturati — Usa SQL quando SQL è lo strumento giusto\u003C\u002Fh2>\n\u003Cp>Non ogni fatto esterno dovrebbe passare attraverso la ricerca semantica. Se la domanda richiede un record corrente esatto, una query diretta al database è di solito più chiara e più deterministica.\u003C\u002Fp>\n\u003Cpre class=\"code-block\">\u003Ccode>import sqlite3\n\ndef get_order_status(order_id):\n    connection = sqlite3.connect(&quot;shop.db&quot;)\n    cursor = connection.cursor()\n\n    cursor.execute(\n        &quot;SELECT status, total, currency FROM orders WHERE id = ?&quot;,\n        (order_id,)\n    )\n\n    row = cursor.fetchone()\n    connection.close()\n\n    if row is None:\n        return None\n\n    return {\n        &quot;order_id&quot;: order_id,\n        &quot;status&quot;: row[0],\n        &quot;total&quot;: row[1],\n        &quot;currency&quot;: row[2],\n    }\n\nprint(get_order_status(4711))\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Se l'applicazione sa già che l'utente sta chiedendo dell'ordine 4711, incorporare l'intera tabella degli ordini e chiedere alla ricerca semantica di riscoprire quella riga di solito aggiunge complessità senza benefici. Una buona regola di progettazione è: \u003Cb>recupera i fatti strutturati con query strutturate; recupera la conoscenza non strutturata con la ricerca.\u003C\u002Fb>\u003C\u002Fp>\n\u003Cp>La riga del database restituita può comunque essere inserita nel contesto del modello, così che l'LLM possa spiegarla in linguaggio naturale. Ma l'accesso diretto allo stato o a un record è concettualmente diverso dalla ricerca in un corpus di conoscenza.\u003C\u002Fp>\n\u003Ch2 id=\"section-63\">Esempio reale 3: Ricerca full-text prima degli embedding\u003C\u002Fh2>\n\u003Cp>Tra un ingenuo ciclo Python e la ricerca vettoriale si colloca una classe matura di sistemi di recupero lessicale. SQLite include FTS5 per la ricerca full-text, incluso il ranking BM25.\u003C\u002Fp>\n\u003Cpre class=\"code-block\">\u003Ccode>import sqlite3\n\nconnection = sqlite3.connect(&quot;knowledge.db&quot;)\ncursor = connection.cursor()\n\ncursor.execute(\n    &quot;CREATE VIRTUAL TABLE IF NOT EXISTS docs USING fts5(title, body)&quot;\n)\n\ncursor.execute(\n    &quot;INSERT INTO docs(title, body) VALUES (?, ?)&quot;,\n    (&quot;AKM&quot;, &quot;The AKM uses 7.62 mm ammunition.&quot;)\n)\n\nconnection.commit()\n\nquery = &quot;AKM ammunition&quot;\n\nrows = cursor.execute(\n    &quot;SELECT title, body, bm25(docs) AS score &quot;\n    &quot;FROM docs WHERE docs MATCH ? &quot;\n    &quot;ORDER BY score LIMIT 5&quot;,\n    (query,)\n).fetchall()\n\nfor row in rows:\n    print(row)\n\nconnection.close()\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>La ricerca lessicale è particolarmente utile quando contano terminologia esatta, codici prodotto, nomi, identificatori o parole specifiche del dominio. La ricerca semantica non è automaticamente migliore. I sistemi di produzione spesso combinano entrambi i segnali.\u003C\u002Fp>\n\u003Ch2 id=\"section-67\">Esempio reale 4: Recupero semantico con gli embedding\u003C\u002Fh2>\n\u003Cp>Gli embedding trasformano il testo in vettori numerici, così passaggi semanticamente correlati possono essere confrontati anche quando non usano una formulazione identica. Sentence Transformers fornisce un'implementazione locale semplice.\u003C\u002Fp>\n\u003Cpre class=\"code-block\">\u003Ccode># pip install sentence-transformers\n\nfrom sentence_transformers import SentenceTransformer, util\n\ndocuments = [\n    &quot;The AKM uses 7.62 mm ammunition.&quot;,\n    &quot;A Med Kit restores health.&quot;,\n    &quot;Vehicle maintenance includes checking oil, brakes and tires.&quot;,\n    &quot;Account recovery requires access to the registered email address.&quot;\n]\n\nmodel = SentenceTransformer(\n    &quot;sentence-transformers\u002Fmulti-qa-mpnet-base-cos-v1&quot;\n)\n\ndocument_embeddings = model.encode_document(\n    documents,\n    convert_to_tensor=True\n)\n\nquestion = &quot;How do I repair my car?&quot;\n\nquery_embedding = model.encode_query(\n    question,\n    convert_to_tensor=True\n)\n\nhits = util.semantic_search(\n    query_embedding,\n    document_embeddings,\n    top_k=2\n)[0]\n\nfor hit in hits:\n    print(round(float(hit[&quot;score&quot;]), 3), documents[hit[&quot;corpus_id&quot;]])\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>La query non contiene la frase “manutenzione del veicolo”, ma un modello semantico può comunque classificare quel passaggio in alto perché i concetti sono correlati. Questa è la ragione pratica per cui gli embedding sono comuni nei sistemi RAG.\u003C\u002Fp>\n\u003Cp>Per piccole collezioni, gli embedding possono rimanere in memoria. I sistemi più grandi di solito li persistono in un indice o database compatibile con i vettori ed eseguono lì la ricerca del vicino più prossimo. La memorizzazione cambia, ma la logica rimane: codifica la domanda, trova le rappresentazioni rilevanti dei documenti, restituisci le prove migliori.\u003C\u002Fp>\n\u003Ch2 id=\"section-72\">Esempio reale 5: Costruire il contesto per l'LLM\u003C\u002Fh2>\n\u003Cp>Un retriever dovrebbe restituire delle prove. Il LLM dovrebbe quindi ricevere la domanda più quelle prove. Mantenere separati il recupero e la generazione rende entrambi più facili da ispezionare e testare.\u003C\u002Fp>\n\u003Cpre class=\"code-block\">\u003Ccode>def build_prompt(question, retrieved_documents):\n    context = &quot;\\n\\n&quot;.join(\n        f&#39;[{doc[&quot;id&quot;]}] {doc[&quot;text&quot;]}&#39;\n        for doc in retrieved_documents\n    )\n\n    return f&quot;&quot;&quot;\nAnswer the question using the supplied context.\n\nRules:\n- Do not invent facts that are not supported by the context.\n- If the context is insufficient, say so.\n- Cite the source IDs you used.\n\nQuestion:\n{question}\n\nContext:\n{context}\n&quot;&quot;&quot;.strip()\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>L'istruzione non rende il modello infallibile. Crea semplicemente un confine esplicito delle prove. Il modello può comunque fraintendere prove valide, ignorare una condizione o generalizzare eccessivamente. Ecco perché la qualità del recupero e la qualità della generazione devono essere valutate separatamente.\u003C\u002Fp>\n\u003Ch2 id=\"section-76\">Esempio reale 6: una pipeline minima completa\u003C\u002Fh2>\n\u003Cpre class=\"code-block\">\u003Ccode>def answer_question(question, all_documents, call_llm):\n    # 1. Retrieve evidence\n    retrieved = retrieve(question, all_documents, top_k=3)\n\n    # 2. Build model context\n    prompt = build_prompt(question, retrieved)\n\n    # 3. Generate the answer\n    answer = call_llm(prompt)\n\n    return {\n        &quot;answer&quot;: answer,\n        &quot;sources&quot;: [doc[&quot;id&quot;] for doc in retrieved]\n    }\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>La funzione riceve \u003Ccode>call_llm\u003C\u002Fcode> come dipendenza di proposito. Il recupero non dovrebbe interessarsi se la generazione è eseguita da un modello cloud, un modello locale o un altro provider. Il percorso dei dati appartiene all'applicazione.\u003C\u002Fp>\n\u003Ch3 id=\"section-79\">Generatore opzionale: OpenAI Responses API\u003C\u002Fh3>\n\u003Cp>Un possibile generatore è l'OpenAI Responses API. Mantenere il nome del modello in una variabile d'ambiente evita di codificare in modo rigido un particolare modello nell'architettura RAG.\u003C\u002Fp>\n\u003Cpre class=\"code-block\">\u003Ccode># pip install openai\n\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI()\n\ndef call_llm(prompt):\n    response = client.responses.create(\n        model=os.environ[&quot;OPENAI_MODEL&quot;],\n        input=prompt,\n    )\n    return response.output_text\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>La stessa pipeline di recupero può essere collegata a un server di inferenza locale. Questo è un punto architetturale importante: \u003Cb>il RAG non è di proprietà del provider del LLM.\u003C\u002Fb> L'applicazione possiede la fonte, il recupero e l'assemblaggio del contesto.\u003C\u002Fp>\n\u003Ch3 id=\"section-83\">L'intera architettura in una sola vista\u003C\u002Fh3>\n\u003Cpre class=\"code-block\">\u003Ccode>USER QUESTION\n     |\n     v\n+-------------+\n|  Retriever  |\n+-------------+\n   |       |\n   |       +----&gt; SQL \u002F API \u002F state query\n   |\n   +------------&gt; keyword \u002F full-text search\n   |\n   +------------&gt; embedding \u002F vector search\n                     |\n                     v\n              relevant evidence\n                     |\n                     v\n+-----------------------------------+\n| question + evidence + instructions |\n+-----------------------------------+\n                     |\n                     v\n                   LLM\n                     |\n                     v\n                  answer\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Questo modello di flusso di dati è più duraturo che memorizzare un singolo framework. Le librerie, i database e i fornitori di modelli cambieranno; i confini delle responsabilità rimangono.\u003C\u002Fp>\n\u003Ch2 id=\"section-86\">Idee sbagliate comuni e modalità di fallimento\u003C\u002Fh2>\n\u003Ch3 id=\"section-87\">“RAG significa database vettoriale.”\u003C\u002Fh3>\n\u003Cp>No. La ricerca vettoriale è un metodo di recupero. Il RAG può utilizzare ricerca full-text, SQL, API, grafi di conoscenza, ricerca vettoriale o combinazioni di essi. Il pattern che lo definisce è il recupero di informazioni esterne per la generazione.\u003C\u002Fp>\n\u003Ch3 id=\"section-89\">“Se i dati sono in PostgreSQL, devo incorporare l'intero database.”\u003C\u002Fh3>\n\u003Cp>No. I record strutturati dovrebbero di solito rimanere interrogabili come record strutturati. Gli embedding sono utili per la rilevanza semantica, non come sostituto delle query deterministiche.\u003C\u002Fp>\n\u003Ch3 id=\"section-91\">“Più chunk significa una risposta migliore.”\u003C\u002Fh3>\n\u003Cp>Non necessariamente. Un contesto extra può introdurre rumore, versioni in conflitto e materiale irrilevante. Il retrieval dovrebbe ottimizzare per prove utili, non per il volume massimo.\u003C\u002Fp>\n\u003Ch3 id=\"section-93\">“Un punteggio di similarità elevato dimostra la risposta.”\u003C\u002Fh3>\n\u003Cp>No. La similarità misura la rilevanza, non la verità o l'applicabilità. Un passaggio altamente simile può essere obsoleto, provenire dalla versione sbagliata del prodotto o essere valido solo in condizioni che non corrispondono alla domanda.\u003C\u002Fp>\n\u003Ch3 id=\"section-95\">“Una volta recuperato il chunk corretto, l'allucinazione è risolta.”\u003C\u002Fh3>\n\u003Cp>No. Il retrieval migliora il grounding ma non garantisce un ragionamento fedele. La generazione necessita comunque di valutazione, e i flussi di lavoro ad alto rischio possono richiedere validazione deterministica o revisione umana.\u003C\u002Fp>\n\u003Ch3 id=\"section-97\">“Il modello ha fallito, quindi cambia il modello.”\u003C\u002Fh3>\n\u003Cp>Non necessariamente. La fonte corretta potrebbe essere mancante, analizzata in modo errato, suddivisa male, filtrata, classificata troppo in basso o omessa dal contesto assemblato. La sostituzione del modello non dovrebbe essere il primo passo diagnostico.\u003C\u002Fp>\n\u003Ch2 id=\"section-99\">Casi limite\u003C\u002Fh2>\n\u003Cul>\u003Cli>\u003Cb>Documenti in conflitto:\u003C\u002Fb> due fonti possono discordare perché versioni, giurisdizioni o prodotti differiscono.\u003C\u002Fli>\u003Cli>\u003Cb>Fatti sensibili al tempo:\u003C\u002Fb> una fonte semanticamente rilevante può essere già obsoleta.\u003C\u002Fli>\u003Cli>\u003Cb>Autorizzazioni:\u003C\u002Fb> un retriever non deve restituire documenti a cui l'utente corrente non è autorizzato ad accedere.\u003C\u002Fli>\u003Cli>\u003Cb>Collezioni multilingua:\u003C\u002Fb> il modello di embedding e la strategia di retrieval devono supportare le lingue effettivamente utilizzate.\u003C\u002Fli>\u003Cli>\u003Cb>Tabelle e codice sorgente:\u003C\u002Fb> il chunking a paragrafi semplici può distruggere la struttura essenziale per la risposta.\u003C\u002Fli>\u003Cli>\u003Cb>Identificatori molto brevi:\u003C\u002Fb> il retrieval semantico può essere più debole della corrispondenza esatta per SKU, ID, codici di errore o acronimi.\u003C\u002Fli>\u003Cli>\u003Cb>Domande lunghe che richiedono diversi fatti:\u003C\u002Fb> il retrieval può richiedere decomposizione, diverse ricerche o reranking invece di una singola query top-k.\u003C\u002Fli>\u003Cli>\u003Cb>Gerarchia delle fonti:\u003C\u002Fb> una politica ufficiale corrente può dover prevalere su un documento di discussione più vecchio ma semanticamente più vicino.\u003C\u002Fli>\u003C\u002Ful>\n\u003Ch2 id=\"section-101\">Limitazioni\u003C\u002Fh2>\n\u003Cp>Gli esempi Python ottimizzano intenzionalmente per la trasparenza, non per la scalabilità. Il retriever per parole chiave è ingenuo, il chunker utilizza la lunghezza in caratteri, gli esempi SQLite non includono la gestione delle connessioni di produzione e l'esempio semantico mantiene tutti gli embedding in memoria.\u003C\u002Fp>\n\u003Cp>Un sistema di produzione può richiedere indici vettoriali, reranker, retrieval ibrido, parser di documenti, caching, indicizzazione incrementale, versioning delle fonti, filtri di controllo degli accessi, osservabilità, dataset di valutazione e gestione degli errori. Nessuna di queste aggiunte cambia l'architettura principale; rendono ogni confine più affidabile.\u003C\u002Fp>\n\u003Cp>Il RAG inoltre non può creare prove assenti dall'insieme delle fonti. Se la fonte è sbagliata, incompleta o obsoleta, un modello di embedding migliore non può trasformarla in conoscenza autorevole.\u003C\u002Fp>\n\u003Ch2 id=\"section-105\">Cosa cambierebbe questa risposta?\u003C\u002Fh2>\n\u003Cp>L'architettura cambia quando il compito richiede più di una semplice ricerca di conoscenza. Uno stato dell'ordine in tempo reale necessita dello stato corrente. Un calcolo finanziario può richiedere codice deterministico. Un compito di ricerca web può richiedere ricerca attiva. Un flusso di lavoro può richiedere strumenti in grado di riscrivere dati su un altro sistema. Un agente autonomo può richiedere pianificazione, autorizzazioni e controllo dell'esecuzione oltre al retrieval.\u003C\u002Fp>\n\u003Cp>Il RAG è quindi meglio inteso come \u003Cb>uno strato di acquisizione di prove all'interno di un sistema AI più ampio\u003C\u002Fb>. È potente proprio perché ha un compito ristretto: trovare informazioni esterne utili e collocarle nel contesto di lavoro del modello.\u003C\u002Fp>\n\u003Ch2 id=\"section-108\">Conclusione\u003C\u002Fh2>\n\u003Cp>RAG diventa molto più facile da capire quando si rimuovono i nomi delle tecnologie. Un file è una fonte. Un database è una fonte. Un'API è una fonte. Una funzione di ricerca recupera le prove. Un prompt porta quelle prove al modello. L'LLM le interpreta e produce linguaggio.\u003C\u002Fp>\n\u003Cp>La parte difficile del RAG in produzione non è chiamare un modello di embedding. È costruire un percorso di prove affidabile dalla fonte originale all'affermazione finale: preservare la provenienza, selezionare il metodo di recupero giusto, mantenere le informazioni aggiornate, controllare l'accesso, valutare il recupero separatamente dalla generazione e sapere quando una chiamata diretta a un database o a uno strumento è meglio della ricerca semantica.\u003C\u002Fp>\n\u003Cp>Questa è la continuazione pratica del modello RAG di base: \u003Cb>prima capire i ruoli, poi rendere esplicito il percorso dei dati.\u003C\u002Fb>\u003C\u002Fp>\n\u003Ch2 id=\"section-112\">Fonti primarie\u003C\u002Fh2>\n\u003Cul>\u003Cli>\u003Ca href=\"https:\u002F\u002Farxiv.org\u002Fabs\u002F2005.11401\">Lewis et al. — Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks\u003C\u002Fa> — il paper del 2020 che introduce la formulazione RAG che combina la generazione con la memoria non parametrica recuperata.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fwww.sbert.net\u002Fexamples\u002Fsentence_transformer\u002Fapplications\u002Fsemantic-search\u002FREADME.html\">Sentence Transformers — Semantic Search\u003C\u002Fa> — documentazione ufficiale per il recupero semantico, gli embedding delle query e gli embedding dei documenti.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fembeddings\">OpenAI — Vector Embeddings\u003C\u002Fa> — documentazione ufficiale che descrive gli embedding come rappresentazioni numeriche usate per la correlazione e la ricerca.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fwww.sqlite.org\u002Ffts5.html\">SQLite — FTS5 Extension\u003C\u002Fa> — documentazione ufficiale per la ricerca full-text e il ranking BM25 in SQLite.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Flibraries\">OpenAI — SDKs and CLI\u003C\u002Fa> — esempio ufficiale dell'SDK Python per la Responses API usato nell'esempio opzionale del generatore.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fit\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">What Is RAG? The Simplest Explanation of How It Works\u003C\u002Fa> — la prima parte concettuale di questa serie.\u003C\u002Fli>\u003C\u002Ful>",{"time":212,"blocks":213,"version":676},1790517411640,[214,218,221,227,231,234,237,240,243,246,249,253,256,259,262,265,268,271,274,277,280,283,286,289,292,295,298,301,337,340,343,346,358,361,364,394,397,400,426,429,432,445,448,451,454,457,460,463,466,469,472,475,479,482,485,488,491,494,497,500,503,506,509,512,515,518,521,524,527,530,533,536,539,542,545,548,551,554,557,560,563,566,569,572,575,578,581,584,587,590,593,596,599,602,605,608,611,614,617,620,631,634,637,640,643,646,649,652,655,658,661,664,667],{"data":215,"type":217},{"text":216},"L'articolo precedente, \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fit\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">Cos'è il RAG? La spiegazione più semplice di come funziona\u003C\u002Fa>, ha stabilito il modello mentale: l'LLM scrive, il RAG recupera conoscenza utile, l'applicazione possiede lo stato corrente e gli strumenti eseguono azioni. Questo articolo fa il passo successivo: \u003Cb>da dove provengono effettivamente i dati e come appare il recupero in Python?\u003C\u002Fb>","paragraph",{"data":219,"type":217},{"text":220},"La sorpresa importante è che una \"fonte dati per LLM\" di solito non è nulla di esotico. Può essere un file di testo, una cartella di documenti Markdown, un database SQL, una risposta API, un catalogo prodotti, un sistema di supporto o un indice vettoriale derivato da quelle fonti. L'IA non conosce magicamente questi sistemi. La tua applicazione deve caricare, interrogare, cercare o recuperare i dati rilevanti e inserire il risultato nel contesto del modello.",{"data":222,"type":226},{"text":223,"caption":224,"alignment":225},"Fonte dati = dove risiedono le informazioni. Recupero = come l'applicazione trova informazioni utili. Contesto = le informazioni selezionate fornite al modello. LLM = il componente che interpreta quel contesto e genera una risposta.","Il modello in quattro parti utilizzato in tutto questo articolo","left","quote",{"data":228,"type":42},{"text":229,"level":230},"Domanda",2,{"data":232,"type":217},{"text":233},"Come utilizza un LLM dati esterni come file, database o API, e come può un piccolo programma Python implementare i passaggi essenziali del RAG senza nasconderli dietro un framework?",{"data":235,"type":42},{"text":236,"level":230},"Cosa significa realmente",{"data":238,"type":217},{"text":239},"Quando gli sviluppatori dicono che un LLM è \"collegato ai dati aziendali\", diverse operazioni differenti possono nascondersi dietro quella frase. Un'applicazione può eseguire SQL. Un'altra può chiamare un'API. Un'altra può eseguire una ricerca full-text. Un'altra può calcolare la similarità degli embedding sui chunk di documenti. Tutte possono fornire informazioni esterne a un LLM, ma non sono lo stesso metodo di recupero e non dovrebbero essere trattate come intercambiabili.",{"data":241,"type":217},{"text":242},"Questa distinzione è importante perché il miglior metodo di recupero dipende dalla forma della domanda. \"Qual è la nostra politica di rimborso?\" è un problema di recupero di documenti. \"Qual è lo stato attuale dell'ordine 4711?\" è di solito una ricerca in un database strutturato. \"Quale paragrafo discute il recupero dell'account?\" può essere una ricerca per parole chiave o semantica. Il RAG è più utile quando il sistema deve \u003Cb>scoprire conoscenza rilevante prima della generazione\u003C\u002Fb>.",{"data":244,"type":42},{"text":245,"level":230},"Esempio più semplice",{"data":247,"type":217},{"text":248},"Inizia con tre stringhe in Python ordinario. Non c'è ancora nessun database vettoriale, nessun framework e nessun LLM. Vogliamo solo rendere visibile il passaggio di recupero.",{"data":250,"type":252},{"code":251},"documents = [\n    \"The AKM uses 7.62 mm ammunition.\",\n    \"A Med Kit restores health.\",\n    \"A 4x scope can be attached to several compatible weapons.\"\n]\n\nquestion = \"Which ammunition does the AKM use?\"\n\nfor document in documents:\n    if \"AKM\" in document:\n        print(document)","code",{"data":254,"type":217},{"text":255},"Il programma stampa la prima frase perché contiene il termine che abbiamo cercato. Questo è un recupero primitivo, ma l'architettura è già visibile: \u003Cb>domanda → ricerca → testo rilevante\u003C\u002Fb>. Il RAG aggiunge un ulteriore passaggio importante: passare il testo recuperato a un modello linguistico insieme alla domanda.",{"data":257,"type":217},{"text":258},"Una versione leggermente più generale classifica i documenti in base alla sovrapposizione dei termini della query:",{"data":260,"type":252},{"code":261},"import re\n\ndocuments = [\n    {\"id\": \"weapon-akm\", \"text\": \"The AKM uses 7.62 mm ammunition.\"},\n    {\"id\": \"healing-medkit\", \"text\": \"A Med Kit restores health.\"},\n    {\"id\": \"scope-4x\", \"text\": \"A 4x scope can be attached to several compatible weapons.\"},\n]\n\ndef words(text):\n    return set(re.findall(r\"[a-zA-Z0-9.]+\", text.lower()))\n\ndef retrieve(question, documents, top_k=2):\n    query_terms = words(question)\n    ranked = []\n\n    for document in documents:\n        score = len(query_terms & words(document[\"text\"]))\n        if score > 0:\n            ranked.append((score, document))\n\n    ranked.sort(key=lambda item: item[0], reverse=True)\n    return [document for _, document in ranked[:top_k]]\n\nquestion = \"Which ammunition does the AKM use?\"\nhits = retrieve(question, documents)\n\nfor hit in hits:\n    print(hit[\"id\"], \"->\", hit[\"text\"])",{"data":263,"type":217},{"text":264},"Questo non è un motore di ricerca di produzione. Ignora la morfologia, i sinonimi, le varianti ortografiche, la lunghezza dei documenti e molti segnali di ranking. Il suo valore è educativo: \u003Cb>il RAG non inizia con un database vettoriale. Inizia con il recupero.\u003C\u002Fb>",{"data":266,"type":42},{"text":267,"level":230},"Dove l'esempio smette di funzionare",{"data":269,"type":217},{"text":270},"La corrispondenza esatta o lessicale diventa debole quando la domanda e la fonte usano parole diverse. Un documento può dire \"manutenzione del veicolo\", mentre l'utente chiede \"come riparo la mia auto?\" Un retriever lessicale può perdere la relazione anche se un umano la vede immediatamente. Il recupero semantico affronta questo problema rappresentando il testo come vettori e confrontando il significato anziché solo i token esatti.",{"data":272,"type":217},{"text":273},"I file lunghi creano un altro problema. Cercare un intero manuale di 80 pagine come un'unica unità è troppo grossolano, ma dividere ogni frase può distruggere il contesto utile. I sistemi RAG reali necessitano quindi di decisioni su parsing, chunking, metadati, ranking, freschezza, autorizzazioni e provenienza.",{"data":275,"type":217},{"text":276},"L'esempio non dice nulla nemmeno sui fatti strutturati in tempo reale. Se l'utente chiede lo stato attuale dell'ordine 4711 e l'applicazione ha già una chiave di database, la ricerca semantica è di solito lo strumento sbagliato come primo approccio. Una query deterministica al database è meglio.",{"data":278,"type":42},{"text":279,"level":230},"Risposta diretta",{"data":281,"type":217},{"text":282},"Una fonte di dati per LLM è qualsiasi sistema esterno dal quale un'applicazione può ottenere informazioni per il modello: file, database, API, indici di ricerca, vector store o stato applicativo in tempo reale. RAG è il pattern di \u003Cb>recuperare conoscenza rilevante da tali fonti prima della generazione\u003C\u002Fb>.",{"data":284,"type":217},{"text":285},"In Python, la pipeline essenziale può essere molto piccola: \u003Cb>caricare i dati → creare unità recuperabili → trovare prove rilevanti → assemblare il contesto → chiamare l'LLM\u003C\u002Fb>. Il metodo di recupero dovrebbe corrispondere alla fonte e alla domanda. Usa SQL per fatti strutturati esatti, ricerca full-text per corrispondenza lessicale, embedding per similarità semantica e recupero ibrido quando diversi segnali sono preziosi.",{"data":287,"type":42},{"text":288,"level":230},"Perché è così",{"data":290,"type":217},{"text":291},"Un modello linguistico non riceve automaticamente il contenuto del tuo filesystem, database PostgreSQL, CRM, API privata o documento appena modificato. L'applicazione decide quali informazioni esterne sono accessibili e cosa viene inserito nel contesto corrente del modello.",{"data":293,"type":217},{"text":294},"Il lavoro originale sulla Retrieval-Augmented Generation di Lewis et al. combinava un modello generativo con memoria esterna non parametrica recuperata da un indice vettoriale denso. L'idea architetturale più ampia sopravvive oltre quella specifica implementazione: le prove esterne possono essere recuperate al momento dell'inferenza invece di aspettarsi che tutta la conoscenza utile sia codificata nei parametri del modello.",{"data":296,"type":217},{"text":297},"Questo crea una separazione utile delle responsabilità: la fonte memorizza le informazioni, il retriever seleziona le prove, il contesto porta tali prove nella richiesta e il modello le interpreta. Mantenere visibili questi confini rende i fallimenti molto più facili da diagnosticare.",{"data":299,"type":42},{"text":300,"level":230},"Contesto: i principali tipi di fonti di dati",{"data":302,"type":336},{"content":303,"withHeadings":14},[304,308,312,316,320,324,328,332],[305,306,307],"Fonte","Metodo di recupero tipico","Adatto per",[309,310,311],"TXT \u002F Markdown \u002F HTML","Parsing + ricerca lessicale o semantica","Documentazione, manuali, articoli, note",[313,314,315],"PDF \u002F DOCX","Estrazione consapevole della struttura + ricerca","Politiche, report, contratti, manuali",[317,318,319],"Database SQL","Query SQL o recupero filtrato","Ordini, utenti, prodotti, record strutturati",[321,322,323],"API REST \u002F GraphQL","Richiesta HTTP con parametri","Sistemi remoti e dati di servizi in tempo reale",[325,326,327],"Indice di ricerca","BM25 \u002F full-text \u002F ricerca ibrida","Grandi collezioni di testo",[329,330,331],"Indice vettoriale","Similarità di embedding","Recupero semantico di documenti",[333,334,335],"Stato applicativo","Lettura diretta dello stato o chiamata a tool","Ciò che è vero in questo momento","table",{"data":338,"type":217},{"text":339},"Un indice vettoriale merita un'attenzione particolare. In molte architetture \u003Cb>non è la fonte canonica di verità\u003C\u002Fb>. È un indice di recupero derivato da documenti o record. Il documento autorevole può risiedere in object storage, un CMS, Git, PostgreSQL o un altro sistema, mentre embedding e metadati sono memorizzati separatamente per una ricerca semantica veloce. Alcuni sistemi usano effettivamente un vector store come storage primario, ma questa è una scelta architetturale piuttosto che un requisito del RAG.",{"data":341,"type":217},{"text":342},"Se il confine tra recupero, memoria persistente, stato corrente e contesto del modello non è ancora chiaro, vedi \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fit\u002Fblog\u002Fai-agent-memory-is-not-rag-how-to-separate-memory-retrieval-state-and-context\">AI Agent Memory Is Not RAG\u003C\u002Fa>. Quegli strati possono usare alcune delle stesse tecnologie di storage pur avendo regole di correttezza diverse.",{"data":344,"type":42},{"text":345,"level":230},"Assunzioni",{"data":347,"type":357},{"items":348,"style":356},[349,350,351,352,353,354,355],"All'applicazione è consentito accedere alla fonte esterna.","La fonte rilevante contiene informazioni sufficienti per rispondere alla domanda.","I dati possono essere analizzati o interrogati in una forma che il livello di recupero può utilizzare.","Le informazioni recuperate sono abbastanza aggiornate per la decisione richiesta.","Il modello riceve le prove selezionate nel suo contesto.","L'autorizzazione è applicata prima che le prove protette raggiungano il modello.","Il modello di generazione può comunque sbagliare anche quando il recupero è corretto.","unordered","list",{"data":359,"type":217},{"text":360},"Queste assunzioni contano perché il recupero non può compensare prove mancanti, versioni obsolete della fonte, parser rotti o accessi non autorizzati. Una pipeline RAG può essere affidabile solo quanto il percorso delle prove che la alimenta.",{"data":362,"type":42},{"text":363,"level":230},"Variabili",{"data":365,"type":336},{"content":366,"withHeadings":14},[367,370,373,376,379,382,385,388,391],[368,369],"Variabile","Perché cambia il design",[371,372],"Struttura della fonte","Una tabella SQL, un PDF legale e un repository di codice sorgente richiedono strategie di recupero diverse",[374,375],"Tipo di domanda","Ricerca esatta, ricerca concettuale e ricerca multi-hop sono compiti diversi",[377,378],"Requisito di aggiornamento","Lo stato in tempo reale può richiedere query dirette invece di indici ricostruiti periodicamente",[380,381],"Dimensione del corpus","La ricerca in memoria può funzionare per centinaia di chunk ma non per collezioni molto grandi",[383,384],"Lingua","Il recupero multilingue richiede modelli e tokenizzazione adatti alle lingue effettive",[386,387],"Permessi","Il recupero deve filtrare in base ai diritti di accesso dell'utente corrente",[389,390],"Latenza e costo","Più fasi di recupero possono migliorare la qualità ma aggiungono costo di runtime e infrastruttura",[392,393],"Necessità di provenienza","I sistemi ad alta affidabilità necessitano di ID di origine, versioni e prove tracciabili",{"data":395,"type":42},{"text":396,"level":230},"Metodo diagnostico \u002F decisionale",{"data":398,"type":217},{"text":399},"La prima decisione non è “Quale database vettoriale dovrei installare?” È: \u003Cb>Che tipo di fatto sto cercando di recuperare?\u003C\u002Fb>",{"data":401,"type":336},{"content":402,"withHeadings":14},[403,406,410,414,418,422],[374,404,405],"Approccio preferito iniziale","Motivo",[407,408,409],"ID esatto o record corrente","SQL \u002F ricerca per chiave \u002F API","Accesso strutturato deterministico",[411,412,413],"Dizione esatta, codici, nomi","Ricerca full-text o per parole chiave","Precisione lessicale",[415,416,417],"Domanda concettuale sui documenti","Ricerca semantica vettoriale","Il significato può differire dalla formulazione",[419,420,421],"Conoscenza aziendale mista","Recupero ibrido + filtri sui metadati","Combina segnali lessicali e semantici",[423,424,425],"Stato corrente dell'applicazione","Accesso diretto allo stato\u002Fstrumento","L'aggiornamento conta più della similarità dei documenti",{"data":427,"type":217},{"text":428},"Un test utile è: \u003Cb>So già quale record mi serve, o il sistema deve scoprire quale passaggio è rilevante?\u003C\u002Fb> Se il record è noto, interrogarlo direttamente. Se la rilevanza deve essere scoperta, la ricerca diventa più importante.",{"data":430,"type":217},{"text":431},"Quando una risposta è sbagliata, diagnosticare la pipeline in ordine invece di cambiare immediatamente l'LLM:",{"data":433,"type":357},{"items":434,"style":444},[435,436,437,438,439,440,441,442,443],"\u003Cb>1. Copertura delle fonti:\u003C\u002Fb> L'informazione corretta esiste nell'insieme di fonti accessibili?","\u003Cb>2. Aggiornamento:\u003C\u002Fb> Quella versione è abbastanza recente per la domanda?","\u003Cb>3. Parsing:\u003C\u002Fb> Il contenuto rilevante è stato estratto correttamente?","\u003Cb>4. Chunking:\u003C\u002Fb> Le prove sono rimaste insieme alle condizioni che danno loro significato?","\u003Cb>5. Recupero:\u003C\u002Fb> Il chunk corretto appare tra i candidati?","\u003Cb>6. Ranking:\u003C\u002Fb> Le fonti più forti sono classificate sopra quelle più deboli o in conflitto?","\u003Cb>7. Assemblaggio del contesto:\u003C\u002Fb> L'applicazione ha effettivamente inviato le prove selezionate al modello?","\u003Cb>8. Generazione:\u003C\u002Fb> L'LLM ha utilizzato fedelmente le prove fornite?","\u003Cb>9. Attribuzione:\u003C\u002Fb> Ogni affermazione importante può essere ricondotta a una fonte?","ordered",{"data":446,"type":217},{"text":447},"Per un metodo più approfondito di debug in produzione, vedere \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fit\u002Fblog\u002Frag-failed-but-which-layer-actually-failed-a-diagnostic-method\">RAG Failed — But Which Layer Actually Failed? A Diagnostic Method\u003C\u002Fa>, che espande questa catena in livelli di errore testabili indipendentemente.",{"data":449,"type":42},{"text":450,"level":230},"Evidenze",{"data":452,"type":217},{"text":453},"Il paper RAG di Lewis et al. ha formalizzato la generazione che si condiziona su una memoria esterna recuperata invece di affidarsi solo ai parametri del modello. Ciò fornisce la base concettuale per separare il generatore da una fonte di conoscenza recuperabile.",{"data":455,"type":217},{"text":456},"Sentence Transformers documenta la ricerca semantica come l'incorporamento del corpus e della query in uno spazio vettoriale e il recupero di elementi con alta similarità semantica. La sua API attuale distingue anche la codifica della query dalla codifica dei documenti per i compiti di recupero.",{"data":458,"type":217},{"text":459},"SQLite FTS5 dimostra l'altro lato dello spettro: il recupero full-text maturo può classificare i documenti senza embeddings. Questo è importante perché la ricerca lessicale rimane preziosa per identificatori, terminologia esatta e molti design di recupero ibrido.",{"data":461,"type":217},{"text":462},"La documentazione sugli embeddings di OpenAI descrive gli embeddings come rappresentazioni vettoriali numeriche utilizzate per la correlazione e la ricerca. Questo è un percorso di implementazione per il recupero semantico, non la definizione di RAG stesso.",{"data":464,"type":42},{"text":465,"level":230},"Esempio reale 1: Una cartella di file di testo",{"data":467,"type":217},{"text":468},"Supponiamo che una directory chiamata \u003Ccode>knowledge\u002F\u003C\u002Fcode> contenga normali file di testo. Python può caricarli senza alcuna libreria AI.",{"data":470,"type":252},{"code":471},"from pathlib import Path\n\ndef load_text_files(folder=\"knowledge\"):\n    documents = []\n\n    for path in Path(folder).glob(\"*.txt\"):\n        documents.append({\n            \"source\": path.name,\n            \"text\": path.read_text(encoding=\"utf-8\")\n        })\n\n    return documents\n\ndocuments = load_text_files()\n\nfor document in documents:\n    print(document[\"source\"], len(document[\"text\"]))",{"data":473,"type":217},{"text":474},"Il filesystem è la fonte dati. La domanda successiva è quanto testo dovrebbe diventare un'unità recuperabile. Per documenti lunghi, cercare un intero file è spesso troppo grossolano. Ecco perché le pipeline RAG comunemente creano chunk.",{"data":476,"type":42},{"text":477,"level":478},"Un chunker molto semplice",3,{"data":480,"type":252},{"code":481},"def chunk_text(text, max_chars=800):\n    paragraphs = [p.strip() for p in text.split(\"\\n\\n\") if p.strip()]\n\n    chunks = []\n    current = \"\"\n\n    for paragraph in paragraphs:\n        candidate = f\"{current}\\n\\n{paragraph}\".strip()\n\n        if current and len(candidate) > max_chars:\n            chunks.append(current)\n            current = paragraph\n        else:\n            current = candidate\n\n    if current:\n        chunks.append(current)\n\n    return chunks",{"data":483,"type":217},{"text":484},"Questo esempio raggruppa i paragrafi fino a raggiungere un limite approssimativo di caratteri. È intenzionalmente comprensibile piuttosto che ottimale. I sistemi di produzione spesso suddividono per token, intestazioni, sezioni, confini di frase o struttura del documento. Tabelle, codice sorgente, contratti e documentazione API possono richiedere strategie diverse.",{"data":486,"type":42},{"text":487,"level":478},"Preservare la provenienza durante il chunking",{"data":489,"type":252},{"code":490},"def build_chunks(documents):\n    chunks = []\n\n    for document in documents:\n        for index, text in enumerate(chunk_text(document[\"text\"])):\n            chunks.append({\n                \"id\": f'{document[\"source\"]}:{index}',\n                \"source\": document[\"source\"],\n                \"chunk\": index,\n                \"text\": text,\n            })\n\n    return chunks",{"data":492,"type":217},{"text":493},"Un chunk utile porta con sé più del semplice testo. Nome della fonte, ID del documento, URL, timestamp, versione o sezione possono in seguito supportare citazioni, debug e controlli di aggiornamento. Se la provenienza viene persa durante l'ingestion, diventa molto più difficile spiegare perché è stata prodotta una particolare risposta.",{"data":495,"type":42},{"text":496,"level":230},"Esempio reale 2: Dati strutturati — Usa SQL quando SQL è lo strumento giusto",{"data":498,"type":217},{"text":499},"Non ogni fatto esterno dovrebbe passare attraverso la ricerca semantica. Se la domanda richiede un record corrente esatto, una query diretta al database è di solito più chiara e più deterministica.",{"data":501,"type":252},{"code":502},"import sqlite3\n\ndef get_order_status(order_id):\n    connection = sqlite3.connect(\"shop.db\")\n    cursor = connection.cursor()\n\n    cursor.execute(\n        \"SELECT status, total, currency FROM orders WHERE id = ?\",\n        (order_id,)\n    )\n\n    row = cursor.fetchone()\n    connection.close()\n\n    if row is None:\n        return None\n\n    return {\n        \"order_id\": order_id,\n        \"status\": row[0],\n        \"total\": row[1],\n        \"currency\": row[2],\n    }\n\nprint(get_order_status(4711))",{"data":504,"type":217},{"text":505},"Se l'applicazione sa già che l'utente sta chiedendo dell'ordine 4711, incorporare l'intera tabella degli ordini e chiedere alla ricerca semantica di riscoprire quella riga di solito aggiunge complessità senza benefici. Una buona regola di progettazione è: \u003Cb>recupera i fatti strutturati con query strutturate; recupera la conoscenza non strutturata con la ricerca.\u003C\u002Fb>",{"data":507,"type":217},{"text":508},"La riga del database restituita può comunque essere inserita nel contesto del modello, così che l'LLM possa spiegarla in linguaggio naturale. Ma l'accesso diretto allo stato o a un record è concettualmente diverso dalla ricerca in un corpus di conoscenza.",{"data":510,"type":42},{"text":511,"level":230},"Esempio reale 3: Ricerca full-text prima degli embedding",{"data":513,"type":217},{"text":514},"Tra un ingenuo ciclo Python e la ricerca vettoriale si colloca una classe matura di sistemi di recupero lessicale. SQLite include FTS5 per la ricerca full-text, incluso il ranking BM25.",{"data":516,"type":252},{"code":517},"import sqlite3\n\nconnection = sqlite3.connect(\"knowledge.db\")\ncursor = connection.cursor()\n\ncursor.execute(\n    \"CREATE VIRTUAL TABLE IF NOT EXISTS docs USING fts5(title, body)\"\n)\n\ncursor.execute(\n    \"INSERT INTO docs(title, body) VALUES (?, ?)\",\n    (\"AKM\", \"The AKM uses 7.62 mm ammunition.\")\n)\n\nconnection.commit()\n\nquery = \"AKM ammunition\"\n\nrows = cursor.execute(\n    \"SELECT title, body, bm25(docs) AS score \"\n    \"FROM docs WHERE docs MATCH ? \"\n    \"ORDER BY score LIMIT 5\",\n    (query,)\n).fetchall()\n\nfor row in rows:\n    print(row)\n\nconnection.close()",{"data":519,"type":217},{"text":520},"La ricerca lessicale è particolarmente utile quando contano terminologia esatta, codici prodotto, nomi, identificatori o parole specifiche del dominio. La ricerca semantica non è automaticamente migliore. I sistemi di produzione spesso combinano entrambi i segnali.",{"data":522,"type":42},{"text":523,"level":230},"Esempio reale 4: Recupero semantico con gli embedding",{"data":525,"type":217},{"text":526},"Gli embedding trasformano il testo in vettori numerici, così passaggi semanticamente correlati possono essere confrontati anche quando non usano una formulazione identica. Sentence Transformers fornisce un'implementazione locale semplice.",{"data":528,"type":252},{"code":529},"# pip install sentence-transformers\n\nfrom sentence_transformers import SentenceTransformer, util\n\ndocuments = [\n    \"The AKM uses 7.62 mm ammunition.\",\n    \"A Med Kit restores health.\",\n    \"Vehicle maintenance includes checking oil, brakes and tires.\",\n    \"Account recovery requires access to the registered email address.\"\n]\n\nmodel = SentenceTransformer(\n    \"sentence-transformers\u002Fmulti-qa-mpnet-base-cos-v1\"\n)\n\ndocument_embeddings = model.encode_document(\n    documents,\n    convert_to_tensor=True\n)\n\nquestion = \"How do I repair my car?\"\n\nquery_embedding = model.encode_query(\n    question,\n    convert_to_tensor=True\n)\n\nhits = util.semantic_search(\n    query_embedding,\n    document_embeddings,\n    top_k=2\n)[0]\n\nfor hit in hits:\n    print(round(float(hit[\"score\"]), 3), documents[hit[\"corpus_id\"]])",{"data":531,"type":217},{"text":532},"La query non contiene la frase “manutenzione del veicolo”, ma un modello semantico può comunque classificare quel passaggio in alto perché i concetti sono correlati. Questa è la ragione pratica per cui gli embedding sono comuni nei sistemi RAG.",{"data":534,"type":217},{"text":535},"Per piccole collezioni, gli embedding possono rimanere in memoria. I sistemi più grandi di solito li persistono in un indice o database compatibile con i vettori ed eseguono lì la ricerca del vicino più prossimo. La memorizzazione cambia, ma la logica rimane: codifica la domanda, trova le rappresentazioni rilevanti dei documenti, restituisci le prove migliori.",{"data":537,"type":42},{"text":538,"level":230},"Esempio reale 5: Costruire il contesto per l'LLM",{"data":540,"type":217},{"text":541},"Un retriever dovrebbe restituire delle prove. Il LLM dovrebbe quindi ricevere la domanda più quelle prove. Mantenere separati il recupero e la generazione rende entrambi più facili da ispezionare e testare.",{"data":543,"type":252},{"code":544},"def build_prompt(question, retrieved_documents):\n    context = \"\\n\\n\".join(\n        f'[{doc[\"id\"]}] {doc[\"text\"]}'\n        for doc in retrieved_documents\n    )\n\n    return f\"\"\"\nAnswer the question using the supplied context.\n\nRules:\n- Do not invent facts that are not supported by the context.\n- If the context is insufficient, say so.\n- Cite the source IDs you used.\n\nQuestion:\n{question}\n\nContext:\n{context}\n\"\"\".strip()",{"data":546,"type":217},{"text":547},"L'istruzione non rende il modello infallibile. Crea semplicemente un confine esplicito delle prove. Il modello può comunque fraintendere prove valide, ignorare una condizione o generalizzare eccessivamente. Ecco perché la qualità del recupero e la qualità della generazione devono essere valutate separatamente.",{"data":549,"type":42},{"text":550,"level":230},"Esempio reale 6: una pipeline minima completa",{"data":552,"type":252},{"code":553},"def answer_question(question, all_documents, call_llm):\n    # 1. Retrieve evidence\n    retrieved = retrieve(question, all_documents, top_k=3)\n\n    # 2. Build model context\n    prompt = build_prompt(question, retrieved)\n\n    # 3. Generate the answer\n    answer = call_llm(prompt)\n\n    return {\n        \"answer\": answer,\n        \"sources\": [doc[\"id\"] for doc in retrieved]\n    }",{"data":555,"type":217},{"text":556},"La funzione riceve \u003Ccode>call_llm\u003C\u002Fcode> come dipendenza di proposito. Il recupero non dovrebbe interessarsi se la generazione è eseguita da un modello cloud, un modello locale o un altro provider. Il percorso dei dati appartiene all'applicazione.",{"data":558,"type":42},{"text":559,"level":478},"Generatore opzionale: OpenAI Responses API",{"data":561,"type":217},{"text":562},"Un possibile generatore è l'OpenAI Responses API. Mantenere il nome del modello in una variabile d'ambiente evita di codificare in modo rigido un particolare modello nell'architettura RAG.",{"data":564,"type":252},{"code":565},"# pip install openai\n\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI()\n\ndef call_llm(prompt):\n    response = client.responses.create(\n        model=os.environ[\"OPENAI_MODEL\"],\n        input=prompt,\n    )\n    return response.output_text",{"data":567,"type":217},{"text":568},"La stessa pipeline di recupero può essere collegata a un server di inferenza locale. Questo è un punto architetturale importante: \u003Cb>il RAG non è di proprietà del provider del LLM.\u003C\u002Fb> L'applicazione possiede la fonte, il recupero e l'assemblaggio del contesto.",{"data":570,"type":42},{"text":571,"level":478},"L'intera architettura in una sola vista",{"data":573,"type":252},{"code":574},"USER QUESTION\n     |\n     v\n+-------------+\n|  Retriever  |\n+-------------+\n   |       |\n   |       +----> SQL \u002F API \u002F state query\n   |\n   +------------> keyword \u002F full-text search\n   |\n   +------------> embedding \u002F vector search\n                     |\n                     v\n              relevant evidence\n                     |\n                     v\n+-----------------------------------+\n| question + evidence + instructions |\n+-----------------------------------+\n                     |\n                     v\n                   LLM\n                     |\n                     v\n                  answer",{"data":576,"type":217},{"text":577},"Questo modello di flusso di dati è più duraturo che memorizzare un singolo framework. Le librerie, i database e i fornitori di modelli cambieranno; i confini delle responsabilità rimangono.",{"data":579,"type":42},{"text":580,"level":230},"Idee sbagliate comuni e modalità di fallimento",{"data":582,"type":42},{"text":583,"level":478},"“RAG significa database vettoriale.”",{"data":585,"type":217},{"text":586},"No. La ricerca vettoriale è un metodo di recupero. Il RAG può utilizzare ricerca full-text, SQL, API, grafi di conoscenza, ricerca vettoriale o combinazioni di essi. Il pattern che lo definisce è il recupero di informazioni esterne per la generazione.",{"data":588,"type":42},{"text":589,"level":478},"“Se i dati sono in PostgreSQL, devo incorporare l'intero database.”",{"data":591,"type":217},{"text":592},"No. I record strutturati dovrebbero di solito rimanere interrogabili come record strutturati. Gli embedding sono utili per la rilevanza semantica, non come sostituto delle query deterministiche.",{"data":594,"type":42},{"text":595,"level":478},"“Più chunk significa una risposta migliore.”",{"data":597,"type":217},{"text":598},"Non necessariamente. Un contesto extra può introdurre rumore, versioni in conflitto e materiale irrilevante. Il retrieval dovrebbe ottimizzare per prove utili, non per il volume massimo.",{"data":600,"type":42},{"text":601,"level":478},"“Un punteggio di similarità elevato dimostra la risposta.”",{"data":603,"type":217},{"text":604},"No. La similarità misura la rilevanza, non la verità o l'applicabilità. Un passaggio altamente simile può essere obsoleto, provenire dalla versione sbagliata del prodotto o essere valido solo in condizioni che non corrispondono alla domanda.",{"data":606,"type":42},{"text":607,"level":478},"“Una volta recuperato il chunk corretto, l'allucinazione è risolta.”",{"data":609,"type":217},{"text":610},"No. Il retrieval migliora il grounding ma non garantisce un ragionamento fedele. La generazione necessita comunque di valutazione, e i flussi di lavoro ad alto rischio possono richiedere validazione deterministica o revisione umana.",{"data":612,"type":42},{"text":613,"level":478},"“Il modello ha fallito, quindi cambia il modello.”",{"data":615,"type":217},{"text":616},"Non necessariamente. La fonte corretta potrebbe essere mancante, analizzata in modo errato, suddivisa male, filtrata, classificata troppo in basso o omessa dal contesto assemblato. La sostituzione del modello non dovrebbe essere il primo passo diagnostico.",{"data":618,"type":42},{"text":619,"level":230},"Casi limite",{"data":621,"type":357},{"items":622,"style":356},[623,624,625,626,627,628,629,630],"\u003Cb>Documenti in conflitto:\u003C\u002Fb> due fonti possono discordare perché versioni, giurisdizioni o prodotti differiscono.","\u003Cb>Fatti sensibili al tempo:\u003C\u002Fb> una fonte semanticamente rilevante può essere già obsoleta.","\u003Cb>Autorizzazioni:\u003C\u002Fb> un retriever non deve restituire documenti a cui l'utente corrente non è autorizzato ad accedere.","\u003Cb>Collezioni multilingua:\u003C\u002Fb> il modello di embedding e la strategia di retrieval devono supportare le lingue effettivamente utilizzate.","\u003Cb>Tabelle e codice sorgente:\u003C\u002Fb> il chunking a paragrafi semplici può distruggere la struttura essenziale per la risposta.","\u003Cb>Identificatori molto brevi:\u003C\u002Fb> il retrieval semantico può essere più debole della corrispondenza esatta per SKU, ID, codici di errore o acronimi.","\u003Cb>Domande lunghe che richiedono diversi fatti:\u003C\u002Fb> il retrieval può richiedere decomposizione, diverse ricerche o reranking invece di una singola query top-k.","\u003Cb>Gerarchia delle fonti:\u003C\u002Fb> una politica ufficiale corrente può dover prevalere su un documento di discussione più vecchio ma semanticamente più vicino.",{"data":632,"type":42},{"text":633,"level":230},"Limitazioni",{"data":635,"type":217},{"text":636},"Gli esempi Python ottimizzano intenzionalmente per la trasparenza, non per la scalabilità. Il retriever per parole chiave è ingenuo, il chunker utilizza la lunghezza in caratteri, gli esempi SQLite non includono la gestione delle connessioni di produzione e l'esempio semantico mantiene tutti gli embedding in memoria.",{"data":638,"type":217},{"text":639},"Un sistema di produzione può richiedere indici vettoriali, reranker, retrieval ibrido, parser di documenti, caching, indicizzazione incrementale, versioning delle fonti, filtri di controllo degli accessi, osservabilità, dataset di valutazione e gestione degli errori. Nessuna di queste aggiunte cambia l'architettura principale; rendono ogni confine più affidabile.",{"data":641,"type":217},{"text":642},"Il RAG inoltre non può creare prove assenti dall'insieme delle fonti. Se la fonte è sbagliata, incompleta o obsoleta, un modello di embedding migliore non può trasformarla in conoscenza autorevole.",{"data":644,"type":42},{"text":645,"level":230},"Cosa cambierebbe questa risposta?",{"data":647,"type":217},{"text":648},"L'architettura cambia quando il compito richiede più di una semplice ricerca di conoscenza. Uno stato dell'ordine in tempo reale necessita dello stato corrente. Un calcolo finanziario può richiedere codice deterministico. Un compito di ricerca web può richiedere ricerca attiva. Un flusso di lavoro può richiedere strumenti in grado di riscrivere dati su un altro sistema. Un agente autonomo può richiedere pianificazione, autorizzazioni e controllo dell'esecuzione oltre al retrieval.",{"data":650,"type":217},{"text":651},"Il RAG è quindi meglio inteso come \u003Cb>uno strato di acquisizione di prove all'interno di un sistema AI più ampio\u003C\u002Fb>. È potente proprio perché ha un compito ristretto: trovare informazioni esterne utili e collocarle nel contesto di lavoro del modello.",{"data":653,"type":42},{"text":654,"level":230},"Conclusione",{"data":656,"type":217},{"text":657},"RAG diventa molto più facile da capire quando si rimuovono i nomi delle tecnologie. Un file è una fonte. Un database è una fonte. Un'API è una fonte. Una funzione di ricerca recupera le prove. Un prompt porta quelle prove al modello. L'LLM le interpreta e produce linguaggio.",{"data":659,"type":217},{"text":660},"La parte difficile del RAG in produzione non è chiamare un modello di embedding. È costruire un percorso di prove affidabile dalla fonte originale all'affermazione finale: preservare la provenienza, selezionare il metodo di recupero giusto, mantenere le informazioni aggiornate, controllare l'accesso, valutare il recupero separatamente dalla generazione e sapere quando una chiamata diretta a un database o a uno strumento è meglio della ricerca semantica.",{"data":662,"type":217},{"text":663},"Questa è la continuazione pratica del modello RAG di base: \u003Cb>prima capire i ruoli, poi rendere esplicito il percorso dei dati.\u003C\u002Fb>",{"data":665,"type":42},{"text":666,"level":230},"Fonti primarie",{"data":668,"type":357},{"items":669,"style":356},[670,671,672,673,674,675],"\u003Ca href=\"https:\u002F\u002Farxiv.org\u002Fabs\u002F2005.11401\">Lewis et al. — Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks\u003C\u002Fa> — il paper del 2020 che introduce la formulazione RAG che combina la generazione con la memoria non parametrica recuperata.","\u003Ca href=\"https:\u002F\u002Fwww.sbert.net\u002Fexamples\u002Fsentence_transformer\u002Fapplications\u002Fsemantic-search\u002FREADME.html\">Sentence Transformers — Semantic Search\u003C\u002Fa> — documentazione ufficiale per il recupero semantico, gli embedding delle query e gli embedding dei documenti.","\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fembeddings\">OpenAI — Vector Embeddings\u003C\u002Fa> — documentazione ufficiale che descrive gli embedding come rappresentazioni numeriche usate per la correlazione e la ricerca.","\u003Ca href=\"https:\u002F\u002Fwww.sqlite.org\u002Ffts5.html\">SQLite — FTS5 Extension\u003C\u002Fa> — documentazione ufficiale per la ricerca full-text e il ranking BM25 in SQLite.","\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Flibraries\">OpenAI — SDKs and CLI\u003C\u002Fa> — esempio ufficiale dell'SDK Python per la Responses API usato nell'esempio opzionale del generatore.","\u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fit\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">What Is RAG? The Simplest Explanation of How It Works\u003C\u002Fa> — la prima parte concettuale di questa serie.","2.31","Un LLM non conosce magicamente i tuoi file, database o API. Questa continuazione pratica della serie RAG mostra, con semplice Python, come i dati esterni diventano prove recuperabili: dai file di testo e SQL alla ricerca full-text, agli embedding, all'assemblaggio del contesto e alla chiamata finale all'LLM.","\u002Fuploads\u002F2026\u002F09\u002Fwhere-does-an-llm-get-its-data-rag-data-sources-in-python-1790517200521-nfsi5i.webp","where-does-an-llm-get-its-data-rag-data-sources-in-python-1790517200521-nfsi5i","PUBLISHED","2026-09-27T09:51:00.000Z","2026-09-27T13:51:43.843Z","2026-09-27T13:58:03.762Z",{"en":685,"de":686,"sr":687,"es":688,"fr":689,"it":690,"ru":691,"zh":692},"\u002Fblog\u002Fwhere-does-an-llm-get-its-data-rag-data-sources-in-python","\u002Fde\u002Fblog\u002Fwhere-does-an-llm-get-its-data-rag-data-sources-in-python","\u002Fsr\u002Fblog\u002Fwhere-does-an-llm-get-its-data-rag-data-sources-in-python","\u002Fes\u002Fblog\u002Fwhere-does-an-llm-get-its-data-rag-data-sources-in-python","\u002Ffr\u002Fblog\u002Fwhere-does-an-llm-get-its-data-rag-data-sources-in-python","\u002Fit\u002Fblog\u002Fwhere-does-an-llm-get-its-data-rag-data-sources-in-python","\u002Fru\u002Fblog\u002Fwhere-does-an-llm-get-its-data-rag-data-sources-in-python","\u002Fzh\u002Fblog\u002Fwhere-does-an-llm-get-its-data-rag-data-sources-in-python",[],{"id":695,"login":696,"email":697,"displayName":698},"20","rooth8233","aleksandar@stajic.de","Aleksandar Stajić",[700,1147],{"lang":701,"title":702,"content":703,"contentJson":704,"excerpt":1146},"en","Where Does an LLM Get Its Data? RAG Data Sources in Python","{\"time\":1790516400000,\"blocks\":[{\"data\":{\"text\":\"The previous article, \u003Ca href=\\\"https:\u002F\u002Fstajic.de\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\\\">What Is RAG? The Simplest Explanation of How It Works\u003C\u002Fa>, established the mental model: the LLM writes, RAG retrieves useful knowledge, the application owns current state, and tools perform actions. This article takes the next step: \u003Cb>where does the data actually come from, and what does retrieval look like in Python?\u003C\u002Fb>\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"The important surprise is that an “LLM data source” is usually nothing exotic. It can be a text file, a folder of Markdown documents, a SQL database, an API response, a product catalog, a support system, or a vector index derived from those sources. The AI does not magically know these systems. Your application has to load, query, search, or retrieve the relevant data and place the result into the model’s context.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Data source = where information lives. Retrieval = how the application finds useful information. Context = the selected information given to the model. LLM = the component that interprets that context and generates an answer.\",\"caption\":\"The four-part model used throughout this article\",\"alignment\":\"left\"},\"type\":\"quote\"},{\"data\":{\"text\":\"Question\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"How does an LLM use external data such as files, databases or APIs, and how can a small Python program implement the essential RAG steps without hiding them behind a framework?\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"What This Really Means\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"When developers say that an LLM is “connected to company data,” several different operations may be hidden behind that sentence. One application may execute SQL. Another may call an API. Another may run full-text search. Another may calculate embedding similarity over document chunks. All of them can provide external information to an LLM, but they are not the same retrieval method and they should not be treated as interchangeable.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"This distinction matters because the best retrieval method depends on the shape of the question. “What is our refund policy?” is a document-retrieval problem. “What is order 4711’s current status?” is usually a structured database lookup. “Which paragraph discusses account recovery?” can be keyword or semantic search. RAG is most useful when the system must \u003Cb>discover relevant knowledge before generation\u003C\u002Fb>.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Simplest Example\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"Start with three strings in ordinary Python. There is no vector database, no framework, and no LLM yet. We only want to make the retrieval step visible.\"},\"type\":\"paragraph\"},{\"data\":{\"code\":\"documents = [\\n    \\\"The AKM uses 7.62 mm ammunition.\\\",\\n    \\\"A Med Kit restores health.\\\",\\n    \\\"A 4x scope can be attached to several compatible weapons.\\\"\\n]\\n\\nquestion = \\\"Which ammunition does the AKM use?\\\"\\n\\nfor document in documents:\\n    if \\\"AKM\\\" in document:\\n        print(document)\"},\"type\":\"code\"},{\"data\":{\"text\":\"The program prints the first sentence because it contains the term we searched for. This is primitive retrieval, but the architecture is already visible: \u003Cb>question → search → relevant text\u003C\u002Fb>. RAG adds one more major step: pass the retrieved text to a language model together with the question.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"A slightly more general version ranks documents by overlapping query terms:\"},\"type\":\"paragraph\"},{\"data\":{\"code\":\"import re\\n\\ndocuments = [\\n    {\\\"id\\\": \\\"weapon-akm\\\", \\\"text\\\": \\\"The AKM uses 7.62 mm ammunition.\\\"},\\n    {\\\"id\\\": \\\"healing-medkit\\\", \\\"text\\\": \\\"A Med Kit restores health.\\\"},\\n    {\\\"id\\\": \\\"scope-4x\\\", \\\"text\\\": \\\"A 4x scope can be attached to several compatible weapons.\\\"},\\n]\\n\\ndef words(text):\\n    return set(re.findall(r\\\"[a-zA-Z0-9.]+\\\", text.lower()))\\n\\ndef retrieve(question, documents, top_k=2):\\n    query_terms = words(question)\\n    ranked = []\\n\\n    for document in documents:\\n        score = len(query_terms & words(document[\\\"text\\\"]))\\n        if score > 0:\\n            ranked.append((score, document))\\n\\n    ranked.sort(key=lambda item: item[0], reverse=True)\\n    return [document for _, document in ranked[:top_k]]\\n\\nquestion = \\\"Which ammunition does the AKM use?\\\"\\nhits = retrieve(question, documents)\\n\\nfor hit in hits:\\n    print(hit[\\\"id\\\"], \\\"->\\\", hit[\\\"text\\\"])\"},\"type\":\"code\"},{\"data\":{\"text\":\"This is not a production search engine. It ignores morphology, synonyms, spelling variants, document length and many ranking signals. Its value is educational: \u003Cb>RAG does not begin with a vector database. It begins with retrieval.\u003C\u002Fb>\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Where the Example Stops Working\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"Exact or lexical matching becomes weak when the question and the source use different words. A document may say “vehicle maintenance,” while the user asks “how do I repair my car?” A lexical retriever can miss the relationship even though a human sees it immediately. Semantic retrieval addresses this by representing text as vectors and comparing meaning rather than only exact tokens.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Long files create another problem. Searching an entire 80-page manual as one unit is too coarse, but splitting every sentence can destroy useful context. Real RAG systems therefore need decisions about parsing, chunking, metadata, ranking, freshness, permissions and provenance.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"The example also says nothing about structured live facts. If the user asks for the current status of order 4711 and the application already has a database key, semantic search is usually the wrong first tool. A deterministic database query is better.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Direct Answer\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"An LLM data source is any external system from which an application can obtain information for the model: files, databases, APIs, search indexes, vector stores or live application state. RAG is the pattern of \u003Cb>retrieving relevant knowledge from such sources before generation\u003C\u002Fb>.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"In Python, the essential pipeline can be very small: \u003Cb>load data → create retrievable units → find relevant evidence → assemble context → call the LLM\u003C\u002Fb>. The retrieval method should match the source and the question. Use SQL for exact structured facts, full-text search for lexical matching, embeddings for semantic similarity, and hybrid retrieval when several signals are valuable.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Why This Is So\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"A language model does not automatically receive the contents of your filesystem, PostgreSQL database, CRM, private API or newly edited document. The application decides what external information is accessible and what is placed into the model’s current context.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"The original Retrieval-Augmented Generation work by Lewis et al. combined a generative model with external non-parametric memory retrieved from a dense vector index. The broader architectural idea survives beyond that specific implementation: external evidence can be retrieved at inference time instead of expecting all useful knowledge to be encoded in model parameters.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"This creates a useful separation of responsibilities: the source stores information, the retriever selects evidence, the context carries that evidence into the request, and the model interprets it. Keeping those boundaries visible makes failures much easier to diagnose.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Context: The Main Types of Data Sources\",\"level\":2},\"type\":\"header\"},{\"data\":{\"content\":[[\"Source\",\"Typical retrieval method\",\"Good for\"],[\"TXT \u002F Markdown \u002F HTML\",\"Parsing + lexical or semantic search\",\"Documentation, manuals, articles, notes\"],[\"PDF \u002F DOCX\",\"Structure-aware extraction + search\",\"Policies, reports, contracts, manuals\"],[\"SQL database\",\"SQL query or filtered retrieval\",\"Orders, users, products, structured records\"],[\"REST \u002F GraphQL API\",\"HTTP request with parameters\",\"Remote systems and live service data\"],[\"Search index\",\"BM25 \u002F full-text \u002F hybrid search\",\"Large text collections\"],[\"Vector index\",\"Embedding similarity\",\"Semantic document retrieval\"],[\"Application state\",\"Direct state read or tool call\",\"What is true right now\"]],\"withHeadings\":true},\"type\":\"table\"},{\"data\":{\"text\":\"A vector index deserves special attention. In many architectures it is \u003Cb>not the canonical source of truth\u003C\u002Fb>. It is a retrieval index derived from documents or records. The authoritative document may live in object storage, a CMS, Git, PostgreSQL or another system, while embeddings and metadata are stored separately for fast semantic lookup. Some systems do use a vector store as primary storage, but that is an architectural choice rather than a requirement of RAG.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"If the boundary between retrieval, persistent memory, current state and model context is still unclear, see \u003Ca href=\\\"https:\u002F\u002Fstajic.de\u002Fblog\u002Fai-agent-memory-is-not-rag-how-to-separate-memory-retrieval-state-and-context\\\">AI Agent Memory Is Not RAG\u003C\u002Fa>. Those layers can use some of the same storage technologies while still having different correctness rules.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Assumptions\",\"level\":2},\"type\":\"header\"},{\"data\":{\"items\":[\"The application is allowed to access the external source.\",\"The relevant source contains enough information to answer the question.\",\"The data can be parsed or queried in a form the retrieval layer can use.\",\"The retrieved information is fresh enough for the requested decision.\",\"The model receives the selected evidence in its context.\",\"Authorization is enforced before protected evidence reaches the model.\",\"The generation model can still be wrong even when retrieval is correct.\"],\"style\":\"unordered\"},\"type\":\"list\"},{\"data\":{\"text\":\"These assumptions matter because retrieval cannot compensate for missing evidence, stale source versions, broken parsers or unauthorized access. A RAG pipeline can only be as trustworthy as the evidence path that feeds it.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Variables\",\"level\":2},\"type\":\"header\"},{\"data\":{\"content\":[[\"Variable\",\"Why it changes the design\"],[\"Source structure\",\"A SQL table, legal PDF and source-code repository need different retrieval strategies\"],[\"Question type\",\"Exact lookup, conceptual search and multi-hop research are different tasks\"],[\"Freshness requirement\",\"Live state may need direct queries instead of periodically rebuilt indexes\"],[\"Corpus size\",\"In-memory search may work for hundreds of chunks but not for very large collections\"],[\"Language\",\"Multilingual retrieval requires models and tokenization suitable for the actual languages\"],[\"Permissions\",\"Retrieval must filter by the current user’s access rights\"],[\"Latency and cost\",\"More retrieval stages can improve quality but add runtime and infrastructure cost\"],[\"Need for provenance\",\"High-trust systems need source IDs, versions and traceable evidence\"]],\"withHeadings\":true},\"type\":\"table\"},{\"data\":{\"text\":\"Diagnostic \u002F Decision Method\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"The first decision is not “Which vector database should I install?” It is: \u003Cb>What kind of fact am I trying to retrieve?\u003C\u002Fb>\"},\"type\":\"paragraph\"},{\"data\":{\"content\":[[\"Question type\",\"Preferred first approach\",\"Reason\"],[\"Exact ID or current record\",\"SQL \u002F key lookup \u002F API\",\"Deterministic structured access\"],[\"Exact wording, codes, names\",\"Full-text or keyword search\",\"Lexical precision\"],[\"Conceptual question over documents\",\"Semantic vector search\",\"Meaning can differ from wording\"],[\"Mixed enterprise knowledge\",\"Hybrid retrieval + metadata filters\",\"Combines lexical and semantic signals\"],[\"Current application state\",\"Direct state\u002Ftool access\",\"Freshness matters more than document similarity\"]],\"withHeadings\":true},\"type\":\"table\"},{\"data\":{\"text\":\"A useful test is: \u003Cb>Do I already know which record I need, or must the system discover which passage is relevant?\u003C\u002Fb> If the record is known, query it directly. If relevance must be discovered, search becomes more important.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"When an answer is wrong, diagnose the pipeline in order instead of immediately changing the LLM:\"},\"type\":\"paragraph\"},{\"data\":{\"items\":[\"\u003Cb>1. Source coverage:\u003C\u002Fb> Does the correct information exist in the accessible source set?\",\"\u003Cb>2. Freshness:\u003C\u002Fb> Is that version current enough for the question?\",\"\u003Cb>3. Parsing:\u003C\u002Fb> Was the relevant content extracted correctly?\",\"\u003Cb>4. Chunking:\u003C\u002Fb> Did the evidence stay together with the conditions that give it meaning?\",\"\u003Cb>5. Retrieval:\u003C\u002Fb> Does the correct chunk appear among the candidates?\",\"\u003Cb>6. Ranking:\u003C\u002Fb> Are stronger sources ranked above weaker or conflicting ones?\",\"\u003Cb>7. Context assembly:\u003C\u002Fb> Did the application actually send the selected evidence to the model?\",\"\u003Cb>8. Generation:\u003C\u002Fb> Did the LLM faithfully use the supplied evidence?\",\"\u003Cb>9. Attribution:\u003C\u002Fb> Can each important claim be traced to a source?\"],\"style\":\"ordered\"},\"type\":\"list\"},{\"data\":{\"text\":\"For a deeper production-debugging method, see \u003Ca href=\\\"https:\u002F\u002Fstajic.de\u002Fblog\u002Frag-failed-but-which-layer-actually-failed-a-diagnostic-method\\\">RAG Failed — But Which Layer Actually Failed? A Diagnostic Method\u003C\u002Fa>, which expands this chain into independently testable failure layers.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Evidence\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"The RAG paper by Lewis et al. formalized generation that conditions on retrieved external memory rather than relying only on model parameters. That provides the conceptual foundation for separating the generator from a retrievable knowledge source.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Sentence Transformers documents semantic search as embedding the corpus and the query into a vector space and retrieving items with high semantic similarity. Its current API also distinguishes query encoding from document encoding for retrieval tasks.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"SQLite FTS5 demonstrates the other side of the spectrum: mature full-text retrieval can rank documents without embeddings. This matters because lexical search remains valuable for identifiers, exact terminology and many hybrid retrieval designs.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"OpenAI’s embeddings documentation describes embeddings as numerical vector representations used for relatedness and search. This is one implementation path for semantic retrieval, not the definition of RAG itself.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Real Example 1: A Folder of Text Files\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"Suppose a directory named \u003Ccode>knowledge\u002F\u003C\u002Fcode> contains ordinary text files. Python can load them with no AI library at all.\"},\"type\":\"paragraph\"},{\"data\":{\"code\":\"from pathlib import Path\\n\\ndef load_text_files(folder=\\\"knowledge\\\"):\\n    documents = []\\n\\n    for path in Path(folder).glob(\\\"*.txt\\\"):\\n        documents.append({\\n            \\\"source\\\": path.name,\\n            \\\"text\\\": path.read_text(encoding=\\\"utf-8\\\")\\n        })\\n\\n    return documents\\n\\ndocuments = load_text_files()\\n\\nfor document in documents:\\n    print(document[\\\"source\\\"], len(document[\\\"text\\\"]))\"},\"type\":\"code\"},{\"data\":{\"text\":\"The filesystem is the data source. The next question is how much text should become one retrievable unit. For long documents, searching one complete file is often too coarse. This is why RAG pipelines commonly create chunks.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"A Very Simple Chunker\",\"level\":3},\"type\":\"header\"},{\"data\":{\"code\":\"def chunk_text(text, max_chars=800):\\n    paragraphs = [p.strip() for p in text.split(\\\"\\\\n\\\\n\\\") if p.strip()]\\n\\n    chunks = []\\n    current = \\\"\\\"\\n\\n    for paragraph in paragraphs:\\n        candidate = f\\\"{current}\\\\n\\\\n{paragraph}\\\".strip()\\n\\n        if current and len(candidate) > max_chars:\\n            chunks.append(current)\\n            current = paragraph\\n        else:\\n            current = candidate\\n\\n    if current:\\n        chunks.append(current)\\n\\n    return chunks\"},\"type\":\"code\"},{\"data\":{\"text\":\"This example groups paragraphs until a rough character limit is reached. It is intentionally understandable rather than optimal. Production systems often chunk by tokens, headings, sections, sentence boundaries or document structure. Tables, source code, contracts and API documentation may need different strategies.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Preserve Provenance While Chunking\",\"level\":3},\"type\":\"header\"},{\"data\":{\"code\":\"def build_chunks(documents):\\n    chunks = []\\n\\n    for document in documents:\\n        for index, text in enumerate(chunk_text(document[\\\"text\\\"])):\\n            chunks.append({\\n                \\\"id\\\": f'{document[\\\"source\\\"]}:{index}',\\n                \\\"source\\\": document[\\\"source\\\"],\\n                \\\"chunk\\\": index,\\n                \\\"text\\\": text,\\n            })\\n\\n    return chunks\"},\"type\":\"code\"},{\"data\":{\"text\":\"A useful chunk carries more than text. Source name, document ID, URL, timestamp, version or section can later support citation, debugging and freshness checks. If provenance is lost during ingestion, it becomes much harder to explain why a particular answer was produced.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Real Example 2: Structured Data — Use SQL When SQL Is the Right Tool\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"Not every external fact should go through semantic search. If the question asks for an exact current record, a direct database query is usually clearer and more deterministic.\"},\"type\":\"paragraph\"},{\"data\":{\"code\":\"import sqlite3\\n\\ndef get_order_status(order_id):\\n    connection = sqlite3.connect(\\\"shop.db\\\")\\n    cursor = connection.cursor()\\n\\n    cursor.execute(\\n        \\\"SELECT status, total, currency FROM orders WHERE id = ?\\\",\\n        (order_id,)\\n    )\\n\\n    row = cursor.fetchone()\\n    connection.close()\\n\\n    if row is None:\\n        return None\\n\\n    return {\\n        \\\"order_id\\\": order_id,\\n        \\\"status\\\": row[0],\\n        \\\"total\\\": row[1],\\n        \\\"currency\\\": row[2],\\n    }\\n\\nprint(get_order_status(4711))\"},\"type\":\"code\"},{\"data\":{\"text\":\"If the application already knows that the user is asking about order 4711, embedding the entire orders table and asking semantic search to rediscover that row usually adds complexity without benefit. A strong design rule is: \u003Cb>retrieve structured facts with structured queries; retrieve unstructured knowledge with search.\u003C\u002Fb>\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"The returned database row can still be placed into the model context so the LLM can explain it in natural language. But direct state or record access is conceptually different from searching a knowledge corpus.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Real Example 3: Full-Text Search Before Embeddings\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"Between a naive Python loop and vector search lies a mature class of lexical retrieval systems. SQLite includes FTS5 for full-text search, including BM25 ranking.\"},\"type\":\"paragraph\"},{\"data\":{\"code\":\"import sqlite3\\n\\nconnection = sqlite3.connect(\\\"knowledge.db\\\")\\ncursor = connection.cursor()\\n\\ncursor.execute(\\n    \\\"CREATE VIRTUAL TABLE IF NOT EXISTS docs USING fts5(title, body)\\\"\\n)\\n\\ncursor.execute(\\n    \\\"INSERT INTO docs(title, body) VALUES (?, ?)\\\",\\n    (\\\"AKM\\\", \\\"The AKM uses 7.62 mm ammunition.\\\")\\n)\\n\\nconnection.commit()\\n\\nquery = \\\"AKM ammunition\\\"\\n\\nrows = cursor.execute(\\n    \\\"SELECT title, body, bm25(docs) AS score \\\"\\n    \\\"FROM docs WHERE docs MATCH ? \\\"\\n    \\\"ORDER BY score LIMIT 5\\\",\\n    (query,)\\n).fetchall()\\n\\nfor row in rows:\\n    print(row)\\n\\nconnection.close()\"},\"type\":\"code\"},{\"data\":{\"text\":\"Lexical search is especially useful when exact terminology, product codes, names, identifiers or domain-specific words matter. Semantic search is not automatically better. Production systems often combine both signals.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Real Example 4: Semantic Retrieval With Embeddings\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"Embeddings turn text into numerical vectors so semantically related passages can be compared even when they do not use identical wording. Sentence Transformers provides a straightforward local implementation.\"},\"type\":\"paragraph\"},{\"data\":{\"code\":\"# pip install sentence-transformers\\n\\nfrom sentence_transformers import SentenceTransformer, util\\n\\ndocuments = [\\n    \\\"The AKM uses 7.62 mm ammunition.\\\",\\n    \\\"A Med Kit restores health.\\\",\\n    \\\"Vehicle maintenance includes checking oil, brakes and tires.\\\",\\n    \\\"Account recovery requires access to the registered email address.\\\"\\n]\\n\\nmodel = SentenceTransformer(\\n    \\\"sentence-transformers\u002Fmulti-qa-mpnet-base-cos-v1\\\"\\n)\\n\\ndocument_embeddings = model.encode_document(\\n    documents,\\n    convert_to_tensor=True\\n)\\n\\nquestion = \\\"How do I repair my car?\\\"\\n\\nquery_embedding = model.encode_query(\\n    question,\\n    convert_to_tensor=True\\n)\\n\\nhits = util.semantic_search(\\n    query_embedding,\\n    document_embeddings,\\n    top_k=2\\n)[0]\\n\\nfor hit in hits:\\n    print(round(float(hit[\\\"score\\\"]), 3), documents[hit[\\\"corpus_id\\\"]])\"},\"type\":\"code\"},{\"data\":{\"text\":\"The query does not contain the phrase “vehicle maintenance,” but a semantic model can still rank that passage highly because the concepts are related. This is the practical reason embeddings are common in RAG systems.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"For small collections, embeddings can stay in memory. Larger systems usually persist them in a vector-capable index or database and perform nearest-neighbor search there. The storage changes, but the logic remains: encode the question, find relevant document representations, return the best evidence.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Real Example 5: Build the Context for the LLM\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"A retriever should return evidence. The LLM should then receive the question plus that evidence. Keeping retrieval and generation separate makes both easier to inspect and test.\"},\"type\":\"paragraph\"},{\"data\":{\"code\":\"def build_prompt(question, retrieved_documents):\\n    context = \\\"\\\\n\\\\n\\\".join(\\n        f'[{doc[\\\"id\\\"]}] {doc[\\\"text\\\"]}'\\n        for doc in retrieved_documents\\n    )\\n\\n    return f\\\"\\\"\\\"\\nAnswer the question using the supplied context.\\n\\nRules:\\n- Do not invent facts that are not supported by the context.\\n- If the context is insufficient, say so.\\n- Cite the source IDs you used.\\n\\nQuestion:\\n{question}\\n\\nContext:\\n{context}\\n\\\"\\\"\\\".strip()\"},\"type\":\"code\"},{\"data\":{\"text\":\"The instruction does not make the model infallible. It simply creates an explicit evidence boundary. The model can still misunderstand good evidence, ignore a condition or overgeneralize. That is why retrieval quality and generation quality must be evaluated separately.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Real Example 6: A Complete Minimal Pipeline\",\"level\":2},\"type\":\"header\"},{\"data\":{\"code\":\"def answer_question(question, all_documents, call_llm):\\n    # 1. Retrieve evidence\\n    retrieved = retrieve(question, all_documents, top_k=3)\\n\\n    # 2. Build model context\\n    prompt = build_prompt(question, retrieved)\\n\\n    # 3. Generate the answer\\n    answer = call_llm(prompt)\\n\\n    return {\\n        \\\"answer\\\": answer,\\n        \\\"sources\\\": [doc[\\\"id\\\"] for doc in retrieved]\\n    }\"},\"type\":\"code\"},{\"data\":{\"text\":\"The function receives \u003Ccode>call_llm\u003C\u002Fcode> as a dependency on purpose. Retrieval should not care whether generation is performed by a cloud model, a local model or another provider. The data path belongs to the application.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Optional Generator: OpenAI Responses API\",\"level\":3},\"type\":\"header\"},{\"data\":{\"text\":\"One possible generator is the OpenAI Responses API. Keeping the model name in an environment variable avoids hard-coding a particular model into the RAG architecture.\"},\"type\":\"paragraph\"},{\"data\":{\"code\":\"# pip install openai\\n\\nimport os\\nfrom openai import OpenAI\\n\\nclient = OpenAI()\\n\\ndef call_llm(prompt):\\n    response = client.responses.create(\\n        model=os.environ[\\\"OPENAI_MODEL\\\"],\\n        input=prompt,\\n    )\\n    return response.output_text\"},\"type\":\"code\"},{\"data\":{\"text\":\"The same retrieval pipeline can be connected to a local inference server. This is an important architectural point: \u003Cb>RAG is not owned by the LLM provider.\u003C\u002Fb> The application owns the source, retrieval and context assembly.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"The Whole Architecture in One View\",\"level\":3},\"type\":\"header\"},{\"data\":{\"code\":\"USER QUESTION\\n     |\\n     v\\n+-------------+\\n|  Retriever  |\\n+-------------+\\n   |       |\\n   |       +----> SQL \u002F API \u002F state query\\n   |\\n   +------------> keyword \u002F full-text search\\n   |\\n   +------------> embedding \u002F vector search\\n                     |\\n                     v\\n              relevant evidence\\n                     |\\n                     v\\n+-----------------------------------+\\n| question + evidence + instructions |\\n+-----------------------------------+\\n                     |\\n                     v\\n                   LLM\\n                     |\\n                     v\\n                  answer\"},\"type\":\"code\"},{\"data\":{\"text\":\"This data-flow model is more durable than memorizing one framework. Libraries, databases and model vendors will change; the responsibility boundaries remain.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Common Misconceptions and Failure Modes\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"“RAG means vector database.”\",\"level\":3},\"type\":\"header\"},{\"data\":{\"text\":\"No. Vector search is one retrieval method. RAG can use full-text search, SQL, APIs, knowledge graphs, vector search or combinations of them. The defining pattern is retrieval of external information for generation.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"“If the data is in PostgreSQL, I must embed the whole database.”\",\"level\":3},\"type\":\"header\"},{\"data\":{\"text\":\"No. Structured records should usually remain queryable as structured records. Embeddings are useful for semantic relevance, not as a replacement for deterministic queries.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"“More chunks means a better answer.”\",\"level\":3},\"type\":\"header\"},{\"data\":{\"text\":\"Not necessarily. Extra context can introduce noise, conflicting versions and irrelevant material. Retrieval should optimize for useful evidence, not maximum volume.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"“A high similarity score proves the answer.”\",\"level\":3},\"type\":\"header\"},{\"data\":{\"text\":\"No. Similarity measures relevance, not truth or applicability. A highly similar passage can be outdated, from the wrong product version or valid only under conditions that do not match the question.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"“Once the correct chunk is retrieved, hallucination is solved.”\",\"level\":3},\"type\":\"header\"},{\"data\":{\"text\":\"No. Retrieval improves grounding but does not guarantee faithful reasoning. Generation still needs evaluation, and high-risk workflows may require deterministic validation or human review.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"“The model failed, so change the model.”\",\"level\":3},\"type\":\"header\"},{\"data\":{\"text\":\"Not necessarily. The correct source may have been missing, parsed incorrectly, split badly, filtered out, ranked too low or omitted from the assembled context. Model replacement should not be the first diagnostic step.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Edge Cases\",\"level\":2},\"type\":\"header\"},{\"data\":{\"items\":[\"\u003Cb>Conflicting documents:\u003C\u002Fb> two sources may disagree because versions, jurisdictions or products differ.\",\"\u003Cb>Time-sensitive facts:\u003C\u002Fb> a semantically relevant source may already be stale.\",\"\u003Cb>Permissions:\u003C\u002Fb> a retriever must not return documents the current user is not authorized to access.\",\"\u003Cb>Multi-language collections:\u003C\u002Fb> the embedding model and retrieval strategy must support the languages actually used.\",\"\u003Cb>Tables and source code:\u003C\u002Fb> plain paragraph chunking can destroy structure that is essential to the answer.\",\"\u003Cb>Very short identifiers:\u003C\u002Fb> semantic retrieval can be weaker than exact matching for SKUs, IDs, error codes or acronyms.\",\"\u003Cb>Long questions requiring several facts:\u003C\u002Fb> retrieval may need decomposition, several searches or reranking rather than one top-k query.\",\"\u003Cb>Source hierarchy:\u003C\u002Fb> an official current policy may need to outrank an older but semantically closer discussion document.\"],\"style\":\"unordered\"},\"type\":\"list\"},{\"data\":{\"text\":\"Limitations\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"The Python examples intentionally optimize for transparency, not scale. The keyword retriever is naive, the chunker uses character length, the SQLite examples do not include production connection management, and the semantic example keeps all embeddings in memory.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"A production system may require vector indexes, rerankers, hybrid retrieval, document parsers, caching, incremental indexing, source versioning, access-control filters, observability, evaluation datasets and failure handling. None of those additions change the core architecture; they make each boundary more reliable.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"RAG also cannot create evidence that is absent from the source set. If the source is wrong, incomplete or stale, a better embedding model cannot turn it into authoritative knowledge.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"What Would Change This Answer?\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"The architecture changes when the task requires more than knowledge lookup. A live order status needs current state. A financial calculation may need deterministic code. A web-research task may need active search. A workflow may need tools that can write data back to another system. An autonomous agent may need planning, permissions and execution control in addition to retrieval.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"RAG is therefore best understood as \u003Cb>one evidence-acquisition layer inside a larger AI system\u003C\u002Fb>. It is powerful precisely because it has a narrow job: find useful external information and place it in the model’s working context.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Conclusion\",\"level\":2},\"type\":\"header\"},{\"data\":{\"text\":\"RAG becomes much easier to understand when the technology names are removed. A file is a source. A database is a source. An API is a source. A search function retrieves evidence. A prompt carries that evidence to the model. The LLM then interprets it and produces language.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"The hard part of production RAG is not calling an embedding model. It is building a trustworthy evidence path from the original source to the final claim: preserving provenance, selecting the right retrieval method, keeping information current, controlling access, evaluating retrieval separately from generation, and knowing when a direct database or tool call is better than semantic search.\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"That is the practical continuation of the basic RAG model: \u003Cb>first understand the roles, then make the data path explicit.\u003C\u002Fb>\"},\"type\":\"paragraph\"},{\"data\":{\"text\":\"Primary Sources\",\"level\":2},\"type\":\"header\"},{\"data\":{\"items\":[\"\u003Ca href=\\\"https:\u002F\u002Farxiv.org\u002Fabs\u002F2005.11401\\\">Lewis et al. — Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks\u003C\u002Fa> — the 2020 paper introducing the RAG formulation that combines generation with retrieved non-parametric memory.\",\"\u003Ca href=\\\"https:\u002F\u002Fwww.sbert.net\u002Fexamples\u002Fsentence_transformer\u002Fapplications\u002Fsemantic-search\u002FREADME.html\\\">Sentence Transformers — Semantic Search\u003C\u002Fa> — official documentation for semantic retrieval, query embeddings and document embeddings.\",\"\u003Ca href=\\\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fembeddings\\\">OpenAI — Vector Embeddings\u003C\u002Fa> — official documentation describing embeddings as numerical representations used for relatedness and search.\",\"\u003Ca href=\\\"https:\u002F\u002Fwww.sqlite.org\u002Ffts5.html\\\">SQLite — FTS5 Extension\u003C\u002Fa> — official documentation for full-text search and BM25 ranking in SQLite.\",\"\u003Ca href=\\\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Flibraries\\\">OpenAI — SDKs and CLI\u003C\u002Fa> — official Python SDK example for the Responses API used in the optional generator example.\",\"\u003Ca href=\\\"https:\u002F\u002Fstajic.de\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\\\">What Is RAG? The Simplest Explanation of How It Works\u003C\u002Fa> — the conceptual first part of this series.\"],\"style\":\"unordered\"},\"type\":\"list\"}],\"version\":\"2.31.0\"}",{"time":705,"blocks":706,"version":1145},1790516400000,[707,710,713,717,720,723,726,729,732,735,738,740,743,746,748,751,754,757,760,763,766,769,772,775,778,781,784,787,820,823,826,829,839,842,845,875,878,881,907,910,913,925,928,931,934,937,940,943,946,949,951,954,957,959,962,965,967,970,973,976,978,981,984,987,990,992,995,998,1001,1003,1006,1009,1012,1015,1017,1020,1023,1025,1028,1031,1034,1036,1039,1042,1044,1047,1050,1053,1056,1059,1062,1065,1068,1071,1074,1077,1080,1083,1086,1089,1100,1103,1106,1109,1112,1115,1118,1121,1124,1127,1130,1133,1136],{"data":708,"type":217},{"text":709},"The previous article, \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">What Is RAG? The Simplest Explanation of How It Works\u003C\u002Fa>, established the mental model: the LLM writes, RAG retrieves useful knowledge, the application owns current state, and tools perform actions. This article takes the next step: \u003Cb>where does the data actually come from, and what does retrieval look like in Python?\u003C\u002Fb>",{"data":711,"type":217},{"text":712},"The important surprise is that an “LLM data source” is usually nothing exotic. It can be a text file, a folder of Markdown documents, a SQL database, an API response, a product catalog, a support system, or a vector index derived from those sources. The AI does not magically know these systems. Your application has to load, query, search, or retrieve the relevant data and place the result into the model’s context.",{"data":714,"type":226},{"text":715,"caption":716,"alignment":225},"Data source = where information lives. Retrieval = how the application finds useful information. Context = the selected information given to the model. LLM = the component that interprets that context and generates an answer.","The four-part model used throughout this article",{"data":718,"type":42},{"text":719,"level":230},"Question",{"data":721,"type":217},{"text":722},"How does an LLM use external data such as files, databases or APIs, and how can a small Python program implement the essential RAG steps without hiding them behind a framework?",{"data":724,"type":42},{"text":725,"level":230},"What This Really Means",{"data":727,"type":217},{"text":728},"When developers say that an LLM is “connected to company data,” several different operations may be hidden behind that sentence. One application may execute SQL. Another may call an API. Another may run full-text search. Another may calculate embedding similarity over document chunks. All of them can provide external information to an LLM, but they are not the same retrieval method and they should not be treated as interchangeable.",{"data":730,"type":217},{"text":731},"This distinction matters because the best retrieval method depends on the shape of the question. “What is our refund policy?” is a document-retrieval problem. “What is order 4711’s current status?” is usually a structured database lookup. “Which paragraph discusses account recovery?” can be keyword or semantic search. RAG is most useful when the system must \u003Cb>discover relevant knowledge before generation\u003C\u002Fb>.",{"data":733,"type":42},{"text":734,"level":230},"Simplest Example",{"data":736,"type":217},{"text":737},"Start with three strings in ordinary Python. There is no vector database, no framework, and no LLM yet. We only want to make the retrieval step visible.",{"data":739,"type":252},{"code":251},{"data":741,"type":217},{"text":742},"The program prints the first sentence because it contains the term we searched for. This is primitive retrieval, but the architecture is already visible: \u003Cb>question → search → relevant text\u003C\u002Fb>. RAG adds one more major step: pass the retrieved text to a language model together with the question.",{"data":744,"type":217},{"text":745},"A slightly more general version ranks documents by overlapping query terms:",{"data":747,"type":252},{"code":261},{"data":749,"type":217},{"text":750},"This is not a production search engine. It ignores morphology, synonyms, spelling variants, document length and many ranking signals. Its value is educational: \u003Cb>RAG does not begin with a vector database. It begins with retrieval.\u003C\u002Fb>",{"data":752,"type":42},{"text":753,"level":230},"Where the Example Stops Working",{"data":755,"type":217},{"text":756},"Exact or lexical matching becomes weak when the question and the source use different words. A document may say “vehicle maintenance,” while the user asks “how do I repair my car?” A lexical retriever can miss the relationship even though a human sees it immediately. Semantic retrieval addresses this by representing text as vectors and comparing meaning rather than only exact tokens.",{"data":758,"type":217},{"text":759},"Long files create another problem. Searching an entire 80-page manual as one unit is too coarse, but splitting every sentence can destroy useful context. Real RAG systems therefore need decisions about parsing, chunking, metadata, ranking, freshness, permissions and provenance.",{"data":761,"type":217},{"text":762},"The example also says nothing about structured live facts. If the user asks for the current status of order 4711 and the application already has a database key, semantic search is usually the wrong first tool. A deterministic database query is better.",{"data":764,"type":42},{"text":765,"level":230},"Direct Answer",{"data":767,"type":217},{"text":768},"An LLM data source is any external system from which an application can obtain information for the model: files, databases, APIs, search indexes, vector stores or live application state. RAG is the pattern of \u003Cb>retrieving relevant knowledge from such sources before generation\u003C\u002Fb>.",{"data":770,"type":217},{"text":771},"In Python, the essential pipeline can be very small: \u003Cb>load data → create retrievable units → find relevant evidence → assemble context → call the LLM\u003C\u002Fb>. The retrieval method should match the source and the question. Use SQL for exact structured facts, full-text search for lexical matching, embeddings for semantic similarity, and hybrid retrieval when several signals are valuable.",{"data":773,"type":42},{"text":774,"level":230},"Why This Is So",{"data":776,"type":217},{"text":777},"A language model does not automatically receive the contents of your filesystem, PostgreSQL database, CRM, private API or newly edited document. The application decides what external information is accessible and what is placed into the model’s current context.",{"data":779,"type":217},{"text":780},"The original Retrieval-Augmented Generation work by Lewis et al. combined a generative model with external non-parametric memory retrieved from a dense vector index. The broader architectural idea survives beyond that specific implementation: external evidence can be retrieved at inference time instead of expecting all useful knowledge to be encoded in model parameters.",{"data":782,"type":217},{"text":783},"This creates a useful separation of responsibilities: the source stores information, the retriever selects evidence, the context carries that evidence into the request, and the model interprets it. Keeping those boundaries visible makes failures much easier to diagnose.",{"data":785,"type":42},{"text":786,"level":230},"Context: The Main Types of Data Sources",{"data":788,"type":336},{"content":789,"withHeadings":14},[790,794,797,800,804,808,812,816],[791,792,793],"Source","Typical retrieval method","Good for",[309,795,796],"Parsing + lexical or semantic search","Documentation, manuals, articles, notes",[313,798,799],"Structure-aware extraction + search","Policies, reports, contracts, manuals",[801,802,803],"SQL database","SQL query or filtered retrieval","Orders, users, products, structured records",[805,806,807],"REST \u002F GraphQL API","HTTP request with parameters","Remote systems and live service data",[809,810,811],"Search index","BM25 \u002F full-text \u002F hybrid search","Large text collections",[813,814,815],"Vector index","Embedding similarity","Semantic document retrieval",[817,818,819],"Application state","Direct state read or tool call","What is true right now",{"data":821,"type":217},{"text":822},"A vector index deserves special attention. In many architectures it is \u003Cb>not the canonical source of truth\u003C\u002Fb>. It is a retrieval index derived from documents or records. The authoritative document may live in object storage, a CMS, Git, PostgreSQL or another system, while embeddings and metadata are stored separately for fast semantic lookup. Some systems do use a vector store as primary storage, but that is an architectural choice rather than a requirement of RAG.",{"data":824,"type":217},{"text":825},"If the boundary between retrieval, persistent memory, current state and model context is still unclear, see \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fblog\u002Fai-agent-memory-is-not-rag-how-to-separate-memory-retrieval-state-and-context\">AI Agent Memory Is Not RAG\u003C\u002Fa>. Those layers can use some of the same storage technologies while still having different correctness rules.",{"data":827,"type":42},{"text":828,"level":230},"Assumptions",{"data":830,"type":357},{"items":831,"style":356},[832,833,834,835,836,837,838],"The application is allowed to access the external source.","The relevant source contains enough information to answer the question.","The data can be parsed or queried in a form the retrieval layer can use.","The retrieved information is fresh enough for the requested decision.","The model receives the selected evidence in its context.","Authorization is enforced before protected evidence reaches the model.","The generation model can still be wrong even when retrieval is correct.",{"data":840,"type":217},{"text":841},"These assumptions matter because retrieval cannot compensate for missing evidence, stale source versions, broken parsers or unauthorized access. A RAG pipeline can only be as trustworthy as the evidence path that feeds it.",{"data":843,"type":42},{"text":844,"level":230},"Variables",{"data":846,"type":336},{"content":847,"withHeadings":14},[848,851,854,857,860,863,866,869,872],[849,850],"Variable","Why it changes the design",[852,853],"Source structure","A SQL table, legal PDF and source-code repository need different retrieval strategies",[855,856],"Question type","Exact lookup, conceptual search and multi-hop research are different tasks",[858,859],"Freshness requirement","Live state may need direct queries instead of periodically rebuilt indexes",[861,862],"Corpus size","In-memory search may work for hundreds of chunks but not for very large collections",[864,865],"Language","Multilingual retrieval requires models and tokenization suitable for the actual languages",[867,868],"Permissions","Retrieval must filter by the current user’s access rights",[870,871],"Latency and cost","More retrieval stages can improve quality but add runtime and infrastructure cost",[873,874],"Need for provenance","High-trust systems need source IDs, versions and traceable evidence",{"data":876,"type":42},{"text":877,"level":230},"Diagnostic \u002F Decision Method",{"data":879,"type":217},{"text":880},"The first decision is not “Which vector database should I install?” It is: \u003Cb>What kind of fact am I trying to retrieve?\u003C\u002Fb>",{"data":882,"type":336},{"content":883,"withHeadings":14},[884,887,891,895,899,903],[855,885,886],"Preferred first approach","Reason",[888,889,890],"Exact ID or current record","SQL \u002F key lookup \u002F API","Deterministic structured access",[892,893,894],"Exact wording, codes, names","Full-text or keyword search","Lexical precision",[896,897,898],"Conceptual question over documents","Semantic vector search","Meaning can differ from wording",[900,901,902],"Mixed enterprise knowledge","Hybrid retrieval + metadata filters","Combines lexical and semantic signals",[904,905,906],"Current application state","Direct state\u002Ftool access","Freshness matters more than document similarity",{"data":908,"type":217},{"text":909},"A useful test is: \u003Cb>Do I already know which record I need, or must the system discover which passage is relevant?\u003C\u002Fb> If the record is known, query it directly. If relevance must be discovered, search becomes more important.",{"data":911,"type":217},{"text":912},"When an answer is wrong, diagnose the pipeline in order instead of immediately changing the LLM:",{"data":914,"type":357},{"items":915,"style":444},[916,917,918,919,920,921,922,923,924],"\u003Cb>1. Source coverage:\u003C\u002Fb> Does the correct information exist in the accessible source set?","\u003Cb>2. Freshness:\u003C\u002Fb> Is that version current enough for the question?","\u003Cb>3. Parsing:\u003C\u002Fb> Was the relevant content extracted correctly?","\u003Cb>4. Chunking:\u003C\u002Fb> Did the evidence stay together with the conditions that give it meaning?","\u003Cb>5. Retrieval:\u003C\u002Fb> Does the correct chunk appear among the candidates?","\u003Cb>6. Ranking:\u003C\u002Fb> Are stronger sources ranked above weaker or conflicting ones?","\u003Cb>7. Context assembly:\u003C\u002Fb> Did the application actually send the selected evidence to the model?","\u003Cb>8. Generation:\u003C\u002Fb> Did the LLM faithfully use the supplied evidence?","\u003Cb>9. Attribution:\u003C\u002Fb> Can each important claim be traced to a source?",{"data":926,"type":217},{"text":927},"For a deeper production-debugging method, see \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fblog\u002Frag-failed-but-which-layer-actually-failed-a-diagnostic-method\">RAG Failed — But Which Layer Actually Failed? A Diagnostic Method\u003C\u002Fa>, which expands this chain into independently testable failure layers.",{"data":929,"type":42},{"text":930,"level":230},"Evidence",{"data":932,"type":217},{"text":933},"The RAG paper by Lewis et al. formalized generation that conditions on retrieved external memory rather than relying only on model parameters. That provides the conceptual foundation for separating the generator from a retrievable knowledge source.",{"data":935,"type":217},{"text":936},"Sentence Transformers documents semantic search as embedding the corpus and the query into a vector space and retrieving items with high semantic similarity. Its current API also distinguishes query encoding from document encoding for retrieval tasks.",{"data":938,"type":217},{"text":939},"SQLite FTS5 demonstrates the other side of the spectrum: mature full-text retrieval can rank documents without embeddings. This matters because lexical search remains valuable for identifiers, exact terminology and many hybrid retrieval designs.",{"data":941,"type":217},{"text":942},"OpenAI’s embeddings documentation describes embeddings as numerical vector representations used for relatedness and search. This is one implementation path for semantic retrieval, not the definition of RAG itself.",{"data":944,"type":42},{"text":945,"level":230},"Real Example 1: A Folder of Text Files",{"data":947,"type":217},{"text":948},"Suppose a directory named \u003Ccode>knowledge\u002F\u003C\u002Fcode> contains ordinary text files. Python can load them with no AI library at all.",{"data":950,"type":252},{"code":471},{"data":952,"type":217},{"text":953},"The filesystem is the data source. The next question is how much text should become one retrievable unit. For long documents, searching one complete file is often too coarse. This is why RAG pipelines commonly create chunks.",{"data":955,"type":42},{"text":956,"level":478},"A Very Simple Chunker",{"data":958,"type":252},{"code":481},{"data":960,"type":217},{"text":961},"This example groups paragraphs until a rough character limit is reached. It is intentionally understandable rather than optimal. Production systems often chunk by tokens, headings, sections, sentence boundaries or document structure. Tables, source code, contracts and API documentation may need different strategies.",{"data":963,"type":42},{"text":964,"level":478},"Preserve Provenance While Chunking",{"data":966,"type":252},{"code":490},{"data":968,"type":217},{"text":969},"A useful chunk carries more than text. Source name, document ID, URL, timestamp, version or section can later support citation, debugging and freshness checks. If provenance is lost during ingestion, it becomes much harder to explain why a particular answer was produced.",{"data":971,"type":42},{"text":972,"level":230},"Real Example 2: Structured Data — Use SQL When SQL Is the Right Tool",{"data":974,"type":217},{"text":975},"Not every external fact should go through semantic search. If the question asks for an exact current record, a direct database query is usually clearer and more deterministic.",{"data":977,"type":252},{"code":502},{"data":979,"type":217},{"text":980},"If the application already knows that the user is asking about order 4711, embedding the entire orders table and asking semantic search to rediscover that row usually adds complexity without benefit. A strong design rule is: \u003Cb>retrieve structured facts with structured queries; retrieve unstructured knowledge with search.\u003C\u002Fb>",{"data":982,"type":217},{"text":983},"The returned database row can still be placed into the model context so the LLM can explain it in natural language. But direct state or record access is conceptually different from searching a knowledge corpus.",{"data":985,"type":42},{"text":986,"level":230},"Real Example 3: Full-Text Search Before Embeddings",{"data":988,"type":217},{"text":989},"Between a naive Python loop and vector search lies a mature class of lexical retrieval systems. SQLite includes FTS5 for full-text search, including BM25 ranking.",{"data":991,"type":252},{"code":517},{"data":993,"type":217},{"text":994},"Lexical search is especially useful when exact terminology, product codes, names, identifiers or domain-specific words matter. Semantic search is not automatically better. Production systems often combine both signals.",{"data":996,"type":42},{"text":997,"level":230},"Real Example 4: Semantic Retrieval With Embeddings",{"data":999,"type":217},{"text":1000},"Embeddings turn text into numerical vectors so semantically related passages can be compared even when they do not use identical wording. Sentence Transformers provides a straightforward local implementation.",{"data":1002,"type":252},{"code":529},{"data":1004,"type":217},{"text":1005},"The query does not contain the phrase “vehicle maintenance,” but a semantic model can still rank that passage highly because the concepts are related. This is the practical reason embeddings are common in RAG systems.",{"data":1007,"type":217},{"text":1008},"For small collections, embeddings can stay in memory. Larger systems usually persist them in a vector-capable index or database and perform nearest-neighbor search there. The storage changes, but the logic remains: encode the question, find relevant document representations, return the best evidence.",{"data":1010,"type":42},{"text":1011,"level":230},"Real Example 5: Build the Context for the LLM",{"data":1013,"type":217},{"text":1014},"A retriever should return evidence. The LLM should then receive the question plus that evidence. Keeping retrieval and generation separate makes both easier to inspect and test.",{"data":1016,"type":252},{"code":544},{"data":1018,"type":217},{"text":1019},"The instruction does not make the model infallible. It simply creates an explicit evidence boundary. The model can still misunderstand good evidence, ignore a condition or overgeneralize. That is why retrieval quality and generation quality must be evaluated separately.",{"data":1021,"type":42},{"text":1022,"level":230},"Real Example 6: A Complete Minimal Pipeline",{"data":1024,"type":252},{"code":553},{"data":1026,"type":217},{"text":1027},"The function receives \u003Ccode>call_llm\u003C\u002Fcode> as a dependency on purpose. Retrieval should not care whether generation is performed by a cloud model, a local model or another provider. The data path belongs to the application.",{"data":1029,"type":42},{"text":1030,"level":478},"Optional Generator: OpenAI Responses API",{"data":1032,"type":217},{"text":1033},"One possible generator is the OpenAI Responses API. Keeping the model name in an environment variable avoids hard-coding a particular model into the RAG architecture.",{"data":1035,"type":252},{"code":565},{"data":1037,"type":217},{"text":1038},"The same retrieval pipeline can be connected to a local inference server. This is an important architectural point: \u003Cb>RAG is not owned by the LLM provider.\u003C\u002Fb> The application owns the source, retrieval and context assembly.",{"data":1040,"type":42},{"text":1041,"level":478},"The Whole Architecture in One View",{"data":1043,"type":252},{"code":574},{"data":1045,"type":217},{"text":1046},"This data-flow model is more durable than memorizing one framework. Libraries, databases and model vendors will change; the responsibility boundaries remain.",{"data":1048,"type":42},{"text":1049,"level":230},"Common Misconceptions and Failure Modes",{"data":1051,"type":42},{"text":1052,"level":478},"“RAG means vector database.”",{"data":1054,"type":217},{"text":1055},"No. Vector search is one retrieval method. RAG can use full-text search, SQL, APIs, knowledge graphs, vector search or combinations of them. The defining pattern is retrieval of external information for generation.",{"data":1057,"type":42},{"text":1058,"level":478},"“If the data is in PostgreSQL, I must embed the whole database.”",{"data":1060,"type":217},{"text":1061},"No. Structured records should usually remain queryable as structured records. Embeddings are useful for semantic relevance, not as a replacement for deterministic queries.",{"data":1063,"type":42},{"text":1064,"level":478},"“More chunks means a better answer.”",{"data":1066,"type":217},{"text":1067},"Not necessarily. Extra context can introduce noise, conflicting versions and irrelevant material. Retrieval should optimize for useful evidence, not maximum volume.",{"data":1069,"type":42},{"text":1070,"level":478},"“A high similarity score proves the answer.”",{"data":1072,"type":217},{"text":1073},"No. Similarity measures relevance, not truth or applicability. A highly similar passage can be outdated, from the wrong product version or valid only under conditions that do not match the question.",{"data":1075,"type":42},{"text":1076,"level":478},"“Once the correct chunk is retrieved, hallucination is solved.”",{"data":1078,"type":217},{"text":1079},"No. Retrieval improves grounding but does not guarantee faithful reasoning. Generation still needs evaluation, and high-risk workflows may require deterministic validation or human review.",{"data":1081,"type":42},{"text":1082,"level":478},"“The model failed, so change the model.”",{"data":1084,"type":217},{"text":1085},"Not necessarily. The correct source may have been missing, parsed incorrectly, split badly, filtered out, ranked too low or omitted from the assembled context. Model replacement should not be the first diagnostic step.",{"data":1087,"type":42},{"text":1088,"level":230},"Edge Cases",{"data":1090,"type":357},{"items":1091,"style":356},[1092,1093,1094,1095,1096,1097,1098,1099],"\u003Cb>Conflicting documents:\u003C\u002Fb> two sources may disagree because versions, jurisdictions or products differ.","\u003Cb>Time-sensitive facts:\u003C\u002Fb> a semantically relevant source may already be stale.","\u003Cb>Permissions:\u003C\u002Fb> a retriever must not return documents the current user is not authorized to access.","\u003Cb>Multi-language collections:\u003C\u002Fb> the embedding model and retrieval strategy must support the languages actually used.","\u003Cb>Tables and source code:\u003C\u002Fb> plain paragraph chunking can destroy structure that is essential to the answer.","\u003Cb>Very short identifiers:\u003C\u002Fb> semantic retrieval can be weaker than exact matching for SKUs, IDs, error codes or acronyms.","\u003Cb>Long questions requiring several facts:\u003C\u002Fb> retrieval may need decomposition, several searches or reranking rather than one top-k query.","\u003Cb>Source hierarchy:\u003C\u002Fb> an official current policy may need to outrank an older but semantically closer discussion document.",{"data":1101,"type":42},{"text":1102,"level":230},"Limitations",{"data":1104,"type":217},{"text":1105},"The Python examples intentionally optimize for transparency, not scale. The keyword retriever is naive, the chunker uses character length, the SQLite examples do not include production connection management, and the semantic example keeps all embeddings in memory.",{"data":1107,"type":217},{"text":1108},"A production system may require vector indexes, rerankers, hybrid retrieval, document parsers, caching, incremental indexing, source versioning, access-control filters, observability, evaluation datasets and failure handling. None of those additions change the core architecture; they make each boundary more reliable.",{"data":1110,"type":217},{"text":1111},"RAG also cannot create evidence that is absent from the source set. If the source is wrong, incomplete or stale, a better embedding model cannot turn it into authoritative knowledge.",{"data":1113,"type":42},{"text":1114,"level":230},"What Would Change This Answer?",{"data":1116,"type":217},{"text":1117},"The architecture changes when the task requires more than knowledge lookup. A live order status needs current state. A financial calculation may need deterministic code. A web-research task may need active search. A workflow may need tools that can write data back to another system. An autonomous agent may need planning, permissions and execution control in addition to retrieval.",{"data":1119,"type":217},{"text":1120},"RAG is therefore best understood as \u003Cb>one evidence-acquisition layer inside a larger AI system\u003C\u002Fb>. It is powerful precisely because it has a narrow job: find useful external information and place it in the model’s working context.",{"data":1122,"type":42},{"text":1123,"level":230},"Conclusion",{"data":1125,"type":217},{"text":1126},"RAG becomes much easier to understand when the technology names are removed. A file is a source. A database is a source. An API is a source. A search function retrieves evidence. A prompt carries that evidence to the model. The LLM then interprets it and produces language.",{"data":1128,"type":217},{"text":1129},"The hard part of production RAG is not calling an embedding model. It is building a trustworthy evidence path from the original source to the final claim: preserving provenance, selecting the right retrieval method, keeping information current, controlling access, evaluating retrieval separately from generation, and knowing when a direct database or tool call is better than semantic search.",{"data":1131,"type":217},{"text":1132},"That is the practical continuation of the basic RAG model: \u003Cb>first understand the roles, then make the data path explicit.\u003C\u002Fb>",{"data":1134,"type":42},{"text":1135,"level":230},"Primary Sources",{"data":1137,"type":357},{"items":1138,"style":356},[1139,1140,1141,1142,1143,1144],"\u003Ca href=\"https:\u002F\u002Farxiv.org\u002Fabs\u002F2005.11401\">Lewis et al. — Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks\u003C\u002Fa> — the 2020 paper introducing the RAG formulation that combines generation with retrieved non-parametric memory.","\u003Ca href=\"https:\u002F\u002Fwww.sbert.net\u002Fexamples\u002Fsentence_transformer\u002Fapplications\u002Fsemantic-search\u002FREADME.html\">Sentence Transformers — Semantic Search\u003C\u002Fa> — official documentation for semantic retrieval, query embeddings and document embeddings.","\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fembeddings\">OpenAI — Vector Embeddings\u003C\u002Fa> — official documentation describing embeddings as numerical representations used for relatedness and search.","\u003Ca href=\"https:\u002F\u002Fwww.sqlite.org\u002Ffts5.html\">SQLite — FTS5 Extension\u003C\u002Fa> — official documentation for full-text search and BM25 ranking in SQLite.","\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Flibraries\">OpenAI — SDKs and CLI\u003C\u002Fa> — official Python SDK example for the Responses API used in the optional generator example.","\u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">What Is RAG? The Simplest Explanation of How It Works\u003C\u002Fa> — the conceptual first part of this series.","2.31.0","An LLM does not magically know your files, databases or APIs. This practical continuation of the RAG series shows, with simple Python, how external data becomes retrievable evidence: from text files and SQL to full-text search, embeddings, context assembly and the final LLM call.",{"lang":7,"title":208,"content":210,"contentJson":1148,"excerpt":677},{"time":212,"blocks":1149,"version":676},[1150,1152,1154,1156,1158,1160,1162,1164,1166,1168,1170,1172,1174,1176,1178,1180,1182,1184,1186,1188,1190,1192,1194,1196,1198,1200,1202,1204,1215,1217,1219,1221,1224,1226,1228,1240,1242,1244,1253,1255,1257,1260,1262,1264,1266,1268,1270,1272,1274,1276,1278,1280,1282,1284,1286,1288,1290,1292,1294,1296,1298,1300,1302,1304,1306,1308,1310,1312,1314,1316,1318,1320,1322,1324,1326,1328,1330,1332,1334,1336,1338,1340,1342,1344,1346,1348,1350,1352,1354,1356,1358,1360,1362,1364,1366,1368,1370,1372,1374,1376,1379,1381,1383,1385,1387,1389,1391,1393,1395,1397,1399,1401,1403],{"data":1151,"type":217},{"text":216},{"data":1153,"type":217},{"text":220},{"data":1155,"type":226},{"text":223,"caption":224,"alignment":225},{"data":1157,"type":42},{"text":229,"level":230},{"data":1159,"type":217},{"text":233},{"data":1161,"type":42},{"text":236,"level":230},{"data":1163,"type":217},{"text":239},{"data":1165,"type":217},{"text":242},{"data":1167,"type":42},{"text":245,"level":230},{"data":1169,"type":217},{"text":248},{"data":1171,"type":252},{"code":251},{"data":1173,"type":217},{"text":255},{"data":1175,"type":217},{"text":258},{"data":1177,"type":252},{"code":261},{"data":1179,"type":217},{"text":264},{"data":1181,"type":42},{"text":267,"level":230},{"data":1183,"type":217},{"text":270},{"data":1185,"type":217},{"text":273},{"data":1187,"type":217},{"text":276},{"data":1189,"type":42},{"text":279,"level":230},{"data":1191,"type":217},{"text":282},{"data":1193,"type":217},{"text":285},{"data":1195,"type":42},{"text":288,"level":230},{"data":1197,"type":217},{"text":291},{"data":1199,"type":217},{"text":294},{"data":1201,"type":217},{"text":297},{"data":1203,"type":42},{"text":300,"level":230},{"data":1205,"type":336},{"content":1206,"withHeadings":14},[1207,1208,1209,1210,1211,1212,1213,1214],[305,306,307],[309,310,311],[313,314,315],[317,318,319],[321,322,323],[325,326,327],[329,330,331],[333,334,335],{"data":1216,"type":217},{"text":339},{"data":1218,"type":217},{"text":342},{"data":1220,"type":42},{"text":345,"level":230},{"data":1222,"type":357},{"items":1223,"style":356},[349,350,351,352,353,354,355],{"data":1225,"type":217},{"text":360},{"data":1227,"type":42},{"text":363,"level":230},{"data":1229,"type":336},{"content":1230,"withHeadings":14},[1231,1232,1233,1234,1235,1236,1237,1238,1239],[368,369],[371,372],[374,375],[377,378],[380,381],[383,384],[386,387],[389,390],[392,393],{"data":1241,"type":42},{"text":396,"level":230},{"data":1243,"type":217},{"text":399},{"data":1245,"type":336},{"content":1246,"withHeadings":14},[1247,1248,1249,1250,1251,1252],[374,404,405],[407,408,409],[411,412,413],[415,416,417],[419,420,421],[423,424,425],{"data":1254,"type":217},{"text":428},{"data":1256,"type":217},{"text":431},{"data":1258,"type":357},{"items":1259,"style":444},[435,436,437,438,439,440,441,442,443],{"data":1261,"type":217},{"text":447},{"data":1263,"type":42},{"text":450,"level":230},{"data":1265,"type":217},{"text":453},{"data":1267,"type":217},{"text":456},{"data":1269,"type":217},{"text":459},{"data":1271,"type":217},{"text":462},{"data":1273,"type":42},{"text":465,"level":230},{"data":1275,"type":217},{"text":468},{"data":1277,"type":252},{"code":471},{"data":1279,"type":217},{"text":474},{"data":1281,"type":42},{"text":477,"level":478},{"data":1283,"type":252},{"code":481},{"data":1285,"type":217},{"text":484},{"data":1287,"type":42},{"text":487,"level":478},{"data":1289,"type":252},{"code":490},{"data":1291,"type":217},{"text":493},{"data":1293,"type":42},{"text":496,"level":230},{"data":1295,"type":217},{"text":499},{"data":1297,"type":252},{"code":502},{"data":1299,"type":217},{"text":505},{"data":1301,"type":217},{"text":508},{"data":1303,"type":42},{"text":511,"level":230},{"data":1305,"type":217},{"text":514},{"data":1307,"type":252},{"code":517},{"data":1309,"type":217},{"text":520},{"data":1311,"type":42},{"text":523,"level":230},{"data":1313,"type":217},{"text":526},{"data":1315,"type":252},{"code":529},{"data":1317,"type":217},{"text":532},{"data":1319,"type":217},{"text":535},{"data":1321,"type":42},{"text":538,"level":230},{"data":1323,"type":217},{"text":541},{"data":1325,"type":252},{"code":544},{"data":1327,"type":217},{"text":547},{"data":1329,"type":42},{"text":550,"level":230},{"data":1331,"type":252},{"code":553},{"data":1333,"type":217},{"text":556},{"data":1335,"type":42},{"text":559,"level":478},{"data":1337,"type":217},{"text":562},{"data":1339,"type":252},{"code":565},{"data":1341,"type":217},{"text":568},{"data":1343,"type":42},{"text":571,"level":478},{"data":1345,"type":252},{"code":574},{"data":1347,"type":217},{"text":577},{"data":1349,"type":42},{"text":580,"level":230},{"data":1351,"type":42},{"text":583,"level":478},{"data":1353,"type":217},{"text":586},{"data":1355,"type":42},{"text":589,"level":478},{"data":1357,"type":217},{"text":592},{"data":1359,"type":42},{"text":595,"level":478},{"data":1361,"type":217},{"text":598},{"data":1363,"type":42},{"text":601,"level":478},{"data":1365,"type":217},{"text":604},{"data":1367,"type":42},{"text":607,"level":478},{"data":1369,"type":217},{"text":610},{"data":1371,"type":42},{"text":613,"level":478},{"data":1373,"type":217},{"text":616},{"data":1375,"type":42},{"text":619,"level":230},{"data":1377,"type":357},{"items":1378,"style":356},[623,624,625,626,627,628,629,630],{"data":1380,"type":42},{"text":633,"level":230},{"data":1382,"type":217},{"text":636},{"data":1384,"type":217},{"text":639},{"data":1386,"type":217},{"text":642},{"data":1388,"type":42},{"text":645,"level":230},{"data":1390,"type":217},{"text":648},{"data":1392,"type":217},{"text":651},{"data":1394,"type":42},{"text":654,"level":230},{"data":1396,"type":217},{"text":657},{"data":1398,"type":217},{"text":660},{"data":1400,"type":217},{"text":663},{"data":1402,"type":42},{"text":666,"level":230},{"data":1404,"type":357},{"items":1405,"style":356},[670,671,672,673,674,675],"Post erfolgreich abgerufen",{"items":1408,"source":1493,"manualIds":1494,"manualMatchedIds":1495},[1409,1416,1423,1430,1437,1444,1451,1458,1465,1472,1479,1486],{"id":1410,"slug":1411,"title":1412,"excerpt":1413,"featuredImage":1414,"publishedAt":1415},"456","zbt-z8102ax-hardware-packaging-review","Recensione hardware e confezione di ZBT Z8102AX: router forte, scatola debole","Lo ZBT Z8102AX fa una solida prima impressione come router OpenWrt 5G sottile in metallo nero con molteplici connettori per antenna, slot dual-SIM, porte USB, LAN\u002FWAN e un pratico set di accessori. L'hardware sembra utile e serio, ma la confezione è chiaramente il punto debole.","\u002Fuploads\u002F2026\u002F06\u002Fopenwrt-router-review-dual-sim-02-1781620590938-y33j4b.webp","2026-06-16T04:40:00.000Z",{"id":1417,"slug":1418,"title":1419,"excerpt":1420,"featuredImage":1421,"publishedAt":1422},"3","postfixadmin-enterprise-grade-management-for-postfix-mail-systems-anno-2026","PostfixAdmin: Gestione di Livello Enterprise per Sistemi di Posta Postfix — Anno 2026","PostfixAdmin è un'interfaccia di amministrazione basata su database progettata per sistemi di posta Postfix professionali. Anziché nascondere la complessità, fornisce un controllo preciso su domini, caselle di posta, alias e permessi del mittente. Questo articolo spiega perché PostfixAdmin rimane una soluzione aziendale affidabile nel 2026 e come si inserisce nelle moderne infrastrutture di posta incentrate sulla sicurezza.","\u002Fuploads\u002F2026\u002F01\u002Fpostfixadmin-enterprise-grade-management-for-postfix-mail-systems-anno-2026-1768311098693-w36cpk.webp","2026-01-13T07:58:00.000Z",{"id":1424,"slug":1425,"title":1426,"excerpt":1427,"featuredImage":1428,"publishedAt":1429},"459","ollama-is-not-the-product-building-production-ready-open-llm-applications","Ollama non è il prodotto: costruire applicazioni Open-LLM pronte per la produzione","Eseguire un modello locale con Ollama è facile. Costruire un'applicazione Open-LLM pronta per la produzione è più difficile: richiede RAG, controllo degli accessi, astrazione del provider, valutazione, logging, disciplina di deployment e un livello applicativo controllato attorno al modello.","\u002Fuploads\u002F2026\u002F06\u002Follama-is-not-the-product-building-production-ready-open-llm-applications-1782679361640-h0usqf.webp","2026-06-28T16:39:00.000Z",{"id":1431,"slug":1432,"title":1433,"excerpt":1434,"featuredImage":1435,"publishedAt":1436},"443","linux","Tendenze emergenti di Linux nel 2026: plasmare il futuro dell'infrastruttura server","Esplora le principali tendenze Linux del 2026, dal dominio di Kubernetes e dalle distribuzioni immutabili all'integrazione dell'IA e alla sicurezza eBPF.","\u002Fuploads\u002F2026\u002F03\u002Flinux-1773696098750-knp03t.webp","2026-03-01T13:52:00.000Z",{"id":1438,"slug":1439,"title":1440,"excerpt":1441,"featuredImage":1442,"publishedAt":1443},"434","evaluation-harness","Guida completa a Evaluation Harness: Padroneggiare la valutazione delle prestazioni degli LLM","Questa guida fornisce una panoramica dettagliata di Evaluation Harness, un framework essenziale per valutare rigorosamente le capacità dei modelli linguistici di grandi dimensioni (LLM) nelle pipeline LLMOps aziendali. Scopri la configurazione, le best practice e le tecniche avanzate per garantire un benchmarking e un'ottimizzazione dei modelli affidabili.","\u002Fuploads\u002F2026\u002F04\u002Fevaluation-harness-1775466944495-4s0xv2.webp","2026-03-01T17:50:00.000Z",{"id":1445,"slug":1446,"title":1447,"excerpt":1448,"featuredImage":1449,"publishedAt":1450},"460","ai-agent-reliability-why-the-final-answer-is-not-enough","Affidabilità degli Agenti AI: Perché la Risposta Finale Non è Sufficiente","Un output corretto non dimostra un ragionamento corretto, un'esecuzione sicura o un sistema affidabile.","\u002Fuploads\u002F2026\u002F09\u002Fai-agent-reliability-why-the-final-answer-is-not-enough-1788955466306-pl0qhz.webp","2026-09-09T04:01:00.000Z",{"id":1452,"slug":1453,"title":1454,"excerpt":1455,"featuredImage":1456,"publishedAt":1457},"383","canonical-architecture-url-design-resolver-logic-api-scalability-specification","Architettura Canonica, Progettazione URL, Logica del Resolver, Specifiche API e Scalabilità","Architettura di scoperta geobasata per portali multi-tenant. Definisce URL canonici, logica di risoluzione, strategia di caching e un modello di lettura geografico senza accoppiamento con CMS o rifattorizzazione del database. Progettata per stabilità SEO, scalabilità ed estensioni future come prenotazioni e mappe.","\u002Fuploads\u002F2026\u002F01\u002Fcanonical-architecture-url-design-resolver-logic-api-scalability-specification-1769890763607-7rghbp.webp","2026-01-31T06:12:00.000Z",{"id":1459,"slug":1460,"title":1461,"excerpt":1462,"featuredImage":1463,"publishedAt":1464},"445","qwen-3-6-in-production-release-runbook-ai-rollback-and-llmops-versioning","Qwen 3.6 in produzione: Runbook di rilascio, Rollback AI e Versionamento LLMOps","Qwen 3.6 non è solo un altro aggiornamento del modello. È un evento di rilascio, uno scenario di rollback e un problema di versionamento allo stesso tempo. Questo articolo spiega come Qwen 3.6 dovrebbe essere gestito in produzione attraverso la disciplina LLMOps, la tracciabilità dei prompt e dei modelli, il rollout controllato e la prontezza al rollback basata sull'evidenza.","\u002Fuploads\u002F2026\u002F02\u002Fnew-qwen-3-5-plus-1771515512741-dcbi9p.webp","2026-05-04T02:49:00.000Z",{"id":1466,"slug":1467,"title":1468,"excerpt":1469,"featuredImage":1470,"publishedAt":1471},"372","convert-mov-to-mp4-using-ffmpeg-a-simple-guide","Convertire MOV in MP4 Con FFmpeg: Una Guida Semplice","Impara come convertire video MOV in MP4 usando FFmpeg con comandi affidabili, elaborazione batch e ottimizzazione della qualità per web, streaming e compatibilità multipiattaforma.","\u002Fuploads\u002F2024\u002F10\u002F20241008-Convert-MOV-to-MP4-Using-FFmpeg_-A-Simple-Guide-large.webp","2024-10-08T09:31:00.000Z",{"id":1473,"slug":1474,"title":1475,"excerpt":1476,"featuredImage":1477,"publishedAt":1478},"475","managed-agent-harness-vs-self-hosted-agent-loop-what-you-gain-what-you-lose","Harness per agenti gestito vs loop per agenti self-hosted: cosa si guadagna, cosa si perde","“Agente self-hosted” può indicare architetture molto diverse. Questa guida separa l'harness gestito, l'ambiente di esecuzione self-hosted e il loop dell'agente completamente autogestito—e mostra quale perimetro di controllo serve effettivamente ai team.","\u002Fuploads\u002F2026\u002F09\u002Fmanaged-agent-harness-vs-self-hosted-agent-loop-what-you-gain-what-you-lose-1790352403475-kj10jh.webp","2026-09-25T12:05:00.000Z",{"id":1480,"slug":1481,"title":1482,"excerpt":1483,"featuredImage":1484,"publishedAt":1485},"454","zbt-z8102ax-rm500u-ea-5g-modem-test","Quectel RM500U-EA nel ZBT Z8102AX: bande 5G, o2 Germania e comportamento del segnale nel mondo reale","Lo ZBT Z8102AX utilizza un modem Quectel RM500U-EA per la connettività 4G e 5G. Nel primo test pratico, il router si è connesso con successo a o2 Germany con la banda LTE 3 e NR n28. Il modem funziona, ma diagnostiche più approfondite come RSRP, RSRQ, SINR, il blocco delle bande e il comportamento delle celle richiedono ancora test adeguati.","\u002Fuploads\u002F2026\u002F06\u002Fopenwrt-router-review-dual-sim-06-1781620597879-qay2sx.webp","2026-06-16T08:39:00.000Z",{"id":1487,"slug":1488,"title":1489,"excerpt":1490,"featuredImage":1491,"publishedAt":1492},"370","boosting-productivity-with-erp-systems-a-case-study-on-relational-databases","Potenziare la Produttività con i Sistemi ERP: Un Caso di Studio sui Database Relazionali","L'integrazione dei sistemi ERP con database relazionali ha aumentato l'efficienza","\u002Fuploads\u002F2024\u002F07\u002F2024-07-25-A-visual-representation-of-an-ERP-Enterprise-Resource-Planning-model-showing-relational-databases-improving-productivity-large.webp","2024-07-25T11:29:00.000Z","fallback",[],[]]