<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Lokale KI on kenji.blog</title><link>http://kenji.blog/de/tags/lokale-ki/</link><description>Recent content in Lokale KI on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>de</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 13:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/de/tags/lokale-ki/index.xml" rel="self" type="application/rss+xml"/><item><title>【RAG Implementierungsleitfaden】Wie Sie einer lokalen KI Ihre eigenen Dokumente beibringen</title><link>http://kenji.blog/de/p/rag-local-ai-implementation-guide/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/rag-local-ai-implementation-guide/</guid><description>&lt;img src="http://kenji.blog/p/rag-local-ai-implementation-guide/img/eyecatch.jpg" alt="Featured image of post 【RAG Implementierungsleitfaden】Wie Sie einer lokalen KI Ihre eigenen Dokumente beibringen" />&lt;h1 id="einführung">Einführung
&lt;/h1>&lt;p>In den letzten Jahren war die Entwicklung von großen Sprachmodellen (LLMs) bemerkenswert, und viele KIs, angeführt von ChatGPT und Claude, haben unseren Alltag und unsere Arbeit durchdrungen. Allgemeine LLMs haben jedoch eine offensichtliche Schwäche. Sie kennen nur &amp;ldquo;öffentliche Informationen zum Zeitpunkt des Trainings&amp;rdquo;. Natürlich können sie keine Fragen zu &amp;ldquo;privaten Dokumenten&amp;rdquo; wie internen Firmenrichtlinien, persönlichen Notizen und unveröffentlichten Projektmaterialien beantworten. Wenn man versucht, sie zur Beantwortung zu zwingen, steigt das Risiko, dass sie plausibel klingende Lügen (Halluzinationen) generieren, die nicht den Tatsachen entsprechen.&lt;/p>
&lt;p>Daher verbreitet sich derzeit eine Technologiearchitektur namens &lt;strong>RAG (Retrieval-Augmented Generation)&lt;/strong> weltweit rasant. Durch den Einsatz von RAG ist es möglich, LLMs dynamisch mit eigenem Wissen aus externen Datenbanken zu versorgen und sie basierend darauf genaue und fundierte Antworten generieren zu lassen.&lt;/p>
&lt;p>Darüber hinaus ist es bei der Verarbeitung von vertraulichen Unternehmens- oder persönlichen Informationen oft aufgrund von Sicherheitsrichtlinien inakzeptabel, Daten an cloudbasierte APIs wie OpenAI zu senden. Was hier benötigt wird, ist der Aufbau eines &amp;ldquo;lokalen RAG&amp;rdquo; in Kombination mit einer &lt;strong>lokalen KI&lt;/strong> (einem LLM, das vollständig auf dem eigenen PC oder On-Premise-Server läuft).&lt;/p>
&lt;p>In diesem Artikel werden wir alles von der grundlegenden RAG-Theorie über die konkrete Implementierung eines lokalen RAG mit Python, den mathematischen Hintergrund (wie die Vektorsuche funktioniert) bis hin zu fortgeschrittenen Techniken für den produktiven Betrieb des Systems umfassend erklären.&lt;/p>
&lt;hr>
&lt;h1 id="1-die-gesamtarchitektur-von-rag">1. Die Gesamtarchitektur von RAG
&lt;/h1>&lt;p>RAG ist nicht ein einzelnes KI-Modell, sondern eine Systemarchitektur, bei der mehrere Komponenten zusammenarbeiten. Es besteht grob aus zwei Phasen: der &amp;ldquo;Ingestionsphase (Datenaufnahme)&amp;rdquo; und der &amp;ldquo;Retrieval- &amp;amp; Generationsphase (Suche und Generierung)&amp;rdquo;.&lt;/p>
&lt;p>Das folgende Mermaid-Diagramm zeigt das Gesamtbild eines RAG-Systems.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Ingestionsphase (Vorbereitung)"
Doc["Eigene Dokumente (PDF, TXT, etc.)"] --> Loader["Dokumenten-Loader"]
Loader --> Splitter["Textaufteilung (Chunking)"]
Splitter --> EmbedModel1["Einbettungsmodell (Embedding)"]
EmbedModel1 --> VectorDB["Vektordatenbank"]
end
subgraph "Inferenzphase (Bei Benutzeranfrage)"
User["Benutzerfrage (Abfrage)"] --> EmbedModel2["Einbettungsmodell (Embedding)"]
EmbedModel2 --> QueryVector["Abfragevektor"]
QueryVector --> Search["Ähnlichkeitssuche (Vektorsuche)"]
VectorDB --> Search
Search --> Context["Relevante Chunks extrahieren (Kontext)"]
User --> PromptBuilder["Prompt-Erstellung"]
Context --> PromptBuilder
PromptBuilder --> LocalLLM["Lokales LLM"]
LocalLLM --> Answer["Endgültige Antwortgenerierung"]
end&lt;/div>
&lt;h2 id="ingestionsphase-vorbereitung">Ingestionsphase (Vorbereitung)
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>Dokumente laden&lt;/strong>: Lesen von unstrukturierten Daten wie PDFs, Word- und Textdateien.&lt;/li>
&lt;li>&lt;strong>Chunking (Textaufteilung)&lt;/strong>: Um in das Eingabelimit (Kontextfenster) des LLM zu passen und die Suchgenauigkeit zu erhöhen, werden lange Texte in sinnvolle Blöcke (Chunks) aufgeteilt.&lt;/li>
&lt;li>&lt;strong>Embedding (Vektorisierung)&lt;/strong>: Die aufgeteilten Chunks werden in ein Einbettungsmodell (Embedding Model) eingegeben und in numerische Arrays (Vektoren) mit Hunderten bis Tausenden von Dimensionen umgewandelt.&lt;/li>
&lt;li>&lt;strong>In der Datenbank speichern&lt;/strong>: Die konvertierten Vektoren werden zusammen mit den ursprünglichen Textdaten in einer Vektordatenbank (Vector DB) gespeichert.&lt;/li>
&lt;/ol>
&lt;h2 id="inferenzphase-laufzeit">Inferenzphase (Laufzeit)
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>Abfrage vektorisieren&lt;/strong>: Die Frage des Benutzers wird mit demselben Einbettungsmodell vektorisiert, das in der Vorbereitungsphase verwendet wurde.&lt;/li>
&lt;li>&lt;strong>Ähnlichkeitssuche&lt;/strong>: Die Ähnlichkeit zwischen dem Abfragevektor und den Dokumentenvektoren in der Datenbank wird berechnet, und die semantisch ähnlichsten (hochrelevanten) Text-Chunks werden abgerufen.&lt;/li>
&lt;li>&lt;strong>Prompt-Erstellung&lt;/strong>: Der abgerufene relevante Text wird als &amp;ldquo;Kontext (Hintergrundwissen)&amp;rdquo; mit der Frage des Benutzers kombiniert, um den Eingabe-Prompt für das LLM zu erstellen.&lt;/li>
&lt;li>&lt;strong>Antwortgenerierung&lt;/strong>: Das LLM empängt den erweiterten Prompt und generiert eine Antwort basierend auf den bereitgestellten Kontextinformationen.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-ein-tieferes-verständnis-von-vektorsuche-und-embeddings">2. Ein tieferes Verständnis von Vektorsuche und Embeddings
&lt;/h1>&lt;p>Der Kern von RAG ist die &amp;ldquo;Vektorsuche (semantische Suche)&amp;rdquo;. Während die traditionelle Stichwortsuche (wie BM25) auf exakten Wortübereinstimmungen oder Häufigkeiten basiert, basiert die Vektorsuche auf &amp;ldquo;semantischer Ähnlichkeit&amp;rdquo;. Auch wenn unterschiedliche Wörter verwendet werden, wie z.B. &amp;ldquo;Hund&amp;rdquo; und &amp;ldquo;Welpe&amp;rdquo; oder &amp;ldquo;PC&amp;rdquo; und &amp;ldquo;Computer&amp;rdquo;, werden sie bei der Suche gefunden, wenn ihre Bedeutungen ähnlich sind.&lt;/p>
&lt;h2 id="was-ist-ein-einbettungsmodell-embedding-model">Was ist ein Einbettungsmodell (Embedding Model)?
&lt;/h2>&lt;p>Ein Einbettungsmodell ist ein neuronales Netzwerk, das natürlichsprachlichen Text als Eingabe nimmt und einen dichten Vektor (Dense Vector) fester Länge als Ausgabe liefert. Gängige Modelle (wie &lt;code>text-embedding-3-small&lt;/code> oder das quelloffene &lt;code>multilingual-e5-large&lt;/code>) bilden Text auf reellwertige Vektoren mit 384 oder 1024 Dimensionen ab.&lt;/p>
&lt;p>In diesem mehrdimensionalen Raum (latenter Raum) werden Modelle so trainiert, dass Sätze mit ähnlichen Bedeutungen näher beieinander im Koordinatenraum liegen.&lt;/p>
&lt;h2 id="der-mathematische-hintergrund-der-ähnlichkeitsberechnung-kosinus-ähnlichkeit">Der mathematische Hintergrund der Ähnlichkeitsberechnung: Kosinus-Ähnlichkeit
&lt;/h2>&lt;p>Wenn eine Vektordatenbank nach relevanten Dokumenten sucht, ist die am häufigsten verwendete Distanzmetrik die &lt;strong>Kosinus-Ähnlichkeit (Cosine Similarity)&lt;/strong>. Im Gegensatz zur euklidischen Distanz (räumliche absolute Distanz) konzentriert sich die Kosinus-Ähnlichkeit auf den &amp;ldquo;Winkel zwischen zwei Vektoren&amp;rdquo;. Sie ist sehr gut für die Textähnlichkeitsberechnung geeignet, da sie weniger durch die Länge des Textes (die Norm des Vektors) beeinflusst wird.&lt;/p>
&lt;p>Mathematisch ausgedrückt ist die Kosinus-Ähnlichkeit zwischen den Vektoren $\mathbf{A}$ und $\mathbf{B}$ wie folgt:&lt;/p>
$$ \text{Cosine Similarity}(\mathbf{A}, \mathbf{B}) = \cos(\theta) = \frac{\mathbf{A} \cdot \mathbf{B}}{\|\mathbf{A}\| \|\mathbf{B}\|} = \frac{\sum_{i=1}^{n} A_i B_i}{\sqrt{\sum_{i=1}^{n} A_i^2} \sqrt{\sum_{i=1}^{n} B_i^2}} $$
&lt;ul>
&lt;li>$\mathbf{A} \cdot \mathbf{B}$ repräsentiert das Skalarprodukt (Dot Product).&lt;/li>
&lt;li>$\|\mathbf{A}\|$ repräsentiert die L2-Norm (Länge) des Vektors $\mathbf{A}$.&lt;/li>
&lt;li>$n$ ist die Anzahl der Dimensionen des Vektors.&lt;/li>
&lt;/ul>
&lt;p>Die Kosinus-Ähnlichkeit nimmt Werte von -1 bis 1 an.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Nahe bei 1&lt;/strong>: Die Richtungen der beiden Vektoren sind fast identisch (die Bedeutungen sind sehr ähnlich)&lt;/li>
&lt;li>&lt;strong>Nahe bei 0&lt;/strong>: Die beiden Vektoren sind orthogonal (kein Zusammenhang)&lt;/li>
&lt;li>&lt;strong>Nahe bei -1&lt;/strong>: Die beiden Vektoren zeigen in entgegengesetzte Richtungen (gegenteilige Bedeutungen)&lt;/li>
&lt;/ul>
&lt;p>Moderne Vektor-DBs (Chroma, FAISS, Qdrant usw.) verwenden Algorithmen zur ungefähren Nächste-Nachbarn-Suche (ANN), wie HNSW (Hierarchical Navigable Small World), die optimiert sind, um Dokumente mit hoher Kosinus-Ähnlichkeit selbst in Millionen von Vektordaten in Millisekunden zu finden.&lt;/p>
&lt;hr>
&lt;h1 id="3-der-technologie-stack-für-den-aufbau-eines-lokalen-rag">3. Der Technologie-Stack für den Aufbau eines lokalen RAG
&lt;/h1>&lt;p>Um ein vollständig lokales RAG aufzubauen, das nicht auf die Cloud angewiesen ist, nutzen wir das Open-Source-Ökosystem. Der folgende Technologie-Stack wird empfohlen:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Sprachmodell (LLM)&lt;/strong>
&lt;ul>
&lt;li>Tool: &lt;code>Ollama&lt;/code> oder &lt;code>Llama.cpp&lt;/code>&lt;/li>
&lt;li>Modelle: Leichte und leistungsstarke offene Modelle wie &lt;code>Llama-3-8B-Instruct&lt;/code>, &lt;code>Gemma-2-9B-It&lt;/code>, &lt;code>Qwen2-7B-Instruct&lt;/code>. Für japanische Aufgaben eignen sich auf Japanisch abgestimmte Modelle wie &lt;code>Llama-3-ELYZA-JP-8B&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Einbettungsmodell (Embedding)&lt;/strong>
&lt;ul>
&lt;li>Modelle: &lt;code>intfloat/multilingual-e5-large&lt;/code> oder &lt;code>BAAI/bge-m3&lt;/code>. Bei lokaler Ausführung ist es üblich, diese von Hugging Face herunterzuladen und mit Sentence-Transformers auszuführen.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Vektordatenbank (Vector DB)&lt;/strong>
&lt;ul>
&lt;li>&lt;code>ChromaDB&lt;/code>: Basiert auf Python und ist extrem einfach einzurichten. Ideal für die lokale Entwicklung.&lt;/li>
&lt;li>&lt;code>FAISS&lt;/code>: Eine von Meta entwickelte schnelle Vektorsuchbibliothek.&lt;/li>
&lt;li>&lt;code>Qdrant&lt;/code> / &lt;code>Milvus&lt;/code>: Besser geeignet für größere Skalierungen und Produktionsumgebungen.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Orchestrierungs-Framework&lt;/strong>
&lt;ul>
&lt;li>&lt;code>LangChain&lt;/code>: Der De-facto-Standard zur Verknüpfung (Chaining) von Komponenten.&lt;/li>
&lt;li>&lt;code>LlamaIndex&lt;/code>: Ein Datenverbindungs-Framework, das speziell auf RAG ausgerichtet ist.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Dieses Mal werden wir es mit der Kombination implementieren, die am einfachsten einzurichten ist: &lt;strong>LangChain + ChromaDB + Ollama + HuggingFaceEmbeddings&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="4-implementierungs-tutorial-vollständiger-lokaler-rag-aufbau-mit-python">4. Implementierungs-Tutorial: Vollständiger lokaler RAG-Aufbau mit Python
&lt;/h1>&lt;p>Von hier an werden wir ein lokales RAG aufbauen, indem wir tatsächlich Python-Code schreiben. Bitte installieren Sie Ollama im Voraus auf Ihrem PC und lassen Sie es im Hintergrund laufen. Ziehen Sie außerdem ein Modell auf Ollama (z.B. &lt;code>ollama run llama3&lt;/code>).&lt;/p>
&lt;h2 id="schritt-1-installation-der-benötigten-bibliotheken">Schritt 1: Installation der benötigten Bibliotheken
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install langchain langchain-community langchain-huggingface
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install chromadb sentence-transformers pypdf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="schritt-2-überblick-über-den-implementierungscode">Schritt 2: Überblick über den Implementierungscode
&lt;/h2>&lt;p>Das Folgende ist ein vollständiges Python-Skript, um eine PDF-Datei zu lesen, sie zu vektorisieren und ein lokales LLM Fragen dazu beantworten zu lassen.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;span class="lnt">87
&lt;/span>&lt;span class="lnt">88
&lt;/span>&lt;span class="lnt">89
&lt;/span>&lt;span class="lnt">90
&lt;/span>&lt;span class="lnt">91
&lt;/span>&lt;span class="lnt">92
&lt;/span>&lt;span class="lnt">93
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.document_loaders&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PyPDFLoader&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_text_splitters&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_huggingface&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.vectorstores&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Chroma&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.llms&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Ollama&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_core.prompts&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PromptTemplate&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain.chains&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RetrievalQA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. Dokumenten-Loader&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Dokumente werden geladen...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Geben Sie den Pfad des PDFs an, das Sie laden möchten&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;sample_company_policy.pdf&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">loader&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PyPDFLoader&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">loader&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. Textaufteilung (Text Splitting)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Aufteilung in eine angemessene Größe, ohne die Bedeutung des Textes zu zerstören&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text_splitter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Maximale Anzahl von Zeichen pro Chunk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_overlap&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Anzahl der überlappenden Zeichen zwischen den Chunks (verhindert Kontextverlust)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">separators&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;。&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;、&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">text_splitter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split_documents&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">documents&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;In &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> Chunks aufgeteilt.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. Initialisierung des Einbettungsmodells (Lokal HuggingFace Model)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Verwendung eines mehrsprachigen Modells&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Einbettungsmodell wird geladen...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embeddings&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;intfloat/multilingual-e5-large&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;device&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;cpu&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># &amp;#39;cuda&amp;#39; oder &amp;#39;mps&amp;#39;, falls eine GPU verfügbar ist&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. Aufbau der Vektordatenbank (Chroma)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Vektordatenbank wird aufgebaut...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">persist_directory&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./chroma_db&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vectorstore&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Chroma&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_documents&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embedding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">embeddings&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">persist_directory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">persist_directory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Erstellung des Retrievers. So konfiguriert, dass die Top-3 der relevanten Dokumente abgerufen werden&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retriever&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">vectorstore&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">as_retriever&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">search_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;k&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. Initialisierung des lokalen LLMs (Ollama)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Verbindung zum lokalen LLM wird hergestellt...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Stellen Sie sicher, dass Sie das Modell vorher mit z.B. &amp;#39;ollama pull llama3&amp;#39; abrufen&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Ollama&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;llama3&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 6. Definition der Prompt-Vorlage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt_template&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Du bist ein hervorragender Assistent, der mit Unternehmensrichtlinien und internen Informationen bestens vertraut ist.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">Bitte beantworte die Fragen des Benutzers ausführlich auf Deutsch, wobei du AUSSCHLIESSLICH den folgenden Kontext (Hintergrundinformationen) verwendest.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">Wenn die Antwort nicht im Kontext zu finden ist, spekuliere nicht, sondern antworte ehrlich: &amp;#34;Aus den bereitgestellten Informationen nicht ersichtlich.&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">[Kontext]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{context}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">[Frage]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{question}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">[Antwort]:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PROMPT&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PromptTemplate&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">template&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">prompt_template&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">input_variables&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;context&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;question&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 7. Aufbau der RAG-Kette&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qa_chain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RetrievalQA&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_chain_type&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">llm&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;stuff&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retriever&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">retriever&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">return_source_documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Legt fest, ob Quellenangaben zurückgegeben werden&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;prompt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">PROMPT&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 8. Ausführung der Frage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">query&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Bitte erläutern Sie die Bedingungen für die Erstattung von Fahrtkosten im Zusammenhang mit Remote-Arbeit.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">Frage: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">qa_chain&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">invoke&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;query&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">query&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;[Antwort]&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;result&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;[Referenzierte Informationsquellen]&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">doc&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;source_documents&amp;#39;&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;- Seite &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;page&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Unbekannt&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">page_content&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="erklärung-der-code-highlights">Erklärung der Code-Highlights
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>RecursiveCharacterTextSplitter&lt;/strong>:
Dies ist der am meisten empfohlene Splitter für das Teilen von natürlicher Sprache. Er versucht, den Text in der Reihenfolge Absatz (&lt;code>\n\n&lt;/code>), Zeile (&lt;code>\n&lt;/code>) und Punkt (&lt;code>。&lt;/code>) aufzuteilen, wobei semantische Gruppierungen so weit wie möglich beibehalten werden, um in die angegebene &lt;code>chunk_size&lt;/code> zu passen. Durch Einstellen von &lt;code>chunk_overlap&lt;/code> verhindern wir, dass Informationen verloren gehen, wenn Kontextgrenzen abgeschnitten werden.&lt;/li>
&lt;li>&lt;strong>HuggingFaceEmbeddings&lt;/strong>:
&lt;code>intfloat/multilingual-e5-large&lt;/code> ist ein sehr leistungsstarkes Open-Source-Einbettungsmodell, das mehrere Sprachen unterstützt. Es ermöglicht Ihnen, Text offline im lokalen Speicher zu vektorisieren, ohne eine Cloud-API (wie &lt;code>text-embedding-ada-002&lt;/code> von OpenAI) zu verwenden.&lt;/li>
&lt;li>&lt;strong>ChromaDB&lt;/strong>:
Da es im Arbeitsspeicher oder im lokalen Speicher (SQLite-basiert) läuft, ist es nicht notwendig, einen komplexen Datenbankserver einzurichten. Durch die Angabe von &lt;code>persist_directory&lt;/code> können Sie den Vektorisierungsprozess bei erneuter Ausführung überspringen und die DB von der Festplatte laden.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="5-fortgeschrittene-rag-techniken-advanced-rag-techniques">5. Fortgeschrittene RAG-Techniken (Advanced RAG Techniques)
&lt;/h1>&lt;p>Obwohl das Basis-RAG-System (Naive RAG), das wir im obigen Tutorial aufgebaut haben, funktioniert, erfordert der produktive Einsatz mit hohen Anforderungen an die Antwortgenauigkeit die Einführung fortgeschrittener Techniken wie den folgenden.&lt;/p>
&lt;h2 id="51-hybride-suche-hybrid-search">5.1 Hybride Suche (Hybrid Search)
&lt;/h2>&lt;p>Die Vektorsuche ist gut darin, &amp;ldquo;Bedeutung&amp;rdquo; zu erfassen, kann aber Schwierigkeiten mit strengen Stichwortsuchen haben, wie z.B. bei &amp;ldquo;bestimmten Eigennamen&amp;rdquo;, &amp;ldquo;Produktmodellnummern&amp;rdquo; oder &amp;ldquo;Mitarbeiter-IDs&amp;rdquo;.
Indem man eine &lt;strong>semantische Suche&lt;/strong> basierend auf der Vektorsuche parallel zu einer &lt;strong>Stichwortsuche&lt;/strong> unter Verwendung von Algorithmen wie BM25 durchführt und die Ergebnisse beider bewertet und integriert (unter Verwendung von Methoden wie Reciprocal Rank Fusion; RRF), können Suchauslassungen drastisch reduziert werden.&lt;/p>
&lt;h2 id="52-re-ranking-neubewertung">5.2 Re-ranking (Neubewertung)
&lt;/h2>&lt;p>Die Vektorsuche ist schnell, wertet aber nicht unbedingt die genaue kontextuelle Eignung des Kontexts aus. Eine gängige Pipeline zur Verbesserung der Suchgenauigkeit sieht wie folgt aus:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Initiale Suche (First-stage Retrieval)&lt;/strong>: Etwa 20 bis 30 relevante Chunks werden breit und flach aus der Vektor-DB abgerufen.&lt;/li>
&lt;li>&lt;strong>Neubewertung (Re-ranking)&lt;/strong>: Ein weiteres, schwereres maschinelles Lernmodell (z.B. &lt;code>bge-reranker&lt;/code>), das als Cross-Encoder bezeichnet wird, wird verwendet, um das Paar aus der Benutzeranfrage und dem abgerufenen Chunk einzugeben und den semantischen Eignungsscore neu zu berechnen.&lt;/li>
&lt;li>&lt;strong>Auswahl&lt;/strong>: Nur die Top 3 bis 5 mit den höchsten Scores werden an den LLM-Prompt als finaler Kontext weitergegeben.&lt;/li>
&lt;/ol>
&lt;p>Diese Methode verhindert, dass irrelevante Rauschinformationen an das LLM weitergegeben werden, und kann die Genauigkeit (Precision) der Antworten erheblich verbessern.&lt;/p>
&lt;div class="mermaid">graph LR
Query["Abfrage"] --> VSearch["Vektorsuche (Top 20)"]
VSearch --> Reranker["Re-ranker Modell (Cross-Encoder)"]
Query --> Reranker
Reranker --> TopK["Hochpräzise Top 3"]
TopK --> LLM["LLM Generierung"]&lt;/div>
&lt;h2 id="53-semantisches-chunking-und-parent-dokument-suche">5.3 Semantisches Chunking und Parent-Dokument-Suche
&lt;/h2>&lt;p>Es gibt eine Technik namens &amp;ldquo;Semantic Chunking&amp;rdquo;, bei der die KI Verschiebungen in der Bedeutung von Sätzen erkennt und den Text entsprechend aufteilt, anstatt den Text mechanisch nach einer festen Zeichenanzahl zu unterteilen.
Zusätzlich verwendet eine Methode, die als &amp;ldquo;Parent Document Retriever&amp;rdquo; bezeichnet wird, sehr kleine Einheiten (wie Sätze) für die Vektorisierung zu Suchzwecken, um eine hochpräzise Suche zu erreichen. Bei der Übergabe an das LLM wird der &amp;ldquo;ursprüngliche große Absatz (das Parent-Dokument)&amp;rdquo;, der diesen Satz enthält, weitergegeben und bietet dem LLM so ausreichend Kontext.&lt;/p>
&lt;hr>
&lt;h1 id="6-herausforderungen-und-lösungen-beim-betrieb-eines-lokalen-rag">6. Herausforderungen und Lösungen beim Betrieb eines lokalen RAG
&lt;/h1>&lt;p>Der Aufbau und Betrieb von RAG in einer lokalen Umgebung bringt spezifische Hürden mit sich.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Erschöpfung von VRAM (Videospeicher)&lt;/strong>:
Um ein lokales LLM mit einer praktischen Geschwindigkeit (Dutzende von Token pro Sekunde) laufen zu lassen, muss das Modell in den VRAM der GPU geladen werden. Ein Modell der 8B-Klasse benötigt bei fp16 (16-Bit-Gleitkomma) etwa 16 GB VRAM. Durch den Einsatz von &lt;strong>Quantisierungstechnologien&lt;/strong> (wie GGUF- oder AWQ-Formate, die auf 4-Bit oder 8-Bit komprimieren) ist es jedoch möglich, es auch mit 8 GB VRAM (wie z.B. in Standard-Gaming-PCs) ausreichend schnell laufen zu lassen. Llama.cpp und Ollama unterstützen diese Quantisierungsformate standardmäßig.&lt;/li>
&lt;li>&lt;strong>Limitierung des Kontextfensters&lt;/strong>:
Wenn die Menge des abgerufenen Kontexts zu groß ist, kann das Eingabelimit (Tokenlimit) des LLM überschritten werden, oder das Modell könnte Informationen im mittleren Teil vergessen (&amp;ldquo;Lost in the middle&amp;rdquo;-Phänomen). Eine Anpassung der Anzahl der extrahierten Chunks und eine sorgfältige Auswahl durch die oben genannten Re-ranking-Techniken sind unerlässlich.&lt;/li>
&lt;li>&lt;strong>Datenaktualitätsmanagement&lt;/strong>:
Wenn ein Quelldokument aktualisiert wird, müssen die Vektoren der entsprechenden Dokumente in der Vektordatenbank ebenfalls aktualisiert oder gelöscht werden (CRUD-Operationen). Da ChromaDB ID-basierte Dokumentenaktualisierungen unterstützt, ist es praktisch, Hash-Werte von Dateien zu verwalten und einen Batch-Prozess einzurichten, der nur die Unterschiede synchronisiert.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="zusammenfassung">Zusammenfassung
&lt;/h1>&lt;p>RAG (Retrieval-Augmented Generation) ist ein mächtiges Paradigma, das KI von einem allgemeinen Allzweck-Assistenten zu &amp;ldquo;Ihrem exklusiven Experten&amp;rdquo; oder &amp;ldquo;einem Experten für interne Abläufe&amp;rdquo; weiterentwickelt.&lt;/p>
&lt;p>Wir haben gesehen, dass es selbst bei hochsensiblen Anforderungen, bei denen Cloud-Dienste nicht genutzt werden können, durch die Kombination von Open-Source-Ökosystemen wie Ollama, LangChain und ChromaDB relativ einfach ist, eine vollständige &amp;ldquo;lokale RAG&amp;rdquo;-Umgebung aufzubauen.&lt;/p>
&lt;p>Bitte versuchen Sie, auf der Grundlage des in diesem Artikel erläuterten mathematischen Verständnisses des Vektorraums und fortgeschrittener Ansätze wie Textaufteilung und Re-ranking ein originelles KI-System mit Ihren eigenen Daten zu entwickeln. Die Entwicklungsgeschwindigkeit von lokalen KIs ist erstaunlich, und das heute aufgebaute System kann sofort in der Leistung verbessert werden, indem es einfach durch ein intelligenteres, leichteres Modell ersetzt wird, das morgen erscheint.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Wir werden auf diesem Blog weiterhin vertiefende Artikel zu KI-Technologien und RAG veröffentlichen. Wenn Sie Fragen oder Feedback haben, hinterlassen Sie diese bitte im Kommentarbereich.&lt;/em>&lt;/p></description></item></channel></rss>