[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"portal-settings:stajic:fr":3,"public-menus:all":38,"post:where-does-an-llm-get-its-data-rag-data-sources-in-python:fr":205,"related:post:where-does-an-llm-get-its-data-rag-data-sources-in-python:fr:1":1401},{"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","fr","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":1400},{"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","D'où un LLM tire-t-il ses données ? Sources de données RAG en Python","where-does-an-llm-get-its-data-rag-data-sources-in-python","\u003Cp>L'article précédent, \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Ffr\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">Qu'est-ce que le RAG ? L'explication la plus simple de son fonctionnement\u003C\u002Fa>, a établi le modèle mental : le LLM écrit, le RAG récupère des connaissances utiles, l'application détient l'état actuel, et les outils exécutent des actions. Cet article passe à l'étape suivante : \u003Cb>d'où viennent réellement les données, et à quoi ressemble la récupération en Python ?\u003C\u002Fb>\u003C\u002Fp>\n\u003Cp>La surprise importante est qu'une « source de données pour LLM » n'a généralement rien d'exotique. Il peut s'agir d'un fichier texte, d'un dossier de documents Markdown, d'une base de données SQL, d'une réponse d'API, d'un catalogue de produits, d'un système de support, ou d'un index vectoriel dérivé de ces sources. L'IA ne connaît pas ces systèmes par magie. Votre application doit charger, interroger, rechercher ou récupérer les données pertinentes et placer le résultat dans le contexte du modèle.\u003C\u002Fp>\n\u003Cblockquote class=\"border-l-4 border-gray-300 pl-4 italic\">Source de données = où réside l'information. Récupération = comment l'application trouve des informations utiles. Contexte = les informations sélectionnées fournies au modèle. LLM = le composant qui interprète ce contexte et génère une réponse.\u003Ccite class=\"block mt-2 text-sm\">— Le modèle en quatre parties utilisé tout au long de cet article\u003C\u002Fcite>\u003C\u002Fblockquote>\n\u003Ch2 id=\"section-4\">Question\u003C\u002Fh2>\n\u003Cp>Comment un LLM utilise-t-il des données externes telles que des fichiers, des bases de données ou des API, et comment un petit programme Python peut-il implémenter les étapes essentielles du RAG sans les masquer derrière un framework ?\u003C\u002Fp>\n\u003Ch2 id=\"section-6\">Ce que cela signifie vraiment\u003C\u002Fh2>\n\u003Cp>Lorsque les développeurs disent qu'un LLM est « connecté aux données de l'entreprise », plusieurs opérations différentes peuvent se cacher derrière cette phrase. Une application peut exécuter du SQL. Une autre peut appeler une API. Une autre peut effectuer une recherche en texte intégral. Une autre peut calculer la similarité d'embeddings sur des segments de documents. Toutes peuvent fournir des informations externes à un LLM, mais ce ne sont pas les mêmes méthodes de récupération et elles ne doivent pas être considérées comme interchangeables.\u003C\u002Fp>\n\u003Cp>Cette distinction est importante car la meilleure méthode de récupération dépend de la forme de la question. « Quelle est notre politique de remboursement ? » est un problème de récupération de documents. « Quel est le statut actuel de la commande 4711 ? » est généralement une consultation de base de données structurée. « Quel paragraphe traite de la récupération de compte ? » peut être une recherche par mots-clés ou sémantique. Le RAG est surtout utile lorsque le système doit \u003Cb>découvrir des connaissances pertinentes avant la génération\u003C\u002Fb>.\u003C\u002Fp>\n\u003Ch2 id=\"section-9\">Exemple le plus simple\u003C\u002Fh2>\n\u003Cp>Commencez avec trois chaînes de caractères en Python ordinaire. Il n'y a pas encore de base de données vectorielle, pas de framework et pas de LLM. Nous voulons seulement rendre visible l'étape de récupération.\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>Le programme affiche la première phrase car elle contient le terme que nous avons recherché. C'est une récupération primitive, mais l'architecture est déjà visible : \u003Cb>question → recherche → texte pertinent\u003C\u002Fb>. Le RAG ajoute une étape majeure supplémentaire : transmettre le texte récupéré à un modèle de langage avec la question.\u003C\u002Fp>\n\u003Cp>Une version légèrement plus générale classe les documents par chevauchement des termes de la requête :\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>Ce n'est pas un moteur de recherche de production. Il ignore la morphologie, les synonymes, les variantes orthographiques, la longueur des documents et de nombreux signaux de classement. Sa valeur est pédagogique : \u003Cb>le RAG ne commence pas par une base de données vectorielle. Il commence par la récupération.\u003C\u002Fb>\u003C\u002Fp>\n\u003Ch2 id=\"section-16\">Où l'exemple cesse de fonctionner\u003C\u002Fh2>\n\u003Cp>La correspondance exacte ou lexicale devient faible lorsque la question et la source utilisent des mots différents. Un document peut dire « entretien du véhicule », tandis que l'utilisateur demande « comment réparer ma voiture ? » Un récupérateur lexical peut manquer la relation même si un humain la voit immédiatement. La récupération sémantique résout ce problème en représentant le texte sous forme de vecteurs et en comparant le sens plutôt que seulement les tokens exacts.\u003C\u002Fp>\n\u003Cp>Les fichiers longs créent un autre problème. Rechercher un manuel entier de 80 pages comme une seule unité est trop grossier, mais diviser chaque phrase peut détruire un contexte utile. Les systèmes RAG réels ont donc besoin de décisions concernant l'analyse, le découpage, les métadonnées, le classement, la fraîcheur, les autorisations et la provenance.\u003C\u002Fp>\n\u003Cp>L'exemple ne dit rien non plus sur les faits structurés en direct. Si l'utilisateur demande le statut actuel de la commande 4711 et que l'application dispose déjà d'une clé de base de données, la recherche sémantique est généralement le mauvais premier outil. Une requête déterministe à la base de données est préférable.\u003C\u002Fp>\n\u003Ch2 id=\"section-20\">Réponse directe\u003C\u002Fh2>\n\u003Cp>Une source de données LLM est tout système externe à partir duquel une application peut obtenir des informations pour le modèle : fichiers, bases de données, API, index de recherche, magasins vectoriels ou état d'application en direct. Le RAG est le modèle consistant à \u003Cb>récupérer des connaissances pertinentes à partir de ces sources avant la génération\u003C\u002Fb>.\u003C\u002Fp>\n\u003Cp>En Python, le pipeline essentiel peut être très simple : \u003Cb>charger les données → créer des unités récupérables → trouver les preuves pertinentes → assembler le contexte → appeler le LLM\u003C\u002Fb>. La méthode de récupération doit correspondre à la source et à la question. Utilisez SQL pour les faits structurés exacts, la recherche en texte intégral pour la correspondance lexicale, les embeddings pour la similarité sémantique, et la récupération hybride lorsque plusieurs signaux sont utiles.\u003C\u002Fp>\n\u003Ch2 id=\"section-23\">Pourquoi il en est ainsi\u003C\u002Fh2>\n\u003Cp>Un modèle de langage ne reçoit pas automatiquement le contenu de votre système de fichiers, de votre base de données PostgreSQL, de votre CRM, de votre API privée ou d'un document récemment modifié. L'application décide quelles informations externes sont accessibles et ce qui est placé dans le contexte actuel du modèle.\u003C\u002Fp>\n\u003Cp>Les travaux originaux sur la génération augmentée par récupération de Lewis et al. combinaient un modèle génératif avec une mémoire externe non paramétrique récupérée à partir d'un index vectoriel dense. L'idée architecturale plus large survit au-delà de cette implémentation spécifique : des preuves externes peuvent être récupérées au moment de l'inférence au lieu de s'attendre à ce que toutes les connaissances utiles soient encodées dans les paramètres du modèle.\u003C\u002Fp>\n\u003Cp>Cela crée une séparation utile des responsabilités : la source stocke les informations, le récupérateur sélectionne les preuves, le contexte transporte ces preuves dans la requête, et le modèle les interprète. Garder ces frontières visibles rend les défaillances beaucoup plus faciles à diagnostiquer.\u003C\u002Fp>\n\u003Ch2 id=\"section-27\">Contexte : les principaux types de sources de données\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\">Source\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Méthode de récupération typique\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Bon pour\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\">Analyse + recherche lexicale ou sémantique\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Documentation, manuels, articles, notes\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\">Extraction sensible à la structure + recherche\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Politiques, rapports, contrats, manuels\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Base de données SQL\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Requête SQL ou récupération filtrée\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Commandes, utilisateurs, produits, enregistrements structurés\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\">Requête HTTP avec paramètres\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Systèmes distants et données de service en direct\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Index de recherche\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Recherche BM25 \u002F texte intégral \u002F hybride\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Grandes collections de textes\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Index vectoriel\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Similarité d'embeddings\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Récupération sémantique de documents\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">État de l'application\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Lecture directe de l'état ou appel d'outil\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Ce qui est vrai en ce moment\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>Un index vectoriel mérite une attention particulière. Dans de nombreuses architectures, il n'est \u003Cb>pas la source de vérité canonique\u003C\u002Fb>. C'est un index de récupération dérivé de documents ou d'enregistrements. Le document faisant autorité peut résider dans un stockage objet, un CMS, Git, PostgreSQL ou un autre système, tandis que les embeddings et les métadonnées sont stockés séparément pour une recherche sémantique rapide. Certains systèmes utilisent effectivement un magasin vectoriel comme stockage principal, mais c'est un choix architectural plutôt qu'une exigence du RAG.\u003C\u002Fp>\n\u003Cp>Si la frontière entre récupération, mémoire persistante, état actuel et contexte du modèle n'est toujours pas claire, voir \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Ffr\u002Fblog\u002Fai-agent-memory-is-not-rag-how-to-separate-memory-retrieval-state-and-context\">AI Agent Memory Is Not RAG\u003C\u002Fa>. Ces couches peuvent utiliser certaines des mêmes technologies de stockage tout en ayant des règles de correction différentes.\u003C\u002Fp>\n\u003Ch2 id=\"section-31\">Hypothèses\u003C\u002Fh2>\n\u003Cul>\u003Cli>L'application est autorisée à accéder à la source externe.\u003C\u002Fli>\u003Cli>La source pertinente contient suffisamment d'informations pour répondre à la question.\u003C\u002Fli>\u003Cli>Les données peuvent être analysées ou interrogées sous une forme utilisable par la couche de récupération.\u003C\u002Fli>\u003Cli>Les informations récupérées sont suffisamment récentes pour la décision demandée.\u003C\u002Fli>\u003Cli>Le modèle reçoit les preuves sélectionnées dans son contexte.\u003C\u002Fli>\u003Cli>L'autorisation est appliquée avant que les preuves protégées n'atteignent le modèle.\u003C\u002Fli>\u003Cli>Le modèle de génération peut encore se tromper même lorsque la récupération est correcte.\u003C\u002Fli>\u003C\u002Ful>\n\u003Cp>Ces hypothèses sont importantes car la récupération ne peut pas compenser des preuves manquantes, des versions de source obsolètes, des analyseurs défectueux ou un accès non autorisé. Un pipeline RAG ne peut être aussi fiable que le chemin de preuve qui l'alimente.\u003C\u002Fp>\n\u003Ch2 id=\"section-34\">Variables\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\">Variable\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Pourquoi cela change la conception\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Structure de la source\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Une table SQL, un PDF juridique et un dépôt de code source nécessitent des stratégies de récupération différentes\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Type de question\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">La recherche exacte, la recherche conceptuelle et la recherche multi-sauts sont des tâches différentes\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Exigence de fraîcheur\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">L'état en direct peut nécessiter des requêtes directes au lieu d'index reconstruits périodiquement\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Taille du corpus\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">La recherche en mémoire peut fonctionner pour des centaines de fragments mais pas pour de très grandes collections\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Langue\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">La récupération multilingue nécessite des modèles et une tokenisation adaptés aux langues réelles\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Permissions\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">La récupération doit filtrer selon les droits d'accès de l'utilisateur actuel\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Latence et coût\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Plus d'étapes de récupération peuvent améliorer la qualité mais ajoutent du temps d'exécution et des coûts d'infrastructure\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Besoin de provenance\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Les systèmes à haute confiance nécessitent des identifiants de source, des versions et des preuves traçables\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Ch2 id=\"section-36\">Méthode de diagnostic \u002F décision\u003C\u002Fh2>\n\u003Cp>La première décision n'est pas « Quelle base de données vectorielle dois-je installer ? » Elle est : \u003Cb>Quel type de fait est-ce que j'essaie de récupérer ?\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\">Type de question\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Première approche privilégiée\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Raison\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">ID exact ou enregistrement actuel\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">SQL \u002F recherche par clé \u002F API\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Accès structuré déterministe\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Formulation exacte, codes, noms\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Recherche en texte intégral ou par mots-clés\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Précision lexicale\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Question conceptuelle sur des documents\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Recherche vectorielle sémantique\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Le sens peut différer de la formulation\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Connaissances d'entreprise mixtes\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Récupération hybride + filtres de métadonnées\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Combine les signaux lexicaux et sémantiques\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">État actuel de l'application\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Accès direct à l'état\u002Faux outils\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">La fraîcheur importe plus que la similarité des documents\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>Un test utile est : \u003Cb>Est-ce que je sais déjà quel enregistrement je dois récupérer, ou le système doit-il découvrir quel passage est pertinent ?\u003C\u002Fb> Si l'enregistrement est connu, interrogez-le directement. Si la pertinence doit être découverte, la recherche devient plus importante.\u003C\u002Fp>\n\u003Cp>Lorsqu'une réponse est erronée, diagnostiquez le pipeline dans l'ordre au lieu de modifier immédiatement le LLM :\u003C\u002Fp>\n\u003Col>\u003Cli>\u003Cb>1. Couverture des sources :\u003C\u002Fb> L'information correcte existe-t-elle dans l'ensemble des sources accessibles ?\u003C\u002Fli>\u003Cli>\u003Cb>2. Fraîcheur :\u003C\u002Fb> Cette version est-elle suffisamment à jour pour la question ?\u003C\u002Fli>\u003Cli>\u003Cb>3. Analyse syntaxique :\u003C\u002Fb> Le contenu pertinent a-t-il été extrait correctement ?\u003C\u002Fli>\u003Cli>\u003Cb>4. Découpage :\u003C\u002Fb> Les preuves sont-elles restées groupées avec les conditions qui leur donnent un sens ?\u003C\u002Fli>\u003Cli>\u003Cb>5. Récupération :\u003C\u002Fb> Le bon fragment apparaît-il parmi les candidats ?\u003C\u002Fli>\u003Cli>\u003Cb>6. Classement :\u003C\u002Fb> Les sources plus solides sont-elles classées au-dessus des sources plus faibles ou contradictoires ?\u003C\u002Fli>\u003Cli>\u003Cb>7. Assemblage du contexte :\u003C\u002Fb> L'application a-t-elle réellement envoyé les preuves sélectionnées au modèle ?\u003C\u002Fli>\u003Cli>\u003Cb>8. Génération :\u003C\u002Fb> Le LLM a-t-il fidèlement utilisé les preuves fournies ?\u003C\u002Fli>\u003Cli>\u003Cb>9. Attribution :\u003C\u002Fb> Chaque affirmation importante peut-elle être rattachée à une source ?\u003C\u002Fli>\u003C\u002Fol>\n\u003Cp>Pour une méthode plus approfondie de débogage en production, voir \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Ffr\u002Fblog\u002Frag-failed-but-which-layer-actually-failed-a-diagnostic-method\">RAG Failed — But Which Layer Actually Failed? A Diagnostic Method\u003C\u002Fa>, qui étend cette chaîne en couches de défaillance testables indépendamment.\u003C\u002Fp>\n\u003Ch2 id=\"section-43\">Preuves\u003C\u002Fh2>\n\u003Cp>L'article RAG de Lewis et al. a formalisé la génération qui se conditionne sur une mémoire externe récupérée plutôt que de s'appuyer uniquement sur les paramètres du modèle. Cela fournit la base conceptuelle pour séparer le générateur d'une source de connaissances récupérable.\u003C\u002Fp>\n\u003Cp>Sentence Transformers documente la recherche sémantique comme l'encodage du corpus et de la requête dans un espace vectoriel et la récupération d'éléments présentant une forte similarité sémantique. Son API actuelle distingue également l'encodage des requêtes de l'encodage des documents pour les tâches de récupération.\u003C\u002Fp>\n\u003Cp>SQLite FTS5 illustre l'autre extrémité du spectre : une récupération en texte intégral mature peut classer des documents sans embeddings. Cela importe car la recherche lexicale reste précieuse pour les identifiants, la terminologie exacte et de nombreuses conceptions de récupération hybride.\u003C\u002Fp>\n\u003Cp>La documentation d'OpenAI sur les embeddings décrit les embeddings comme des représentations vectorielles numériques utilisées pour la parenté et la recherche. Il s'agit d'une voie d'implémentation pour la récupération sémantique, et non de la définition du RAG lui-même.\u003C\u002Fp>\n\u003Ch2 id=\"section-48\">Exemple réel 1 : un dossier de fichiers texte\u003C\u002Fh2>\n\u003Cp>Supposons qu'un répertoire nommé \u003Ccode>knowledge\u002F\u003C\u002Fcode> contienne des fichiers texte ordinaires. Python peut les charger sans aucune bibliothèque d'IA.\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>Le système de fichiers est la source de données. La question suivante est de savoir quelle quantité de texte doit devenir une unité récupérable. Pour les documents longs, rechercher un fichier complet est souvent trop grossier. C'est pourquoi les pipelines RAG créent couramment des fragments.\u003C\u002Fp>\n\u003Ch3 id=\"section-52\">Un découpeur très simple\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>Cet exemple regroupe les paragraphes jusqu'à atteindre une limite approximative de caractères. Il est intentionnellement compréhensible plutôt qu'optimal. Les systèmes de production découpent souvent par tokens, titres, sections, limites de phrases ou structure du document. Les tableaux, le code source, les contrats et la documentation d'API peuvent nécessiter des stratégies différentes.\u003C\u002Fp>\n\u003Ch3 id=\"section-55\">Préserver la provenance lors du découpage\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 segment utile transporte plus que du texte. Le nom de la source, l'identifiant du document, l'URL, l'horodatage, la version ou la section peuvent ensuite servir à la citation, au débogage et aux vérifications de fraîcheur. Si la provenance est perdue lors de l'ingestion, il devient beaucoup plus difficile d'expliquer pourquoi une réponse particulière a été produite.\u003C\u002Fp>\n\u003Ch2 id=\"section-58\">Exemple réel 2 : Données structurées — utilisez SQL quand SQL est l'outil approprié\u003C\u002Fh2>\n\u003Cp>Tous les faits externes ne doivent pas passer par la recherche sémantique. Si la question demande un enregistrement actuel exact, une requête directe à la base de données est généralement plus claire et plus déterministe.\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>Si l'application sait déjà que l'utilisateur pose une question sur la commande 4711, intégrer toute la table des commandes et demander à la recherche sémantique de redécouvrir cette ligne ajoute généralement de la complexité sans bénéfice. Une règle de conception solide est : \u003Cb>récupérez les faits structurés avec des requêtes structurées ; récupérez les connaissances non structurées avec la recherche.\u003C\u002Fb>\u003C\u002Fp>\n\u003Cp>La ligne de base de données renvoyée peut toujours être placée dans le contexte du modèle afin que le LLM puisse l'expliquer en langage naturel. Mais l'accès direct à un état ou à un enregistrement est conceptuellement différent de la recherche dans un corpus de connaissances.\u003C\u002Fp>\n\u003Ch2 id=\"section-63\">Exemple réel 3 : Recherche en texte intégral avant les embeddings\u003C\u002Fh2>\n\u003Cp>Entre une boucle Python naïve et la recherche vectorielle se trouve une classe mature de systèmes de recherche lexicale. SQLite inclut FTS5 pour la recherche en texte intégral, y compris le classement 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 recherche lexicale est particulièrement utile lorsque la terminologie exacte, les codes produit, les noms, les identifiants ou les mots spécifiques au domaine importent. La recherche sémantique n'est pas automatiquement meilleure. Les systèmes de production combinent souvent les deux signaux.\u003C\u002Fp>\n\u003Ch2 id=\"section-67\">Exemple réel 4 : Récupération sémantique avec des embeddings\u003C\u002Fh2>\n\u003Cp>Les embeddings transforment le texte en vecteurs numériques afin que des passages sémantiquement liés puissent être comparés même lorsqu'ils n'utilisent pas une formulation identique. Sentence Transformers fournit une implémentation locale simple.\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 requête ne contient pas l'expression « entretien du véhicule », mais un modèle sémantique peut tout de même classer ce passage haut, car les concepts sont liés. C'est la raison pratique pour laquelle les embeddings sont courants dans les systèmes RAG.\u003C\u002Fp>\n\u003Cp>Pour les petites collections, les embeddings peuvent rester en mémoire. Les systèmes plus grands les persistent généralement dans un index ou une base de données compatible avec les vecteurs et y effectuent une recherche des plus proches voisins. Le stockage change, mais la logique reste : encoder la question, trouver les représentations de documents pertinentes, renvoyer les meilleures preuves.\u003C\u002Fp>\n\u003Ch2 id=\"section-72\">Exemple réel 5 : Construire le contexte pour le LLM\u003C\u002Fh2>\n\u003Cp>Un récupérateur doit renvoyer des preuves. Le LLM doit ensuite recevoir la question plus ces preuves. Garder la récupération et la génération séparées rend les deux plus faciles à inspecter et à tester.\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'instruction ne rend pas le modèle infaillible. Elle crée simplement une frontière explicite de preuves. Le modèle peut encore mal comprendre de bonnes preuves, ignorer une condition ou généraliser à l'excès. C'est pourquoi la qualité de la récupération et la qualité de la génération doivent être évaluées séparément.\u003C\u002Fp>\n\u003Ch2 id=\"section-76\">Exemple réel 6 : un pipeline minimal complet\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 fonction reçoit \u003Ccode>call_llm\u003C\u002Fcode> comme dépendance à dessein. La récupération ne devrait pas se soucier de savoir si la génération est effectuée par un modèle cloud, un modèle local ou un autre fournisseur. Le chemin de données appartient à l'application.\u003C\u002Fp>\n\u003Ch3 id=\"section-79\">Générateur optionnel : API OpenAI Responses\u003C\u002Fh3>\n\u003Cp>Un générateur possible est l'API OpenAI Responses. Conserver le nom du modèle dans une variable d'environnement évite de coder en dur un modèle particulier dans l'architecture 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>Le même pipeline de récupération peut être connecté à un serveur d'inférence local. C'est un point architectural important : \u003Cb>le RAG n'appartient pas au fournisseur de LLM.\u003C\u002Fb> L'application possède la source, la récupération et l'assemblage du contexte.\u003C\u002Fp>\n\u003Ch3 id=\"section-83\">Toute l'architecture en une vue\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>Ce modèle de flux de données est plus durable que la mémorisation d'un framework. Les bibliothèques, les bases de données et les fournisseurs de modèles changeront ; les frontières de responsabilité demeurent.\u003C\u002Fp>\n\u003Ch2 id=\"section-86\">Idées fausses courantes et modes de défaillance\u003C\u002Fh2>\n\u003Ch3 id=\"section-87\">« RAG signifie base de données vectorielle. »\u003C\u002Fh3>\n\u003Cp>Non. La recherche vectorielle est une méthode de récupération. Le RAG peut utiliser la recherche en texte intégral, SQL, des API, des graphes de connaissances, la recherche vectorielle ou des combinaisons de ceux-ci. Le modèle déterminant est la récupération d'informations externes pour la génération.\u003C\u002Fp>\n\u003Ch3 id=\"section-89\">« Si les données sont dans PostgreSQL, je dois intégrer toute la base de données. »\u003C\u002Fh3>\n\u003Cp>Non. Les enregistrements structurés devraient généralement rester interrogeables en tant qu'enregistrements structurés. Les embeddings sont utiles pour la pertinence sémantique, pas comme remplacement des requêtes déterministes.\u003C\u002Fp>\n\u003Ch3 id=\"section-91\">« Plus de segments signifie une meilleure réponse. »\u003C\u002Fh3>\n\u003Cp>Pas nécessairement. Un contexte supplémentaire peut introduire du bruit, des versions contradictoires et des éléments non pertinents. La récupération doit optimiser pour des preuves utiles, et non pour un volume maximal.\u003C\u002Fp>\n\u003Ch3 id=\"section-93\">« Un score de similarité élevé prouve la réponse. »\u003C\u002Fh3>\n\u003Cp>Non. La similarité mesure la pertinence, pas la vérité ni l'applicabilité. Un passage très similaire peut être obsolète, provenir d'une mauvaise version du produit ou n'être valable que dans des conditions qui ne correspondent pas à la question.\u003C\u002Fp>\n\u003Ch3 id=\"section-95\">« Une fois le bon segment récupéré, l'hallucination est résolue. »\u003C\u002Fh3>\n\u003Cp>Non. La récupération améliore l'ancrage mais ne garantit pas un raisonnement fidèle. La génération nécessite toujours une évaluation, et les flux de travail à haut risque peuvent exiger une validation déterministe ou une révision humaine.\u003C\u002Fp>\n\u003Ch3 id=\"section-97\">« Le modèle a échoué, donc changeons de modèle. »\u003C\u002Fh3>\n\u003Cp>Pas nécessairement. La source correcte peut avoir été manquante, mal analysée, mal découpée, filtrée, classée trop bas ou omise du contexte assemblé. Le remplacement du modèle ne devrait pas être la première étape de diagnostic.\u003C\u002Fp>\n\u003Ch2 id=\"section-99\">Cas limites\u003C\u002Fh2>\n\u003Cul>\u003Cli>\u003Cb>Documents contradictoires :\u003C\u002Fb> deux sources peuvent diverger parce que les versions, les juridictions ou les produits diffèrent.\u003C\u002Fli>\u003Cli>\u003Cb>Faits sensibles au temps :\u003C\u002Fb> une source sémantiquement pertinente peut déjà être obsolète.\u003C\u002Fli>\u003Cli>\u003Cb>Autorisations :\u003C\u002Fb> un système de récupération ne doit pas renvoyer des documents auxquels l'utilisateur actuel n'est pas autorisé à accéder.\u003C\u002Fli>\u003Cli>\u003Cb>Collections multilingues :\u003C\u002Fb> le modèle d'embedding et la stratégie de récupération doivent prendre en charge les langues réellement utilisées.\u003C\u002Fli>\u003Cli>\u003Cb>Tableaux et code source :\u003C\u002Fb> un découpage en paragraphes simples peut détruire une structure essentielle à la réponse.\u003C\u002Fli>\u003Cli>\u003Cb>Identifiants très courts :\u003C\u002Fb> la récupération sémantique peut être plus faible que la correspondance exacte pour les SKU, les identifiants, les codes d'erreur ou les acronymes.\u003C\u002Fli>\u003Cli>\u003Cb>Questions longues nécessitant plusieurs faits :\u003C\u002Fb> la récupération peut nécessiter une décomposition, plusieurs recherches ou un reranking plutôt qu'une seule requête top-k.\u003C\u002Fli>\u003Cli>\u003Cb>Hiérarchie des sources :\u003C\u002Fb> une politique officielle actuelle peut devoir primer sur un document de discussion plus ancien mais sémantiquement plus proche.\u003C\u002Fli>\u003C\u002Ful>\n\u003Ch2 id=\"section-101\">Limites\u003C\u002Fh2>\n\u003Cp>Les exemples Python optimisent intentionnellement la transparence, et non l'échelle. Le récupérateur par mots-clés est naïf, le découpeur utilise la longueur en caractères, les exemples SQLite n'incluent pas de gestion des connexions en production, et l'exemple sémantique conserve tous les embeddings en mémoire.\u003C\u002Fp>\n\u003Cp>Un système de production peut nécessiter des index vectoriels, des rerankers, une récupération hybride, des analyseurs de documents, de la mise en cache, de l'indexation incrémentielle, du versionnage des sources, des filtres de contrôle d'accès, de l'observabilité, des jeux de données d'évaluation et une gestion des défaillances. Aucun de ces ajouts ne change l'architecture de base ; ils rendent chaque frontière plus fiable.\u003C\u002Fp>\n\u003Cp>Le RAG ne peut pas non plus créer des preuves absentes de l'ensemble des sources. Si la source est erronée, incomplète ou obsolète, un meilleur modèle d'embedding ne peut pas la transformer en connaissance faisant autorité.\u003C\u002Fp>\n\u003Ch2 id=\"section-105\">Qu'est-ce qui changerait cette réponse ?\u003C\u002Fh2>\n\u003Cp>L'architecture change lorsque la tâche nécessite plus qu'une simple recherche de connaissances. Un statut de commande en direct nécessite l'état actuel. Un calcul financier peut nécessiter du code déterministe. Une tâche de recherche web peut nécessiter une recherche active. Un flux de travail peut nécessiter des outils capables d'écrire des données dans un autre système. Un agent autonome peut nécessiter la planification, les autorisations et le contrôle de l'exécution en plus de la récupération.\u003C\u002Fp>\n\u003Cp>Le RAG est donc mieux compris comme \u003Cb>une couche d'acquisition de preuves au sein d'un système d'IA plus vaste\u003C\u002Fb>. Il est puissant précisément parce qu'il a un rôle étroit : trouver des informations externes utiles et les placer dans le contexte de travail du modèle.\u003C\u002Fp>\n\u003Ch2 id=\"section-108\">Conclusion\u003C\u002Fh2>\n\u003Cp>Le RAG devient beaucoup plus facile à comprendre lorsque les noms des technologies sont retirés. Un fichier est une source. Une base de données est une source. Une API est une source. Une fonction de recherche récupère des preuves. Un prompt transporte ces preuves jusqu'au modèle. Le LLM les interprète ensuite et produit du langage.\u003C\u002Fp>\n\u003Cp>La partie difficile du RAG en production n'est pas d'appeler un modèle d'embedding. C'est de construire un chemin de preuve fiable depuis la source originale jusqu'à l'affirmation finale : préserver la provenance, sélectionner la bonne méthode de récupération, maintenir l'information à jour, contrôler l'accès, évaluer la récupération séparément de la génération, et savoir quand un appel direct à une base de données ou à un outil est préférable à une recherche sémantique.\u003C\u002Fp>\n\u003Cp>C'est la continuation pratique du modèle RAG de base : \u003Cb>comprendre d'abord les rôles, puis rendre le chemin des données explicite.\u003C\u002Fb>\u003C\u002Fp>\n\u003Ch2 id=\"section-112\">Sources primaires\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> — l'article de 2020 introduisant la formulation du RAG qui combine la génération avec une mémoire non paramétrique récupérée.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fwww.sbert.net\u002Fexamples\u002Fsentence_transformer\u002Fapplications\u002Fsemantic-search\u002FREADME.html\">Sentence Transformers — Semantic Search\u003C\u002Fa> — documentation officielle pour la récupération sémantique, les embeddings de requêtes et les embeddings de documents.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fembeddings\">OpenAI — Vector Embeddings\u003C\u002Fa> — documentation officielle décrivant les embeddings comme des représentations numériques utilisées pour la similarité et la recherche.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fwww.sqlite.org\u002Ffts5.html\">SQLite — FTS5 Extension\u003C\u002Fa> — documentation officielle pour la recherche en texte intégral et le classement BM25 dans SQLite.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Flibraries\">OpenAI — SDKs and CLI\u003C\u002Fa> — exemple officiel du SDK Python pour l'API Responses utilisé dans l'exemple optionnel de générateur.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fstajic.de\u002Ffr\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">What Is RAG? The Simplest Explanation of How It Works\u003C\u002Fa> — la première partie conceptuelle de cette série.\u003C\u002Fli>\u003C\u002Ful>",{"time":212,"blocks":213,"version":676},1790517374501,[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'article précédent, \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Ffr\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">Qu'est-ce que le RAG ? L'explication la plus simple de son fonctionnement\u003C\u002Fa>, a établi le modèle mental : le LLM écrit, le RAG récupère des connaissances utiles, l'application détient l'état actuel, et les outils exécutent des actions. Cet article passe à l'étape suivante : \u003Cb>d'où viennent réellement les données, et à quoi ressemble la récupération en Python ?\u003C\u002Fb>","paragraph",{"data":219,"type":217},{"text":220},"La surprise importante est qu'une « source de données pour LLM » n'a généralement rien d'exotique. Il peut s'agir d'un fichier texte, d'un dossier de documents Markdown, d'une base de données SQL, d'une réponse d'API, d'un catalogue de produits, d'un système de support, ou d'un index vectoriel dérivé de ces sources. L'IA ne connaît pas ces systèmes par magie. Votre application doit charger, interroger, rechercher ou récupérer les données pertinentes et placer le résultat dans le contexte du modèle.",{"data":222,"type":226},{"text":223,"caption":224,"alignment":225},"Source de données = où réside l'information. Récupération = comment l'application trouve des informations utiles. Contexte = les informations sélectionnées fournies au modèle. LLM = le composant qui interprète ce contexte et génère une réponse.","Le modèle en quatre parties utilisé tout au long de cet article","left","quote",{"data":228,"type":42},{"text":229,"level":230},"Question",2,{"data":232,"type":217},{"text":233},"Comment un LLM utilise-t-il des données externes telles que des fichiers, des bases de données ou des API, et comment un petit programme Python peut-il implémenter les étapes essentielles du RAG sans les masquer derrière un framework ?",{"data":235,"type":42},{"text":236,"level":230},"Ce que cela signifie vraiment",{"data":238,"type":217},{"text":239},"Lorsque les développeurs disent qu'un LLM est « connecté aux données de l'entreprise », plusieurs opérations différentes peuvent se cacher derrière cette phrase. Une application peut exécuter du SQL. Une autre peut appeler une API. Une autre peut effectuer une recherche en texte intégral. Une autre peut calculer la similarité d'embeddings sur des segments de documents. Toutes peuvent fournir des informations externes à un LLM, mais ce ne sont pas les mêmes méthodes de récupération et elles ne doivent pas être considérées comme interchangeables.",{"data":241,"type":217},{"text":242},"Cette distinction est importante car la meilleure méthode de récupération dépend de la forme de la question. « Quelle est notre politique de remboursement ? » est un problème de récupération de documents. « Quel est le statut actuel de la commande 4711 ? » est généralement une consultation de base de données structurée. « Quel paragraphe traite de la récupération de compte ? » peut être une recherche par mots-clés ou sémantique. Le RAG est surtout utile lorsque le système doit \u003Cb>découvrir des connaissances pertinentes avant la génération\u003C\u002Fb>.",{"data":244,"type":42},{"text":245,"level":230},"Exemple le plus simple",{"data":247,"type":217},{"text":248},"Commencez avec trois chaînes de caractères en Python ordinaire. Il n'y a pas encore de base de données vectorielle, pas de framework et pas de LLM. Nous voulons seulement rendre visible l'étape de récupération.",{"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},"Le programme affiche la première phrase car elle contient le terme que nous avons recherché. C'est une récupération primitive, mais l'architecture est déjà visible : \u003Cb>question → recherche → texte pertinent\u003C\u002Fb>. Le RAG ajoute une étape majeure supplémentaire : transmettre le texte récupéré à un modèle de langage avec la question.",{"data":257,"type":217},{"text":258},"Une version légèrement plus générale classe les documents par chevauchement des termes de la requête :",{"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},"Ce n'est pas un moteur de recherche de production. Il ignore la morphologie, les synonymes, les variantes orthographiques, la longueur des documents et de nombreux signaux de classement. Sa valeur est pédagogique : \u003Cb>le RAG ne commence pas par une base de données vectorielle. Il commence par la récupération.\u003C\u002Fb>",{"data":266,"type":42},{"text":267,"level":230},"Où l'exemple cesse de fonctionner",{"data":269,"type":217},{"text":270},"La correspondance exacte ou lexicale devient faible lorsque la question et la source utilisent des mots différents. Un document peut dire « entretien du véhicule », tandis que l'utilisateur demande « comment réparer ma voiture ? » Un récupérateur lexical peut manquer la relation même si un humain la voit immédiatement. La récupération sémantique résout ce problème en représentant le texte sous forme de vecteurs et en comparant le sens plutôt que seulement les tokens exacts.",{"data":272,"type":217},{"text":273},"Les fichiers longs créent un autre problème. Rechercher un manuel entier de 80 pages comme une seule unité est trop grossier, mais diviser chaque phrase peut détruire un contexte utile. Les systèmes RAG réels ont donc besoin de décisions concernant l'analyse, le découpage, les métadonnées, le classement, la fraîcheur, les autorisations et la provenance.",{"data":275,"type":217},{"text":276},"L'exemple ne dit rien non plus sur les faits structurés en direct. Si l'utilisateur demande le statut actuel de la commande 4711 et que l'application dispose déjà d'une clé de base de données, la recherche sémantique est généralement le mauvais premier outil. Une requête déterministe à la base de données est préférable.",{"data":278,"type":42},{"text":279,"level":230},"Réponse directe",{"data":281,"type":217},{"text":282},"Une source de données LLM est tout système externe à partir duquel une application peut obtenir des informations pour le modèle : fichiers, bases de données, API, index de recherche, magasins vectoriels ou état d'application en direct. Le RAG est le modèle consistant à \u003Cb>récupérer des connaissances pertinentes à partir de ces sources avant la génération\u003C\u002Fb>.",{"data":284,"type":217},{"text":285},"En Python, le pipeline essentiel peut être très simple : \u003Cb>charger les données → créer des unités récupérables → trouver les preuves pertinentes → assembler le contexte → appeler le LLM\u003C\u002Fb>. La méthode de récupération doit correspondre à la source et à la question. Utilisez SQL pour les faits structurés exacts, la recherche en texte intégral pour la correspondance lexicale, les embeddings pour la similarité sémantique, et la récupération hybride lorsque plusieurs signaux sont utiles.",{"data":287,"type":42},{"text":288,"level":230},"Pourquoi il en est ainsi",{"data":290,"type":217},{"text":291},"Un modèle de langage ne reçoit pas automatiquement le contenu de votre système de fichiers, de votre base de données PostgreSQL, de votre CRM, de votre API privée ou d'un document récemment modifié. L'application décide quelles informations externes sont accessibles et ce qui est placé dans le contexte actuel du modèle.",{"data":293,"type":217},{"text":294},"Les travaux originaux sur la génération augmentée par récupération de Lewis et al. combinaient un modèle génératif avec une mémoire externe non paramétrique récupérée à partir d'un index vectoriel dense. L'idée architecturale plus large survit au-delà de cette implémentation spécifique : des preuves externes peuvent être récupérées au moment de l'inférence au lieu de s'attendre à ce que toutes les connaissances utiles soient encodées dans les paramètres du modèle.",{"data":296,"type":217},{"text":297},"Cela crée une séparation utile des responsabilités : la source stocke les informations, le récupérateur sélectionne les preuves, le contexte transporte ces preuves dans la requête, et le modèle les interprète. Garder ces frontières visibles rend les défaillances beaucoup plus faciles à diagnostiquer.",{"data":299,"type":42},{"text":300,"level":230},"Contexte : les principaux types de sources de données",{"data":302,"type":336},{"content":303,"withHeadings":14},[304,308,312,316,320,324,328,332],[305,306,307],"Source","Méthode de récupération typique","Bon pour",[309,310,311],"TXT \u002F Markdown \u002F HTML","Analyse + recherche lexicale ou sémantique","Documentation, manuels, articles, notes",[313,314,315],"PDF \u002F DOCX","Extraction sensible à la structure + recherche","Politiques, rapports, contrats, manuels",[317,318,319],"Base de données SQL","Requête SQL ou récupération filtrée","Commandes, utilisateurs, produits, enregistrements structurés",[321,322,323],"API REST \u002F GraphQL","Requête HTTP avec paramètres","Systèmes distants et données de service en direct",[325,326,327],"Index de recherche","Recherche BM25 \u002F texte intégral \u002F hybride","Grandes collections de textes",[329,330,331],"Index vectoriel","Similarité d'embeddings","Récupération sémantique de documents",[333,334,335],"État de l'application","Lecture directe de l'état ou appel d'outil","Ce qui est vrai en ce moment","table",{"data":338,"type":217},{"text":339},"Un index vectoriel mérite une attention particulière. Dans de nombreuses architectures, il n'est \u003Cb>pas la source de vérité canonique\u003C\u002Fb>. C'est un index de récupération dérivé de documents ou d'enregistrements. Le document faisant autorité peut résider dans un stockage objet, un CMS, Git, PostgreSQL ou un autre système, tandis que les embeddings et les métadonnées sont stockés séparément pour une recherche sémantique rapide. Certains systèmes utilisent effectivement un magasin vectoriel comme stockage principal, mais c'est un choix architectural plutôt qu'une exigence du RAG.",{"data":341,"type":217},{"text":342},"Si la frontière entre récupération, mémoire persistante, état actuel et contexte du modèle n'est toujours pas claire, voir \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Ffr\u002Fblog\u002Fai-agent-memory-is-not-rag-how-to-separate-memory-retrieval-state-and-context\">AI Agent Memory Is Not RAG\u003C\u002Fa>. Ces couches peuvent utiliser certaines des mêmes technologies de stockage tout en ayant des règles de correction différentes.",{"data":344,"type":42},{"text":345,"level":230},"Hypothèses",{"data":347,"type":357},{"items":348,"style":356},[349,350,351,352,353,354,355],"L'application est autorisée à accéder à la source externe.","La source pertinente contient suffisamment d'informations pour répondre à la question.","Les données peuvent être analysées ou interrogées sous une forme utilisable par la couche de récupération.","Les informations récupérées sont suffisamment récentes pour la décision demandée.","Le modèle reçoit les preuves sélectionnées dans son contexte.","L'autorisation est appliquée avant que les preuves protégées n'atteignent le modèle.","Le modèle de génération peut encore se tromper même lorsque la récupération est correcte.","unordered","list",{"data":359,"type":217},{"text":360},"Ces hypothèses sont importantes car la récupération ne peut pas compenser des preuves manquantes, des versions de source obsolètes, des analyseurs défectueux ou un accès non autorisé. Un pipeline RAG ne peut être aussi fiable que le chemin de preuve qui l'alimente.",{"data":362,"type":42},{"text":363,"level":230},"Variables",{"data":365,"type":336},{"content":366,"withHeadings":14},[367,370,373,376,379,382,385,388,391],[368,369],"Variable","Pourquoi cela change la conception",[371,372],"Structure de la source","Une table SQL, un PDF juridique et un dépôt de code source nécessitent des stratégies de récupération différentes",[374,375],"Type de question","La recherche exacte, la recherche conceptuelle et la recherche multi-sauts sont des tâches différentes",[377,378],"Exigence de fraîcheur","L'état en direct peut nécessiter des requêtes directes au lieu d'index reconstruits périodiquement",[380,381],"Taille du corpus","La recherche en mémoire peut fonctionner pour des centaines de fragments mais pas pour de très grandes collections",[383,384],"Langue","La récupération multilingue nécessite des modèles et une tokenisation adaptés aux langues réelles",[386,387],"Permissions","La récupération doit filtrer selon les droits d'accès de l'utilisateur actuel",[389,390],"Latence et coût","Plus d'étapes de récupération peuvent améliorer la qualité mais ajoutent du temps d'exécution et des coûts d'infrastructure",[392,393],"Besoin de provenance","Les systèmes à haute confiance nécessitent des identifiants de source, des versions et des preuves traçables",{"data":395,"type":42},{"text":396,"level":230},"Méthode de diagnostic \u002F décision",{"data":398,"type":217},{"text":399},"La première décision n'est pas « Quelle base de données vectorielle dois-je installer ? » Elle est : \u003Cb>Quel type de fait est-ce que j'essaie de récupérer ?\u003C\u002Fb>",{"data":401,"type":336},{"content":402,"withHeadings":14},[403,406,410,414,418,422],[374,404,405],"Première approche privilégiée","Raison",[407,408,409],"ID exact ou enregistrement actuel","SQL \u002F recherche par clé \u002F API","Accès structuré déterministe",[411,412,413],"Formulation exacte, codes, noms","Recherche en texte intégral ou par mots-clés","Précision lexicale",[415,416,417],"Question conceptuelle sur des documents","Recherche vectorielle sémantique","Le sens peut différer de la formulation",[419,420,421],"Connaissances d'entreprise mixtes","Récupération hybride + filtres de métadonnées","Combine les signaux lexicaux et sémantiques",[423,424,425],"État actuel de l'application","Accès direct à l'état\u002Faux outils","La fraîcheur importe plus que la similarité des documents",{"data":427,"type":217},{"text":428},"Un test utile est : \u003Cb>Est-ce que je sais déjà quel enregistrement je dois récupérer, ou le système doit-il découvrir quel passage est pertinent ?\u003C\u002Fb> Si l'enregistrement est connu, interrogez-le directement. Si la pertinence doit être découverte, la recherche devient plus importante.",{"data":430,"type":217},{"text":431},"Lorsqu'une réponse est erronée, diagnostiquez le pipeline dans l'ordre au lieu de modifier immédiatement le LLM :",{"data":433,"type":357},{"items":434,"style":444},[435,436,437,438,439,440,441,442,443],"\u003Cb>1. Couverture des sources :\u003C\u002Fb> L'information correcte existe-t-elle dans l'ensemble des sources accessibles ?","\u003Cb>2. Fraîcheur :\u003C\u002Fb> Cette version est-elle suffisamment à jour pour la question ?","\u003Cb>3. Analyse syntaxique :\u003C\u002Fb> Le contenu pertinent a-t-il été extrait correctement ?","\u003Cb>4. Découpage :\u003C\u002Fb> Les preuves sont-elles restées groupées avec les conditions qui leur donnent un sens ?","\u003Cb>5. Récupération :\u003C\u002Fb> Le bon fragment apparaît-il parmi les candidats ?","\u003Cb>6. Classement :\u003C\u002Fb> Les sources plus solides sont-elles classées au-dessus des sources plus faibles ou contradictoires ?","\u003Cb>7. Assemblage du contexte :\u003C\u002Fb> L'application a-t-elle réellement envoyé les preuves sélectionnées au modèle ?","\u003Cb>8. Génération :\u003C\u002Fb> Le LLM a-t-il fidèlement utilisé les preuves fournies ?","\u003Cb>9. Attribution :\u003C\u002Fb> Chaque affirmation importante peut-elle être rattachée à une source ?","ordered",{"data":446,"type":217},{"text":447},"Pour une méthode plus approfondie de débogage en production, voir \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Ffr\u002Fblog\u002Frag-failed-but-which-layer-actually-failed-a-diagnostic-method\">RAG Failed — But Which Layer Actually Failed? A Diagnostic Method\u003C\u002Fa>, qui étend cette chaîne en couches de défaillance testables indépendamment.",{"data":449,"type":42},{"text":450,"level":230},"Preuves",{"data":452,"type":217},{"text":453},"L'article RAG de Lewis et al. a formalisé la génération qui se conditionne sur une mémoire externe récupérée plutôt que de s'appuyer uniquement sur les paramètres du modèle. Cela fournit la base conceptuelle pour séparer le générateur d'une source de connaissances récupérable.",{"data":455,"type":217},{"text":456},"Sentence Transformers documente la recherche sémantique comme l'encodage du corpus et de la requête dans un espace vectoriel et la récupération d'éléments présentant une forte similarité sémantique. Son API actuelle distingue également l'encodage des requêtes de l'encodage des documents pour les tâches de récupération.",{"data":458,"type":217},{"text":459},"SQLite FTS5 illustre l'autre extrémité du spectre : une récupération en texte intégral mature peut classer des documents sans embeddings. Cela importe car la recherche lexicale reste précieuse pour les identifiants, la terminologie exacte et de nombreuses conceptions de récupération hybride.",{"data":461,"type":217},{"text":462},"La documentation d'OpenAI sur les embeddings décrit les embeddings comme des représentations vectorielles numériques utilisées pour la parenté et la recherche. Il s'agit d'une voie d'implémentation pour la récupération sémantique, et non de la définition du RAG lui-même.",{"data":464,"type":42},{"text":465,"level":230},"Exemple réel 1 : un dossier de fichiers texte",{"data":467,"type":217},{"text":468},"Supposons qu'un répertoire nommé \u003Ccode>knowledge\u002F\u003C\u002Fcode> contienne des fichiers texte ordinaires. Python peut les charger sans aucune bibliothèque d'IA.",{"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},"Le système de fichiers est la source de données. La question suivante est de savoir quelle quantité de texte doit devenir une unité récupérable. Pour les documents longs, rechercher un fichier complet est souvent trop grossier. C'est pourquoi les pipelines RAG créent couramment des fragments.",{"data":476,"type":42},{"text":477,"level":478},"Un découpeur très simple",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},"Cet exemple regroupe les paragraphes jusqu'à atteindre une limite approximative de caractères. Il est intentionnellement compréhensible plutôt qu'optimal. Les systèmes de production découpent souvent par tokens, titres, sections, limites de phrases ou structure du document. Les tableaux, le code source, les contrats et la documentation d'API peuvent nécessiter des stratégies différentes.",{"data":486,"type":42},{"text":487,"level":478},"Préserver la provenance lors du découpage",{"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 segment utile transporte plus que du texte. Le nom de la source, l'identifiant du document, l'URL, l'horodatage, la version ou la section peuvent ensuite servir à la citation, au débogage et aux vérifications de fraîcheur. Si la provenance est perdue lors de l'ingestion, il devient beaucoup plus difficile d'expliquer pourquoi une réponse particulière a été produite.",{"data":495,"type":42},{"text":496,"level":230},"Exemple réel 2 : Données structurées — utilisez SQL quand SQL est l'outil approprié",{"data":498,"type":217},{"text":499},"Tous les faits externes ne doivent pas passer par la recherche sémantique. Si la question demande un enregistrement actuel exact, une requête directe à la base de données est généralement plus claire et plus déterministe.",{"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},"Si l'application sait déjà que l'utilisateur pose une question sur la commande 4711, intégrer toute la table des commandes et demander à la recherche sémantique de redécouvrir cette ligne ajoute généralement de la complexité sans bénéfice. Une règle de conception solide est : \u003Cb>récupérez les faits structurés avec des requêtes structurées ; récupérez les connaissances non structurées avec la recherche.\u003C\u002Fb>",{"data":507,"type":217},{"text":508},"La ligne de base de données renvoyée peut toujours être placée dans le contexte du modèle afin que le LLM puisse l'expliquer en langage naturel. Mais l'accès direct à un état ou à un enregistrement est conceptuellement différent de la recherche dans un corpus de connaissances.",{"data":510,"type":42},{"text":511,"level":230},"Exemple réel 3 : Recherche en texte intégral avant les embeddings",{"data":513,"type":217},{"text":514},"Entre une boucle Python naïve et la recherche vectorielle se trouve une classe mature de systèmes de recherche lexicale. SQLite inclut FTS5 pour la recherche en texte intégral, y compris le classement 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 recherche lexicale est particulièrement utile lorsque la terminologie exacte, les codes produit, les noms, les identifiants ou les mots spécifiques au domaine importent. La recherche sémantique n'est pas automatiquement meilleure. Les systèmes de production combinent souvent les deux signaux.",{"data":522,"type":42},{"text":523,"level":230},"Exemple réel 4 : Récupération sémantique avec des embeddings",{"data":525,"type":217},{"text":526},"Les embeddings transforment le texte en vecteurs numériques afin que des passages sémantiquement liés puissent être comparés même lorsqu'ils n'utilisent pas une formulation identique. Sentence Transformers fournit une implémentation locale simple.",{"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 requête ne contient pas l'expression « entretien du véhicule », mais un modèle sémantique peut tout de même classer ce passage haut, car les concepts sont liés. C'est la raison pratique pour laquelle les embeddings sont courants dans les systèmes RAG.",{"data":534,"type":217},{"text":535},"Pour les petites collections, les embeddings peuvent rester en mémoire. Les systèmes plus grands les persistent généralement dans un index ou une base de données compatible avec les vecteurs et y effectuent une recherche des plus proches voisins. Le stockage change, mais la logique reste : encoder la question, trouver les représentations de documents pertinentes, renvoyer les meilleures preuves.",{"data":537,"type":42},{"text":538,"level":230},"Exemple réel 5 : Construire le contexte pour le LLM",{"data":540,"type":217},{"text":541},"Un récupérateur doit renvoyer des preuves. Le LLM doit ensuite recevoir la question plus ces preuves. Garder la récupération et la génération séparées rend les deux plus faciles à inspecter et à tester.",{"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'instruction ne rend pas le modèle infaillible. Elle crée simplement une frontière explicite de preuves. Le modèle peut encore mal comprendre de bonnes preuves, ignorer une condition ou généraliser à l'excès. C'est pourquoi la qualité de la récupération et la qualité de la génération doivent être évaluées séparément.",{"data":549,"type":42},{"text":550,"level":230},"Exemple réel 6 : un pipeline minimal complet",{"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 fonction reçoit \u003Ccode>call_llm\u003C\u002Fcode> comme dépendance à dessein. La récupération ne devrait pas se soucier de savoir si la génération est effectuée par un modèle cloud, un modèle local ou un autre fournisseur. Le chemin de données appartient à l'application.",{"data":558,"type":42},{"text":559,"level":478},"Générateur optionnel : API OpenAI Responses",{"data":561,"type":217},{"text":562},"Un générateur possible est l'API OpenAI Responses. Conserver le nom du modèle dans une variable d'environnement évite de coder en dur un modèle particulier dans l'architecture 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},"Le même pipeline de récupération peut être connecté à un serveur d'inférence local. C'est un point architectural important : \u003Cb>le RAG n'appartient pas au fournisseur de LLM.\u003C\u002Fb> L'application possède la source, la récupération et l'assemblage du contexte.",{"data":570,"type":42},{"text":571,"level":478},"Toute l'architecture en une vue",{"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},"Ce modèle de flux de données est plus durable que la mémorisation d'un framework. Les bibliothèques, les bases de données et les fournisseurs de modèles changeront ; les frontières de responsabilité demeurent.",{"data":579,"type":42},{"text":580,"level":230},"Idées fausses courantes et modes de défaillance",{"data":582,"type":42},{"text":583,"level":478},"« RAG signifie base de données vectorielle. »",{"data":585,"type":217},{"text":586},"Non. La recherche vectorielle est une méthode de récupération. Le RAG peut utiliser la recherche en texte intégral, SQL, des API, des graphes de connaissances, la recherche vectorielle ou des combinaisons de ceux-ci. Le modèle déterminant est la récupération d'informations externes pour la génération.",{"data":588,"type":42},{"text":589,"level":478},"« Si les données sont dans PostgreSQL, je dois intégrer toute la base de données. »",{"data":591,"type":217},{"text":592},"Non. Les enregistrements structurés devraient généralement rester interrogeables en tant qu'enregistrements structurés. Les embeddings sont utiles pour la pertinence sémantique, pas comme remplacement des requêtes déterministes.",{"data":594,"type":42},{"text":595,"level":478},"« Plus de segments signifie une meilleure réponse. »",{"data":597,"type":217},{"text":598},"Pas nécessairement. Un contexte supplémentaire peut introduire du bruit, des versions contradictoires et des éléments non pertinents. La récupération doit optimiser pour des preuves utiles, et non pour un volume maximal.",{"data":600,"type":42},{"text":601,"level":478},"« Un score de similarité élevé prouve la réponse. »",{"data":603,"type":217},{"text":604},"Non. La similarité mesure la pertinence, pas la vérité ni l'applicabilité. Un passage très similaire peut être obsolète, provenir d'une mauvaise version du produit ou n'être valable que dans des conditions qui ne correspondent pas à la question.",{"data":606,"type":42},{"text":607,"level":478},"« Une fois le bon segment récupéré, l'hallucination est résolue. »",{"data":609,"type":217},{"text":610},"Non. La récupération améliore l'ancrage mais ne garantit pas un raisonnement fidèle. La génération nécessite toujours une évaluation, et les flux de travail à haut risque peuvent exiger une validation déterministe ou une révision humaine.",{"data":612,"type":42},{"text":613,"level":478},"« Le modèle a échoué, donc changeons de modèle. »",{"data":615,"type":217},{"text":616},"Pas nécessairement. La source correcte peut avoir été manquante, mal analysée, mal découpée, filtrée, classée trop bas ou omise du contexte assemblé. Le remplacement du modèle ne devrait pas être la première étape de diagnostic.",{"data":618,"type":42},{"text":619,"level":230},"Cas limites",{"data":621,"type":357},{"items":622,"style":356},[623,624,625,626,627,628,629,630],"\u003Cb>Documents contradictoires :\u003C\u002Fb> deux sources peuvent diverger parce que les versions, les juridictions ou les produits diffèrent.","\u003Cb>Faits sensibles au temps :\u003C\u002Fb> une source sémantiquement pertinente peut déjà être obsolète.","\u003Cb>Autorisations :\u003C\u002Fb> un système de récupération ne doit pas renvoyer des documents auxquels l'utilisateur actuel n'est pas autorisé à accéder.","\u003Cb>Collections multilingues :\u003C\u002Fb> le modèle d'embedding et la stratégie de récupération doivent prendre en charge les langues réellement utilisées.","\u003Cb>Tableaux et code source :\u003C\u002Fb> un découpage en paragraphes simples peut détruire une structure essentielle à la réponse.","\u003Cb>Identifiants très courts :\u003C\u002Fb> la récupération sémantique peut être plus faible que la correspondance exacte pour les SKU, les identifiants, les codes d'erreur ou les acronymes.","\u003Cb>Questions longues nécessitant plusieurs faits :\u003C\u002Fb> la récupération peut nécessiter une décomposition, plusieurs recherches ou un reranking plutôt qu'une seule requête top-k.","\u003Cb>Hiérarchie des sources :\u003C\u002Fb> une politique officielle actuelle peut devoir primer sur un document de discussion plus ancien mais sémantiquement plus proche.",{"data":632,"type":42},{"text":633,"level":230},"Limites",{"data":635,"type":217},{"text":636},"Les exemples Python optimisent intentionnellement la transparence, et non l'échelle. Le récupérateur par mots-clés est naïf, le découpeur utilise la longueur en caractères, les exemples SQLite n'incluent pas de gestion des connexions en production, et l'exemple sémantique conserve tous les embeddings en mémoire.",{"data":638,"type":217},{"text":639},"Un système de production peut nécessiter des index vectoriels, des rerankers, une récupération hybride, des analyseurs de documents, de la mise en cache, de l'indexation incrémentielle, du versionnage des sources, des filtres de contrôle d'accès, de l'observabilité, des jeux de données d'évaluation et une gestion des défaillances. Aucun de ces ajouts ne change l'architecture de base ; ils rendent chaque frontière plus fiable.",{"data":641,"type":217},{"text":642},"Le RAG ne peut pas non plus créer des preuves absentes de l'ensemble des sources. Si la source est erronée, incomplète ou obsolète, un meilleur modèle d'embedding ne peut pas la transformer en connaissance faisant autorité.",{"data":644,"type":42},{"text":645,"level":230},"Qu'est-ce qui changerait cette réponse ?",{"data":647,"type":217},{"text":648},"L'architecture change lorsque la tâche nécessite plus qu'une simple recherche de connaissances. Un statut de commande en direct nécessite l'état actuel. Un calcul financier peut nécessiter du code déterministe. Une tâche de recherche web peut nécessiter une recherche active. Un flux de travail peut nécessiter des outils capables d'écrire des données dans un autre système. Un agent autonome peut nécessiter la planification, les autorisations et le contrôle de l'exécution en plus de la récupération.",{"data":650,"type":217},{"text":651},"Le RAG est donc mieux compris comme \u003Cb>une couche d'acquisition de preuves au sein d'un système d'IA plus vaste\u003C\u002Fb>. Il est puissant précisément parce qu'il a un rôle étroit : trouver des informations externes utiles et les placer dans le contexte de travail du modèle.",{"data":653,"type":42},{"text":654,"level":230},"Conclusion",{"data":656,"type":217},{"text":657},"Le RAG devient beaucoup plus facile à comprendre lorsque les noms des technologies sont retirés. Un fichier est une source. Une base de données est une source. Une API est une source. Une fonction de recherche récupère des preuves. Un prompt transporte ces preuves jusqu'au modèle. Le LLM les interprète ensuite et produit du langage.",{"data":659,"type":217},{"text":660},"La partie difficile du RAG en production n'est pas d'appeler un modèle d'embedding. C'est de construire un chemin de preuve fiable depuis la source originale jusqu'à l'affirmation finale : préserver la provenance, sélectionner la bonne méthode de récupération, maintenir l'information à jour, contrôler l'accès, évaluer la récupération séparément de la génération, et savoir quand un appel direct à une base de données ou à un outil est préférable à une recherche sémantique.",{"data":662,"type":217},{"text":663},"C'est la continuation pratique du modèle RAG de base : \u003Cb>comprendre d'abord les rôles, puis rendre le chemin des données explicite.\u003C\u002Fb>",{"data":665,"type":42},{"text":666,"level":230},"Sources primaires",{"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> — l'article de 2020 introduisant la formulation du RAG qui combine la génération avec une mémoire non paramétrique récupérée.","\u003Ca href=\"https:\u002F\u002Fwww.sbert.net\u002Fexamples\u002Fsentence_transformer\u002Fapplications\u002Fsemantic-search\u002FREADME.html\">Sentence Transformers — Semantic Search\u003C\u002Fa> — documentation officielle pour la récupération sémantique, les embeddings de requêtes et les embeddings de documents.","\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fembeddings\">OpenAI — Vector Embeddings\u003C\u002Fa> — documentation officielle décrivant les embeddings comme des représentations numériques utilisées pour la similarité et la recherche.","\u003Ca href=\"https:\u002F\u002Fwww.sqlite.org\u002Ffts5.html\">SQLite — FTS5 Extension\u003C\u002Fa> — documentation officielle pour la recherche en texte intégral et le classement BM25 dans SQLite.","\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Flibraries\">OpenAI — SDKs and CLI\u003C\u002Fa> — exemple officiel du SDK Python pour l'API Responses utilisé dans l'exemple optionnel de générateur.","\u003Ca href=\"https:\u002F\u002Fstajic.de\u002Ffr\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">What Is RAG? The Simplest Explanation of How It Works\u003C\u002Fa> — la première partie conceptuelle de cette série.","2.31","Un LLM ne connaît pas magiquement vos fichiers, bases de données ou API. Cette suite pratique de la série sur le RAG montre, avec du Python simple, comment des données externes deviennent des preuves récupérables : des fichiers texte et du SQL à la recherche en texte intégral, aux embeddings, à l'assemblage du contexte et à l'appel final au 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,1141],{"lang":701,"title":702,"content":703,"contentJson":704,"excerpt":1140},"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":1139},1790516400000,[707,710,713,717,719,722,725,728,731,734,737,739,742,745,747,750,753,756,759,762,765,768,771,774,777,780,783,786,818,821,824,827,837,840,842,870,873,876,902,905,908,920,923,926,929,932,935,938,941,944,946,949,952,954,957,960,962,965,968,971,973,976,979,982,985,987,990,993,996,998,1001,1004,1007,1010,1012,1015,1018,1020,1023,1026,1029,1031,1034,1037,1039,1042,1045,1048,1051,1054,1057,1060,1063,1066,1069,1072,1075,1078,1081,1084,1095,1098,1101,1104,1107,1110,1113,1116,1118,1121,1124,1127,1130],{"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":229,"level":230},{"data":720,"type":217},{"text":721},"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":723,"type":42},{"text":724,"level":230},"What This Really Means",{"data":726,"type":217},{"text":727},"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":729,"type":217},{"text":730},"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":732,"type":42},{"text":733,"level":230},"Simplest Example",{"data":735,"type":217},{"text":736},"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":738,"type":252},{"code":251},{"data":740,"type":217},{"text":741},"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":743,"type":217},{"text":744},"A slightly more general version ranks documents by overlapping query terms:",{"data":746,"type":252},{"code":261},{"data":748,"type":217},{"text":749},"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":751,"type":42},{"text":752,"level":230},"Where the Example Stops Working",{"data":754,"type":217},{"text":755},"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":757,"type":217},{"text":758},"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":760,"type":217},{"text":761},"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":763,"type":42},{"text":764,"level":230},"Direct Answer",{"data":766,"type":217},{"text":767},"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":769,"type":217},{"text":770},"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":772,"type":42},{"text":773,"level":230},"Why This Is So",{"data":775,"type":217},{"text":776},"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":778,"type":217},{"text":779},"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":781,"type":217},{"text":782},"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":784,"type":42},{"text":785,"level":230},"Context: The Main Types of Data Sources",{"data":787,"type":336},{"content":788,"withHeadings":14},[789,792,795,798,802,806,810,814],[305,790,791],"Typical retrieval method","Good for",[309,793,794],"Parsing + lexical or semantic search","Documentation, manuals, articles, notes",[313,796,797],"Structure-aware extraction + search","Policies, reports, contracts, manuals",[799,800,801],"SQL database","SQL query or filtered retrieval","Orders, users, products, structured records",[803,804,805],"REST \u002F GraphQL API","HTTP request with parameters","Remote systems and live service data",[807,808,809],"Search index","BM25 \u002F full-text \u002F hybrid search","Large text collections",[811,812,813],"Vector index","Embedding similarity","Semantic document retrieval",[815,816,817],"Application state","Direct state read or tool call","What is true right now",{"data":819,"type":217},{"text":820},"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":822,"type":217},{"text":823},"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":825,"type":42},{"text":826,"level":230},"Assumptions",{"data":828,"type":357},{"items":829,"style":356},[830,831,832,833,834,835,836],"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":838,"type":217},{"text":839},"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":841,"type":42},{"text":363,"level":230},{"data":843,"type":336},{"content":844,"withHeadings":14},[845,847,850,853,856,859,862,864,867],[368,846],"Why it changes the design",[848,849],"Source structure","A SQL table, legal PDF and source-code repository need different retrieval strategies",[851,852],"Question type","Exact lookup, conceptual search and multi-hop research are different tasks",[854,855],"Freshness requirement","Live state may need direct queries instead of periodically rebuilt indexes",[857,858],"Corpus size","In-memory search may work for hundreds of chunks but not for very large collections",[860,861],"Language","Multilingual retrieval requires models and tokenization suitable for the actual languages",[386,863],"Retrieval must filter by the current user’s access rights",[865,866],"Latency and cost","More retrieval stages can improve quality but add runtime and infrastructure cost",[868,869],"Need for provenance","High-trust systems need source IDs, versions and traceable evidence",{"data":871,"type":42},{"text":872,"level":230},"Diagnostic \u002F Decision Method",{"data":874,"type":217},{"text":875},"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":877,"type":336},{"content":878,"withHeadings":14},[879,882,886,890,894,898],[851,880,881],"Preferred first approach","Reason",[883,884,885],"Exact ID or current record","SQL \u002F key lookup \u002F API","Deterministic structured access",[887,888,889],"Exact wording, codes, names","Full-text or keyword search","Lexical precision",[891,892,893],"Conceptual question over documents","Semantic vector search","Meaning can differ from wording",[895,896,897],"Mixed enterprise knowledge","Hybrid retrieval + metadata filters","Combines lexical and semantic signals",[899,900,901],"Current application state","Direct state\u002Ftool access","Freshness matters more than document similarity",{"data":903,"type":217},{"text":904},"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":906,"type":217},{"text":907},"When an answer is wrong, diagnose the pipeline in order instead of immediately changing the LLM:",{"data":909,"type":357},{"items":910,"style":444},[911,912,913,914,915,916,917,918,919],"\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":921,"type":217},{"text":922},"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":924,"type":42},{"text":925,"level":230},"Evidence",{"data":927,"type":217},{"text":928},"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":930,"type":217},{"text":931},"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":933,"type":217},{"text":934},"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":936,"type":217},{"text":937},"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":939,"type":42},{"text":940,"level":230},"Real Example 1: A Folder of Text Files",{"data":942,"type":217},{"text":943},"Suppose a directory named \u003Ccode>knowledge\u002F\u003C\u002Fcode> contains ordinary text files. Python can load them with no AI library at all.",{"data":945,"type":252},{"code":471},{"data":947,"type":217},{"text":948},"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":950,"type":42},{"text":951,"level":478},"A Very Simple Chunker",{"data":953,"type":252},{"code":481},{"data":955,"type":217},{"text":956},"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":958,"type":42},{"text":959,"level":478},"Preserve Provenance While Chunking",{"data":961,"type":252},{"code":490},{"data":963,"type":217},{"text":964},"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":966,"type":42},{"text":967,"level":230},"Real Example 2: Structured Data — Use SQL When SQL Is the Right Tool",{"data":969,"type":217},{"text":970},"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":972,"type":252},{"code":502},{"data":974,"type":217},{"text":975},"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":977,"type":217},{"text":978},"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":980,"type":42},{"text":981,"level":230},"Real Example 3: Full-Text Search Before Embeddings",{"data":983,"type":217},{"text":984},"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":986,"type":252},{"code":517},{"data":988,"type":217},{"text":989},"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":991,"type":42},{"text":992,"level":230},"Real Example 4: Semantic Retrieval With Embeddings",{"data":994,"type":217},{"text":995},"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":997,"type":252},{"code":529},{"data":999,"type":217},{"text":1000},"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":1002,"type":217},{"text":1003},"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":1005,"type":42},{"text":1006,"level":230},"Real Example 5: Build the Context for the LLM",{"data":1008,"type":217},{"text":1009},"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":1011,"type":252},{"code":544},{"data":1013,"type":217},{"text":1014},"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":1016,"type":42},{"text":1017,"level":230},"Real Example 6: A Complete Minimal Pipeline",{"data":1019,"type":252},{"code":553},{"data":1021,"type":217},{"text":1022},"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":1024,"type":42},{"text":1025,"level":478},"Optional Generator: OpenAI Responses API",{"data":1027,"type":217},{"text":1028},"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":1030,"type":252},{"code":565},{"data":1032,"type":217},{"text":1033},"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":1035,"type":42},{"text":1036,"level":478},"The Whole Architecture in One View",{"data":1038,"type":252},{"code":574},{"data":1040,"type":217},{"text":1041},"This data-flow model is more durable than memorizing one framework. Libraries, databases and model vendors will change; the responsibility boundaries remain.",{"data":1043,"type":42},{"text":1044,"level":230},"Common Misconceptions and Failure Modes",{"data":1046,"type":42},{"text":1047,"level":478},"“RAG means vector database.”",{"data":1049,"type":217},{"text":1050},"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":1052,"type":42},{"text":1053,"level":478},"“If the data is in PostgreSQL, I must embed the whole database.”",{"data":1055,"type":217},{"text":1056},"No. Structured records should usually remain queryable as structured records. Embeddings are useful for semantic relevance, not as a replacement for deterministic queries.",{"data":1058,"type":42},{"text":1059,"level":478},"“More chunks means a better answer.”",{"data":1061,"type":217},{"text":1062},"Not necessarily. Extra context can introduce noise, conflicting versions and irrelevant material. Retrieval should optimize for useful evidence, not maximum volume.",{"data":1064,"type":42},{"text":1065,"level":478},"“A high similarity score proves the answer.”",{"data":1067,"type":217},{"text":1068},"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":1070,"type":42},{"text":1071,"level":478},"“Once the correct chunk is retrieved, hallucination is solved.”",{"data":1073,"type":217},{"text":1074},"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":1076,"type":42},{"text":1077,"level":478},"“The model failed, so change the model.”",{"data":1079,"type":217},{"text":1080},"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":1082,"type":42},{"text":1083,"level":230},"Edge Cases",{"data":1085,"type":357},{"items":1086,"style":356},[1087,1088,1089,1090,1091,1092,1093,1094],"\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":1096,"type":42},{"text":1097,"level":230},"Limitations",{"data":1099,"type":217},{"text":1100},"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":1102,"type":217},{"text":1103},"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":1105,"type":217},{"text":1106},"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":1108,"type":42},{"text":1109,"level":230},"What Would Change This Answer?",{"data":1111,"type":217},{"text":1112},"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":1114,"type":217},{"text":1115},"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":1117,"type":42},{"text":654,"level":230},{"data":1119,"type":217},{"text":1120},"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":1122,"type":217},{"text":1123},"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":1125,"type":217},{"text":1126},"That is the practical continuation of the basic RAG model: \u003Cb>first understand the roles, then make the data path explicit.\u003C\u002Fb>",{"data":1128,"type":42},{"text":1129,"level":230},"Primary Sources",{"data":1131,"type":357},{"items":1132,"style":356},[1133,1134,1135,1136,1137,1138],"\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":1142,"excerpt":677},{"time":212,"blocks":1143,"version":676},[1144,1146,1148,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,1209,1211,1213,1215,1218,1220,1222,1234,1236,1238,1247,1249,1251,1254,1256,1258,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,1373,1375,1377,1379,1381,1383,1385,1387,1389,1391,1393,1395,1397],{"data":1145,"type":217},{"text":216},{"data":1147,"type":217},{"text":220},{"data":1149,"type":226},{"text":223,"caption":224,"alignment":225},{"data":1151,"type":42},{"text":229,"level":230},{"data":1153,"type":217},{"text":233},{"data":1155,"type":42},{"text":236,"level":230},{"data":1157,"type":217},{"text":239},{"data":1159,"type":217},{"text":242},{"data":1161,"type":42},{"text":245,"level":230},{"data":1163,"type":217},{"text":248},{"data":1165,"type":252},{"code":251},{"data":1167,"type":217},{"text":255},{"data":1169,"type":217},{"text":258},{"data":1171,"type":252},{"code":261},{"data":1173,"type":217},{"text":264},{"data":1175,"type":42},{"text":267,"level":230},{"data":1177,"type":217},{"text":270},{"data":1179,"type":217},{"text":273},{"data":1181,"type":217},{"text":276},{"data":1183,"type":42},{"text":279,"level":230},{"data":1185,"type":217},{"text":282},{"data":1187,"type":217},{"text":285},{"data":1189,"type":42},{"text":288,"level":230},{"data":1191,"type":217},{"text":291},{"data":1193,"type":217},{"text":294},{"data":1195,"type":217},{"text":297},{"data":1197,"type":42},{"text":300,"level":230},{"data":1199,"type":336},{"content":1200,"withHeadings":14},[1201,1202,1203,1204,1205,1206,1207,1208],[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":1210,"type":217},{"text":339},{"data":1212,"type":217},{"text":342},{"data":1214,"type":42},{"text":345,"level":230},{"data":1216,"type":357},{"items":1217,"style":356},[349,350,351,352,353,354,355],{"data":1219,"type":217},{"text":360},{"data":1221,"type":42},{"text":363,"level":230},{"data":1223,"type":336},{"content":1224,"withHeadings":14},[1225,1226,1227,1228,1229,1230,1231,1232,1233],[368,369],[371,372],[374,375],[377,378],[380,381],[383,384],[386,387],[389,390],[392,393],{"data":1235,"type":42},{"text":396,"level":230},{"data":1237,"type":217},{"text":399},{"data":1239,"type":336},{"content":1240,"withHeadings":14},[1241,1242,1243,1244,1245,1246],[374,404,405],[407,408,409],[411,412,413],[415,416,417],[419,420,421],[423,424,425],{"data":1248,"type":217},{"text":428},{"data":1250,"type":217},{"text":431},{"data":1252,"type":357},{"items":1253,"style":444},[435,436,437,438,439,440,441,442,443],{"data":1255,"type":217},{"text":447},{"data":1257,"type":42},{"text":450,"level":230},{"data":1259,"type":217},{"text":453},{"data":1261,"type":217},{"text":456},{"data":1263,"type":217},{"text":459},{"data":1265,"type":217},{"text":462},{"data":1267,"type":42},{"text":465,"level":230},{"data":1269,"type":217},{"text":468},{"data":1271,"type":252},{"code":471},{"data":1273,"type":217},{"text":474},{"data":1275,"type":42},{"text":477,"level":478},{"data":1277,"type":252},{"code":481},{"data":1279,"type":217},{"text":484},{"data":1281,"type":42},{"text":487,"level":478},{"data":1283,"type":252},{"code":490},{"data":1285,"type":217},{"text":493},{"data":1287,"type":42},{"text":496,"level":230},{"data":1289,"type":217},{"text":499},{"data":1291,"type":252},{"code":502},{"data":1293,"type":217},{"text":505},{"data":1295,"type":217},{"text":508},{"data":1297,"type":42},{"text":511,"level":230},{"data":1299,"type":217},{"text":514},{"data":1301,"type":252},{"code":517},{"data":1303,"type":217},{"text":520},{"data":1305,"type":42},{"text":523,"level":230},{"data":1307,"type":217},{"text":526},{"data":1309,"type":252},{"code":529},{"data":1311,"type":217},{"text":532},{"data":1313,"type":217},{"text":535},{"data":1315,"type":42},{"text":538,"level":230},{"data":1317,"type":217},{"text":541},{"data":1319,"type":252},{"code":544},{"data":1321,"type":217},{"text":547},{"data":1323,"type":42},{"text":550,"level":230},{"data":1325,"type":252},{"code":553},{"data":1327,"type":217},{"text":556},{"data":1329,"type":42},{"text":559,"level":478},{"data":1331,"type":217},{"text":562},{"data":1333,"type":252},{"code":565},{"data":1335,"type":217},{"text":568},{"data":1337,"type":42},{"text":571,"level":478},{"data":1339,"type":252},{"code":574},{"data":1341,"type":217},{"text":577},{"data":1343,"type":42},{"text":580,"level":230},{"data":1345,"type":42},{"text":583,"level":478},{"data":1347,"type":217},{"text":586},{"data":1349,"type":42},{"text":589,"level":478},{"data":1351,"type":217},{"text":592},{"data":1353,"type":42},{"text":595,"level":478},{"data":1355,"type":217},{"text":598},{"data":1357,"type":42},{"text":601,"level":478},{"data":1359,"type":217},{"text":604},{"data":1361,"type":42},{"text":607,"level":478},{"data":1363,"type":217},{"text":610},{"data":1365,"type":42},{"text":613,"level":478},{"data":1367,"type":217},{"text":616},{"data":1369,"type":42},{"text":619,"level":230},{"data":1371,"type":357},{"items":1372,"style":356},[623,624,625,626,627,628,629,630],{"data":1374,"type":42},{"text":633,"level":230},{"data":1376,"type":217},{"text":636},{"data":1378,"type":217},{"text":639},{"data":1380,"type":217},{"text":642},{"data":1382,"type":42},{"text":645,"level":230},{"data":1384,"type":217},{"text":648},{"data":1386,"type":217},{"text":651},{"data":1388,"type":42},{"text":654,"level":230},{"data":1390,"type":217},{"text":657},{"data":1392,"type":217},{"text":660},{"data":1394,"type":217},{"text":663},{"data":1396,"type":42},{"text":666,"level":230},{"data":1398,"type":357},{"items":1399,"style":356},[670,671,672,673,674,675],"Post erfolgreich abgerufen",{"items":1402,"source":1487,"manualIds":1488,"manualMatchedIds":1489},[1403,1410,1417,1424,1431,1438,1445,1452,1459,1466,1473,1480],{"id":1404,"slug":1405,"title":1406,"excerpt":1407,"featuredImage":1408,"publishedAt":1409},"383","canonical-architecture-url-design-resolver-logic-api-scalability-specification","Architecture Canonique, Conception d'URL, Logique de Résolution, Spécification d'API et d'Évolutivité","Architecture de découverte géolocalisée pour les portails multi-locataires. Définit les URL canoniques, la logique de résolution, la stratégie de mise en cache et un modèle de lecture géo sans couplage CMS ni refactorisation de base de données. Conçue pour la stabilité SEO, l'évolutivité et les futures extensions comme la réservation et les cartes.","\u002Fuploads\u002F2026\u002F01\u002Fcanonical-architecture-url-design-resolver-logic-api-scalability-specification-1769890763607-7rghbp.webp","2026-01-31T06:12:00.000Z",{"id":1411,"slug":1412,"title":1413,"excerpt":1414,"featuredImage":1415,"publishedAt":1416},"453","zbt-z8102ax-openwrt-2102-firmware-review","Test du firmware OpenWrt 21.02 du ZBT Z8102AX : assez stable, mais est-il paré pour l'avenir ?","Le ZBT Z8102AX fonctionne sous une version d'OpenWrt 21.02 modifiée par le fabricant avec le noyau 5.4.246. Lors des tests pratiques, le firmware a fonctionné avec succès et a maintenu le routeur stable pendant plusieurs jours, mais cette ancienne base soulève d'importantes questions sur la sécurité, le contrôle du modem, les chemins de mise à niveau et la maintenabilité à long terme.","\u002Fuploads\u002F2026\u002F06\u002Fopenwrt-router-review-dual-sim-04-1781620594653-uvf5oy.webp","2026-06-16T10:39:00.000Z",{"id":1418,"slug":1419,"title":1420,"excerpt":1421,"featuredImage":1422,"publishedAt":1423},"475","managed-agent-harness-vs-self-hosted-agent-loop-what-you-gain-what-you-lose","Harnais d'agent géré vs boucle d'agent auto-hébergée : ce que vous gagnez, ce que vous perdez","“Agent auto-hébergé” peut désigner des architectures très différentes. Ce guide distingue le harnais géré, l'environnement d'exécution auto-hébergé et la boucle d'agent entièrement auto-opérée—et montre de quelle frontière de contrôle les équipes ont réellement besoin.","\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":1425,"slug":1426,"title":1427,"excerpt":1428,"featuredImage":1429,"publishedAt":1430},"448","google-io-2026-android-xr-and-intelligent-eyewear","Google I\u002FO 2026 : Android XR, lunettes intelligentes et l'interface d'IA ambiante","Google I\u002FO 2026 a fait passer Android XR et les lunettes intelligentes du concept vers une véritable orientation de plateforme. Cet article décrypte les lunettes audio, les lunettes à affichage, la conscience contextuelle alimentée par Gemini, les implications pour les développeurs, les risques pour la vie privée, et pourquoi l'IA portable consiste moins à remplacer les téléphones qu'à créer des surfaces d'assistance ambiante.","\u002Fuploads\u002F2026\u002F05\u002Fgoogle-io-2026-android-xr-and-intelligent-eyewear-1779227942270-dtsm9y.webp","2026-05-21T11:05:00.000Z",{"id":1432,"slug":1433,"title":1434,"excerpt":1435,"featuredImage":1436,"publishedAt":1437},"455","zbt-z8102ax-dual-sim-failover-test","Basculement double SIM du ZBT Z8102AX : ce qui fonctionne, ce qui manque et ce qui nécessite un meilleur firmware","Le ZBT Z8102AX est un routeur OpenWrt 5G double SIM, mais le matériel double SIM à lui seul n'est pas la même chose qu'un basculement intelligent. Le routeur reconnaît la carte SIM et se connecte avec succès, mais la commutation automatique, la récupération du modem, les décisions basées sur le signal et une logique de basculement propre nécessitent encore des tests plus approfondis.","\u002Fuploads\u002F2026\u002F06\u002Fopenwrt-router-review-dual-sim-03-1781620592829-7t77j7.webp","2026-06-16T10:40:00.000Z",{"id":1439,"slug":1440,"title":1441,"excerpt":1442,"featuredImage":1443,"publishedAt":1444},"469","rag-failed-but-which-layer-actually-failed-a-diagnostic-method","Échec du RAG — mais quelle couche a réellement échoué ? Une méthode de diagnostic","Lorsqu'une réponse RAG est erronée, blâmer la récupération ou le modèle est trop vague. Cette méthode de diagnostic isole la couverture des sources, la construction de la requête, la récupération, le classement, l'assemblage du contexte, la génération, l'attribution des preuves et la fraîcheur—afin que la défaillance réelle puisse être reproduite et corrigée.","\u002Fuploads\u002F2026\u002F09\u002Frag-failed-but-which-layer-actually-failed-a-diagnostic-method-1790350847177-pior4c.webp","2026-09-24T19:39:00.000Z",{"id":1446,"slug":1447,"title":1448,"excerpt":1449,"featuredImage":1450,"publishedAt":1451},"472","why-more-context-can-make-ai-answers-worse","Pourquoi plus de contexte peut rendre les réponses de l'IA pires","Une fenêtre de contexte plus grande ne garantit pas une meilleure réponse. Cet article explique comment la dilution du signal, les preuves contradictoires, l'état obsolète, la sensibilité à la position et la compression avec perte peuvent réduire la fiabilité de l'IA — et présente un test pratique de pression de contexte.","\u002Fuploads\u002F2026\u002F09\u002Fwhy-more-context-can-make-ai-answers-worse-1790351615793-2ntv2v.webp","2026-09-25T11:51:00.000Z",{"id":1453,"slug":1454,"title":1455,"excerpt":1456,"featuredImage":1457,"publishedAt":1458},"372","convert-mov-to-mp4-using-ffmpeg-a-simple-guide","Convertir MOV en MP4 en utilisant FFmpeg : Un guide simple","Apprenez à convertir des vidéos MOV en MP4 en utilisant FFmpeg avec des commandes fiables, le traitement par lots et l'optimisation de la qualité pour le web, le streaming et la compatibilité multiplateforme.","\u002Fuploads\u002F2024\u002F10\u002F20241008-Convert-MOV-to-MP4-Using-FFmpeg_-A-Simple-Guide-large.webp","2024-10-08T09:31:00.000Z",{"id":1460,"slug":1461,"title":1462,"excerpt":1463,"featuredImage":1464,"publishedAt":1465},"449","google-io-2026-agentic-products-search-workspace-and-shopping","Google I\u002FO 2026 : Produits agentiels dans la Recherche, Workspace et Shopping","Google I\u002FO 2026 a montré que l'IA agentielle va au-delà des démonstrations de modèles et des outils de développement pour s'intégrer dans les interfaces des produits du quotidien. Cet article explique comment Search, Workspace, Gemini Spark et Universal Cart pointent vers un nouveau modèle de produit où les agents Google aident les utilisateurs à effectuer des recherches, travailler, faire des achats et agir à travers des services connectés.","\u002Fuploads\u002F2026\u002F05\u002Fgoogle-io-2026-agentic-products-search-workspace-and-shopping-1779228004340-9mqs07.webp","2026-05-21T11:09:00.000Z",{"id":1467,"slug":1468,"title":1469,"excerpt":1470,"featuredImage":1471,"publishedAt":1472},"470","what-should-an-ai-agent-remember-forget-recompute-or-retrieve-again","Que devrait mémoriser, oublier, recalculer ou récupérer à nouveau un agent IA ?","Les agents à exécution longue ne devraient pas tout retenir. Cet article propose un modèle de cycle de vie pratique pour décider de ce qui a sa place dans la mémoire durable, de ce qui devrait être récupéré à nouveau, de ce qu'il est plus sûr de recalculer et de ce qui devrait expirer ou être remplacé.","\u002Fuploads\u002F2026\u002F09\u002Fwhat-should-an-ai-agent-remember-forget-recompute-or-retrieve-again-1790351131087-iehz28.webp","2026-09-25T09:43:00.000Z",{"id":1474,"slug":1475,"title":1476,"excerpt":1477,"featuredImage":1478,"publishedAt":1479},"3","postfixadmin-enterprise-grade-management-for-postfix-mail-systems-anno-2026","PostfixAdmin : Gestion de niveau entreprise pour les systèmes de messagerie Postfix — Anno 2026","PostfixAdmin est une interface d'administration centrée sur une base de données conçue pour les systèmes de messagerie Postfix professionnels. Plutôt que de masquer la complexité, il offre un contrôle précis sur les domaines, les boîtes aux lettres, les alias et les permissions d'expéditeur. Cet article explique pourquoi PostfixAdmin reste une solution d'entreprise fiable en 2026 et comment il s'intègre dans les infrastructures de messagerie modernes et axées sur la sécurité.","\u002Fuploads\u002F2026\u002F01\u002Fpostfixadmin-enterprise-grade-management-for-postfix-mail-systems-anno-2026-1768311098693-w36cpk.webp","2026-01-13T07:58:00.000Z",{"id":1481,"slug":1482,"title":1483,"excerpt":1484,"featuredImage":1485,"publishedAt":1486},"376","laravel-12-custom-cms-with-filament3","Laravel 12 CMS personnalisé avec Filament 3 : Le workflow des experts","Une analyse détaillée des synergies entre Laravel 12 et Filament 3 pour la création de systèmes de gestion de contenu sur mesure. Des experts analysent le flux de travail innovant, les avantages, les inconvénients et le défi du flux de travail Jetstream.","\u002Fuploads\u002F2025\u002F01\u002FLaravel-12-Custom-CMS-with-a-Filament3-large.webp","2025-01-12T02:18:00.000Z","fallback",[],[]]