Architektur¶
Die Anwendung folgt einem geschichteten Aufbau mit klarer Trennung zwischen Bedienoberfläche, Eingabeverarbeitung, Berechnungskern und Ausgabeformaten. Eine zentrale Designentscheidung ist die Isolation des LLMs auf die Eingabeverarbeitung: sobald die Parameter strukturiert vorliegen, übernimmt ein deterministischer Rechenkern. Dadurch sind die Berechnungsergebnisse reproduzierbar und unabhängig vom verwendeten Modell.
Auf einen Blick¶
- Schichtenmodell mit Bedienoberfläche, LLM-gestützter Parser-Schicht, deterministischem Rechenkern, Sitzungsverwaltung und Ausgabeschicht
- Strikte Trennung von KI-gestützter Eingabeverarbeitung und regelbasierter Berechnung
- Zustandsverwaltung über eine Zustandsmaschine mit definierten Übergängen
- Konfiguration vollständig über Umgebungsvariablen, Tarifdaten als separate Konfigurationsmodule
- Containerisierung über Docker; Reverse-Proxy-fähig über konfigurierbares URL-Präfix
- Anbindung des LLMs über eine OpenAI-kompatible Chat-API
- Importwerkzeug zur Aktualisierung der Tarifdaten aus externen Excel-Quellen
Architekturbeschreibung¶
Komponentenübersicht¶
flowchart TB
User([Nutzer])
subgraph UI["Bedienoberfläche"]
Form[Formular]
Chat[Chat]
Result[Ergebnisanzeige]
end
subgraph Session["Sitzungsverwaltung"]
State[Zustandsmaschine]
History[Verlauf]
end
subgraph Parser["Parser-Schicht"]
Extractor[Parameter-Extraktor]
Validator[Schema-Validator]
LLMClient[LLM-Client]
end
subgraph Calculator["Rechenkern (deterministisch)"]
Core[Berechnungslogik]
Periods[Jahresscheiben]
Steps[Stufenaufstieg]
end
subgraph Output["Ausgabe"]
Tables[Markdown-Tabellen]
Excel[Excel-Export]
PDF[PDF-Export]
end
subgraph Config["Konfiguration"]
TVL[Entgelttabelle]
AG[AG-Anteile]
SHK[SHK-Sätze]
end
LLM[(OpenAI-kompatible<br/>Chat-API)]
Importer[Tarifdaten-Importer]
Excel_Source[(Excel-Quelle)]
User --> Form
User --> Chat
Form --> Session
Chat --> Session
Session --> State
Session --> Parser
Extractor --> LLMClient
Extractor --> Validator
LLMClient <--> LLM
Session --> Calculator
Calculator --> Core
Core --> Periods
Core --> Steps
Calculator --> Output
Output --> Result
Output --> Excel
Output --> PDF
Result --> User
Config -.-> Calculator
Importer --> Config
Excel_Source --> Importer
Bedienoberfläche und Sitzungsverwaltung¶
Die Bedienoberfläche ist als zweispaltiges Layout aufgebaut. Die linke Spalte enthält ein Formular mit Akkordeons für Einstellungen, Stelleneingabe und Stellenliste; die rechte Spalte führt einen Chat-Verlauf und zeigt das Berechnungsergebnis. Beide Eingabewege schreiben in dieselbe Stellenliste, sodass sie in einer Sitzung kombiniert werden können.
Die Sitzungsverwaltung verwaltet pro Nutzer einen Zustand (z.B. initial, parsing, clarifying, calculating, complete, q_and_a, fallback) und einen Konversationsverlauf. Eine Zustandsmaschine lässt nur definierte Übergänge zu; nach einer festgelegten Anzahl an erfolglosen Parse-Versuchen wechselt sie in den Fallback-Modus und aktiviert das Formular.
Parser-Schicht¶
Der Parameter-Extraktor formuliert die Anfrage an das LLM, extrahiert die JSON-Antwort und führt eine schemabasierte Validierung mit Pydantic durch. Vor der eigentlichen Validierung läuft eine Vorprüfung: liefert das LLM eine Stellenliste mit fehlenden Pflichtfeldern, wird sie in eine konkrete Rückfrage umgewandelt. Schlägt die Verarbeitung fehl, ruft der Extraktor das LLM erneut mit einem fehlerorientierten Prompt auf; wiederholte Fehlschläge werden an die Sitzungsverwaltung gemeldet.
Der LLM-Client kapselt die Kommunikation mit einer OpenAI-kompatiblen Chat-API. Die Verfügbarkeit der Schnittstelle wird beim Sitzungsstart geprüft; bei nicht erreichbarem Endpunkt fällt das System auf einen Mock-Client zurück, mit dem sich die Anwendung auch ohne aktives LLM betreiben lässt.
Nach einer abgeschlossenen Berechnung übernimmt eine zweite Prompt-Konfiguration den Q&A-Modus: das LLM beantwortet Fragen zur Kalkulation auf Basis des bereits berechneten Ergebnisses, das ihm als Kontext mitgegeben wird. Eigenständige numerische Werte werden in diesem Modus nicht berechnet.
Rechenkern¶
Der Rechenkern arbeitet vollständig deterministisch und unabhängig vom LLM. Eine Kalkulation umfasst mehrere Stellen; jede Stelle wird zunächst in Jahresscheiben zerlegt. Pro Scheibe werden Grundentgelt, Arbeitgeber-Brutto, anteilige Zuwendung und Gesamtkosten ermittelt. Tarifsteigerungen werden kumulativ pro Jahr angewandt; geplante Stufenaufstiege erzeugen innerhalb des betroffenen Jahres einen Übergang zwischen alter und neuer Stufe. Studentische Hilfskräfte werden separat auf Stundenbasis berechnet, mit einer Begrenzung auf 80 Stunden pro Monat und einem jahresweise fortgeschriebenen Stundensatz.
Für die BUND-Aufschlüsselung werden Renten-, Kranken-, Arbeitslosen- und Pflegeversicherung als feste Anteile des Bruttos separat ausgewiesen. Sämtliche Berechnungen erfolgen mit Dezimal-Arithmetik, um Rundungsabweichungen zu vermeiden.
Konfiguration und Tarifdaten¶
Tarifdaten (Entgelttabelle, Zuwendungssätze, Arbeitgeberanteile, SHK-Stundensätze) liegen als separate Konfigurationsmodule vor und werden vom Rechenkern zur Laufzeit eingelesen. Anwendungsparameter (LLM-Endpunkt, Server-Host und -Port, URL-Präfix, Standard-Tarifgebiet, Tarifsteigerungen, Log-Level) werden über Umgebungsvariablen gesteuert. Ein eigenständiges Kommandozeilenwerkzeug importiert aktualisierte Tarifdaten aus Excel-Dateien und erzeugt daraus die Konfigurationsmodule; eine Validierungsoption prüft die Plausibilität.
Betrieb¶
Die Anwendung wird als Docker-Container betrieben. Der Container exponiert einen einzelnen HTTP-Port; ein Health-Check prüft die Erreichbarkeit der Bedienoberfläche. Über das konfigurierbare URL-Präfix lässt sich die Anwendung hinter einem Reverse-Proxy unter einem beliebigen Pfad betreiben. Der Standardnutzer im Container besitzt keine Root-Rechte.
Eingesetzte Technologien¶
- Web-Framework: Gradio
- Schema-Validierung: Pydantic
- HTTP-Client: requests
- Excel-Verarbeitung: openpyxl, pandas, xlrd
- PDF-Erstellung: reportlab
- LLM-Schnittstelle: OpenAI-kompatible Chat-API
- Containerisierung: Docker
- Testumgebung: pytest