Skip to content
BotServBotServ
WissensdatenbankRAGSemantische SucheQ&ADokumente

Wissensdatenbank aus Dokumenten

Wissensdatenbank aus Dokumenten aufbauen. RAG, semantische Suche, Q&A-System und Praxisbeispiele.

S

schutzgeist

4 min read
Wissensdatenbank aus Dokumenten

Wissensdatenbank aus Dokumenten

Was dieser Artikel über Wissensdatenbanken behandelt

  • Wie Du eine Wissensdatenbank aus Deinen Dokumenten baust.
  • Wie RAG, Embeddings und semantische Suche funktionieren.
  • Wie Du Fragen an Deine Dokumente stellst.
  • Praxisbeispiele für interne Wikis, FAQ-Systeme und Support.
  • Best Practices für Qualität, Performance und Wartung.

Einleitung: Wissensdatenbank verständlich erklärt

Eine Wissensdatenbank macht Deine Dokumente durchsuchbar und beantwortbar. Statt in Ordnern zu suchen, fragst Du: „Wie funktioniert der Urlaubsantrag?” und das System findet das richtige Dokument und gibt eine Antwort mit Quellenangabe.

Dieser Artikel richtet sich an Anwender, die eine Dokumenten-Wissensdatenbank aufbauen wollen. Grundlagen findest Du in Lokales RAG und Dokumentenanalyse.

Warum brauche ich eine Wissensdatenbank?

Stell Dir vor, Du hast 500 Dokumente: Anleitungen, Verträge, Berichte. Statt alle zu durchsuchen, fragst Du das System: „Was steht im Vertrag über Kündigung?” und bekommst die Antwort mit Quellenangabe. Das ist RAG: Retrieval-Augmented Generation.

Wissensdatenbank kurz erklärt

Dokumente → Chunks → Embeddings → Vektordatenbank. Bei Frage: Embedding → ähnliche Chunks → Kontext → LLM → Antwort mit Quellen. Alles lokal mit Ollama + Qdrant.

Der Kerngedanke lautet: Erst suchen, dann antworten.

Für wen ist dieser Artikel gedacht?

  • Wissensmanager, die Dokumente durchsuchbar machen.
  • Support-Teams, die FAQ automatisieren.
  • Unternehmen, die internes Wissen zugänglich machen.
  • Entwickler, die Q&A-Systeme bauen.

Wichtige Begriffe

  • RAG - Retrieval-Augmented Generation. Wann nützlich: das Konzept.
  • Embeddings - Text zu Vektor. Wann nützlich: für Suche.
  • Vektordatenbank - Speicher. Wann nützlich: für Embeddings.
  • Chunking - Text teilen. Wann nützlich: für bessere Suche.
  • Ollama - Modellserver. Wann nützlich: für Embeddings + LLM.

Architektur

INDEXING:
Dokumente (PDF/Word/Text)
    │
    ▼
Text extrahieren → Chunking (500-800 Zeichen)
    │
    ▼
Embeddings (Ollama: multilingual-e5)
    │
    ▼
Vektordatenbank (Qdrant/ChromaDB)

QUERY:
Frage
    │
    ▼
Embedding → Vektorsuche → Top-K Chunks
    │
    ▼
Kontext + Frage → LLM (Ollama: llama3.1)
    │
    ▼
Antwort + Quellenangaben

Setup: Qdrant + Ollama

version: "3.8"

services:
  qdrant:
    image: qdrant/qdrant:latest
    ports:
      - "6333:6333"
    volumes:
      - qdrant_data:/qdrant/storage

  ollama:
    image: ollama/ollama:latest
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama

volumes:
  qdrant_data:
  ollama_data:
# Embedding-Modell laden
ollama pull multilingual-e5

# LLM laden
ollama pull llama3.1

Praxisbeispiel: Wissensdatenbank

import chromadb
import requests
import uuid

class KnowledgeBase:
    def __init__(self):
        self.chroma = chromadb.HttpClient(host="chromadb", port=8000)
        self.collection = self.chroma.get_or_create_collection("wissen")

    def get_embedding(self, text):
        response = requests.post("http://ollama:11434/api/embeddings", json={
            "model": "multilingual-e5",
            "prompt": text
        })
        return response.json()["embedding"]

    def add_document(self, text, source, metadata=None):
        """Dokument indexieren"""
        chunks = self.chunk_text(text, 500)
        for i, chunk in enumerate(chunks):
            embedding = self.get_embedding(chunk)
            self.collection.add(
                ids=[f"{source}_{i}"],
                documents=[chunk],
                embeddings=[embedding],
                metadatas=[{
                    "source": source,
                    "chunk": i,
                    **(metadata or {})
                }]
            )

    def ask(self, question):
        """Frage an die Wissensdatenbank"""
        # Ähnliche Chunks suchen
        query_embedding = self.get_embedding(question)
        results = self.collection.query(
            query_embeddings=[query_embedding],
            n_results=5
        )

        context = "\n\n".join(results["documents"][0])
        sources = [m["source"] for m in results["metadatas"][0]]

        # Antwort generieren
        response = requests.post("http://ollama:11434/api/chat", json={
            "model": "llama3.1",
            "messages": [
                {"role": "system", "content": "Beantworte die Frage basierend auf dem Kontext. Gib Quellen an. Wenn der Kontext nicht reicht, sage das ehrlich."},
                {"role": "user", "content": f"Kontext:\n{context}\n\nFrage: {question}"}
            ],
            "stream": False
        })

        return {
            "answer": response.json()["message"]["content"],
            "sources": list(set(sources))
        }

# Nutzung
kb = KnowledgeBase()
kb.add_document("Urlaubsantrag: Formular HR-2024 ausfüllen...", "urlaub.pdf")
result = kb.ask("Wie beantrage ich Urlaub?")
print(result["answer"])
print(f"Quellen: {result['sources']}")

Praxisbeispiel: Dokumente aus Ordner indexieren

import os
from pathlib import Path

def index_folder(kb, folder):
    """Alle Dokumente in einem Ordner indexieren"""
    for filepath in Path(folder).rglob("*.txt"):
        with open(filepath) as f:
            text = f.read()
        kb.add_document(text, filepath.name)
        print(f"Indexiert: {filepath.name}")

# Alle .txt Dateien indexieren
index_folder(kb, "./dokumente/")

Qualität verbessern

Reranking

def rerank_chunks(question, chunks, top_k=3):
    """Chunks nach Relevanz neu sortieren"""
    scores = []
    for chunk in chunks:
        response = requests.post("http://ollama:11434/api/chat", json={
            "model": "llama3.1",
            "messages": [
                {"role": "user", "content": f"Bewerte die Relevanz dieses Textes für die Frage '{question}' auf einer Skala 0-10. Nur Zahl.\n\nText: {chunk}"}
            ],
            "stream": False
        })
        score = float(response.json()["message"]["content"].strip())
        scores.append((score, chunk))

    scores.sort(reverse=True)
    return [c for s, c in scores[:top_k]]

Quellenangaben

def format_answer(result):
    """Antwort mit Quellen formatieren"""
    answer = result["answer"]
    sources = result["sources"]

    formatted = f"{answer}\n\n---\nQuellen:\n"
    for s in sources:
        formatted += f"- {s}\n"
    return formatted

Sicherheitshinweise

  • Zugriffskontrolle: Wer darf welche Dokumente abfragen? Filtere nach Berechtigungen.
  • Prompt Injection: Dokumente können Injections enthalten. Siehe Prompt Injection.
  • Datenqualität: Schlechte Dokumente = schlechte Antworten. Siehe Dokumente vorbereiten.
  • Datenschutz: Alle Daten bleiben lokal. Siehe Datenschutz.

Typische Stolpersteine

  • Chunks zu groß: Über 1000 Zeichen verlieren Präzision. 300-800 ist optimal.
  • Zu wenige Chunks: Top-5 reicht nicht immer. Hole Top-20, reranke auf Top-5.
  • Falsches Embedding-Modell: Für Deutsch: multilingual-e5 oder bge-m3.
  • Keine Quellen: Ohne Quellen ist die Antwort nicht überprüfbar.
  • Halluzinationen: Ohne gutes Retrieval halluziniert das Modell.

Key Takeaways:

  • Wissensdatenbank: Dokumente → Embeddings → Vektordatenbank → Q&A.
  • multilingual-e5 für deutsche Dokumente.
  • Chunking-Strategie und Reranking entscheiden über Qualität.
  • Immer Quellenangaben, nie blind vertrauen.
  • Lokal mit Ollama + Qdrant: alle Daten bleiben privat.

FAQ

Was ist eine Wissensdatenbank?

Ein System, das Dokumente durchsuchbar und beantwortbar macht. Du fragst, das System findet relevante Dokumente und antwortet mit Quellenangabe.

Wie baue ich eine Wissensdatenbank?

Dokumente → Text extrahieren → Chunking → Embeddings → Vektordatenbank. Bei Fragen: Embedding → Suche → Kontext → LLM → Antwort.

Welches Embedding-Modell für Deutsch?

multilingual-e5 oder bge-m3. Beide unterstützen Deutsch sehr gut. nomic-embed-text ist nur für Englisch optimiert.

Wie groß sollten Chunks sein?

300-800 Zeichen mit 50-100 Zeichen Overlap. Zu kleine Chunks verlieren Kontext, zu große verlieren Präzision.

Wie verhindere ich Halluzinationen?

Gutes Retrieval (richtige Chunks), klare System-Prompts (“nur aus Kontext”), Quellenangaben fordern und bei Unsicherheit “weiß nicht” erlauben.

Wie halte ich die Datenbank aktuell?

Workflow: Bei neuem Dokument automatisch indexieren. Bei Updates alte Chunks löschen und neu indexieren. Siehe Wissensbestand aktualisieren.

Was kostet das?

Nur Hardware-Kosten. Ollama, Qdrant und ChromaDB sind Open Source. Keine API-Kosten pro Dokument oder Abfrage.

Sind meine Dokumente sicher?

Ja, wenn Du lokale Tools nutzt. Alle Daten bleiben auf Deinem Server. Bei Cloud-APIs gehen Dokumente raus, für vertrauliche Dokumente lokal bleiben.

Quellen und weiterführende Literatur

Zurück zum KI Blog
Share:

Ähnliche Beiträge