Zum Inhalt

Architektur

Die Anwendung ist als monolithischer Python-Dienst aufgebaut, der in einer einzigen Container-Instanz betrieben wird. Innerhalb des Dienstes sind die Verantwortlichkeiten in vier voneinander getrennten Schichten organisiert: Benutzeroberfläche, Dokumenten-Aufbereitung, Sprachmodell-Anbindung und Konfiguration. Externe Dienste werden ausschließlich für die LLM-Inferenz angesprochen; die gesamte Dokumentenverarbeitung erfolgt lokal innerhalb des Containers.

Auf einen Blick

  • Container-basiertes Deployment (Docker, optional über Docker Compose)
  • Schichtenarchitektur mit klarer Trennung von Oberfläche, Pipeline, LLM-Anbindung und Konfiguration
  • Webframework Gradio als kombinierte UI- und HTTP-Schicht
  • Aufbereitungspipeline mit Extraktion, Bereinigung, Deduplizierung, Markdown-Konvertierung und Referenzierung
  • Sprachmodell-Anbindung über das OpenAI-API-Protokoll mit Streaming-Unterstützung
  • In-Memory-Sitzungsverwaltung pro Browser-Sitzung
  • Konfiguration ausschließlich über Umgebungsvariablen und CLI-Argumente

Architekturüberblick

Die UI-Schicht basiert auf Gradio und stellt sowohl die HTTP-Schnittstelle als auch das Frontend bereit. Sie nimmt Datei-Uploads entgegen, leitet Anfragen an die Pipeline weiter, streamt Modellantworten zurück und verwaltet pro Browser-Sitzung einen eigenen Zustand mit den geladenen Dokumenten und dem Chatverlauf.

Die Aufbereitungsschicht kapselt alle Schritte, die zwischen einem hochgeladenen Dokument und dem dem Sprachmodell übergebenen Kontext liegen. Sie ist in drei Teilbereiche gegliedert: Extraktion (Auslesen der Rohinhalte aus binären Formaten), Optimierung (Bereinigung, Deduplizierung, Markdown-Formatierung) und Referenzierung (Vergabe eindeutiger Absatzmarker für die Quellen­nachverfolgung).

Die LLM-Schicht verwaltet den Mehrdokumenten­kontext, prüft Tokenlimits, baut den Prompt mit System- und Nutzeranweisungen auf und führt den Aufruf gegen den konfigurierten Sprachmodell-Endpunkt durch. Die Antwort wird im Streaming entgegen­genommen und unmittelbar an die UI-Schicht weitergeleitet.

Die Konfigurations­schicht liest Umgebungsvariablen und CLI-Argumente ein, validiert sie und stellt sie als typisierte Datenklassen den übrigen Komponenten zur Verfügung.

flowchart TB
    User([Nutzer])

    subgraph Container[Container]
        UI[Gradio UI<br/>Datei-Upload · Chat · Streaming]

        subgraph Pipeline[Aufbereitungspipeline]
            EX[Extraktion<br/>unstructured + pypdf]
            CL[Bereinigung<br/>Header · Footer · Seitenzahlen]
            DD[Deduplizierung<br/>Hash + Fuzzy-Match]
            FM[Markdown-Formatter]
            RF[Referenzsystem<br/>P1, P2, ...]
        end

        subgraph LLM[LLM-Anbindung]
            MM[Multi-Document Manager<br/>Token- und Limit-Kontrolle]
            IF[LLM-Interface<br/>OpenAI-API-Client]
        end

        WX[Word-Export<br/>python-docx]

        CFG[Konfiguration<br/>ENV + CLI]
    end

    LLMSrv[(Sprachmodell-Endpunkt<br/>OpenAI-API-kompatibel)]

    User -->|Upload| UI
    UI --> EX
    EX --> CL --> DD --> FM --> RF
    RF --> MM
    User -->|Frage| UI
    UI --> MM --> IF
    IF -->|HTTPS| LLMSrv
    LLMSrv -.->|Streaming| IF
    IF -.-> UI
    UI -.-> User
    UI -.-> WX
    WX -.->|.docx| User
    CFG -.-> UI
    CFG -.-> IF
    CFG -.-> Pipeline

Workflow

Der typische Ablauf beginnt mit dem Upload eines oder mehrerer Dokumente. Die UI-Schicht reicht jede Datei an die Extraktions­komponente weiter, die das Dokument anhand des Dateityps an einen passenden Parser übergibt. Für PDFs werden zusätzlich interaktive Formularfelder (AcroForm) ausgelesen und an den extrahierten Text angehängt. Das Ergebnis ist ein strukturierter Rohtext mit Überschrifts­markierungen und — wo verfügbar — Seitenangaben.

Im Optimierungsschritt entfernt die Bereinigungs­komponente wiederkehrende Headers, Footers, Seitenzahlen und typografische Artefakte über kompilierte Regex-Muster und eine Häufigkeits­analyse. Anschließend prüft die Deduplizierung jedes Element gegen einen wachsenden Speicher zuvor gesehener Inhalte: Exakte Duplikate werden über MD5-Hashes erkannt, Near-Duplicates über Sequenz-Matching mit konfigurierbarem Ähnlichkeits­schwellwert. Tabellen und Listen werden zusätzlich strukturell verglichen. Der Markdown-Formatter überführt das Ergebnis in einheitliches Markdown und erhält dabei Listen, Tabellen und Überschriften.

Im Referenzierungsschritt wird jedem hinreichend langen Absatz eine eindeutige ID in der Form [Pn] zugewiesen. Eine interne Map speichert für jede ID einen Vorschautext, den vollständigen Absatz, den zugehörigen Dokumentnamen und — falls erkennbar — die Seitennummer. Diese Map dient später der Auflösung der vom Modell ausgegebenen Marker.

Stellt der Nutzer eine Frage, kombiniert der Multi-Document Manager alle aktiven Dokumente zu einem zusammen­gesetzten Kontext und prüft, ob dieser zusammen mit der Frage in das Kontextlimit passt. Das LLM-Interface baut einen Systemprompt — mit oder ohne Anweisung zur Nutzung von Quellenmarkern — und einen Nutzerprompt auf und ruft den Sprachmodell-Endpunkt im Streaming-Modus auf. Eingehende Token werden gepuffert, an Satzgrenzen oder bei vollem Buffer in die UI gespielt und dort fortlaufend gerendert. Nach Abschluss der Antwort werden vorhandene Marker [Pn] extrahiert, gegen die Referenzmap aufgelöst und gruppiert nach Dokument als Quellenliste angehängt.

Auf Anforderung erzeugt der Word-Exporter aus dem Chatverlauf ein formatiertes .docx-Dokument einschließlich der Quellenangaben.

Nebenläufigkeit, Robustheit und Konfiguration

Die Anwendung nutzt die Queue-Funktionalität von Gradio für die Anfrage­serialisierung und ermöglicht das gezielte Abbrechen einer laufenden Streaming-Antwort durch den Nutzer. Sitzungen werden durch eine UUID identifiziert und im Arbeitsspeicher gehalten; nach Sitzungsende wird der zugehörige Speicher freigegeben. Fehler bei der Dokument­extraktion werden auf einen generischen Fallback-Pfad umgeleitet und je Datei separat in der Oberfläche zurückgemeldet, sodass eine fehlerhafte Datei nicht den gesamten Verarbeitungslauf blockiert. Tokenüber­schreitungen werden vor dem LLM-Aufruf erkannt und mit einer entsprechenden Meldung abgewiesen.

Die Konfiguration erfolgt vollständig deklarativ über Umgebungsvariablen oder CLI-Argumente. Eine zentrale Konfigurations­klasse liest die Werte ein, validiert sie und stellt sie typisiert zur Verfügung. Damit lässt sich die Anwendung ohne Codeänderung an unterschiedliche Sprachmodell-Endpunkte, Subpfad-Deployments hinter einem Reverse Proxy und abweichende Tokenlimits anpassen.

Technologie-Übersicht

Bereich Komponente
Sprache und Laufzeit Python 3.13
Webframework / UI Gradio (Version 5+)
Dokumentextraktion unstructured (PDF, DOCX, PPTX), pypdf für interaktive Formularfelder, pdfplumber, openpyxl, python-pptx
Sprachmodell-Anbindung OpenAI Python SDK (OpenAI-API-Protokoll)
Word-Export python-docx
Hilfsbibliotheken beautifulsoup4, lxml, chardet, python-magic, tiktoken
Containerisierung Docker (Multi-Stage-Build), Docker Compose
Systemabhängigkeiten poppler-utils, tesseract-ocr, libreoffice, libmagic