Startseite / Artikel / Praktische Hinweise: Erstellung einer Produktionsreifen lokalen RAG-Pipeline – 100% kostenlos, ohne

Praktische Hinweise: Erstellung einer Produktionsreifen lokalen RAG-Pipeline – 100% kostenlos, ohne

Schritt-für-Schritt-Anleitung zu den Praktischen Hinweisen: Erstellung einer Produktionsreifen lokalen RAG-Pipeline – 100% kostenlos, ohne Verträge, Überprüfungen sowie Code-Blöcke für Teams, die dieses Muster einsetzen.

4700 Wörter

Dieser Leitfaden zeigt Schritt für Schritt den Weg von Rohstoffen bis zu einem funktionsfähigen System für: Den Aufbau einer Produktionsreifen lokalen RAG-Pipeline – zu 100 % kostenlos, ohne Cloud erforderlich. Der Schwerpunkt liegt auf ausführbaren Schritten, expliziten Überprüfungen sowie Code, den man ohne Rätseln über die Absicht direkt in ein Repository einfügen kann. In der Übersichtsphase sollten Eingaben, Verantwortliche für die Schritte sowie Abbruchkriterien definiert werden, bevor Code geändert wird. Die Betreiber sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Notfallweg gemeinsam. Wiederholversuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.

Warum das wichtig ist

Beim Bearbeiten der Phase „Warum ist das wichtig?“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikator sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Messen Sie die Erinnerungskraft anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Abrufverhalten.

Der vollständige Technologiestack

Beim Bearbeiten der Phase „The Complete Tech Stack“ sollten Sie zunächst einen Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Erzeugnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Ergebnisse ab. Messen Sie die Genauigkeit anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Suchverhalten.

Voraussetzungen

Während der Voraussetzungsphase sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgszeichen sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Weg von einer Demo in gemeinsame Umgebungen wechselt. Messen Sie die Trefferquote anhand eines festgelegten Fragebogens, bevor Sie die Anfragenanweisungen anpassen. Häufige Änderungen der Anfragenanweisungen beheben selten ein schwaches Suchverhalten. Während der Voraussetzungsphase sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgszeichen sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholte Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen.

Teil 1 – Umgebungs einrichten

Die Phase „Umgebungs-Einrichtung“ in Teil 1 funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein gelungenes Beispiel, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Ziehen Sie kleine, testbare Einheiten vor umfangreichen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Trennen Sie die Aufteilungspolitik von der Abrufpolitik. Ein Änderungsbedarf bei einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

Schritt 1: Projekt erstellen

Schritt 1: Die Erstellung der Plattform funktioniert am besten, wenn sie als messbare Oberfläche betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein erfolgreiches Beispiel, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Ergebnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Trennen Sie die Aufteilungspolitik von der Abrufpolitik. Eine Änderung sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

mkdir local-rag
cd local-rag
uv init

Schritt 2: Erstellen und aktivieren Sie die virtuelle Umgebung

Schritt 2 „Erstellen und bereitstellen“ funktioniert am besten, wenn er als messbarer Bereich betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes Transkript“, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Erhalten Sie neben den funktionalen Ergebnissen auch Aufzeichnungen zu Zeiten sowie Kosten für Tokens oder Abfragen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Prozess von einer Demo in gemeinsam genutzte Umgebungen übergeht. Trennen Sie die Strategie zur Aufteilung in Blöcke von der Strategie zum Abrufen. Ein Änderungsbedarf bei einer dieser Strategien sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

uv venv
.venv\Scripts\activate

Schritt 2 „Erstellen und bereitstellen“ funktioniert am besten, wenn er als messbarer Bereich betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes Transkript“, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholungsversuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.

Schritt 3: Alle Abhängigkeiten installieren

Zur Schritt-3-Phase „Installiere alle Stufen“ sollten vor der Codeänderung die Eingabedaten, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckten Zuständen schließen zu müssen. Vorzuziehen sind kleine, testbare Einheiten statt umfangreicher Skripte. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Pipeline-System. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.

uv add google-genai pypdf chromadb rich python-dotenv huggingface_hub fpdf2

Schritt 4: Erstelle die Projektstruktur

Zur Schritt 4 „Bühne erstellen“ sollten vor der Codeänderung die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Zitieren Sie die Passagen, die tatsächlich die Antwort begründen. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.

mkdir pdfs
mkdir pdfs\versions
type nul > local_rag.ipynb
type nul > .env
type nul > .gitignore
local-rag/
├── .venv/                    ← virtual environment (never commit)
├── pdfs/                     ← drop your PDFs here
│   └── versions/             ← test PDFs for CDC testing
├── chroma_db/                ← auto-created on first ingest
├── memory_checkpoints/       ← auto-created on first memory session
├── staleness_registry.json   ← auto-created
├── chunk_registry.json       ← auto-created
├── local_rag.ipynb           ← your notebook
├── .env                      ← API keys (never commit)
├── .gitignore
└── pyproject.toml

Schritt 5: API-Schlüssel konfigurieren

In der Phase „Schritt 5: API konfigurieren“ sollten die Eingabedaten, der Verantwortliche für diesen Schritt sowie die Abbruchkriterien vor dem Codeändern definiert werden. Die Betreiber sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Erhalten Sie neben den funktionalen Ergebnissen auch Aufzeichnungen der Laufzeiten sowie der Kosten für Token oder Abfragen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Prozess von einer Demo-Umgebung in eine gemeinsam genutzte Umgebung übergeht. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können die Betreiber nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden. In der Phase „Schritt 5: API konfigurieren“ sollten die Eingabedaten, der Verantwortliche für diesen Schritt sowie die Abbruchkriterien vor dem Codeändern definiert werden. Die Betreiber sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch die Notfallbehandlung gemeinsam. Wiederholungsversuche, menschliche Überprüfungen sowie die Handhabung fehlgeschlagener Nachrichten gehören zum Produkt selbst und nicht zu späteren Optimierungen.

GEMINI_API_KEY=your_gemini_key_here
HF_API_KEY=your_huggingface_token_here
.env
chroma_db/
memory_checkpoints/
staleness_registry.json
chunk_registry.json
__pycache__/
.venv/
*.pyc

Schritt 6: VS Code einrichten

Beim Bearbeiten des Schritts 6 „Einrichten“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Wählen Sie lieber kleine, testbare Einheiten statt umfangreicher Skripte. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Messen Sie die Genauigkeit anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Abrufverhalten.

Ctrl+Shift+P → Python: Select Interpreter → .venv\Scripts\python.exe

Teil 2 – Detaillierte Erklärung des Kern-Ablaufs

Beim Arbeiten an der Stufe „Part 2 Core Pipeline“ sollten Sie zunächst einen Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Stufe als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Erzeugnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab. Messen Sie die Trefferquote anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Suchverhalten.

Zelle 1 – Abhängigkeiten (innerhalb des Notebooks)

Beim Arbeiten an den Abhängigkeiten von Zelle 1 innerhalb der Phase sollte man zunächst einen Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie die Laufzeiten sowie die Kosten für Token oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Weg von einer Demo-Umgebung in gemeinsam genutzte Umgebungen wechselt. Messen Sie die Trefferquote anhand einer festgelegten Fragestellung, bevor Sie die Anfragenanweisungen anpassen. Häufige Änderungen der Anfragenanweisungen beheben selten ein schwaches Suchverhalten.

# Run once inside the notebook if uv add was not used externally
# %pip install google-genai pypdf chromadb rich python-dotenv huggingface_hub fpdf2

Beim Arbeiten an den Abhängigkeiten von Zelle 1 innerhalb der Phase sollte man zunächst einen Vertrag aufschreiben: erforderliche Eingaben, Erfolgssignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie gleichzeitig den erfolgreichen Ablauf und den Notfallweg. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.

Zelle 2 – Konfiguration

Die Phase der Zelle 2-Konfiguration funktioniert am besten, wenn sie als messbare Oberfläche betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie die Notizen zum Rollback, bevor Sie den Umfang erweitern. Ziehen Sie kleine, testbare Einheiten vor umfangreichen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Trennen Sie die Aufteilungspolitik von der Abrufpolitik. Ein Änderungs an einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

import os
from dotenv import load_dotenv

load_dotenv()
GEMINI_API_KEY     = os.environ.get("GEMINI_API_KEY", "")
EMBED_DIM          = 768
HF_API_KEY         = os.environ.get("HF_API_KEY", "")
GEMINI_EMBED_MODEL = "gemini-embedding-001"
HF_LLM_MODEL       = "openai/gpt-oss-20b:groq"
CHROMA_DB_PATH     = "./chroma_db"
COLLECTION_NAME    = "local_rag"
CHUNK_SIZE         = 800
CHUNK_OVERLAP      = 120
TOP_K              = 5
EMBED_BATCH_SIZE   = 50
BATCH_SLEEP_SEC    = 0.3
LLM_MAX_NEW_TOKENS = 1024
LLM_TEMPERATURE    = 0.1
assert GEMINI_API_KEY, "❌ GEMINI_API_KEY not set"
assert HF_API_KEY,     "❌ HF_API_KEY not set"

Zelle 3 – PDF-Textextraktion

Die Phase „Cell 3 PDF Text“ funktioniert am besten, wenn sie als messbare Oberfläche betrachtet wird. Erfassen Sie einen erfolgreichen Transkriptbeispiel, einen Fehlerfall sowie die Notizen zur Rücksetzung, bevor Sie den Umfang erweitern. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Erzeugnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Trennen Sie die Strategie zur Aufteilung in Blöcke von der Strategie zum Abrufen. Ein Änderungs an einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

from pypdf import PdfReader

def extract_text_from_pdf(pdf_path: str) -> tuple[str, int]:
    reader = PdfReader(pdf_path)
    pages = []
    for i, page in enumerate(reader.pages):
        text = page.extract_text()
        if text and text.strip():
            pages.append(f"[Page {i + 1}]\n{text.strip()}")
    return "\n\n".join(pages), len(reader.pages)

Cell 4 – Schiebelfenster-Blöckung

Die Cell 4 Sliding Window-Ebene funktioniert am besten, wenn sie als messbare Oberfläche betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Erhalten Sie neben den funktionalen Ergebnissen auch Aufzeichnungen zu Zeiten sowie Kosten für Tokens oder Abfragen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn sich der Weg von einer Demo in gemeinsame Umgebungen verschiebt. Trennen Sie die Chunking-Strategie von der Abrufstrategie. Ein Änderung in einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

def chunk_text(text: str) -> list[str]:
    chunks, start = [], 0
    while start < len(text):
        end   = start + CHUNK_SIZE
        chunk = text[start:end].strip()
        if len(chunk) >= 80:
            chunks.append(chunk)
        start += CHUNK_SIZE - CHUNK_OVERLAP
    return chunks

Die Cell 4 Sliding Window-Ebene funktioniert am besten, wenn sie als messbare Oberfläche betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Wiederherstellungsprozess. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.

Cell 5 — Gemini Embeddings

Zur Phase der Cell 5 Gemini Embeddings muss man vor dem Ändern des Codes die Eingaben, den Verantwortlichen für den Schritt sowie die Abbruchkriterien definieren. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Man sollte kleine, testbare Einheiten vor umfangreichen Skripten bevorzugen. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Pipeline-System. Trennen Sie den Aufbau des Clients von der Nachrichtenschleife, damit Provider ausgetauscht werden können, ohne die Zustandsmaschine des Gesprächs umschreiben zu müssen.

from google import genai
from google.genai import types

genai_client = genai.Client(api_key=GEMINI_API_KEY)
def embed_documents_batch(chunks: list[str]) -> list[list[float]]:
    all_embeddings = []
    for i, chunk in enumerate(chunks, 1):
        result = genai_client.models.embed_content(
            model=GEMINI_EMBED_MODEL,
            contents=chunk,
            config=types.EmbedContentConfig(
                task_type="RETRIEVAL_DOCUMENT",
                output_dimensionality=EMBED_DIM,
            ),
        )
        all_embeddings.append(result.embeddings[0].values)
    return all_embeddings
def embed_query(text: str) -> list[float]:
    result = genai_client.models.embed_content(
        model=GEMINI_EMBED_MODEL,
        contents=text,
        config=types.EmbedContentConfig(
            task_type="RETRIEVAL_QUERY",
            output_dimensionality=EMBED_DIM,
        ),
    )
    return result.embeddings[0].values

Cell 6 — ChromaDB Speicherung und Abruf

Für die Cell 6 ChromaDB-Speicherebene sollten vor der Codeänderung Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckten Zuständen schließen zu müssen. Betrachten Sie diese Ebene als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Zitieren Sie die Passagen, die tatsächlich die Antwort begründen. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken bei der Indizierung unterscheiden.

import uuid, chromadb

def get_collection():
    client = chromadb.PersistentClient(path=CHROMA_DB_PATH)
    return client.get_or_create_collection(
        name=COLLECTION_NAME,
        metadata={"hnsw:space": "cosine"},
    )
def store_in_chroma(chunks, embeddings, doc_name):
    collection = get_collection()
    ids        = [str(uuid.uuid4()) for _ in chunks]
    metadatas  = [{"source": doc_name, "chunk_index": i}
                  for i in range(len(chunks))]
    collection.add(ids=ids, embeddings=embeddings,
                   documents=chunks, metadatas=metadatas)
    return len(chunks)
def retrieve_context(query: str) -> list[dict]:
    collection      = get_collection()
    query_embedding = embed_query(query)
    results = collection.query(
        query_embeddings=[query_embedding],
        n_results=TOP_K,
        include=["documents", "metadatas", "distances"],
    )
    chunks = []
    for doc, meta, dist in zip(results["documents"][0],
                               results["metadatas"][0],
                               results["distances"][0]):
        chunks.append({
            "text":        doc,
            "source":      meta.get("source", "unknown"),
            "chunk_index": meta.get("chunk_index", -1),
            "score":       round(1 - dist, 4),
        })
    return sorted(chunks, key=lambda x: x["score"], reverse=True)

Cell 7 – Durchführung der Eingabeverarbeitung

Für die Phase der Eingabenerfassung in Zelle 7 sollten vor dem Ändern des Codes die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Erfassen Sie die Laufzeiten sowie die Kosten für Tokens oder Abfragen zusammen mit den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Weg von Demonstrumgebungen in gemeinsam genutzte Umgebungen wechselt. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.

PDF_PATH = "./pdfs/attention.pdf"

raw_text, page_count = extract_text_from_pdf(PDF_PATH)
chunks               = chunk_text(raw_text)
embeddings           = embed_documents_batch(chunks)
stored               = store_in_chroma(chunks, embeddings,
                                        os.path.basename(PDF_PATH))

Für die Phase der laufenden Eingabe in Zelle 7 sollten vor dem Ändern des Codes die Eingabedaten, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholungsversuche, menschliche Überprüfungen und die Handhabung von Fehlnachrichten gehören zum Produkt selbst, nicht zu späteren Optimierungen.

Zelle 8 — LLM: gpt-oss-20b über HuggingFace

Beim Arbeiten an der Cell 8 LLM gpt-oss-20b-Stufe sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Cachen Sie stabile Systemanweisungen sowie Tool-Schemata. Das erneute Senden identischer Vorlagen ist eine häufige Ursache für Ressourcenverschwendung.

from huggingface_hub import InferenceClient

hf_client = InferenceClient(api_key=HF_API_KEY)
def build_messages(query: str, context_chunks: list[dict]) -> list[dict]:
    context_str  = "\n\n---\n\n".join([
        f"[Source: {c['source']} | Chunk #{c['chunk_index']} | "
        f"Relevance: {c['score']}]\n{c['text']}"
        for c in context_chunks
    ])
    return [
        {"role": "system",  "content": SYSTEM_MSG},
        {"role": "user",    "content":
            f"CONTEXT:\n{context_str}\n\nQUESTION:\n{query}"},
    ]
def generate_answer(messages: list[dict]) -> str:
    completion = hf_client.chat.completions.create(
        model=HF_LLM_MODEL,
        messages=messages,
        max_tokens=LLM_MAX_NEW_TOKENS,
        temperature=LLM_TEMPERATURE,
    )
    return completion.choices[0].message.content.strip()

Cell 9–11 — Der ask() Ablauf und REPL

Beim Arbeiten an der Phase „Zelle 9–11“ sollten Sie zunächst einen Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Ergebnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab. Messen Sie die Erinnerungsfähigkeit anhand eines festgelegten Fragebogens, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Abrufverhalten.

query → embed_query() → ChromaDB cosine search → top-5 chunks
      → build_messages() → generate_answer() → printed answer
1. attention.pdf chunk #34  [██████████████████████░░░░░░░░]  0.7335

Teil 3 – Gesprächsmerkmal

Beim Bearbeiten der Phase „Konversationsgedächtnis – Teil 3“ sollten Sie zunächst den Vertrag aufschreiben: die erforderlichen Eingaben, das Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie neben den funktionalen Ergebnissen außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Einsatzbereich von einer Demo-Umgebung in gemeinsam genutzte Umgebungen wechselt. Messen Sie die Wiedererkennungsfähigkeit anhand eines festgelegten Fragebogens, bevor Sie die Anfragen anpassen. Häufige Änderungen der Anfragen beheben selten ein schwaches Abrufverhalten.

Das Problem

Während der Problemanalyse sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt sein, den Betreiber ohne das Durchlesen des gesamten Systems überprüfen können. Messen Sie die Trefferquote anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Suchverhalten.

Die Lösung: ConversationMemory

Beim Arbeiten an der Konversationsgedächtnis-Phase schreiben Sie zunächst den Vertrag auf: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Wiederherstellungsprozess. Wiederholte Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen. Messen Sie die Erinnerungsfähigkeit anhand eines festgelegten Fragebogens, bevor Sie die Anfragenanweisungen anpassen – eine häufige Änderung dieser Anweisungen behebt selten ein schwaches Abrufverhalten.

class ConversationMemory:
    def __init__(self, session_id: str = None):
        self.session_id = session_id or datetime.now().strftime("%Y%m%d_%H%M%S")
        self.filepath   = os.path.join(MEMORY_DIR, f"{self.session_id}.json")
        self.history    = []
        # Auto-loads if resuming an existing session
        if os.path.exists(self.filepath):
            self._load()

    def add_turn(self, question: str, answer: str, chunks: list[dict]):
        # Append user + assistant turns, checkpoint immediately
        ...
        self._save()
    def get_messages_with_history(self, query, context_chunks, system_msg):
        # Injects last 6 Q&A pairs into the message list before the current turn
        ...
# New session
memory = ConversationMemory()

# Resume yesterday's session
memory = ConversationMemory("20260413_104959")
Turn 4 question: "How does that compare to what you said about the BLEU score?"
Turn 4 answer: "The context also reports a BLEU score of 28.4 for the
               Transformer (big) on WMT 2014 English-to-German. This matches
               exactly what I previously stated."

Teil 4 – Verfallszeitverfolgung, CDC und Aktualitätsgewichtung

Beim Arbeiten an der Phase „Staleness Tracking“ in Teil 4 sollten Sie zunächst den Vertrag aufschreiben: die erforderlichen Eingaben, das Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Messen Sie die Trefferquote anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Suchsystem.

Das Problem in der Praxis

Während der Phase „Reales Problem“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikator sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Ergebnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab. Messen Sie die Genauigkeit anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Suchverhalten.

Ablaufzeitverfolgung (Zelle 14A)

Beim Arbeiten an der Stufe „Staleness Tracking Cell 14A“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie die Laufzeiten sowie die Kosten für Tokens oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Weg von einer Demo-Umgebung in gemeinsam genutzte Umgebungen wechselt. Messen Sie die Trefferquote anhand einer festgelegten Fragestellung, bevor Sie die Anfragenanweisungen anpassen. Häufige Änderungen der Anfragenanweisungen beheben selten ein schwaches Suchsystem. Beim Arbeiten an der Stufe „Staleness Tracking Cell 14A“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgssignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholte Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen.

def compute_file_hash(pdf_path: str) -> str:
    sha = hashlib.sha256()
    with open(pdf_path, "rb") as f:
        for block in iter(lambda: f.read(65536), b""):
            sha.update(block)
    return sha.hexdigest()

CDC Engine (Cell 14B)

Die CDC Engine Cell 14B-Ebene funktioniert am besten, wenn sie als messbare Oberfläche betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie die Rollback-Anmerkung, bevor Sie den Umfang erweitern. Ziehen Sie kleine, testbare Einheiten vor umfangreichen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Trennen Sie die Chunking-Strategie von der Abrufstrategie – ein Änderung in einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

def compute_chunk_hash(text: str) -> str:
    return hashlib.md5(text.encode("utf-8")).hexdigest()

def diff_chunks(old_registry: dict, new_chunks: list[str]) -> dict:
    new_hash_map = {compute_chunk_hash(c): c for c in new_chunks}
    old_hashes   = set(old_registry.keys())
    new_hashes   = set(new_hash_map.keys())
    return {
        "added":     {h: new_hash_map[h] for h in (new_hashes - old_hashes)},
        "removed":   {h: old_registry[h] for h in (old_hashes - new_hashes)},
        "unchanged": {h: old_registry[h] for h in (old_hashes & new_hashes)},
    }
v1 → v2 CDC result:
  ✅ Unchanged : 8   (kept — zero re-embedding cost)
  ➕ Added     : 6   (embedded + inserted)
  ➖ Removed   : 4   (deleted from ChromaDB)
  💰 API calls saved: 8/14 (57% reuse)

v2 → v3 CDC result:
  ✅ Unchanged : 10  (kept - zero re-embedding cost)
  ➕ Added     : 4   (embedded + inserted)
  ➖ Removed   : 2   (deleted from ChromaDB)
  💰 API calls saved: 10/14 (71% reuse)

Jüngstkeitsgewichteter Abruf (Cell 14C)

Die Recency-Weighted Retrieval Cell 14C-Stufe funktioniert am besten, wenn sie als messbare Oberfläche betrachtet wird. Erfassen Sie ein gelungenes Beispiel, einen Fehlfall sowie die Rollback-Anmerkung, bevor Sie den Umfang erweitern. Betrachten Sie diese Stufe als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Trennen Sie die Chunking-Strategie von der Retrieval-Strategie. Ein Änderung in einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

def recency_decay(ingested_at_str: str, half_life_days: float = 30) -> float:
    ingested  = datetime.fromisoformat(ingested_at_str)
    days_gone = (datetime.now() - ingested).total_seconds() / 86400
    λ         = math.log(2) / half_life_days
    return round(math.exp(-λ * days_gone), 4)
blended = alpha * cosine_score + (1 - alpha) * recency_score
# Default: 0.85 * cosine + 0.15 * recency

Teil 5 – Testing mit Mehrfachversionen von PDFs

Der Part 5 Testing with Stage funktioniert am besten, wenn er als messbare Ebene betrachtet wird. Erfassen Sie vor Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Erfassen Sie außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn sich der Prozess von einer Demo in gemeinsame Umgebungen verschiebt. Trennen Sie die Strategie zur Aufteilung in Blöcke von der Strategie zur Abrufung. Ein Änderungsbedarf bei einer dieser Strategien sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern. Der Part 5 Testing with Stage funktioniert am besten, wenn er als messbare Ebene betrachtet wird. Erfassen Sie vor Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Dokumentieren Sie den erfolgreichen Ablauf sowie den Wiederherstellungsprozess gemeinsam. Wiederholversuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.

TEST 1: Full ingest of v1
TEST 2: Staleness check — same file, correctly skipped
TEST 3: Baseline queries against v1
TEST 4: Copy v2 over active file → CDC kicks in
TEST 5: Same queries now return v2 content, newer chunks visible in recency scores
TEST 6: Copy v3 over active file → second CDC cycle
TEST 7: Recency verification — v3 chunks score highest across the board
TEST 8: Full stack test — weighted retrieval + conversation memory combined

Ergebnisse und überprüfte Antworten

In der Phase „Ergebnisse und überprüfte Antworten“ sollten Eingabedaten, Verantwortliche für die jeweiligen Schritte sowie Abbruchkriterien definiert werden, bevor der Code geändert wird. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Es ist besser, kleine, testbare Einheiten statt umfangreicher Skripte zu verwenden. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortungsbereich verweisen und nicht auf ein verworrenes Ablaufschema. Zitieren Sie die Passagen, die tatsächlich die Grundlage für die Antwort bilden. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.

Zusammenfassung der Effizienz

In der Phase des Effizienzüberblicks sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden, bevor der Code geändert wird. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Zitieren Sie die Passagen, die tatsächlich die Antwort begründen. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.

Bekannte Einschränkungen

In der Phase der bekannten Einschränkungen sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Codeändern definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Erhalten Sie neben den funktionalen Ergebnissen auch Aufzeichnungen der Laufzeiten sowie der Kosten für Token oder Abfragen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Prozess von einer Demo-Umgebung in eine gemeinsam genutzte Umgebung übergeht. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden. In der Phase der bekannten Einschränkungen sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Codeändern definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Notfallweg gemeinsam. Wiederholungsversuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.

Was Sie bereits erstellt haben

Während der Phase „Was Sie bereits erstellt haben“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikator sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Messen Sie die Trefferquote anhand einer festgelegten Fragestellung, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Suchsystem.

PDF on disk
 └► SHA256 hash check (staleness)
      ├► Unchanged → skip
      └► Changed → CDC diff
           ├► Unchanged chunks → kept in ChromaDB (zero API cost)
           ├► Removed chunks → deleted from ChromaDB
           └► Added chunks → embed (Gemini) → store (ChromaDB)
                                                    ↓
User question
 └► embed_query() [RETRIEVAL_QUERY task type]
      └► ChromaDB cosine search (TOP_K × 3 candidates)
           └► recency_decay() per chunk
                └► blended score re-ranking
                     └► top-5 chunks as context
                          └► ConversationMemory.get_messages_with_history()
                               └► gpt-oss-20b via Groq/HuggingFace
                                    └► grounded answer + checkpoint to disk

Betriebscheckliste

Die Phase der Betriebscheckliste funktioniert am besten, wenn sie als messbarer Aspekt betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein perfektes Beispiel, einen Fehlfall sowie eine Notiz zur Rücksetzung.

Halten Sie die Konfiguration außerhalb des Anwendungscode. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt sein, den Betreiber überprüfen können, ohne den gesamten Ablauf durchlesen zu müssen.

Trennen Sie die Chunking-Strategie von der Abrufstrategie. Ein Änderung in einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

Fügen Sie so oft wie möglich, solange das Budget es zulässt, einen Smoke-Test hinzu, der den kritischen Pfad in CI mit Fixtures und nicht mit live genutzten, bezahlten APIs testet.

Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Wiederherstellungsprozess gemeinsam. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.

Trennen Sie die Chunking-Strategie von der Abrufstrategie. Ein Änderung in einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

Vor der Veröffentlichung des Stacks sollten Versionen eingefroren werden, ein „goldener“ Transkript für den kritischen Pfad erstellt und die Rollback-Schritte bestätigt werden. Gemeinsam genutzte Umgebungen benötigen Rate Limits, Überprüfungen der Nutzerzuordnung sowie einen klaren Verantwortlichen für die Rotation von Geheimnissen. Man sollte langweilige Zuverlässigkeit vor cleveren, einmaligen Demonstrationen bevorzugen.

Batch-Hinweis für 8d172e929623: Halten Sie die Anbieter-Schlüssel außerhalb des Repositories, legen Sie eine Obergrenze für Tokens pro Sitzung fest und speichern Sie die Transkripte neben den Evaluierungs-Fixtures, damit spätere Modellwechsel vergleichbar bleiben.