[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"portal-settings:stajic:de":3,"public-menus:all":37,"post:where-does-an-llm-get-its-data-rag-data-sources-in-python:de":204,"related:post:where-does-an-llm-get-its-data-rag-data-sources-in-python:de:1":1404},{"statusCode":4,"data":5,"message":36},200,{"tenantId":6,"lang":7,"defaultLang":7,"siteUrl":8,"contactEmail":9,"brandName":10,"logoUrl":11,"siteName":10,"siteDescription":12,"ogImage":9,"robotsIndex":13,"socialLinks":9,"reservedSlugs":9,"seoPolicy":14},"stajic","de","https:\u002F\u002Fstajic.de",null,"Stajic Platform","\u002FLogo_Planet.svg","Stajic Portal",true,{"branding":15,"relatedContent":16,"crossDomainLinks":17},{"logoUrl":11},{"enabled":13},[18,21,24,27,30,33],{"url":19,"label":20,"isActive":13,"showInFooter":13,"includeInSameAs":13},"https:\u002F\u002Ffigure.rocks","figure.rocks",{"url":22,"label":23,"isActive":13,"showInFooter":13,"includeInSameAs":13},"https:\u002F\u002Floving.rocks","loving.rocks",{"url":25,"label":26,"isActive":13,"showInFooter":13,"includeInSameAs":13},"https:\u002F\u002Fbazify.com","bazify.com",{"url":28,"label":29,"isActive":13,"showInFooter":13,"includeInSameAs":13},"https:\u002F\u002Fbazify.de","bazify.de",{"url":31,"label":32,"isActive":13,"showInFooter":13,"includeInSameAs":13},"https:\u002F\u002Fbazify.at","bazify.at",{"url":34,"label":35,"isActive":13,"showInFooter":13,"includeInSameAs":13},"https:\u002F\u002Fbazify.ba","bazify.ba","Portal settings resolved",[38,44],{"id":39,"name":40,"location":41,"isActive":13,"isDefault":42,"items":43},1,"main-navigation","header",false,[],{"id":45,"name":46,"location":47,"isActive":13,"isDefault":13,"items":48},4,"main-menu","sidebar",[49,65,78,92,102,117,132],{"id":50,"title":51,"url":59,"target":60,"icon":61,"isActive":13,"type":62,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":63,"portfolioId":9,"children":64},"item-18",{"de":52,"en":53,"es":54,"fr":55,"it":53,"ru":56,"sr":57,"zh":58},"Startseite","Home","Inicio","Accueil","Главная","Почетна","首页","\u002Ffull-stack-web-developer-munich-performance-seo-and-maintainable-builds","_self","i-lucide-home","page",111,[],{"id":66,"title":67,"url":74,"target":60,"icon":75,"isActive":13,"type":62,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":76,"portfolioId":9,"children":77},"item-22",{"de":68,"en":68,"es":69,"fr":68,"it":70,"ru":71,"sr":72,"zh":73},"Vision","Visión","Visione","Видение","Визија","想象","\u002Fueber-uns-webdesign-muenchen-webaplikation","i-lucide-eye",113,[],{"id":79,"title":80,"url":88,"target":60,"icon":89,"isActive":13,"type":62,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":90,"portfolioId":9,"children":91},"item-19",{"de":81,"en":82,"es":83,"fr":82,"it":84,"ru":85,"sr":86,"zh":87},"Leistungen","Services","Servicios","Servizi","Услуги","Услуге","服务","\u002Fservices-dienstleistungen-muenchen","i-lucide-wrench",116,[],{"id":93,"title":94,"url":98,"target":60,"icon":99,"isActive":13,"type":62,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":100,"portfolioId":9,"children":101},"item-23",{"de":95,"en":95,"es":95,"fr":95,"it":95,"ru":96,"sr":96,"zh":97},"Blog","Блог","博客","\u002Fblog","i-lucide-book-open",112,[],{"id":103,"title":104,"url":113,"target":60,"icon":114,"isActive":13,"type":62,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":115,"portfolioId":9,"children":116},"item-32",{"de":105,"en":106,"es":107,"fr":108,"it":109,"ru":110,"sr":111,"zh":112},"Neue Technologien","New Technologies","Nuevas tecnologías","Nouvelles technologies","Nuove tecnologie","Новые технологии","Нове технологије","新技术！","\u002Fneue-webtechnologien","i-lucide-sparkles",122,[],{"id":118,"title":119,"url":128,"target":60,"icon":129,"isActive":13,"type":62,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":130,"portfolioId":9,"children":131},"item-20",{"de":120,"en":121,"es":122,"fr":123,"it":124,"ru":125,"sr":126,"zh":127},"Kontakt","Contact us!","Contacto","Contact","Contatto","Контакт","Контактирајте нас","联系我们！","\u002Fcontact","i-lucide-mail",115,[],{"id":133,"title":134,"url":143,"target":60,"icon":144,"isActive":13,"type":62,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":145,"portfolioId":9,"children":146},"item-21",{"de":135,"en":136,"es":137,"fr":138,"it":139,"ru":140,"sr":141,"zh":142},"Unsere Arbeit","Our Work","Nuestro trabajo","Nos réalisations","I nostri lavori","Наши работы","Наши радови","文件夹","\u002Fportfolio","i-lucide-briefcase",114,[147,160,174,180,192],{"id":148,"title":149,"url":143,"target":60,"icon":158,"isActive":13,"type":62,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":145,"portfolioId":9,"children":159},"item-24",{"de":150,"en":151,"es":152,"fr":153,"it":154,"ru":155,"sr":156,"zh":157},"Alle Projekte","All Projects","Todos los proyectos","Tous les projets","Tutti i progetti","Все проекты","Сви пројекти","所有项目","i-lucide-grid-3x3",[],{"id":161,"title":162,"url":170,"target":60,"icon":171,"isActive":13,"type":172,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":9,"portfolioId":9,"children":173},"item-29",{"de":163,"en":164,"es":165,"fr":166,"it":167,"ru":168,"sr":169,"zh":142},"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":175,"title":176,"url":178,"target":60,"icon":171,"isActive":13,"type":172,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":9,"portfolioId":9,"children":179},"item-28",{"de":177,"en":177,"es":177,"fr":177,"it":177,"ru":177,"sr":177,"zh":177},"Solr Suggester","\u002Fportfolio\u002Fsolr-fuzzy-suggester-und-solr-infix-suggester-abfrage-ueber-ajax-und-filterung",[],{"id":181,"title":182,"url":190,"target":60,"icon":171,"isActive":13,"type":172,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":9,"portfolioId":9,"children":191},"item-27",{"de":183,"en":184,"es":185,"fr":186,"it":187,"ru":188,"sr":189,"zh":184},"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":193,"title":194,"url":202,"target":60,"icon":171,"isActive":13,"type":172,"productId":9,"categoryId":9,"shopCategoryId":9,"articleId":9,"pageId":9,"portfolioId":9,"children":203},"item-31",{"de":195,"en":196,"es":197,"fr":198,"it":199,"ru":200,"sr":201,"zh":196},"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":205,"message":1403},{"id":206,"title":207,"slug":208,"content":209,"contentJson":210,"excerpt":676,"featuredImage":677,"featuredImageAlt":678,"featuredImageCaption":9,"featuredImageTitle":9,"featuredImageCopyright":9,"featuredImageAuthor":9,"featuredImageSourceUrl":9,"featuredImageLicense":9,"featuredImageIsAiGenerated":42,"status":679,"publishedAt":680,"createdAt":681,"updatedAt":682,"seoLocalePaths":683,"categories":692,"author":693,"translations":698},"479","Woher bezieht ein LLM seine Daten? RAG-Datenquellen in Python","where-does-an-llm-get-its-data-rag-data-sources-in-python","\u003Cp>Der vorherige Artikel, \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fde\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">Was ist RAG? Die einfachste Erklärung, wie es funktioniert\u003C\u002Fa>, hat das mentale Modell etabliert: Das LLM schreibt, RAG ruft nützliches Wissen ab, die Anwendung besitzt den aktuellen Zustand, und Tools führen Aktionen aus. Dieser Artikel geht den nächsten Schritt: \u003Cb>Woher kommen die Daten eigentlich, und wie sieht Retrieval in Python aus?\u003C\u002Fb>\u003C\u002Fp>\n\u003Cp>Die wichtige Überraschung ist, dass eine „LLM-Datenquelle“ normalerweise nichts Exotisches ist. Es kann eine Textdatei sein, ein Ordner mit Markdown-Dokumenten, eine SQL-Datenbank, eine API-Antwort, ein Produktkatalog, ein Support-System oder ein Vektorindex, der aus diesen Quellen abgeleitet wurde. Die KI kennt diese Systeme nicht auf magische Weise. Ihre Anwendung muss die relevanten Daten laden, abfragen, durchsuchen oder abrufen und das Ergebnis in den Kontext des Modells einfügen.\u003C\u002Fp>\n\u003Cblockquote class=\"border-l-4 border-gray-300 pl-4 italic\">Datenquelle = wo Informationen leben. Retrieval = wie die Anwendung nützliche Informationen findet. Kontext = die ausgewählten Informationen, die dem Modell gegeben werden. LLM = die Komponente, die diesen Kontext interpretiert und eine Antwort generiert.\u003Ccite class=\"block mt-2 text-sm\">— Das Vier-Teile-Modell, das in diesem Artikel verwendet wird\u003C\u002Fcite>\u003C\u002Fblockquote>\n\u003Ch2 id=\"section-4\">Frage\u003C\u002Fh2>\n\u003Cp>Wie nutzt ein LLM externe Daten wie Dateien, Datenbanken oder APIs, und wie kann ein kleines Python-Programm die wesentlichen RAG-Schritte implementieren, ohne sie hinter einem Framework zu verbergen?\u003C\u002Fp>\n\u003Ch2 id=\"section-6\">Was das wirklich bedeutet\u003C\u002Fh2>\n\u003Cp>Wenn Entwickler sagen, dass ein LLM „mit Unternehmensdaten verbunden“ ist, können sich hinter diesem Satz mehrere verschiedene Operationen verbergen. Eine Anwendung führt möglicherweise SQL aus. Eine andere ruft eine API auf. Eine weitere führt eine Volltextsuche durch. Eine andere berechnet die Embedding-Ähnlichkeit über Dokument-Chunks. Alle können einem LLM externe Informationen liefern, aber sie sind nicht die gleiche Retrieval-Methode und sollten nicht als austauschbar behandelt werden.\u003C\u002Fp>\n\u003Cp>Diese Unterscheidung ist wichtig, weil die beste Retrieval-Methode von der Form der Frage abhängt. „Wie lautet unsere Rückerstattungsrichtlinie?“ ist ein Dokument-Retrieval-Problem. „Wie lautet der aktuelle Status von Bestellung 4711?“ ist normalerweise eine strukturierte Datenbankabfrage. „Welcher Absatz behandelt die Kontowiederherstellung?“ kann eine Keyword- oder semantische Suche sein. RAG ist am nützlichsten, wenn das System \u003Cb>relevantes Wissen vor der Generierung entdecken muss\u003C\u002Fb>.\u003C\u002Fp>\n\u003Ch2 id=\"section-9\">Einfachstes Beispiel\u003C\u002Fh2>\n\u003Cp>Beginnen Sie mit drei Strings in gewöhnlichem Python. Es gibt noch keine Vektordatenbank, kein Framework und kein LLM. Wir wollen nur den Retrieval-Schritt sichtbar machen.\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>Das Programm gibt den ersten Satz aus, weil er den Begriff enthält, nach dem wir gesucht haben. Dies ist primitives Retrieval, aber die Architektur ist bereits sichtbar: \u003Cb>Frage → Suche → relevanter Text\u003C\u002Fb>. RAG fügt einen weiteren wichtigen Schritt hinzu: den abgerufenen Text zusammen mit der Frage an ein Sprachmodell übergeben.\u003C\u002Fp>\n\u003Cp>Eine etwas allgemeinere Version ordnet Dokumente nach überlappenden Abfragebegriffen:\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>Dies ist keine Produktionssuchmaschine. Sie ignoriert Morphologie, Synonyme, Schreibvarianten, Dokumentlänge und viele Ranking-Signale. Ihr Wert ist pädagogisch: \u003Cb>RAG beginnt nicht mit einer Vektordatenbank. Es beginnt mit Retrieval.\u003C\u002Fb>\u003C\u002Fp>\n\u003Ch2 id=\"section-16\">Wo das Beispiel nicht mehr funktioniert\u003C\u002Fh2>\n\u003Cp>Exakte oder lexikalische Übereinstimmung wird schwach, wenn die Frage und die Quelle unterschiedliche Wörter verwenden. Ein Dokument kann „Fahrzeugwartung“ sagen, während der Benutzer fragt: „Wie repariere ich mein Auto?“ Ein lexikalischer Retriever kann die Beziehung verfehlen, obwohl ein Mensch sie sofort sieht. Semantisches Retrieval adressiert dies, indem es Text als Vektoren darstellt und Bedeutung vergleicht, nicht nur exakte Tokens.\u003C\u002Fp>\n\u003Cp>Lange Dateien schaffen ein weiteres Problem. Ein ganzes 80-seitiges Handbuch als eine Einheit zu durchsuchen ist zu grob, aber jeden Satz aufzuteilen kann nützlichen Kontext zerstören. Echte RAG-Systeme benötigen daher Entscheidungen über Parsing, Chunking, Metadaten, Ranking, Aktualität, Berechtigungen und Herkunft.\u003C\u002Fp>\n\u003Cp>Das Beispiel sagt auch nichts über strukturierte Live-Fakten aus. Wenn der Benutzer nach dem aktuellen Status der Bestellung 4711 fragt und die Anwendung bereits einen Datenbankschlüssel hat, ist die semantische Suche normalerweise das falsche erste Werkzeug. Eine deterministische Datenbankabfrage ist besser.\u003C\u002Fp>\n\u003Ch2 id=\"section-20\">Direkte Antwort\u003C\u002Fh2>\n\u003Cp>Eine LLM-Datenquelle ist jedes externe System, aus dem eine Anwendung Informationen für das Modell beziehen kann: Dateien, Datenbanken, APIs, Suchindizes, Vektorspeicher oder Live-Anwendungszustand. RAG ist das Muster, \u003Cb>relevantes Wissen aus solchen Quellen vor der Generierung abzurufen\u003C\u002Fb>.\u003C\u002Fp>\n\u003Cp>In Python kann die wesentliche Pipeline sehr klein sein: \u003Cb>Daten laden → abrufbare Einheiten erstellen → relevante Belege finden → Kontext zusammenstellen → das LLM aufrufen\u003C\u002Fb>. Die Abrufmethode sollte zur Quelle und zur Frage passen. Verwenden Sie SQL für exakte strukturierte Fakten, Volltextsuche für lexikalisches Matching, Embeddings für semantische Ähnlichkeit und hybride Suche, wenn mehrere Signale wertvoll sind.\u003C\u002Fp>\n\u003Ch2 id=\"section-23\">Warum das so ist\u003C\u002Fh2>\n\u003Cp>Ein Sprachmodell erhält nicht automatisch die Inhalte Ihres Dateisystems, Ihrer PostgreSQL-Datenbank, Ihres CRM, Ihrer privaten API oder eines neu bearbeiteten Dokuments. Die Anwendung entscheidet, auf welche externen Informationen zugegriffen werden kann und was in den aktuellen Kontext des Modells eingefügt wird.\u003C\u002Fp>\n\u003Cp>Die ursprüngliche Arbeit zur Retrieval-Augmented Generation von Lewis et al. kombinierte ein generatives Modell mit externem nicht-parametrischem Speicher, der aus einem dichten Vektorindex abgerufen wurde. Die breitere architektonische Idee überlebt über diese spezifische Implementierung hinaus: Externe Belege können zur Inferenzzeit abgerufen werden, anstatt zu erwarten, dass alles nützliche Wissen in den Modellparametern kodiert ist.\u003C\u002Fp>\n\u003Cp>Dies schafft eine nützliche Trennung der Zuständigkeiten: Die Quelle speichert Informationen, der Retriever wählt Belege aus, der Kontext trägt diese Belege in die Anfrage, und das Modell interpretiert sie. Wenn diese Grenzen sichtbar bleiben, lassen sich Fehler viel leichter diagnostizieren.\u003C\u002Fp>\n\u003Ch2 id=\"section-27\">Kontext: Die wichtigsten Arten von Datenquellen\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\">Quelle\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Typische Abrufmethode\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Geeignet für\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">TXT \u002F Markdown \u002F HTML\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Parsing + lexikalische oder semantische Suche\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Dokumentation, Handbücher, Artikel, Notizen\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\">Struktur-bewusste Extraktion + Suche\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Richtlinien, Berichte, Verträge, Handbücher\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">SQL-Datenbank\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">SQL-Abfrage oder gefilterter Abruf\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Bestellungen, Benutzer, Produkte, strukturierte Datensätze\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">REST \u002F GraphQL API\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">HTTP-Anfrage mit Parametern\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Remote-Systeme und Live-Service-Daten\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Suchindex\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">BM25 \u002F Volltext \u002F hybride Suche\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Große Textsammlungen\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Vektorindex\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Embedding-Ähnlichkeit\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Semantischer Dokumentenabruf\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Anwendungszustand\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Direktes Zustandslesen oder Tool-Aufruf\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Was gerade jetzt wahr ist\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>Ein Vektorindex verdient besondere Aufmerksamkeit. In vielen Architekturen ist er \u003Cb>nicht die kanonische Quelle der Wahrheit\u003C\u002Fb>. Er ist ein Abrufindex, der aus Dokumenten oder Datensätzen abgeleitet wurde. Das maßgebliche Dokument kann in Objektspeicher, einem CMS, Git, PostgreSQL oder einem anderen System liegen, während Embeddings und Metadaten separat für schnelle semantische Suche gespeichert werden. Einige Systeme verwenden einen Vektorspeicher tatsächlich als Primärspeicher, aber das ist eine architektonische Entscheidung und keine Anforderung von RAG.\u003C\u002Fp>\n\u003Cp>Wenn die Grenze zwischen Abruf, persistentem Gedächtnis, aktuellem Zustand und Modellkontext noch unklar ist, siehe \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fde\u002Fblog\u002Fai-agent-memory-is-not-rag-how-to-separate-memory-retrieval-state-and-context\">AI Agent Memory Is Not RAG\u003C\u002Fa>. Diese Schichten können einige derselben Speichertechnologien verwenden und dennoch unterschiedliche Korrektheitsregeln haben.\u003C\u002Fp>\n\u003Ch2 id=\"section-31\">Annahmen\u003C\u002Fh2>\n\u003Cul>\u003Cli>Die Anwendung darf auf die externe Quelle zugreifen.\u003C\u002Fli>\u003Cli>Die relevante Quelle enthält genügend Informationen, um die Frage zu beantworten.\u003C\u002Fli>\u003Cli>Die Daten können in einer Form geparst oder abgefragt werden, die die Abrufschicht nutzen kann.\u003C\u002Fli>\u003Cli>Die abgerufenen Informationen sind frisch genug für die angeforderte Entscheidung.\u003C\u002Fli>\u003Cli>Das Modell erhält die ausgewählten Belege in seinem Kontext.\u003C\u002Fli>\u003Cli>Die Autorisierung wird durchgesetzt, bevor geschützte Belege das Modell erreichen.\u003C\u002Fli>\u003Cli>Das Generierungsmodell kann immer noch falsch liegen, selbst wenn der Abruf korrekt ist.\u003C\u002Fli>\u003C\u002Ful>\n\u003Cp>Diese Annahmen sind wichtig, weil der Abruf fehlende Belege, veraltete Quellversionen, defekte Parser oder unbefugten Zugriff nicht kompensieren kann. Eine RAG-Pipeline kann nur so vertrauenswürdig sein wie der Belegpfad, der sie speist.\u003C\u002Fp>\n\u003Ch2 id=\"section-34\">Variablen\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\">Warum sie das Design verändert\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Quellstruktur\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Eine SQL-Tabelle, ein juristisches PDF und ein Quellcode-Repository benötigen unterschiedliche Abrufstrategien\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Fragetyp\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Exakte Suche, konzeptionelle Suche und Multi-Hop-Recherche sind unterschiedliche Aufgaben\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Aktualitätsanforderung\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Live-Zustand kann direkte Abfragen erfordern anstelle regelmäßig neu aufgebauter Indizes\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Korpusgröße\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">In-Memory-Suche kann für Hunderte von Chunks funktionieren, aber nicht für sehr große Sammlungen\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Sprache\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Mehrsprachiger Abruf erfordert Modelle und Tokenisierung, die für die tatsächlichen Sprachen geeignet sind\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Berechtigungen\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Der Abruf muss nach den Zugriffsrechten des aktuellen Benutzers filtern\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Latenz und Kosten\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Mehr Abrufstufen können die Qualität verbessern, aber Laufzeit- und Infrastrukturkosten erhöhen\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Bedarf an Herkunftsnachweis\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Systeme mit hohem Vertrauen benötigen Quell-IDs, Versionen und nachverfolgbare Belege\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Ch2 id=\"section-36\">Diagnostische \u002F Entscheidungsmethode\u003C\u002Fh2>\n\u003Cp>Die erste Entscheidung ist nicht „Welche Vektordatenbank soll ich installieren?“ Sie lautet: \u003Cb>Welche Art von Fakt versuche ich abzurufen?\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\">Fragetyp\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Bevorzugter erster Ansatz\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">Grund\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Exakte ID oder aktueller Datensatz\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">SQL \u002F Schlüsselsuche \u002F API\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Deterministischer strukturierter Zugriff\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Exakter Wortlaut, Codes, Namen\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Volltext- oder Stichwortsuche\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Lexikalische Präzision\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Konzeptionelle Frage über Dokumente\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Semantische Vektorsuche\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Bedeutung kann vom Wortlaut abweichen\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Gemischtes Unternehmenswissen\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Hybrides Retrieval + Metadatenfilter\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Kombiniert lexikalische und semantische Signale\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Aktueller Anwendungszustand\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Direkter Zustands-\u002FWerkzeugzugriff\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Aktualität ist wichtiger als Dokumentähnlichkeit\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>Ein nützlicher Test ist: \u003Cb>Weiß ich bereits, welchen Datensatz ich brauche, oder muss das System entdecken, welche Passage relevant ist?\u003C\u002Fb> Wenn der Datensatz bekannt ist, frage ihn direkt ab. Wenn Relevanz entdeckt werden muss, wird die Suche wichtiger.\u003C\u002Fp>\n\u003Cp>Wenn eine Antwort falsch ist, diagnostiziere die Pipeline der Reihe nach, anstatt sofort das LLM zu ändern:\u003C\u002Fp>\n\u003Col>\u003Cli>\u003Cb>1. Quellenabdeckung:\u003C\u002Fb> Existiert die korrekte Information im zugänglichen Quellensatz?\u003C\u002Fli>\u003Cli>\u003Cb>2. Aktualität:\u003C\u002Fb> Ist diese Version aktuell genug für die Frage?\u003C\u002Fli>\u003Cli>\u003Cb>3. Parsing:\u003C\u002Fb> Wurde der relevante Inhalt korrekt extrahiert?\u003C\u002Fli>\u003Cli>\u003Cb>4. Chunking:\u003C\u002Fb> Blieb der Beleg zusammen mit den Bedingungen, die ihm Bedeutung verleihen?\u003C\u002Fli>\u003Cli>\u003Cb>5. Retrieval:\u003C\u002Fb> Erscheint der korrekte Chunk unter den Kandidaten?\u003C\u002Fli>\u003Cli>\u003Cb>6. Ranking:\u003C\u002Fb> Werden stärkere Quellen über schwächeren oder widersprüchlichen eingestuft?\u003C\u002Fli>\u003Cli>\u003Cb>7. Kontextzusammenstellung:\u003C\u002Fb> Hat die Anwendung die ausgewählten Belege tatsächlich an das Modell gesendet?\u003C\u002Fli>\u003Cli>\u003Cb>8. Generierung:\u003C\u002Fb> Hat das LLM die bereitgestellten Belege getreu verwendet?\u003C\u002Fli>\u003Cli>\u003Cb>9. Attribution:\u003C\u002Fb> Kann jede wichtige Aussage auf eine Quelle zurückgeführt werden?\u003C\u002Fli>\u003C\u002Fol>\n\u003Cp>Für eine tiefergehende Methode zur Produktionsfehlersuche siehe \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fde\u002Fblog\u002Frag-failed-but-which-layer-actually-failed-a-diagnostic-method\">RAG Failed — But Which Layer Actually Failed? A Diagnostic Method\u003C\u002Fa>, die diese Kette in unabhängig testbare Fehlerebenen erweitert.\u003C\u002Fp>\n\u003Ch2 id=\"section-43\">Belege\u003C\u002Fh2>\n\u003Cp>Das RAG-Papier von Lewis et al. formalisierte die Generierung, die auf abgerufenem externem Gedächtnis basiert, anstatt sich nur auf Modellparameter zu verlassen. Das liefert die konzeptionelle Grundlage für die Trennung des Generators von einer abrufbaren Wissensquelle.\u003C\u002Fp>\n\u003Cp>Sentence Transformers dokumentiert semantische Suche als Einbettung des Korpus und der Anfrage in einen Vektorraum und Abruf von Elementen mit hoher semantischer Ähnlichkeit. Seine aktuelle API unterscheidet auch zwischen Anfragekodierung und Dokumentkodierung für Retrieval-Aufgaben.\u003C\u002Fp>\n\u003Cp>SQLite FTS5 demonstriert die andere Seite des Spektrums: Ausgereiftes Volltext-Retrieval kann Dokumente ohne Einbettungen einstufen. Das ist wichtig, weil lexikalische Suche für Identifikatoren, exakte Terminologie und viele hybride Retrieval-Designs wertvoll bleibt.\u003C\u002Fp>\n\u003Cp>OpenAIs Einbettungsdokumentation beschreibt Einbettungen als numerische Vektordarstellungen, die für Verwandtschaft und Suche verwendet werden. Dies ist ein Implementierungspfad für semantisches Retrieval, nicht die Definition von RAG selbst.\u003C\u002Fp>\n\u003Ch2 id=\"section-48\">Praxisbeispiel 1: Ein Ordner mit Textdateien\u003C\u002Fh2>\n\u003Cp>Angenommen, ein Verzeichnis namens \u003Ccode>knowledge\u002F\u003C\u002Fcode> enthält gewöhnliche Textdateien. Python kann sie ohne jegliche KI-Bibliothek laden.\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>Das Dateisystem ist die Datenquelle. Die nächste Frage ist, wie viel Text eine abrufbare Einheit werden soll. Bei langen Dokumenten ist die Suche in einer kompletten Datei oft zu grob. Deshalb erstellen RAG-Pipelines üblicherweise Chunks.\u003C\u002Fp>\n\u003Ch3 id=\"section-52\">Ein sehr einfacher Chunker\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>Dieses Beispiel gruppiert Absätze, bis ein grobes Zeichenlimit erreicht ist. Es ist absichtlich verständlich statt optimal. Produktionssysteme chunkieren oft nach Tokens, Überschriften, Abschnitten, Satzgrenzen oder Dokumentstruktur. Tabellen, Quellcode, Verträge und API-Dokumentation können unterschiedliche Strategien erfordern.\u003C\u002Fp>\n\u003Ch3 id=\"section-55\">Provenienz beim Chunking bewahren\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>Ein nützlicher Chunk enthält mehr als nur Text. Quellenname, Dokument-ID, URL, Zeitstempel, Version oder Abschnitt können später Zitate, Debugging und Aktualitätsprüfungen unterstützen. Wenn die Provenienz während der Ingestion verloren geht, wird es viel schwieriger zu erklären, warum eine bestimmte Antwort erzeugt wurde.\u003C\u002Fp>\n\u003Ch2 id=\"section-58\">Praxisbeispiel 2: Strukturierte Daten — SQL verwenden, wenn SQL das richtige Werkzeug ist\u003C\u002Fh2>\n\u003Cp>Nicht jede externe Tatsache sollte durch semantische Suche gehen. Wenn die Frage einen exakten aktuellen Datensatz verlangt, ist eine direkte Datenbankabfrage normalerweise klarer und deterministischer.\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>Wenn die Anwendung bereits weiß, dass der Benutzer nach Bestellung 4711 fragt, fügt das Einbetten der gesamten Bestelltabelle und das Auffordern der semantischen Suche, diese Zeile wiederzuentdecken, normalerweise Komplexität ohne Nutzen hinzu. Eine starke Designregel lautet: \u003Cb>Strukturierte Fakten mit strukturierten Abfragen abrufen; unstrukturiertes Wissen mit Suche abrufen.\u003C\u002Fb>\u003C\u002Fp>\n\u003Cp>Die zurückgegebene Datenbankzeile kann trotzdem in den Modellkontext eingefügt werden, damit das LLM sie in natürlicher Sprache erklären kann. Aber direkter Zustands- oder Datensatzzugriff ist konzeptionell anders als die Suche in einem Wissenskorpus.\u003C\u002Fp>\n\u003Ch2 id=\"section-63\">Praxisbeispiel 3: Volltextsuche vor Embeddings\u003C\u002Fh2>\n\u003Cp>Zwischen einer naiven Python-Schleife und der Vektorsuche liegt eine ausgereifte Klasse lexikalischer Retrieval-Systeme. SQLite enthält FTS5 für die Volltextsuche, einschließlich BM25-Ranking.\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>Lexikalische Suche ist besonders nützlich, wenn exakte Terminologie, Produktcodes, Namen, Identifikatoren oder domänenspezifische Wörter wichtig sind. Semantische Suche ist nicht automatisch besser. Produktionssysteme kombinieren oft beide Signale.\u003C\u002Fp>\n\u003Ch2 id=\"section-67\">Praxisbeispiel 4: Semantisches Retrieval mit Embeddings\u003C\u002Fh2>\n\u003Cp>Embeddings verwandeln Text in numerische Vektoren, sodass semantisch verwandte Passagen verglichen werden können, auch wenn sie nicht identische Formulierungen verwenden. Sentence Transformers bietet eine unkomplizierte lokale Implementierung.\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>Die Abfrage enthält nicht den Ausdruck „Fahrzeugwartung“, aber ein semantisches Modell kann diese Passage trotzdem hoch einordnen, weil die Konzepte verwandt sind. Das ist der praktische Grund, warum Embeddings in RAG-Systemen üblich sind.\u003C\u002Fp>\n\u003Cp>Für kleine Sammlungen können Embeddings im Speicher bleiben. Größere Systeme speichern sie normalerweise in einem vektorfähigen Index oder einer Datenbank und führen dort die Nächste-Nachbarn-Suche durch. Die Speicherung ändert sich, aber die Logik bleibt: die Frage kodieren, relevante Dokumentrepräsentationen finden, die beste Evidenz zurückgeben.\u003C\u002Fp>\n\u003Ch2 id=\"section-72\">Praxisbeispiel 5: Den Kontext für das LLM aufbauen\u003C\u002Fh2>\n\u003Cp>Ein Retriever sollte Belege zurückgeben. Das LLM sollte dann die Frage plus diese Belege erhalten. Die Trennung von Retrieval und Generierung macht beides leichter überprüfbar und testbar.\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>Die Anweisung macht das Modell nicht unfehlbar. Sie schafft lediglich eine explizite Evidenzgrenze. Das Modell kann gute Belege immer noch missverstehen, eine Bedingung ignorieren oder verallgemeinern. Deshalb müssen Retrieval-Qualität und Generierungsqualität getrennt bewertet werden.\u003C\u002Fp>\n\u003Ch2 id=\"section-76\">Reales Beispiel 6: Eine vollständige minimale Pipeline\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>Die Funktion erhält \u003Ccode>call_llm\u003C\u002Fcode> absichtlich als Abhängigkeit. Retrieval sollte nicht davon abhängen, ob die Generierung von einem Cloud-Modell, einem lokalen Modell oder einem anderen Anbieter durchgeführt wird. Der Datenpfad gehört zur Anwendung.\u003C\u002Fp>\n\u003Ch3 id=\"section-79\">Optionaler Generator: OpenAI Responses API\u003C\u002Fh3>\n\u003Cp>Ein möglicher Generator ist die OpenAI Responses API. Den Modellnamen in einer Umgebungsvariable zu halten, vermeidet die Festcodierung eines bestimmten Modells in die RAG-Architektur.\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>Dieselbe Retrieval-Pipeline kann mit einem lokalen Inferenzserver verbunden werden. Dies ist ein wichtiger architektonischer Punkt: \u003Cb>RAG gehört nicht dem LLM-Anbieter.\u003C\u002Fb> Die Anwendung besitzt die Quelle, das Retrieval und die Kontextzusammenstellung.\u003C\u002Fp>\n\u003Ch3 id=\"section-83\">Die gesamte Architektur in einer Ansicht\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>Dieses Datenflussmodell ist beständiger als das Auswendiglernen eines Frameworks. Bibliotheken, Datenbanken und Modellanbieter werden sich ändern; die Verantwortlichkeitsgrenzen bleiben bestehen.\u003C\u002Fp>\n\u003Ch2 id=\"section-86\">Häufige Missverständnisse und Fehlermodi\u003C\u002Fh2>\n\u003Ch3 id=\"section-87\">„RAG bedeutet Vektordatenbank.“\u003C\u002Fh3>\n\u003Cp>Nein. Vektorsuche ist eine Retrieval-Methode. RAG kann Volltextsuche, SQL, APIs, Wissensgraphen, Vektorsuche oder Kombinationen davon verwenden. Das definierende Muster ist das Abrufen externer Informationen für die Generierung.\u003C\u002Fp>\n\u003Ch3 id=\"section-89\">„Wenn die Daten in PostgreSQL sind, muss ich die gesamte Datenbank einbetten.“\u003C\u002Fh3>\n\u003Cp>Nein. Strukturierte Datensätze sollten in der Regel als strukturierte Datensätze abfragbar bleiben. Embeddings sind nützlich für semantische Relevanz, nicht als Ersatz für deterministische Abfragen.\u003C\u002Fp>\n\u003Ch3 id=\"section-91\">„Mehr Chunks bedeuten eine bessere Antwort.“\u003C\u002Fh3>\n\u003Cp>Nicht unbedingt. Zusätzlicher Kontext kann Rauschen, widersprüchliche Versionen und irrelevantes Material einbringen. Retrieval sollte auf nützliche Belege optimieren, nicht auf maximales Volumen.\u003C\u002Fp>\n\u003Ch3 id=\"section-93\">„Ein hoher Ähnlichkeitswert beweist die Antwort.“\u003C\u002Fh3>\n\u003Cp>Nein. Ähnlichkeit misst Relevanz, nicht Wahrheit oder Anwendbarkeit. Eine hochgradig ähnliche Passage kann veraltet sein, aus der falschen Produktversion stammen oder nur unter Bedingungen gültig sein, die nicht zur Frage passen.\u003C\u002Fp>\n\u003Ch3 id=\"section-95\">„Sobald der richtige Chunk abgerufen ist, ist Halluzination gelöst.“\u003C\u002Fh3>\n\u003Cp>Nein. Retrieval verbessert die Verankerung, garantiert aber kein treues Schlussfolgern. Die Generierung muss weiterhin evaluiert werden, und risikoreiche Workflows können deterministische Validierung oder menschliche Prüfung erfordern.\u003C\u002Fp>\n\u003Ch3 id=\"section-97\">„Das Modell hat versagt, also wechsle das Modell.“\u003C\u002Fh3>\n\u003Cp>Nicht unbedingt. Die richtige Quelle kann gefehlt haben, falsch geparst, schlecht aufgeteilt, herausgefiltert, zu niedrig eingestuft oder aus dem zusammengestellten Kontext ausgelassen worden sein. Der Modellwechsel sollte nicht der erste Diagnoseschritt sein.\u003C\u002Fp>\n\u003Ch2 id=\"section-99\">Randfälle\u003C\u002Fh2>\n\u003Cul>\u003Cli>\u003Cb>Widersprüchliche Dokumente:\u003C\u002Fb> zwei Quellen können voneinander abweichen, weil Versionen, Rechtsordnungen oder Produkte unterschiedlich sind.\u003C\u002Fli>\u003Cli>\u003Cb>Zeitkritische Fakten:\u003C\u002Fb> eine semantisch relevante Quelle kann bereits veraltet sein.\u003C\u002Fli>\u003Cli>\u003Cb>Berechtigungen:\u003C\u002Fb> ein Retriever darf keine Dokumente zurückgeben, auf die der aktuelle Benutzer nicht zugreifen darf.\u003C\u002Fli>\u003Cli>\u003Cb>Mehrsprachige Sammlungen:\u003C\u002Fb> das Embedding-Modell und die Retrieval-Strategie müssen die tatsächlich verwendeten Sprachen unterstützen.\u003C\u002Fli>\u003Cli>\u003Cb>Tabellen und Quellcode:\u003C\u002Fb> einfaches Absatz-Chunking kann Strukturen zerstören, die für die Antwort wesentlich sind.\u003C\u002Fli>\u003Cli>\u003Cb>Sehr kurze Identifikatoren:\u003C\u002Fb> semantisches Retrieval kann bei SKUs, IDs, Fehlercodes oder Akronymen schwächer sein als exakte Übereinstimmung.\u003C\u002Fli>\u003Cli>\u003Cb>Lange Fragen, die mehrere Fakten erfordern:\u003C\u002Fb> Retrieval kann Dekomposition, mehrere Suchen oder Reranking statt einer einzigen Top-k-Abfrage benötigen.\u003C\u002Fli>\u003Cli>\u003Cb>Quellenhierarchie:\u003C\u002Fb> eine offizielle aktuelle Richtlinie muss möglicherweise ein älteres, aber semantisch näheres Diskussionsdokument überstimmen.\u003C\u002Fli>\u003C\u002Ful>\n\u003Ch2 id=\"section-101\">Einschränkungen\u003C\u002Fh2>\n\u003Cp>Die Python-Beispiele optimieren bewusst auf Transparenz, nicht auf Skalierung. Der Keyword-Retriever ist naiv, der Chunker verwendet Zeichenlänge, die SQLite-Beispiele enthalten kein Produktions-Verbindungsmanagement, und das semantische Beispiel hält alle Embeddings im Speicher.\u003C\u002Fp>\n\u003Cp>Ein Produktionssystem kann Vektorindizes, Reranker, hybrides Retrieval, Dokumentenparser, Caching, inkrementelle Indexierung, Quellenversionierung, Zugriffskontrollfilter, Observability, Evaluierungsdatensätze und Fehlerbehandlung erfordern. Keine dieser Ergänzungen ändert die Kernarchitektur; sie machen jede Grenze zuverlässiger.\u003C\u002Fp>\n\u003Cp>RAG kann auch keine Belege erzeugen, die im Quellensatz fehlen. Wenn die Quelle falsch, unvollständig oder veraltet ist, kann ein besseres Embedding-Modell sie nicht in autoritatives Wissen verwandeln.\u003C\u002Fp>\n\u003Ch2 id=\"section-105\">Was würde diese Antwort ändern?\u003C\u002Fh2>\n\u003Cp>Die Architektur ändert sich, wenn die Aufgabe mehr als Wissensabruf erfordert. Ein Live-Bestellstatus benötigt den aktuellen Zustand. Eine Finanzberechnung kann deterministischen Code erfordern. Eine Web-Recherche-Aufgabe kann aktive Suche erfordern. Ein Workflow kann Tools benötigen, die Daten in ein anderes System zurückschreiben können. Ein autonomer Agent kann zusätzlich zum Retrieval Planung, Berechtigungen und Ausführungskontrolle benötigen.\u003C\u002Fp>\n\u003Cp>RAG lässt sich daher am besten als \u003Cb>eine Ebene der Belegbeschaffung innerhalb eines größeren KI-Systems\u003C\u002Fb> verstehen. Es ist gerade deshalb leistungsfähig, weil es eine enge Aufgabe hat: nützliche externe Informationen finden und in den Arbeitskontext des Modells einfügen.\u003C\u002Fp>\n\u003Ch2 id=\"section-108\">Fazit\u003C\u002Fh2>\n\u003Cp>RAG wird viel leichter zu verstehen, wenn die Technologienamen entfernt werden. Eine Datei ist eine Quelle. Eine Datenbank ist eine Quelle. Eine API ist eine Quelle. Eine Suchfunktion ruft Belege ab. Ein Prompt trägt diese Belege zum Modell. Das LLM interpretiert sie dann und erzeugt Sprache.\u003C\u002Fp>\n\u003Cp>Das Schwierige an Produktions-RAG ist nicht der Aufruf eines Embedding-Modells. Es ist der Aufbau eines vertrauenswürdigen Belegpfads von der Originalquelle bis zur endgültigen Aussage: die Herkunft bewahren, die richtige Retrieval-Methode auswählen, Informationen aktuell halten, den Zugriff kontrollieren, Retrieval getrennt von der Generierung bewerten und wissen, wann ein direkter Datenbank- oder Tool-Aufruf besser ist als semantische Suche.\u003C\u002Fp>\n\u003Cp>Das ist die praktische Fortsetzung des grundlegenden RAG-Modells: \u003Cb>zuerst die Rollen verstehen, dann den Datenpfad explizit machen.\u003C\u002Fb>\u003C\u002Fp>\n\u003Ch2 id=\"section-112\">Primärquellen\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> — das Paper von 2020, das die RAG-Formulierung einführte, die Generierung mit abgerufenem nicht-parametrischem Speicher kombiniert.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fwww.sbert.net\u002Fexamples\u002Fsentence_transformer\u002Fapplications\u002Fsemantic-search\u002FREADME.html\">Sentence Transformers — Semantic Search\u003C\u002Fa> — offizielle Dokumentation für semantisches Retrieval, Query-Embeddings und Dokument-Embeddings.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fembeddings\">OpenAI — Vector Embeddings\u003C\u002Fa> — offizielle Dokumentation, die Embeddings als numerische Repräsentationen beschreibt, die für Verwandtschaft und Suche verwendet werden.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fwww.sqlite.org\u002Ffts5.html\">SQLite — FTS5 Extension\u003C\u002Fa> — offizielle Dokumentation für Volltextsuche und BM25-Ranking in SQLite.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Flibraries\">OpenAI — SDKs and CLI\u003C\u002Fa> — offizielles Python-SDK-Beispiel für die Responses API, das im optionalen Generator-Beispiel verwendet wird.\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fde\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">What Is RAG? The Simplest Explanation of How It Works\u003C\u002Fa> — der konzeptionelle erste Teil dieser Serie.\u003C\u002Fli>\u003C\u002Ful>",{"time":211,"blocks":212,"version":675},1790517253212,[213,217,220,226,230,233,236,239,242,245,248,252,255,258,261,264,267,270,273,276,279,282,285,288,291,294,297,300,336,339,342,345,357,360,363,393,396,399,425,428,431,444,447,450,453,456,459,462,465,468,471,474,478,481,484,487,490,493,496,499,502,505,508,511,514,517,520,523,526,529,532,535,538,541,544,547,550,553,556,559,562,565,568,571,574,577,580,583,586,589,592,595,598,601,604,607,610,613,616,619,630,633,636,639,642,645,648,651,654,657,660,663,666],{"data":214,"type":216},{"text":215},"Der vorherige Artikel, \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fde\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">Was ist RAG? Die einfachste Erklärung, wie es funktioniert\u003C\u002Fa>, hat das mentale Modell etabliert: Das LLM schreibt, RAG ruft nützliches Wissen ab, die Anwendung besitzt den aktuellen Zustand, und Tools führen Aktionen aus. Dieser Artikel geht den nächsten Schritt: \u003Cb>Woher kommen die Daten eigentlich, und wie sieht Retrieval in Python aus?\u003C\u002Fb>","paragraph",{"data":218,"type":216},{"text":219},"Die wichtige Überraschung ist, dass eine „LLM-Datenquelle“ normalerweise nichts Exotisches ist. Es kann eine Textdatei sein, ein Ordner mit Markdown-Dokumenten, eine SQL-Datenbank, eine API-Antwort, ein Produktkatalog, ein Support-System oder ein Vektorindex, der aus diesen Quellen abgeleitet wurde. Die KI kennt diese Systeme nicht auf magische Weise. Ihre Anwendung muss die relevanten Daten laden, abfragen, durchsuchen oder abrufen und das Ergebnis in den Kontext des Modells einfügen.",{"data":221,"type":225},{"text":222,"caption":223,"alignment":224},"Datenquelle = wo Informationen leben. Retrieval = wie die Anwendung nützliche Informationen findet. Kontext = die ausgewählten Informationen, die dem Modell gegeben werden. LLM = die Komponente, die diesen Kontext interpretiert und eine Antwort generiert.","Das Vier-Teile-Modell, das in diesem Artikel verwendet wird","left","quote",{"data":227,"type":41},{"text":228,"level":229},"Frage",2,{"data":231,"type":216},{"text":232},"Wie nutzt ein LLM externe Daten wie Dateien, Datenbanken oder APIs, und wie kann ein kleines Python-Programm die wesentlichen RAG-Schritte implementieren, ohne sie hinter einem Framework zu verbergen?",{"data":234,"type":41},{"text":235,"level":229},"Was das wirklich bedeutet",{"data":237,"type":216},{"text":238},"Wenn Entwickler sagen, dass ein LLM „mit Unternehmensdaten verbunden“ ist, können sich hinter diesem Satz mehrere verschiedene Operationen verbergen. Eine Anwendung führt möglicherweise SQL aus. Eine andere ruft eine API auf. Eine weitere führt eine Volltextsuche durch. Eine andere berechnet die Embedding-Ähnlichkeit über Dokument-Chunks. Alle können einem LLM externe Informationen liefern, aber sie sind nicht die gleiche Retrieval-Methode und sollten nicht als austauschbar behandelt werden.",{"data":240,"type":216},{"text":241},"Diese Unterscheidung ist wichtig, weil die beste Retrieval-Methode von der Form der Frage abhängt. „Wie lautet unsere Rückerstattungsrichtlinie?“ ist ein Dokument-Retrieval-Problem. „Wie lautet der aktuelle Status von Bestellung 4711?“ ist normalerweise eine strukturierte Datenbankabfrage. „Welcher Absatz behandelt die Kontowiederherstellung?“ kann eine Keyword- oder semantische Suche sein. RAG ist am nützlichsten, wenn das System \u003Cb>relevantes Wissen vor der Generierung entdecken muss\u003C\u002Fb>.",{"data":243,"type":41},{"text":244,"level":229},"Einfachstes Beispiel",{"data":246,"type":216},{"text":247},"Beginnen Sie mit drei Strings in gewöhnlichem Python. Es gibt noch keine Vektordatenbank, kein Framework und kein LLM. Wir wollen nur den Retrieval-Schritt sichtbar machen.",{"data":249,"type":251},{"code":250},"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":253,"type":216},{"text":254},"Das Programm gibt den ersten Satz aus, weil er den Begriff enthält, nach dem wir gesucht haben. Dies ist primitives Retrieval, aber die Architektur ist bereits sichtbar: \u003Cb>Frage → Suche → relevanter Text\u003C\u002Fb>. RAG fügt einen weiteren wichtigen Schritt hinzu: den abgerufenen Text zusammen mit der Frage an ein Sprachmodell übergeben.",{"data":256,"type":216},{"text":257},"Eine etwas allgemeinere Version ordnet Dokumente nach überlappenden Abfragebegriffen:",{"data":259,"type":251},{"code":260},"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":262,"type":216},{"text":263},"Dies ist keine Produktionssuchmaschine. Sie ignoriert Morphologie, Synonyme, Schreibvarianten, Dokumentlänge und viele Ranking-Signale. Ihr Wert ist pädagogisch: \u003Cb>RAG beginnt nicht mit einer Vektordatenbank. Es beginnt mit Retrieval.\u003C\u002Fb>",{"data":265,"type":41},{"text":266,"level":229},"Wo das Beispiel nicht mehr funktioniert",{"data":268,"type":216},{"text":269},"Exakte oder lexikalische Übereinstimmung wird schwach, wenn die Frage und die Quelle unterschiedliche Wörter verwenden. Ein Dokument kann „Fahrzeugwartung“ sagen, während der Benutzer fragt: „Wie repariere ich mein Auto?“ Ein lexikalischer Retriever kann die Beziehung verfehlen, obwohl ein Mensch sie sofort sieht. Semantisches Retrieval adressiert dies, indem es Text als Vektoren darstellt und Bedeutung vergleicht, nicht nur exakte Tokens.",{"data":271,"type":216},{"text":272},"Lange Dateien schaffen ein weiteres Problem. Ein ganzes 80-seitiges Handbuch als eine Einheit zu durchsuchen ist zu grob, aber jeden Satz aufzuteilen kann nützlichen Kontext zerstören. Echte RAG-Systeme benötigen daher Entscheidungen über Parsing, Chunking, Metadaten, Ranking, Aktualität, Berechtigungen und Herkunft.",{"data":274,"type":216},{"text":275},"Das Beispiel sagt auch nichts über strukturierte Live-Fakten aus. Wenn der Benutzer nach dem aktuellen Status der Bestellung 4711 fragt und die Anwendung bereits einen Datenbankschlüssel hat, ist die semantische Suche normalerweise das falsche erste Werkzeug. Eine deterministische Datenbankabfrage ist besser.",{"data":277,"type":41},{"text":278,"level":229},"Direkte Antwort",{"data":280,"type":216},{"text":281},"Eine LLM-Datenquelle ist jedes externe System, aus dem eine Anwendung Informationen für das Modell beziehen kann: Dateien, Datenbanken, APIs, Suchindizes, Vektorspeicher oder Live-Anwendungszustand. RAG ist das Muster, \u003Cb>relevantes Wissen aus solchen Quellen vor der Generierung abzurufen\u003C\u002Fb>.",{"data":283,"type":216},{"text":284},"In Python kann die wesentliche Pipeline sehr klein sein: \u003Cb>Daten laden → abrufbare Einheiten erstellen → relevante Belege finden → Kontext zusammenstellen → das LLM aufrufen\u003C\u002Fb>. Die Abrufmethode sollte zur Quelle und zur Frage passen. Verwenden Sie SQL für exakte strukturierte Fakten, Volltextsuche für lexikalisches Matching, Embeddings für semantische Ähnlichkeit und hybride Suche, wenn mehrere Signale wertvoll sind.",{"data":286,"type":41},{"text":287,"level":229},"Warum das so ist",{"data":289,"type":216},{"text":290},"Ein Sprachmodell erhält nicht automatisch die Inhalte Ihres Dateisystems, Ihrer PostgreSQL-Datenbank, Ihres CRM, Ihrer privaten API oder eines neu bearbeiteten Dokuments. Die Anwendung entscheidet, auf welche externen Informationen zugegriffen werden kann und was in den aktuellen Kontext des Modells eingefügt wird.",{"data":292,"type":216},{"text":293},"Die ursprüngliche Arbeit zur Retrieval-Augmented Generation von Lewis et al. kombinierte ein generatives Modell mit externem nicht-parametrischem Speicher, der aus einem dichten Vektorindex abgerufen wurde. Die breitere architektonische Idee überlebt über diese spezifische Implementierung hinaus: Externe Belege können zur Inferenzzeit abgerufen werden, anstatt zu erwarten, dass alles nützliche Wissen in den Modellparametern kodiert ist.",{"data":295,"type":216},{"text":296},"Dies schafft eine nützliche Trennung der Zuständigkeiten: Die Quelle speichert Informationen, der Retriever wählt Belege aus, der Kontext trägt diese Belege in die Anfrage, und das Modell interpretiert sie. Wenn diese Grenzen sichtbar bleiben, lassen sich Fehler viel leichter diagnostizieren.",{"data":298,"type":41},{"text":299,"level":229},"Kontext: Die wichtigsten Arten von Datenquellen",{"data":301,"type":335},{"content":302,"withHeadings":13},[303,307,311,315,319,323,327,331],[304,305,306],"Quelle","Typische Abrufmethode","Geeignet für",[308,309,310],"TXT \u002F Markdown \u002F HTML","Parsing + lexikalische oder semantische Suche","Dokumentation, Handbücher, Artikel, Notizen",[312,313,314],"PDF \u002F DOCX","Struktur-bewusste Extraktion + Suche","Richtlinien, Berichte, Verträge, Handbücher",[316,317,318],"SQL-Datenbank","SQL-Abfrage oder gefilterter Abruf","Bestellungen, Benutzer, Produkte, strukturierte Datensätze",[320,321,322],"REST \u002F GraphQL API","HTTP-Anfrage mit Parametern","Remote-Systeme und Live-Service-Daten",[324,325,326],"Suchindex","BM25 \u002F Volltext \u002F hybride Suche","Große Textsammlungen",[328,329,330],"Vektorindex","Embedding-Ähnlichkeit","Semantischer Dokumentenabruf",[332,333,334],"Anwendungszustand","Direktes Zustandslesen oder Tool-Aufruf","Was gerade jetzt wahr ist","table",{"data":337,"type":216},{"text":338},"Ein Vektorindex verdient besondere Aufmerksamkeit. In vielen Architekturen ist er \u003Cb>nicht die kanonische Quelle der Wahrheit\u003C\u002Fb>. Er ist ein Abrufindex, der aus Dokumenten oder Datensätzen abgeleitet wurde. Das maßgebliche Dokument kann in Objektspeicher, einem CMS, Git, PostgreSQL oder einem anderen System liegen, während Embeddings und Metadaten separat für schnelle semantische Suche gespeichert werden. Einige Systeme verwenden einen Vektorspeicher tatsächlich als Primärspeicher, aber das ist eine architektonische Entscheidung und keine Anforderung von RAG.",{"data":340,"type":216},{"text":341},"Wenn die Grenze zwischen Abruf, persistentem Gedächtnis, aktuellem Zustand und Modellkontext noch unklar ist, siehe \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fde\u002Fblog\u002Fai-agent-memory-is-not-rag-how-to-separate-memory-retrieval-state-and-context\">AI Agent Memory Is Not RAG\u003C\u002Fa>. Diese Schichten können einige derselben Speichertechnologien verwenden und dennoch unterschiedliche Korrektheitsregeln haben.",{"data":343,"type":41},{"text":344,"level":229},"Annahmen",{"data":346,"type":356},{"items":347,"style":355},[348,349,350,351,352,353,354],"Die Anwendung darf auf die externe Quelle zugreifen.","Die relevante Quelle enthält genügend Informationen, um die Frage zu beantworten.","Die Daten können in einer Form geparst oder abgefragt werden, die die Abrufschicht nutzen kann.","Die abgerufenen Informationen sind frisch genug für die angeforderte Entscheidung.","Das Modell erhält die ausgewählten Belege in seinem Kontext.","Die Autorisierung wird durchgesetzt, bevor geschützte Belege das Modell erreichen.","Das Generierungsmodell kann immer noch falsch liegen, selbst wenn der Abruf korrekt ist.","unordered","list",{"data":358,"type":216},{"text":359},"Diese Annahmen sind wichtig, weil der Abruf fehlende Belege, veraltete Quellversionen, defekte Parser oder unbefugten Zugriff nicht kompensieren kann. Eine RAG-Pipeline kann nur so vertrauenswürdig sein wie der Belegpfad, der sie speist.",{"data":361,"type":41},{"text":362,"level":229},"Variablen",{"data":364,"type":335},{"content":365,"withHeadings":13},[366,369,372,375,378,381,384,387,390],[367,368],"Variable","Warum sie das Design verändert",[370,371],"Quellstruktur","Eine SQL-Tabelle, ein juristisches PDF und ein Quellcode-Repository benötigen unterschiedliche Abrufstrategien",[373,374],"Fragetyp","Exakte Suche, konzeptionelle Suche und Multi-Hop-Recherche sind unterschiedliche Aufgaben",[376,377],"Aktualitätsanforderung","Live-Zustand kann direkte Abfragen erfordern anstelle regelmäßig neu aufgebauter Indizes",[379,380],"Korpusgröße","In-Memory-Suche kann für Hunderte von Chunks funktionieren, aber nicht für sehr große Sammlungen",[382,383],"Sprache","Mehrsprachiger Abruf erfordert Modelle und Tokenisierung, die für die tatsächlichen Sprachen geeignet sind",[385,386],"Berechtigungen","Der Abruf muss nach den Zugriffsrechten des aktuellen Benutzers filtern",[388,389],"Latenz und Kosten","Mehr Abrufstufen können die Qualität verbessern, aber Laufzeit- und Infrastrukturkosten erhöhen",[391,392],"Bedarf an Herkunftsnachweis","Systeme mit hohem Vertrauen benötigen Quell-IDs, Versionen und nachverfolgbare Belege",{"data":394,"type":41},{"text":395,"level":229},"Diagnostische \u002F Entscheidungsmethode",{"data":397,"type":216},{"text":398},"Die erste Entscheidung ist nicht „Welche Vektordatenbank soll ich installieren?“ Sie lautet: \u003Cb>Welche Art von Fakt versuche ich abzurufen?\u003C\u002Fb>",{"data":400,"type":335},{"content":401,"withHeadings":13},[402,405,409,413,417,421],[373,403,404],"Bevorzugter erster Ansatz","Grund",[406,407,408],"Exakte ID oder aktueller Datensatz","SQL \u002F Schlüsselsuche \u002F API","Deterministischer strukturierter Zugriff",[410,411,412],"Exakter Wortlaut, Codes, Namen","Volltext- oder Stichwortsuche","Lexikalische Präzision",[414,415,416],"Konzeptionelle Frage über Dokumente","Semantische Vektorsuche","Bedeutung kann vom Wortlaut abweichen",[418,419,420],"Gemischtes Unternehmenswissen","Hybrides Retrieval + Metadatenfilter","Kombiniert lexikalische und semantische Signale",[422,423,424],"Aktueller Anwendungszustand","Direkter Zustands-\u002FWerkzeugzugriff","Aktualität ist wichtiger als Dokumentähnlichkeit",{"data":426,"type":216},{"text":427},"Ein nützlicher Test ist: \u003Cb>Weiß ich bereits, welchen Datensatz ich brauche, oder muss das System entdecken, welche Passage relevant ist?\u003C\u002Fb> Wenn der Datensatz bekannt ist, frage ihn direkt ab. Wenn Relevanz entdeckt werden muss, wird die Suche wichtiger.",{"data":429,"type":216},{"text":430},"Wenn eine Antwort falsch ist, diagnostiziere die Pipeline der Reihe nach, anstatt sofort das LLM zu ändern:",{"data":432,"type":356},{"items":433,"style":443},[434,435,436,437,438,439,440,441,442],"\u003Cb>1. Quellenabdeckung:\u003C\u002Fb> Existiert die korrekte Information im zugänglichen Quellensatz?","\u003Cb>2. Aktualität:\u003C\u002Fb> Ist diese Version aktuell genug für die Frage?","\u003Cb>3. Parsing:\u003C\u002Fb> Wurde der relevante Inhalt korrekt extrahiert?","\u003Cb>4. Chunking:\u003C\u002Fb> Blieb der Beleg zusammen mit den Bedingungen, die ihm Bedeutung verleihen?","\u003Cb>5. Retrieval:\u003C\u002Fb> Erscheint der korrekte Chunk unter den Kandidaten?","\u003Cb>6. Ranking:\u003C\u002Fb> Werden stärkere Quellen über schwächeren oder widersprüchlichen eingestuft?","\u003Cb>7. Kontextzusammenstellung:\u003C\u002Fb> Hat die Anwendung die ausgewählten Belege tatsächlich an das Modell gesendet?","\u003Cb>8. Generierung:\u003C\u002Fb> Hat das LLM die bereitgestellten Belege getreu verwendet?","\u003Cb>9. Attribution:\u003C\u002Fb> Kann jede wichtige Aussage auf eine Quelle zurückgeführt werden?","ordered",{"data":445,"type":216},{"text":446},"Für eine tiefergehende Methode zur Produktionsfehlersuche siehe \u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fde\u002Fblog\u002Frag-failed-but-which-layer-actually-failed-a-diagnostic-method\">RAG Failed — But Which Layer Actually Failed? A Diagnostic Method\u003C\u002Fa>, die diese Kette in unabhängig testbare Fehlerebenen erweitert.",{"data":448,"type":41},{"text":449,"level":229},"Belege",{"data":451,"type":216},{"text":452},"Das RAG-Papier von Lewis et al. formalisierte die Generierung, die auf abgerufenem externem Gedächtnis basiert, anstatt sich nur auf Modellparameter zu verlassen. Das liefert die konzeptionelle Grundlage für die Trennung des Generators von einer abrufbaren Wissensquelle.",{"data":454,"type":216},{"text":455},"Sentence Transformers dokumentiert semantische Suche als Einbettung des Korpus und der Anfrage in einen Vektorraum und Abruf von Elementen mit hoher semantischer Ähnlichkeit. Seine aktuelle API unterscheidet auch zwischen Anfragekodierung und Dokumentkodierung für Retrieval-Aufgaben.",{"data":457,"type":216},{"text":458},"SQLite FTS5 demonstriert die andere Seite des Spektrums: Ausgereiftes Volltext-Retrieval kann Dokumente ohne Einbettungen einstufen. Das ist wichtig, weil lexikalische Suche für Identifikatoren, exakte Terminologie und viele hybride Retrieval-Designs wertvoll bleibt.",{"data":460,"type":216},{"text":461},"OpenAIs Einbettungsdokumentation beschreibt Einbettungen als numerische Vektordarstellungen, die für Verwandtschaft und Suche verwendet werden. Dies ist ein Implementierungspfad für semantisches Retrieval, nicht die Definition von RAG selbst.",{"data":463,"type":41},{"text":464,"level":229},"Praxisbeispiel 1: Ein Ordner mit Textdateien",{"data":466,"type":216},{"text":467},"Angenommen, ein Verzeichnis namens \u003Ccode>knowledge\u002F\u003C\u002Fcode> enthält gewöhnliche Textdateien. Python kann sie ohne jegliche KI-Bibliothek laden.",{"data":469,"type":251},{"code":470},"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":472,"type":216},{"text":473},"Das Dateisystem ist die Datenquelle. Die nächste Frage ist, wie viel Text eine abrufbare Einheit werden soll. Bei langen Dokumenten ist die Suche in einer kompletten Datei oft zu grob. Deshalb erstellen RAG-Pipelines üblicherweise Chunks.",{"data":475,"type":41},{"text":476,"level":477},"Ein sehr einfacher Chunker",3,{"data":479,"type":251},{"code":480},"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":482,"type":216},{"text":483},"Dieses Beispiel gruppiert Absätze, bis ein grobes Zeichenlimit erreicht ist. Es ist absichtlich verständlich statt optimal. Produktionssysteme chunkieren oft nach Tokens, Überschriften, Abschnitten, Satzgrenzen oder Dokumentstruktur. Tabellen, Quellcode, Verträge und API-Dokumentation können unterschiedliche Strategien erfordern.",{"data":485,"type":41},{"text":486,"level":477},"Provenienz beim Chunking bewahren",{"data":488,"type":251},{"code":489},"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":491,"type":216},{"text":492},"Ein nützlicher Chunk enthält mehr als nur Text. Quellenname, Dokument-ID, URL, Zeitstempel, Version oder Abschnitt können später Zitate, Debugging und Aktualitätsprüfungen unterstützen. Wenn die Provenienz während der Ingestion verloren geht, wird es viel schwieriger zu erklären, warum eine bestimmte Antwort erzeugt wurde.",{"data":494,"type":41},{"text":495,"level":229},"Praxisbeispiel 2: Strukturierte Daten — SQL verwenden, wenn SQL das richtige Werkzeug ist",{"data":497,"type":216},{"text":498},"Nicht jede externe Tatsache sollte durch semantische Suche gehen. Wenn die Frage einen exakten aktuellen Datensatz verlangt, ist eine direkte Datenbankabfrage normalerweise klarer und deterministischer.",{"data":500,"type":251},{"code":501},"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":503,"type":216},{"text":504},"Wenn die Anwendung bereits weiß, dass der Benutzer nach Bestellung 4711 fragt, fügt das Einbetten der gesamten Bestelltabelle und das Auffordern der semantischen Suche, diese Zeile wiederzuentdecken, normalerweise Komplexität ohne Nutzen hinzu. Eine starke Designregel lautet: \u003Cb>Strukturierte Fakten mit strukturierten Abfragen abrufen; unstrukturiertes Wissen mit Suche abrufen.\u003C\u002Fb>",{"data":506,"type":216},{"text":507},"Die zurückgegebene Datenbankzeile kann trotzdem in den Modellkontext eingefügt werden, damit das LLM sie in natürlicher Sprache erklären kann. Aber direkter Zustands- oder Datensatzzugriff ist konzeptionell anders als die Suche in einem Wissenskorpus.",{"data":509,"type":41},{"text":510,"level":229},"Praxisbeispiel 3: Volltextsuche vor Embeddings",{"data":512,"type":216},{"text":513},"Zwischen einer naiven Python-Schleife und der Vektorsuche liegt eine ausgereifte Klasse lexikalischer Retrieval-Systeme. SQLite enthält FTS5 für die Volltextsuche, einschließlich BM25-Ranking.",{"data":515,"type":251},{"code":516},"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":518,"type":216},{"text":519},"Lexikalische Suche ist besonders nützlich, wenn exakte Terminologie, Produktcodes, Namen, Identifikatoren oder domänenspezifische Wörter wichtig sind. Semantische Suche ist nicht automatisch besser. Produktionssysteme kombinieren oft beide Signale.",{"data":521,"type":41},{"text":522,"level":229},"Praxisbeispiel 4: Semantisches Retrieval mit Embeddings",{"data":524,"type":216},{"text":525},"Embeddings verwandeln Text in numerische Vektoren, sodass semantisch verwandte Passagen verglichen werden können, auch wenn sie nicht identische Formulierungen verwenden. Sentence Transformers bietet eine unkomplizierte lokale Implementierung.",{"data":527,"type":251},{"code":528},"# 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":530,"type":216},{"text":531},"Die Abfrage enthält nicht den Ausdruck „Fahrzeugwartung“, aber ein semantisches Modell kann diese Passage trotzdem hoch einordnen, weil die Konzepte verwandt sind. Das ist der praktische Grund, warum Embeddings in RAG-Systemen üblich sind.",{"data":533,"type":216},{"text":534},"Für kleine Sammlungen können Embeddings im Speicher bleiben. Größere Systeme speichern sie normalerweise in einem vektorfähigen Index oder einer Datenbank und führen dort die Nächste-Nachbarn-Suche durch. Die Speicherung ändert sich, aber die Logik bleibt: die Frage kodieren, relevante Dokumentrepräsentationen finden, die beste Evidenz zurückgeben.",{"data":536,"type":41},{"text":537,"level":229},"Praxisbeispiel 5: Den Kontext für das LLM aufbauen",{"data":539,"type":216},{"text":540},"Ein Retriever sollte Belege zurückgeben. Das LLM sollte dann die Frage plus diese Belege erhalten. Die Trennung von Retrieval und Generierung macht beides leichter überprüfbar und testbar.",{"data":542,"type":251},{"code":543},"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":545,"type":216},{"text":546},"Die Anweisung macht das Modell nicht unfehlbar. Sie schafft lediglich eine explizite Evidenzgrenze. Das Modell kann gute Belege immer noch missverstehen, eine Bedingung ignorieren oder verallgemeinern. Deshalb müssen Retrieval-Qualität und Generierungsqualität getrennt bewertet werden.",{"data":548,"type":41},{"text":549,"level":229},"Reales Beispiel 6: Eine vollständige minimale Pipeline",{"data":551,"type":251},{"code":552},"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":554,"type":216},{"text":555},"Die Funktion erhält \u003Ccode>call_llm\u003C\u002Fcode> absichtlich als Abhängigkeit. Retrieval sollte nicht davon abhängen, ob die Generierung von einem Cloud-Modell, einem lokalen Modell oder einem anderen Anbieter durchgeführt wird. Der Datenpfad gehört zur Anwendung.",{"data":557,"type":41},{"text":558,"level":477},"Optionaler Generator: OpenAI Responses API",{"data":560,"type":216},{"text":561},"Ein möglicher Generator ist die OpenAI Responses API. Den Modellnamen in einer Umgebungsvariable zu halten, vermeidet die Festcodierung eines bestimmten Modells in die RAG-Architektur.",{"data":563,"type":251},{"code":564},"# 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":566,"type":216},{"text":567},"Dieselbe Retrieval-Pipeline kann mit einem lokalen Inferenzserver verbunden werden. Dies ist ein wichtiger architektonischer Punkt: \u003Cb>RAG gehört nicht dem LLM-Anbieter.\u003C\u002Fb> Die Anwendung besitzt die Quelle, das Retrieval und die Kontextzusammenstellung.",{"data":569,"type":41},{"text":570,"level":477},"Die gesamte Architektur in einer Ansicht",{"data":572,"type":251},{"code":573},"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":575,"type":216},{"text":576},"Dieses Datenflussmodell ist beständiger als das Auswendiglernen eines Frameworks. Bibliotheken, Datenbanken und Modellanbieter werden sich ändern; die Verantwortlichkeitsgrenzen bleiben bestehen.",{"data":578,"type":41},{"text":579,"level":229},"Häufige Missverständnisse und Fehlermodi",{"data":581,"type":41},{"text":582,"level":477},"„RAG bedeutet Vektordatenbank.“",{"data":584,"type":216},{"text":585},"Nein. Vektorsuche ist eine Retrieval-Methode. RAG kann Volltextsuche, SQL, APIs, Wissensgraphen, Vektorsuche oder Kombinationen davon verwenden. Das definierende Muster ist das Abrufen externer Informationen für die Generierung.",{"data":587,"type":41},{"text":588,"level":477},"„Wenn die Daten in PostgreSQL sind, muss ich die gesamte Datenbank einbetten.“",{"data":590,"type":216},{"text":591},"Nein. Strukturierte Datensätze sollten in der Regel als strukturierte Datensätze abfragbar bleiben. Embeddings sind nützlich für semantische Relevanz, nicht als Ersatz für deterministische Abfragen.",{"data":593,"type":41},{"text":594,"level":477},"„Mehr Chunks bedeuten eine bessere Antwort.“",{"data":596,"type":216},{"text":597},"Nicht unbedingt. Zusätzlicher Kontext kann Rauschen, widersprüchliche Versionen und irrelevantes Material einbringen. Retrieval sollte auf nützliche Belege optimieren, nicht auf maximales Volumen.",{"data":599,"type":41},{"text":600,"level":477},"„Ein hoher Ähnlichkeitswert beweist die Antwort.“",{"data":602,"type":216},{"text":603},"Nein. Ähnlichkeit misst Relevanz, nicht Wahrheit oder Anwendbarkeit. Eine hochgradig ähnliche Passage kann veraltet sein, aus der falschen Produktversion stammen oder nur unter Bedingungen gültig sein, die nicht zur Frage passen.",{"data":605,"type":41},{"text":606,"level":477},"„Sobald der richtige Chunk abgerufen ist, ist Halluzination gelöst.“",{"data":608,"type":216},{"text":609},"Nein. Retrieval verbessert die Verankerung, garantiert aber kein treues Schlussfolgern. Die Generierung muss weiterhin evaluiert werden, und risikoreiche Workflows können deterministische Validierung oder menschliche Prüfung erfordern.",{"data":611,"type":41},{"text":612,"level":477},"„Das Modell hat versagt, also wechsle das Modell.“",{"data":614,"type":216},{"text":615},"Nicht unbedingt. Die richtige Quelle kann gefehlt haben, falsch geparst, schlecht aufgeteilt, herausgefiltert, zu niedrig eingestuft oder aus dem zusammengestellten Kontext ausgelassen worden sein. Der Modellwechsel sollte nicht der erste Diagnoseschritt sein.",{"data":617,"type":41},{"text":618,"level":229},"Randfälle",{"data":620,"type":356},{"items":621,"style":355},[622,623,624,625,626,627,628,629],"\u003Cb>Widersprüchliche Dokumente:\u003C\u002Fb> zwei Quellen können voneinander abweichen, weil Versionen, Rechtsordnungen oder Produkte unterschiedlich sind.","\u003Cb>Zeitkritische Fakten:\u003C\u002Fb> eine semantisch relevante Quelle kann bereits veraltet sein.","\u003Cb>Berechtigungen:\u003C\u002Fb> ein Retriever darf keine Dokumente zurückgeben, auf die der aktuelle Benutzer nicht zugreifen darf.","\u003Cb>Mehrsprachige Sammlungen:\u003C\u002Fb> das Embedding-Modell und die Retrieval-Strategie müssen die tatsächlich verwendeten Sprachen unterstützen.","\u003Cb>Tabellen und Quellcode:\u003C\u002Fb> einfaches Absatz-Chunking kann Strukturen zerstören, die für die Antwort wesentlich sind.","\u003Cb>Sehr kurze Identifikatoren:\u003C\u002Fb> semantisches Retrieval kann bei SKUs, IDs, Fehlercodes oder Akronymen schwächer sein als exakte Übereinstimmung.","\u003Cb>Lange Fragen, die mehrere Fakten erfordern:\u003C\u002Fb> Retrieval kann Dekomposition, mehrere Suchen oder Reranking statt einer einzigen Top-k-Abfrage benötigen.","\u003Cb>Quellenhierarchie:\u003C\u002Fb> eine offizielle aktuelle Richtlinie muss möglicherweise ein älteres, aber semantisch näheres Diskussionsdokument überstimmen.",{"data":631,"type":41},{"text":632,"level":229},"Einschränkungen",{"data":634,"type":216},{"text":635},"Die Python-Beispiele optimieren bewusst auf Transparenz, nicht auf Skalierung. Der Keyword-Retriever ist naiv, der Chunker verwendet Zeichenlänge, die SQLite-Beispiele enthalten kein Produktions-Verbindungsmanagement, und das semantische Beispiel hält alle Embeddings im Speicher.",{"data":637,"type":216},{"text":638},"Ein Produktionssystem kann Vektorindizes, Reranker, hybrides Retrieval, Dokumentenparser, Caching, inkrementelle Indexierung, Quellenversionierung, Zugriffskontrollfilter, Observability, Evaluierungsdatensätze und Fehlerbehandlung erfordern. Keine dieser Ergänzungen ändert die Kernarchitektur; sie machen jede Grenze zuverlässiger.",{"data":640,"type":216},{"text":641},"RAG kann auch keine Belege erzeugen, die im Quellensatz fehlen. Wenn die Quelle falsch, unvollständig oder veraltet ist, kann ein besseres Embedding-Modell sie nicht in autoritatives Wissen verwandeln.",{"data":643,"type":41},{"text":644,"level":229},"Was würde diese Antwort ändern?",{"data":646,"type":216},{"text":647},"Die Architektur ändert sich, wenn die Aufgabe mehr als Wissensabruf erfordert. Ein Live-Bestellstatus benötigt den aktuellen Zustand. Eine Finanzberechnung kann deterministischen Code erfordern. Eine Web-Recherche-Aufgabe kann aktive Suche erfordern. Ein Workflow kann Tools benötigen, die Daten in ein anderes System zurückschreiben können. Ein autonomer Agent kann zusätzlich zum Retrieval Planung, Berechtigungen und Ausführungskontrolle benötigen.",{"data":649,"type":216},{"text":650},"RAG lässt sich daher am besten als \u003Cb>eine Ebene der Belegbeschaffung innerhalb eines größeren KI-Systems\u003C\u002Fb> verstehen. Es ist gerade deshalb leistungsfähig, weil es eine enge Aufgabe hat: nützliche externe Informationen finden und in den Arbeitskontext des Modells einfügen.",{"data":652,"type":41},{"text":653,"level":229},"Fazit",{"data":655,"type":216},{"text":656},"RAG wird viel leichter zu verstehen, wenn die Technologienamen entfernt werden. Eine Datei ist eine Quelle. Eine Datenbank ist eine Quelle. Eine API ist eine Quelle. Eine Suchfunktion ruft Belege ab. Ein Prompt trägt diese Belege zum Modell. Das LLM interpretiert sie dann und erzeugt Sprache.",{"data":658,"type":216},{"text":659},"Das Schwierige an Produktions-RAG ist nicht der Aufruf eines Embedding-Modells. Es ist der Aufbau eines vertrauenswürdigen Belegpfads von der Originalquelle bis zur endgültigen Aussage: die Herkunft bewahren, die richtige Retrieval-Methode auswählen, Informationen aktuell halten, den Zugriff kontrollieren, Retrieval getrennt von der Generierung bewerten und wissen, wann ein direkter Datenbank- oder Tool-Aufruf besser ist als semantische Suche.",{"data":661,"type":216},{"text":662},"Das ist die praktische Fortsetzung des grundlegenden RAG-Modells: \u003Cb>zuerst die Rollen verstehen, dann den Datenpfad explizit machen.\u003C\u002Fb>",{"data":664,"type":41},{"text":665,"level":229},"Primärquellen",{"data":667,"type":356},{"items":668,"style":355},[669,670,671,672,673,674],"\u003Ca href=\"https:\u002F\u002Farxiv.org\u002Fabs\u002F2005.11401\">Lewis et al. — Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks\u003C\u002Fa> — das Paper von 2020, das die RAG-Formulierung einführte, die Generierung mit abgerufenem nicht-parametrischem Speicher kombiniert.","\u003Ca href=\"https:\u002F\u002Fwww.sbert.net\u002Fexamples\u002Fsentence_transformer\u002Fapplications\u002Fsemantic-search\u002FREADME.html\">Sentence Transformers — Semantic Search\u003C\u002Fa> — offizielle Dokumentation für semantisches Retrieval, Query-Embeddings und Dokument-Embeddings.","\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fembeddings\">OpenAI — Vector Embeddings\u003C\u002Fa> — offizielle Dokumentation, die Embeddings als numerische Repräsentationen beschreibt, die für Verwandtschaft und Suche verwendet werden.","\u003Ca href=\"https:\u002F\u002Fwww.sqlite.org\u002Ffts5.html\">SQLite — FTS5 Extension\u003C\u002Fa> — offizielle Dokumentation für Volltextsuche und BM25-Ranking in SQLite.","\u003Ca href=\"https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Flibraries\">OpenAI — SDKs and CLI\u003C\u002Fa> — offizielles Python-SDK-Beispiel für die Responses API, das im optionalen Generator-Beispiel verwendet wird.","\u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fde\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\">What Is RAG? The Simplest Explanation of How It Works\u003C\u002Fa> — der konzeptionelle erste Teil dieser Serie.","2.31","Ein LLM kennt deine Dateien, Datenbanken oder APIs nicht auf magische Weise. Diese praktische Fortsetzung der RAG-Reihe zeigt mit einfachem Python, wie externe Daten zu abrufbaren Belegen werden: von Textdateien und SQL bis hin zu Volltextsuche, Embeddings, Kontextzusammenstellung und dem abschließenden LLM-Aufruf.","\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":684,"de":685,"sr":686,"es":687,"fr":688,"it":689,"ru":690,"zh":691},"\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":694,"login":695,"email":696,"displayName":697},"20","rooth8233","aleksandar@stajic.de","Aleksandar Stajić",[699,958],{"lang":7,"title":207,"content":209,"contentJson":700,"excerpt":676},{"time":211,"blocks":701,"version":675},[702,704,706,708,710,712,714,716,718,720,722,724,726,728,730,732,734,736,738,740,742,744,746,748,750,752,754,756,767,769,771,773,776,778,780,792,794,796,805,807,809,812,814,816,818,820,822,824,826,828,830,832,834,836,838,840,842,844,846,848,850,852,854,856,858,860,862,864,866,868,870,872,874,876,878,880,882,884,886,888,890,892,894,896,898,900,902,904,906,908,910,912,914,916,918,920,922,924,926,928,931,933,935,937,939,941,943,945,947,949,951,953,955],{"data":703,"type":216},{"text":215},{"data":705,"type":216},{"text":219},{"data":707,"type":225},{"text":222,"caption":223,"alignment":224},{"data":709,"type":41},{"text":228,"level":229},{"data":711,"type":216},{"text":232},{"data":713,"type":41},{"text":235,"level":229},{"data":715,"type":216},{"text":238},{"data":717,"type":216},{"text":241},{"data":719,"type":41},{"text":244,"level":229},{"data":721,"type":216},{"text":247},{"data":723,"type":251},{"code":250},{"data":725,"type":216},{"text":254},{"data":727,"type":216},{"text":257},{"data":729,"type":251},{"code":260},{"data":731,"type":216},{"text":263},{"data":733,"type":41},{"text":266,"level":229},{"data":735,"type":216},{"text":269},{"data":737,"type":216},{"text":272},{"data":739,"type":216},{"text":275},{"data":741,"type":41},{"text":278,"level":229},{"data":743,"type":216},{"text":281},{"data":745,"type":216},{"text":284},{"data":747,"type":41},{"text":287,"level":229},{"data":749,"type":216},{"text":290},{"data":751,"type":216},{"text":293},{"data":753,"type":216},{"text":296},{"data":755,"type":41},{"text":299,"level":229},{"data":757,"type":335},{"content":758,"withHeadings":13},[759,760,761,762,763,764,765,766],[304,305,306],[308,309,310],[312,313,314],[316,317,318],[320,321,322],[324,325,326],[328,329,330],[332,333,334],{"data":768,"type":216},{"text":338},{"data":770,"type":216},{"text":341},{"data":772,"type":41},{"text":344,"level":229},{"data":774,"type":356},{"items":775,"style":355},[348,349,350,351,352,353,354],{"data":777,"type":216},{"text":359},{"data":779,"type":41},{"text":362,"level":229},{"data":781,"type":335},{"content":782,"withHeadings":13},[783,784,785,786,787,788,789,790,791],[367,368],[370,371],[373,374],[376,377],[379,380],[382,383],[385,386],[388,389],[391,392],{"data":793,"type":41},{"text":395,"level":229},{"data":795,"type":216},{"text":398},{"data":797,"type":335},{"content":798,"withHeadings":13},[799,800,801,802,803,804],[373,403,404],[406,407,408],[410,411,412],[414,415,416],[418,419,420],[422,423,424],{"data":806,"type":216},{"text":427},{"data":808,"type":216},{"text":430},{"data":810,"type":356},{"items":811,"style":443},[434,435,436,437,438,439,440,441,442],{"data":813,"type":216},{"text":446},{"data":815,"type":41},{"text":449,"level":229},{"data":817,"type":216},{"text":452},{"data":819,"type":216},{"text":455},{"data":821,"type":216},{"text":458},{"data":823,"type":216},{"text":461},{"data":825,"type":41},{"text":464,"level":229},{"data":827,"type":216},{"text":467},{"data":829,"type":251},{"code":470},{"data":831,"type":216},{"text":473},{"data":833,"type":41},{"text":476,"level":477},{"data":835,"type":251},{"code":480},{"data":837,"type":216},{"text":483},{"data":839,"type":41},{"text":486,"level":477},{"data":841,"type":251},{"code":489},{"data":843,"type":216},{"text":492},{"data":845,"type":41},{"text":495,"level":229},{"data":847,"type":216},{"text":498},{"data":849,"type":251},{"code":501},{"data":851,"type":216},{"text":504},{"data":853,"type":216},{"text":507},{"data":855,"type":41},{"text":510,"level":229},{"data":857,"type":216},{"text":513},{"data":859,"type":251},{"code":516},{"data":861,"type":216},{"text":519},{"data":863,"type":41},{"text":522,"level":229},{"data":865,"type":216},{"text":525},{"data":867,"type":251},{"code":528},{"data":869,"type":216},{"text":531},{"data":871,"type":216},{"text":534},{"data":873,"type":41},{"text":537,"level":229},{"data":875,"type":216},{"text":540},{"data":877,"type":251},{"code":543},{"data":879,"type":216},{"text":546},{"data":881,"type":41},{"text":549,"level":229},{"data":883,"type":251},{"code":552},{"data":885,"type":216},{"text":555},{"data":887,"type":41},{"text":558,"level":477},{"data":889,"type":216},{"text":561},{"data":891,"type":251},{"code":564},{"data":893,"type":216},{"text":567},{"data":895,"type":41},{"text":570,"level":477},{"data":897,"type":251},{"code":573},{"data":899,"type":216},{"text":576},{"data":901,"type":41},{"text":579,"level":229},{"data":903,"type":41},{"text":582,"level":477},{"data":905,"type":216},{"text":585},{"data":907,"type":41},{"text":588,"level":477},{"data":909,"type":216},{"text":591},{"data":911,"type":41},{"text":594,"level":477},{"data":913,"type":216},{"text":597},{"data":915,"type":41},{"text":600,"level":477},{"data":917,"type":216},{"text":603},{"data":919,"type":41},{"text":606,"level":477},{"data":921,"type":216},{"text":609},{"data":923,"type":41},{"text":612,"level":477},{"data":925,"type":216},{"text":615},{"data":927,"type":41},{"text":618,"level":229},{"data":929,"type":356},{"items":930,"style":355},[622,623,624,625,626,627,628,629],{"data":932,"type":41},{"text":632,"level":229},{"data":934,"type":216},{"text":635},{"data":936,"type":216},{"text":638},{"data":938,"type":216},{"text":641},{"data":940,"type":41},{"text":644,"level":229},{"data":942,"type":216},{"text":647},{"data":944,"type":216},{"text":650},{"data":946,"type":41},{"text":653,"level":229},{"data":948,"type":216},{"text":656},{"data":950,"type":216},{"text":659},{"data":952,"type":216},{"text":662},{"data":954,"type":41},{"text":665,"level":229},{"data":956,"type":356},{"items":957,"style":355},[669,670,671,672,673,674],{"lang":959,"title":960,"content":961,"contentJson":962,"excerpt":1402},"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":963,"blocks":964,"version":1401},1790516400000,[965,968,971,975,978,981,984,987,990,993,996,998,1001,1004,1006,1009,1012,1015,1018,1021,1024,1027,1030,1033,1036,1039,1042,1045,1077,1080,1083,1086,1096,1099,1102,1131,1134,1137,1163,1166,1169,1181,1184,1187,1190,1193,1196,1199,1202,1205,1207,1210,1213,1215,1218,1221,1223,1226,1229,1232,1234,1237,1240,1243,1246,1248,1251,1254,1257,1259,1262,1265,1268,1271,1273,1276,1279,1281,1284,1287,1290,1292,1295,1298,1300,1303,1306,1309,1312,1315,1318,1321,1324,1327,1330,1333,1336,1339,1342,1345,1356,1359,1362,1365,1368,1371,1374,1377,1380,1383,1386,1389,1392],{"data":966,"type":216},{"text":967},"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":969,"type":216},{"text":970},"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":972,"type":225},{"text":973,"caption":974,"alignment":224},"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":976,"type":41},{"text":977,"level":229},"Question",{"data":979,"type":216},{"text":980},"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":982,"type":41},{"text":983,"level":229},"What This Really Means",{"data":985,"type":216},{"text":986},"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":988,"type":216},{"text":989},"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":991,"type":41},{"text":992,"level":229},"Simplest Example",{"data":994,"type":216},{"text":995},"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":997,"type":251},{"code":250},{"data":999,"type":216},{"text":1000},"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":1002,"type":216},{"text":1003},"A slightly more general version ranks documents by overlapping query terms:",{"data":1005,"type":251},{"code":260},{"data":1007,"type":216},{"text":1008},"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":1010,"type":41},{"text":1011,"level":229},"Where the Example Stops Working",{"data":1013,"type":216},{"text":1014},"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":1016,"type":216},{"text":1017},"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":1019,"type":216},{"text":1020},"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":1022,"type":41},{"text":1023,"level":229},"Direct Answer",{"data":1025,"type":216},{"text":1026},"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":1028,"type":216},{"text":1029},"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":1031,"type":41},{"text":1032,"level":229},"Why This Is So",{"data":1034,"type":216},{"text":1035},"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":1037,"type":216},{"text":1038},"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":1040,"type":216},{"text":1041},"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":1043,"type":41},{"text":1044,"level":229},"Context: The Main Types of Data Sources",{"data":1046,"type":335},{"content":1047,"withHeadings":13},[1048,1052,1055,1058,1062,1065,1069,1073],[1049,1050,1051],"Source","Typical retrieval method","Good for",[308,1053,1054],"Parsing + lexical or semantic search","Documentation, manuals, articles, notes",[312,1056,1057],"Structure-aware extraction + search","Policies, reports, contracts, manuals",[1059,1060,1061],"SQL database","SQL query or filtered retrieval","Orders, users, products, structured records",[320,1063,1064],"HTTP request with parameters","Remote systems and live service data",[1066,1067,1068],"Search index","BM25 \u002F full-text \u002F hybrid search","Large text collections",[1070,1071,1072],"Vector index","Embedding similarity","Semantic document retrieval",[1074,1075,1076],"Application state","Direct state read or tool call","What is true right now",{"data":1078,"type":216},{"text":1079},"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":1081,"type":216},{"text":1082},"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":1084,"type":41},{"text":1085,"level":229},"Assumptions",{"data":1087,"type":356},{"items":1088,"style":355},[1089,1090,1091,1092,1093,1094,1095],"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":1097,"type":216},{"text":1098},"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":1100,"type":41},{"text":1101,"level":229},"Variables",{"data":1103,"type":335},{"content":1104,"withHeadings":13},[1105,1107,1110,1113,1116,1119,1122,1125,1128],[367,1106],"Why it changes the design",[1108,1109],"Source structure","A SQL table, legal PDF and source-code repository need different retrieval strategies",[1111,1112],"Question type","Exact lookup, conceptual search and multi-hop research are different tasks",[1114,1115],"Freshness requirement","Live state may need direct queries instead of periodically rebuilt indexes",[1117,1118],"Corpus size","In-memory search may work for hundreds of chunks but not for very large collections",[1120,1121],"Language","Multilingual retrieval requires models and tokenization suitable for the actual languages",[1123,1124],"Permissions","Retrieval must filter by the current user’s access rights",[1126,1127],"Latency and cost","More retrieval stages can improve quality but add runtime and infrastructure cost",[1129,1130],"Need for provenance","High-trust systems need source IDs, versions and traceable evidence",{"data":1132,"type":41},{"text":1133,"level":229},"Diagnostic \u002F Decision Method",{"data":1135,"type":216},{"text":1136},"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":1138,"type":335},{"content":1139,"withHeadings":13},[1140,1143,1147,1151,1155,1159],[1111,1141,1142],"Preferred first approach","Reason",[1144,1145,1146],"Exact ID or current record","SQL \u002F key lookup \u002F API","Deterministic structured access",[1148,1149,1150],"Exact wording, codes, names","Full-text or keyword search","Lexical precision",[1152,1153,1154],"Conceptual question over documents","Semantic vector search","Meaning can differ from wording",[1156,1157,1158],"Mixed enterprise knowledge","Hybrid retrieval + metadata filters","Combines lexical and semantic signals",[1160,1161,1162],"Current application state","Direct state\u002Ftool access","Freshness matters more than document similarity",{"data":1164,"type":216},{"text":1165},"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":1167,"type":216},{"text":1168},"When an answer is wrong, diagnose the pipeline in order instead of immediately changing the LLM:",{"data":1170,"type":356},{"items":1171,"style":443},[1172,1173,1174,1175,1176,1177,1178,1179,1180],"\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":1182,"type":216},{"text":1183},"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":1185,"type":41},{"text":1186,"level":229},"Evidence",{"data":1188,"type":216},{"text":1189},"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":1191,"type":216},{"text":1192},"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":1194,"type":216},{"text":1195},"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":1197,"type":216},{"text":1198},"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":1200,"type":41},{"text":1201,"level":229},"Real Example 1: A Folder of Text Files",{"data":1203,"type":216},{"text":1204},"Suppose a directory named \u003Ccode>knowledge\u002F\u003C\u002Fcode> contains ordinary text files. Python can load them with no AI library at all.",{"data":1206,"type":251},{"code":470},{"data":1208,"type":216},{"text":1209},"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":1211,"type":41},{"text":1212,"level":477},"A Very Simple Chunker",{"data":1214,"type":251},{"code":480},{"data":1216,"type":216},{"text":1217},"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":1219,"type":41},{"text":1220,"level":477},"Preserve Provenance While Chunking",{"data":1222,"type":251},{"code":489},{"data":1224,"type":216},{"text":1225},"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":1227,"type":41},{"text":1228,"level":229},"Real Example 2: Structured Data — Use SQL When SQL Is the Right Tool",{"data":1230,"type":216},{"text":1231},"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":1233,"type":251},{"code":501},{"data":1235,"type":216},{"text":1236},"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":1238,"type":216},{"text":1239},"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":1241,"type":41},{"text":1242,"level":229},"Real Example 3: Full-Text Search Before Embeddings",{"data":1244,"type":216},{"text":1245},"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":1247,"type":251},{"code":516},{"data":1249,"type":216},{"text":1250},"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":1252,"type":41},{"text":1253,"level":229},"Real Example 4: Semantic Retrieval With Embeddings",{"data":1255,"type":216},{"text":1256},"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":1258,"type":251},{"code":528},{"data":1260,"type":216},{"text":1261},"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":1263,"type":216},{"text":1264},"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":1266,"type":41},{"text":1267,"level":229},"Real Example 5: Build the Context for the LLM",{"data":1269,"type":216},{"text":1270},"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":1272,"type":251},{"code":543},{"data":1274,"type":216},{"text":1275},"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":1277,"type":41},{"text":1278,"level":229},"Real Example 6: A Complete Minimal Pipeline",{"data":1280,"type":251},{"code":552},{"data":1282,"type":216},{"text":1283},"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":1285,"type":41},{"text":1286,"level":477},"Optional Generator: OpenAI Responses API",{"data":1288,"type":216},{"text":1289},"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":1291,"type":251},{"code":564},{"data":1293,"type":216},{"text":1294},"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":1296,"type":41},{"text":1297,"level":477},"The Whole Architecture in One View",{"data":1299,"type":251},{"code":573},{"data":1301,"type":216},{"text":1302},"This data-flow model is more durable than memorizing one framework. Libraries, databases and model vendors will change; the responsibility boundaries remain.",{"data":1304,"type":41},{"text":1305,"level":229},"Common Misconceptions and Failure Modes",{"data":1307,"type":41},{"text":1308,"level":477},"“RAG means vector database.”",{"data":1310,"type":216},{"text":1311},"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":1313,"type":41},{"text":1314,"level":477},"“If the data is in PostgreSQL, I must embed the whole database.”",{"data":1316,"type":216},{"text":1317},"No. Structured records should usually remain queryable as structured records. Embeddings are useful for semantic relevance, not as a replacement for deterministic queries.",{"data":1319,"type":41},{"text":1320,"level":477},"“More chunks means a better answer.”",{"data":1322,"type":216},{"text":1323},"Not necessarily. Extra context can introduce noise, conflicting versions and irrelevant material. Retrieval should optimize for useful evidence, not maximum volume.",{"data":1325,"type":41},{"text":1326,"level":477},"“A high similarity score proves the answer.”",{"data":1328,"type":216},{"text":1329},"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":1331,"type":41},{"text":1332,"level":477},"“Once the correct chunk is retrieved, hallucination is solved.”",{"data":1334,"type":216},{"text":1335},"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":1337,"type":41},{"text":1338,"level":477},"“The model failed, so change the model.”",{"data":1340,"type":216},{"text":1341},"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":1343,"type":41},{"text":1344,"level":229},"Edge Cases",{"data":1346,"type":356},{"items":1347,"style":355},[1348,1349,1350,1351,1352,1353,1354,1355],"\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":1357,"type":41},{"text":1358,"level":229},"Limitations",{"data":1360,"type":216},{"text":1361},"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":1363,"type":216},{"text":1364},"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":1366,"type":216},{"text":1367},"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":1369,"type":41},{"text":1370,"level":229},"What Would Change This Answer?",{"data":1372,"type":216},{"text":1373},"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":1375,"type":216},{"text":1376},"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":1378,"type":41},{"text":1379,"level":229},"Conclusion",{"data":1381,"type":216},{"text":1382},"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":1384,"type":216},{"text":1385},"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":1387,"type":216},{"text":1388},"That is the practical continuation of the basic RAG model: \u003Cb>first understand the roles, then make the data path explicit.\u003C\u002Fb>",{"data":1390,"type":41},{"text":1391,"level":229},"Primary Sources",{"data":1393,"type":356},{"items":1394,"style":355},[1395,1396,1397,1398,1399,1400],"\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.","Post erfolgreich abgerufen",{"items":1405,"source":1490,"manualIds":1491,"manualMatchedIds":1492},[1406,1413,1420,1427,1434,1441,1448,1455,1462,1469,1476,1483],{"id":1407,"slug":1408,"title":1409,"excerpt":1410,"featuredImage":1411,"publishedAt":1412},"468","ai-agent-memory-is-not-rag-how-to-separate-memory-retrieval-state-and-context","KI-Agenten-Gedächtnis ist kein RAG: Wie man Gedächtnis, Retrieval, Zustand und Kontext voneinander trennt","Agentengedächtnis, RAG, Zustand und Kontext werden oft so verwendet, als wären sie austauschbar. Das sind sie nicht. Dieses praktische Architekturmodell trennt die vier Schichten, zeigt, wohin jede gehört, und erklärt, was kaputtgeht, wenn Systeme sie zu einer einzigen zusammenfassen.","\u002Fuploads\u002F2026\u002F09\u002Fai-agent-memory-is-not-rag-how-to-separate-memory-retrieval-state-and-context-1790350560308-np0xy6.webp","2026-09-25T11:34:00.000Z",{"id":1414,"slug":1415,"title":1416,"excerpt":1417,"featuredImage":1418,"publishedAt":1419},"478","what-is-rag-the-simplest-explanation-of-how-it-works","Was ist RAG? Die einfachste Erklärung, wie es funktioniert","RAG klingt kompliziert, aber die Idee ist einfach: Bevor eine KI antwortet, sucht sie zunächst nützliche Informationen aus einer Wissensquelle und gibt diese Informationen an das Sprachmodell weiter. Dieser Leitfaden erklärt RAG, LLMs, Zustand, Gedächtnis und Werkzeuge anhand eines einfachen mentalen Modells.","\u002Fuploads\u002F2026\u002F09\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works-1790377492124-khjagt.webp","2026-09-25T19:03:00.000Z",{"id":1421,"slug":1422,"title":1423,"excerpt":1424,"featuredImage":1425,"publishedAt":1426},"464","falsification-for-ai-reasoning-from-answers-to-tested-hypotheses","Falsifikation für KI-Schlussfolgern: Von Antworten zu getesteten Hypothesen","KI-Modelle können überzeugende Belege für nahezu jede plausible Hypothese generieren. Eine zuverlässigere Methodik stellt die entgegengesetzte Frage: Welche Belege würden die Schlussfolgerung abschwächen, ihr widersprechen oder uns zwingen, sie aufzugeben? Dieser Artikel entwickelt eine falsifikationsorientierte Argumentation für LLMs mithilfe konkurrierender Hypothesen, diskriminierender Tests, Gegenbelegen und expliziter Ablehnungskriterien.","\u002Fuploads\u002F2026\u002F09\u002Ffalsification-for-ai-reasoning-from-answers-to-tested-hypotheses-1789811137616-3hce1b.webp","2026-09-19T01:11:00.000Z",{"id":1428,"slug":1429,"title":1430,"excerpt":1431,"featuredImage":1432,"publishedAt":1433},"375","database-marketing","Datenbankmarketing: Ein moderner Ansatz zu Kundenbeziehungen","Datenbankmarketing ist unerlässlich für modernes Kundenbeziehungsmanagement. Erfahren Sie, wie strategische Datennutzung, technisches Fachwissen und Innovation personalisierte Kundeninteraktionen und nachhaltiges Wachstum vorantreiben.","\u002Fuploads\u002F2025\u002F01\u002FDatabasemarketing.png-medium.webp","2025-01-06T00:20:00.000Z",{"id":1435,"slug":1436,"title":1437,"excerpt":1438,"featuredImage":1439,"publishedAt":1440},"443","linux","Aufkommende Linux-Trends 2026: Die Zukunft der Serverinfrastruktur gestalten","Entdecken Sie die wichtigsten Linux-Trends von 2026, von der Kubernetes-Dominanz und unveränderlichen Distributionen bis hin zur KI-Integration und eBPF-Sicherheit.","\u002Fuploads\u002F2026\u002F03\u002Flinux-1773696098750-knp03t.webp","2026-03-01T13:52:00.000Z",{"id":1442,"slug":1443,"title":1444,"excerpt":1445,"featuredImage":1446,"publishedAt":1447},"471","how-to-know-whether-an-ai-agent-actually-used-the-right-evidence","Wie man erkennt, ob ein KI-Agent tatsächlich die richtigen Belege verwendet hat","Ein KI-Agent kann Quellen zitieren und trotzdem die falschen Belege verwenden. Dieser Artikel stellt eine praktische Methode zur Überprüfung der Belegung von Behauptungen, der Quellenautorität, der Anwendbarkeit, der Herkunft sowie der Frage vor, ob die Belege die Antwort tatsächlich beeinflusst haben.","\u002Fuploads\u002F2026\u002F09\u002Fhow-to-know-whether-an-ai-agent-actually-used-the-right-evidence-1790351317188-o5z9ve.webp","2026-09-25T11:47:00.000Z",{"id":1449,"slug":1450,"title":1451,"excerpt":1452,"featuredImage":1453,"publishedAt":1454},"448","google-io-2026-android-xr-and-intelligent-eyewear","Google I\u002FO 2026: Android XR, intelligente Brillen und das Ambient-AI-Interface","Google I\u002FO 2026 hat Android XR und intelligente Brillen von einem Konzept hin zu einer echten Plattformrichtung vorangetrieben. Dieser Artikel schlüsselt Audio-Brillen, Display-Brillen, Gemini-gestütztes Kontextbewusstsein, Auswirkungen auf Entwickler sowie Datenschutzrisiken auf und erklärt, warum es bei Wearable-KI weniger darum geht, Telefone zu ersetzen, als vielmehr darum, ambiente Assistenzflächen zu schaffen.","\u002Fuploads\u002F2026\u002F05\u002Fgoogle-io-2026-android-xr-and-intelligent-eyewear-1779227942270-dtsm9y.webp","2026-05-21T11:05:00.000Z",{"id":1456,"slug":1457,"title":1458,"excerpt":1459,"featuredImage":1460,"publishedAt":1461},"477","computer-use-agents-why-a-successful-demo-can-still-be-an-unreliable-system","Computer-Use-Agenten: Warum eine erfolgreiche Demo dennoch ein unzuverlässiges System sein kann","Computer-Use-Agenten können mittlerweile beeindruckende Browser- und Desktop-Workflows abschließen, aber ein erfolgreicher Durchlauf beweist Fähigkeit—nicht Zuverlässigkeit. Dieser Artikel zeigt, wie man Wiederholbarkeit, Umgebungsrobustheit, Steuerung über lange Zeithorizonte, Zustandsbewusstsein, Ergebnisüberprüfung und sichere Zielhandhabung testet.","\u002Fuploads\u002F2026\u002F09\u002Fcomputer-use-agents-why-a-successful-demo-can-still-be-an-unreliable-system-1790352854690-75qnrg.webp","2026-09-25T12:13:00.000Z",{"id":1463,"slug":1464,"title":1465,"excerpt":1466,"featuredImage":1467,"publishedAt":1468},"459","ollama-is-not-the-product-building-production-ready-open-llm-applications","Ollama ist nicht das Produkt: Entwicklung produktionsreifer Open-LLM-Anwendungen","Das Ausführen eines lokalen Modells mit Ollama ist einfach. Das Erstellen einer produktionsreifen Open-LLM-Anwendung ist schwieriger: Es erfordert RAG, Zugriffskontrolle, Anbieterabstraktion, Evaluierung, Protokollierung, Bereitstellungsdisziplin und eine kontrollierte Anwendungsschicht um das Modell herum.","\u002Fuploads\u002F2026\u002F06\u002Follama-is-not-the-product-building-production-ready-open-llm-applications-1782679361640-h0usqf.webp","2026-06-28T16:39:00.000Z",{"id":1470,"slug":1471,"title":1472,"excerpt":1473,"featuredImage":1474,"publishedAt":1475},"457","should-you-buy-5g-openwrt-router-old-firmware","Sollten Sie einen 5G-OpenWrt-Router mit alter Firmware kaufen? ZBT Z8102AX als praktisches Beispiel","Kauf eines 5G-OpenWrt-Routers mit älterer Firmware kann sinnvoll sein, aber nur unter den richtigen Bedingungen. Der ZBT Z8102AX zeigt beide Seiten deutlich: Die Hardware ist nützlich, das Modem funktioniert, und der Router blieb im Test stabil, aber OpenWrt 21.02, schwache Verpackung und unklare Upgrade-Pfade erfordern eine sorgfältige Kaufentscheidung.","\u002Fuploads\u002F2026\u002F06\u002Fopenwrt-router-review-dual-sim-05-1781620596218-5ldld4.webp","2026-06-16T10:41:00.000Z",{"id":1477,"slug":1478,"title":1479,"excerpt":1480,"featuredImage":1481,"publishedAt":1482},"469","rag-failed-but-which-layer-actually-failed-a-diagnostic-method","RAG fehlgeschlagen – aber welche Ebene ist tatsächlich fehlgeschlagen? Eine diagnostische Methode","Wenn eine RAG-Antwort falsch ist, ist es zu vage, das Retrieval oder das Modell verantwortlich zu machen. Diese Diagnosemethode isoliert Quellenabdeckung, Query-Konstruktion, Retrieval, Ranking, Kontextzusammenstellung, Generierung, Evidenzzuordnung und Aktualität – sodass der tatsächliche Fehler reproduziert und behoben werden kann.","\u002Fuploads\u002F2026\u002F09\u002Frag-failed-but-which-layer-actually-failed-a-diagnostic-method-1790350847177-pior4c.webp","2026-09-24T19:39:00.000Z",{"id":1484,"slug":1485,"title":1486,"excerpt":1487,"featuredImage":1488,"publishedAt":1489},"463","prompt-invariance-does-the-conclusion-survive-the-prompt","Prompt-Invarianz: Überlebt die Schlussfolgerung den Prompt?","Eine praktische Methodik zur Überprüfung, ob eine KI-Schlussfolgerung davon abhängt, wie ein Problem gerahmt wurde. Prompt Invariance vergleicht ursprüngliche, blinde, invertierte und adversariale Formulierungen, während die Evidenzstruktur kontrolliert bleibt.","\u002Fuploads\u002F2026\u002F09\u002Fprompt-invariance-does-the-conclusion-survive-the-prompt-1789809799910-s0vbcb.webp","2026-09-19T01:09:00.000Z","fallback",[],[]]