LLM-gestützte Datenvisualisierung: Code-Generierung als Lösungsansatz#
Kontext und Motivation#
Large Language Models (LLMs) haben oft noch Schwierigkeiten bei derr Bearbeitung von tabellarischen Daten und numerischen Berechnungen. Dieses Experiment untersuchte einen alternativen Ansatz: Statt das LLM direkt mit Zahlen arbeiten zu lassen, generiert es Python-Code zur Datenanalyse und Visualisierung, der in einer gesicherten Umgebung ausgeführt wird.
Die funktionale Fragestellung war pragmatisch: Lässt sich ein Tool entwickeln, das bei der Auswahl passender Grafiken für Daten schnell und unkompliziert unterstützt und einfache Visualisierungen weitgehend automatisch erstellt? Das Projekt diente als Lernvehikel zur Exploration der Machbarkeit eines Multi-Agenten-Systems mit Code-Generierung.
Das Tool: Interactive Chart Generator#
Der entwickelte Chart Generator verarbeitet CSV- und Excel-Dateien (inklusive Multi-Sheet-Unterstützung) und ermöglicht die Erstellung interaktiver Plotly-Visualisierungen über natürlichsprachige Chat-Anfragen. Ein Nutzer kann beispielsweise eingeben: “Erstelle Balkendiagramme für alle Sheets” oder “Färbe die Balken grün für positive Werte”.
Das System basiert auf einer Web-Oberfläche (Gradio) und nutzt lokale LLMs über eine OpenAI-kompatible API. Die Architektur umfasst ~8.500 Zeilen Code in 27 Python-Dateien und wurde vollständig LLM-gestützt entwickelt.
Technische Architektur#
Die Systemarchitektur entwickelte sich iterativ in drei Hauptstufen:
Version 1: Ein Chat-Agent und ein Chart-Agent arbeiteten direkt zusammen. Dieser Ansatz erwies sich als zu instabil – das System konnte nicht zuverlässig zwischen Diskussion und Ausführungsanfragen unterscheiden.
Version 2: Einführung einer Intent-Erkennung. Der IntentService analysiert Nutzeranfragen und klassifiziert sie (Modifikation, Einzelchart, Mehrfachchart, Analyse). Dies verbesserte die Zielgenauigkeit erheblich.
Version 3 (Final): Ein dreistufiger Workflow: Intent → Plan → Execute. Der PlanService übersetzt erkannte Intents in detaillierte Ausführungspläne mit konkreten Chart-Spezifikationen. Der ExecutionService koordiniert die Ausführung mit Retry-Logik und Fehlerkorrektur.
Die Code-Ausführung erfolgt in einer kontrollierten Umgebung mit eingeschränkten Builtins (ohne __import__) und vordefinierten Safe-Globals für Pandas, Plotly und NumPy.
Entwicklungsentscheidung: Pattern-Bibliotheken#
Eine zentrale Erkenntnis war, dass reine LLM-Code-Generierung für Chart-Erstellung nicht stabil genug funktionierte. Die Lösung: Integration umfangreicher Pattern-Bibliotheken mit 44 Code-Patterns.
Diese umfassen:
- 23 funktionierende Implementierungsmuster (z.B.
PATTERN_SIMPLE_BAR,PATTERN_TIME_SERIES_GROUPED) - 7 Anti-Patterns zur Vermeidung instabiler Konstrukte (z.B.
ANTI_PATTERN_COMPLEX_CATEGORICAL) - 9 Modifikationsmuster für Chart-Anpassungen
- 5 semantische und Auswahlmuster
Das LLM wählt und adaptiert diese Patterns basierend auf Datentypen und Nutzeranfrage. Dieser Hybrid-Ansatz (LLM-Intelligenz + Templates) erwies sich als deutlich robuster als reine Generierung.
Methodische Erkenntnisse#
1. Spezifikationsgetriebene Entwicklung#
Der Entwicklungsprozess war stark spezifikationsgetrieben: Für jede Iterationsstufe wurde eine umfangreiche Spezifikation erstell, implementiert und angepasst (~1 Stunde). Die Gesamtentwicklungszeit betrug ca. 3 Stunden plus 30 Minuten für Docker-Deployment.
Hochwertige, detaillierte Spezifikationen erwiesen sich als essentiell. Kleinteiliges Micro-Prompting führte zu fragmentierter, inkonsistenter Entwicklung. Die Spezifikationen umfassten: technische Architektur, UI-Design, Komponenteninteraktionen und funktionale Ziele.
2. Intent→Plan→Execute als bewährtes Pattern#
Die Trennung von Intent-Erkennung, Planungsstrategie und Ausführung ermöglichte:
- Klarere Unterscheidung zwischen Chat-Diskussion und Aktionsanfragen
- Bessere Testbarkeit einzelner Komponenten
- Gezieltere Fehlerbehandlung in jeder Phase
3. LLM-Steuerung vs. Heuristiken#
Trotz nicht-perfekter Zuverlässigkeit erwies sich LLM-gesteuerte Verarbeitung als überlegen gegenüber regel-basierten Heuristiken. Heuristiken funktionieren nur für sehr spezifische Fälle; LLMs generalisieren besser über verschiedene Formulierungen hinweg.
4. Retry-Logik und Selbstkorrektur#
Die implementierte fix_code() Methode ermöglicht LLM-basierte Fehlerkorrektur. Bei Code-Fehlern wird der Error-Message an das LLM zurückgegeben, das einen korrigierten Code generiert. Dies reduzierte die Fehlerrate moderat, erreicht aber keine 100%-Zuverlässigkeit.
5. Beispiele kompensieren Model-Schwächen#
Die verwendeten lokalen LLMs (HU-Modelle) bewältigen große Kontexte, zeigen aber Schwächen bei Code-Generierung. Die umfangreichen Pattern-Bibliotheken kompensierten dies erfolgreich und verbesserten die Leistungsfähigkeit erheblich.
Herausforderungen und Grenzen#
Multi-Sheet-Handling: Die Unterscheidung zwischen Anfragen für einzelne vs. mehrere Grafiken war anfangs problematisch. Die Intent-Erkennung mit expliziten Trigger-Wörtern (“alle Sheets”, “für jedes”) löste dies.
Semantische Farb-Zuordnung: Natürlichsprachige Farbangaben wie “grün für positive Werte” erforderten zusätzliche Logik (SemanticColorHelper) zur Erkennung ordinaler Skalen (Likert-Skalen) und kategorie-basierter Farb-Mappings.
Zuverlässigkeit: Es bleibt schwierig, Lösungen zu implementieren, die zu 100% funktionieren. Die aktuelle Implementierung funktioniert in der Mehrzahl der Fälle zuverlässig, aber nicht universell.
Status und Ausblick#
Das Tool befindet sich derzeit in der Erprobungsphase mit einem breiteren Nutzerkreis. Erste Tests mit verschiedenen Excel-Dateien (inklusive komplexer Multi-Sheet-Strukturen) verliefen erfolgreich. Weiteres Feedback ist notwendig, um Edge Cases zu identifizieren und die Robustheit weiter zu verbessern.
Die zentralen übertragbaren Erkenntnisse sind: Multi-Agenten-Architekturen mit klarer Phasentrennung funktionieren gut für komplexe Aufgaben; spezifikationsgetriebene Entwicklung ist micro-iterativen Ansätzen überlegen; Pattern-Bibliotheken stabilisieren Code-Generierung erheblich; und Code-Indirektion ist ein vielversprechender Ansatz für LLM-Limitierungen bei numerischen Aufgaben.