LLM-gestütztes Coding bei mehrstufigen Workflows: Detaillierte Dokumentation eines Umfrage-Tool-Experiments#
Zusammenfassung#
Dieser Artikel dokumentiert ein Lernexperiment zur Entwicklung eines KI-gestützten Umfrage-Tools mit Large Language Models. Das Projekt explorierte methodische Grenzen und Möglichkeiten des LLM-Codings bei komplexen, mehrstufigen Workflows. Die zentrale Erkenntnis: Bei der Entwicklung solcher Systeme ist Architektur-Verständnis der limitierende Faktor, nicht die Code-Generierung selbst. Der Artikel bietet detaillierte Einblicke in technische Umsetzung, Entwicklungsprozess und übertragbare methodische Learnings.
1. Experimenteller Kontext#
1.1 Motivation und Lernziele#
Das Projekt entstand im Kontext geplanter Umfragen und der Fragestellung: Wie weit lassen sich mit LLM-Tools Umfrage-ähnliche Systeme erstellen, die sicherstellen, dass Antworten tatsächlich verwertbar sind? Das primäre Lernziel war die methodische Exploration von LLM-Coding bei komplexeren Architekturen, konkret:
- Wie orchestriert man mehrstufige Workflows mit LLMs?
- Welche Architekturmuster eignen sich für Agent-basierte Systeme?
- Wo liegen praktische Grenzen der automatischen Kriterienableitung?
- Wie strukturiert man Spezifikationen für solche Aufgaben optimal?
Das Tool selbst war explizit als Lernvehikel konzipiert, nicht als produktives System. Die gewonnenen Erkenntnisse sollten in ein verbessertes Nachfolgeprojekt fließen.
1.2 Einordnung in die Lernkurve#
Das Experiment fand in der Mitte einer längeren Lernphase mit LLM-gestütztem Coding statt. Es existierte bereits Grundlagenwissen über Prompt Engineering und einfache Tool-Entwicklung, aber keine Erfahrung mit komplexen Agent-Workflow-Interaktionen. Diese Positionierung war bewusst gewählt: Das Projekt sollte die Grenzen des bisherigen Verständnisses ausloten.
2. Technische Umsetzung#
2.1 Architektur-Überblick#
Das System implementiert einen Single-Agent-Ansatz mit klar getrennten Verantwortlichkeiten. Entgegen der initialen Vermutung mehrerer separater Agenten kristallisierte sich während der Entwicklung heraus, dass ein SurveyAgent mit spezialisierten Methoden die angemessene Komplexität bietet:
Kernkomponenten:
SurveyAgent (
src/agent.py): Hauptkomponente mit drei Kernfunktionenevaluate_answer(): Bewertet Antwort-Klarheit und -Spezifität (Clarity Score 0-1)generate_followup(): Generiert kontextspezifische Nachfragen bei unklaren Antwortenstructure_final_answer(): Bereitet finale Antworten für Clustering auf
ConversationManager (
src/agent.py): Orchestriert den Umfrage-Workflow- Verwaltet Frage-Sequenzen
- Steuert Nachfrage-Logik
- Tracked Session-State
LLMClient (
src/llm_client.py): OpenAI-kompatible API-Integration- Unterstützt lokale und Remote-LLMs
- Robustes Error-Handling mit Retry-Logik
- Mock-Client für Tests ohne LLM
PromptManager (
src/prompts.py): Zentrale Prompt-Verwaltung- Templates für alle Agent-Funktionen
- Strukturierte JSON-Output-Definitionen
- Versionierung und Fallback-Mechanismen
Interface (
interface/): Modulares Gradio-UI- Experimentier-Playground für Live-Testing
- Batch-Testing-Funktionalität
- Performance-Monitoring
- Demo-Modus für Stakeholder
2.2 Technologie-Stack#
Die Wahl des Technologie-Stacks basierte auf vorhandener Erfahrung, um Fokus auf die eigentlichen Lernziele zu ermöglichen:
- Python 3.x: Hauptsprache
- Gradio 4.x: UI-Framework (einfach, schnell, für Prototypen geeignet)
- Pydantic 2.x: Datenvalidierung und Type-Safety
- asyncio: Asynchrone LLM-Anfragen und Timeout-Handling
- Mistral Small 2506: Runtime-LLM für Bewertungen und Nachfragen
- OpenAI-kompatibler API-Client: Flexibilität für verschiedene LLM-Backends
Diese Kombination erlaubte es, innerhalb kurzer Zeit (4 Stunden aktive Entwicklung) ein funktionales System zu erstellen, ohne Zeit mit Technologie-Learning zu verlieren.
2.3 Modularität und Strukturierung#
Die modulare Struktur war von Anfang an in der Spezifikation festgelegt. Dies erwies sich als entscheidend für die Wartbarkeit:
Projektstruktur (4.000 Zeilen, 15 Dateien):
├── src/
│ ├── agent.py # Agent-Kernlogik (500 Zeilen)
│ ├── llm_client.py # LLM-Integration (300 Zeilen)
│ ├── prompts.py # Prompt-Management (600 Zeilen)
│ ├── models.py # Pydantic-Datenmodelle (400 Zeilen)
│ └── config_loader.py # Konfiguration (200 Zeilen)
├── interface/
│ ├── gradio_interface.py # UI-Logik (800 Zeilen)
│ ├── gradio_handlers.py # Event-Handler (600 Zeilen)
│ ├── gradio_tabs.py # UI-Layout (500 Zeilen)
│ └── timing_metrics.py # Performance-Monitoring (400 Zeilen)
└── config/
├── config.yaml # System-Konfiguration
└── survey_mvp.yaml # Umfrage-DefinitionenDie klare Trennung zwischen Datenmodellen, Business-Logik und Präsentationsschicht ermöglichte iterative Entwicklung ohne größere Refactorings.
3. Der Entwicklungsprozess#
3.1 Spezifikationsphase (2 Stunden)#
Die initiale Spezifikation definierte:
- Grundlegende Anforderungen: Nachfrage-System, Antwort-Bewertung, Clustering-Vorbereitung
- Architektur-Grobstruktur: Agent-basierter Ansatz, Modularisierung
- Technologie-Stack: Python, Gradio, Pydantic
- Nicht-funktionale Anforderungen: Timeouts, Error-Handling, Performance-Monitoring
Wichtige Erkenntnis: Die Spezifikation war bewusst auf konzeptioneller Ebene gehalten, nicht als detaillierte technische Blaupause. Der Grund: Bei neuartigen Architekturmustern fehlt das Verständnis für optimale Strukturierung. Die Spezifikation definierte das “Was” und “Warum”, überließ aber das “Wie genau” dem iterativen Prozess.
3.2 Entwicklung mit LLM (4 Stunden über 3 Tage)#
Interaktionsmuster: Die Zusammenarbeit mit dem LLM folgte einem strukturierten Dialog-Ansatz:
- Präsentation der Spezifikation und Architektur-Anforderungen
- Diskussion möglicher Umsetzungsansätze
- Schrittweise Implementierung der Komponenten
- Iterative Verfeinerung basierend auf Tests
Phasen:
Phase 1 - Grundgerüst (1h):
- LLM-Client-Integration mit Retry-Logik
- Basis-Datenmodelle (Question, AnswerEvaluation, etc.)
- Konfigurationssystem
- Erste Prompt-Templates
Phase 2 - Agent-Logik (1,5h):
- Implementierung evaluate_answer()
- Entwicklung der Bewertungskriterien
- Erste Tests mit Mock-Daten
- Herausforderung: LLM schlug komplexe Scoring-Mechanismen mit gewichteten Sub-Scores vor. Musste zu einfacher 0-1 Score-Bewertung zurückgeführt werden.
Phase 3 - Workflow-Orchestrierung (1h):
- ConversationManager-Implementierung
- State-Management zwischen Fragen
- Integration von Nachfrage-Logik
- Herausforderung: Abstimmung zwischen Agent-Entscheidungen und Workflow-Steuerung war nicht trivial. Mehrere Iterations-Runden notwendig, um Race-Conditions zu vermeiden.
Phase 4 - UI und Refinement (0,5h):
- Gradio-Interface-Aufbau
- Performance-Monitoring
- Error-Handling-Verbesserungen
- Herausforderung: Gradio-spezifische Type-Format-Probleme erforderten Wrapper-Funktionen.
3.3 Prompt-Engineering-Iterationen (5-6 Runden)#
Die Entwicklung konsistenter Prompt-Templates für die Antwort-Bewertung erforderte am meisten Iterationen:
Iteration 1-2: Initiale Prompts waren zu offen formuliert, führten zu inkonsistenten Bewertungen.
Iteration 3-4: Hinzufügen von Beispielen für “vage” vs. “klare” Antworten verbesserte Konsistenz deutlich. Strukturierte JSON-Output-Definition wurde zentral.
Iteration 5-6: Feintuning der Bewertungskriterien. Explizite Anweisungen gegen zu nachsichtige Bewertungen notwendig.
Finale Template-Struktur:
System-Prompt: Rolle, Bewertungskriterien, Output-Format
User-Prompt: Frage-Kontext, zu bewertende Antwort, Beispiele
Expected Output: JSON mit clarity_score, needs_followup, reasoning, problem_areas3.4 Umgang mit LLM-Overengineering#
Ein wiederkehrendes Muster: Das LLM neigte zu komplexen Lösungen:
Beispiel 1 - Bewertungs-Logik: LLM-Vorschlag: Multi-Dimensionales Scoring mit Gewichtungen für Spezifität, Vollständigkeit, Relevanz, Clusterbarkeit, separaten Sub-Scores. Tatsächlich implementiert: Einfacher 0-1 Clarity Score mit boolean needs_followup.
Beispiel 2 - State-Management: LLM-Vorschlag: Komplexes State-Machine-Pattern mit expliziten Zustandsübergängen. Tatsächlich implementiert: Einfaches Session-Objekt mit Liste von Interactions.
Beispiel 3 - Error-Handling: LLM-Vorschlag: Hierarchisches Exception-System mit Custom-Exceptions für jede Fehlerquelle. Tatsächlich implementiert: Robuste Try-Catch-Blöcke mit Fallback-Werten.
4. Methodische Erkenntnisse#
4.1 Konzeptionelle Komplexität als limitierender Faktor#
Die entscheidende Erkenntnis dieses Experiments: Die Herausforderung lag nicht in der Code-Menge (4.000 Zeilen), sondern im Verständnis der benötigten Architekturmuster.
Konkret: Ohne vorherige Erfahrung mit Agent-Workflow-Orchestrierung war es schwierig zu spezifizieren:
- Wie interagieren Agent und ConversationManager optimal?
- Wann sollte der Agent Entscheidungen treffen, wann der Manager?
- Wie verhindert man zirkuläre Abhängigkeiten?
- Welche State-Informationen müssen wo vorgehalten werden?
Diese Fragen ließen sich nicht durch intensiveres Nachdenken beantworten, sondern nur durch praktisches Experimentieren. Das führt zu einem grundlegenden Prinzip:
Hilfreich scheint der Ansatz, erst durch explorative Prototypen die Architekturmuster kennenzulernen und dann gezielt zu spezifizieren und zu implementieren.**
4.2 Optimale Spezifikations-Strategien#
Aus diesem Projekt ergeben sich konkrete Empfehlungen für die Spezifikation LLM-gestützter Entwicklungsprojekte:
Was funktioniert:
- Klare Anforderungen auf konzeptioneller Ebene
- Beispiele für erwartetes Verhalten
- Nicht-funktionale Anforderungen (Timeouts, Error-Handling)
- Architektur-Grobstruktur mit klaren Verantwortlichkeiten
- Explizite Constraints (“einfachste Lösung”, “keine vorzeitige Abstraktion”)
Was nicht funktioniert:
- Detaillierte technische Blaupausen bei unbekannten Architekturmustern
- Zu offene Formulierungen ohne Beispiele
- Implizite Erwartungen an Code-Qualität
- Fehlende Vorgaben gegen Overengineering
Optimaler Ansatz: Iterativer Prozess aus grober Spezifikation, prototypischer Implementierung, Architektur-Learning und anschließender präziserer Spezifikation für Produktivsystem.
4.3 Strukturierte JSON-Outputs#
Die konsequente Verwendung strukturierter JSON-Responses war zentral für das Funktionieren des Systems:
Vorteile:
- Typsichere Verarbeitung durch Pydantic-Validierung
- Klare Schnittstellen zwischen Komponenten
- Einfaches State-Management
- Vorhersagbare Datenflüsse
Implementierung:
class AnswerEvaluation(BaseModel):
clarity_score: float # 0.0-1.0
needs_followup: bool
reasoning: str
problem_areas: List[str]
suggested_clarifications: List[str]Kritischer Aspekt: JSON-gesteuerte Systeme können anfällig für Schleifen sein. Konkret beobachtet:
- Fehlerhafte Bewertung → Nachfrage → Gleiche Bewertung → Erneute Nachfrage
- Lösung: Explizite max_followups-Limits, Timeout-Mechanismen, Fallback-Bewertungen
4.4 Grenzen der Kriterienableitung#
Die größte technische Herausforderung war die automatische Ableitung von Bewertungskriterien für Antwort-Vollständigkeit:
Gut funktionierende Bereiche:
- Erkennung sehr vager Antworten (“Cloud”, “Gut”, “OK”)
- Erkennung sehr spezifischer Antworten (“Office 365 für E-Mail und Dokumentenbearbeitung”)
- Bewertung von Antwortlänge
Problematische Bereiche:
- Beurteilung der Vollständigkeit (Was fehlt noch?)
- Kontextabhängige Spezifität (Wann ist “AWS” spezifisch genug?)
- Mehrdeutige Antworten (Meint “Cloud” nun Speicher oder Software?)
Ursache: Das LLM verfügt nicht über den vollständigen Kontext der Umfrage-Ziele. Es kann syntaktische und oberflächlich-semantische Muster erkennen, aber nicht beurteilen, ob eine Antwort für die spezifische Forschungsfrage ausreichend ist.
Praktische Konsequenz: Solche Systeme funktionieren am besten bei standardisierten Umfragen mit klaren Bewertungskriterien, weniger bei explorativen Umfragen mit offenen Zielsetzungen.
4.5 Workflow-Orchestrierung als Kernkompetenz#
Die Orchestrierung der einzelnen Komponenten erwies sich als komplexer als die Implementierung einzelner Funktionen:
Herausforderungen:
- Synchronisation zwischen Agent-Bewertungen und UI-Updates
- State-Konsistenz bei asynchronen LLM-Anfragen
- Fehlerbehandlung über Komponenten-Grenzen hinweg
- Performance-Optimierung ohne Funktions-Verlust
Lösung: Klare Event-basierte Architektur mit definierten Schnittstellen und robustem Error-Handling auf jeder Ebene. Threading-Locks zur Vermeidung von Race-Conditions.
Learning: Bei Multi-Komponenten-Systemen sollte mehr Entwicklungszeit für Orchestrierung als für Einzelkomponenten eingeplant werden.
5. Validierung und praktische Tauglichkeit#
5.1 Funktionale Tests#
Das System wurde mit zwei Test-Fragen validiert:
- “Welche Cloud-Technologien setzen Sie hauptsächlich ein?”
- “Wie bewerten Sie Ihre aktuelle IT-Sicherheitslage?”
Ergebnisse:
- Bei eindeutig vagen Antworten (“Cloud”, “Gut”) funktionierte Nachfrage-System zuverlässig
- Nachfragen waren kontextuell relevant und führten zu präziseren Antworten
- Strukturierung für Clustering funktionierte bei klaren Antworten gut
- Probleme bei Grenzfällen und Bewertung der Vollständigkeit
Quantitative Metriken:
- Durchschnittliche Response-Zeit: 2-4 Sekunden pro Bewertung
- Nachfrage-Rate: 30-40% bei typischen Test-Antworten
- Konsistenz der Bewertungen: Gut bei klaren Fällen, inkonsistent bei Grenzfällen
5.2 Praktische Limitation: Endlosschleifen-Risiko#
Ein kritisches Learning aus den Tests: JSON-gesteuerte LLM-Systeme können bei unzureichender Absicherung in Endlosschleifen laufen.
Beobachtetes Szenario:
- User-Antwort: “Cloud-Services”
- Agent-Bewertung: needs_followup = true
- Nachfrage: “Welche konkreten Cloud-Services?”
- User-Antwort: “Cloud-Dienste”
- Agent-Bewertung: needs_followup = true (Kriterien nicht erfüllt)
- Erneute Nachfrage…
Implementierte Safeguards:
- Harte Limits: max_followups = 1-3 (konfigurierbar)
- Timeouts: Maximale Verarbeitungszeit pro Bewertung
- Fallback-Bewertungen: Bei Timeout oder Fehler akzeptieren
- Monitoring: Logging aller Iterations-Counts
Generelle Empfehlung: Alle LLM-gesteuerten Loop-Systeme benötigen explizite Exit-Bedingungen, die nicht vom LLM-Output abhängen.
5.3 Nutzung und Folgearbeiten#
Das Tool wurde ausschließlich explorativ genutzt. Der Hauptwert lag in den gewonnenen Erkenntnissen zur Architektur-Gestaltung solcher Systeme.
Direkter Nutzen:
- Verständnis für Agent-Workflow-Orchestrierung
- Erkenntnisse zu Grenzen automatischer Kriterienableitung
- Prompt-Engineering-Patterns für strukturierte Outputs
- Awareness für Fehlerquellen (Endlosschleifen, Race-Conditions)
Nachfolgeprojekt “ppt-helper”: Die Erkenntnisse flossen in ein verbessertes System mit mehreren spezialisierten Agenten ein. Dort konnten die Architekturmuster gezielter angewendet werden, da das Grundverständnis bereits vorhanden war.
Dies illustriert den eigentlichen Wert solcher Lernprojekte: Nicht die unmittelbare Produktivnutzung, sondern der systematische Kompetenzaufbau für komplexere Folge-Implementierungen.
6. Übertragbare Erkenntnisse#
6.1 Entwicklungs-Workflow für komplexe LLM-Systeme#
Basierend auf diesem Experiment lässt sich folgender Workflow empfehlen:
Phase 1 - Konzeptionelle Spezifikation (20% der Zeit):
- Anforderungen auf konzeptioneller Ebene
- Beispiele für erwartetes Verhalten
- Grobe Architektur-Struktur
- Explizite Constraints gegen Overengineering
Phase 2 - Explorativer Prototyp (30% der Zeit):
- Fokus auf Architektur-Learning, nicht Produktivität
- Schnelle Iteration ohne Perfektion
- Dokumentation von Learnings
- Identifikation kritischer Stellen
Phase 3 - Verfeinerte Spezifikation (10% der Zeit):
- Einarbeitung der Prototype-Erkenntnisse
- Präzisierung der Architektur
- Definition robuster Schnittstellen
- Festlegung von Safeguards
Phase 4 - Produktiv-Implementierung (40% der Zeit):
- Umsetzung mit bewährten Patterns
- Fokus auf Robustheit und Error-Handling
- Systematisches Testing
- Performance-Optimierung
6.2 Prompt-Engineering für strukturierte Workflows#
Bewährte Patterns:
- Explizite JSON-Schema-Definition im Prompt:
Du musst IMMER mit validem JSON antworten im Format:
{
"clarity_score": <float 0.0-1.0>,
"needs_followup": <boolean>,
"reasoning": "<string>"
}Konkrete Beispiele statt abstrakter Regeln: Statt: “Bewerte die Spezifität der Antwort” Besser: “Beispiele für VAGE: ‘Cloud’, ‘Software’. Beispiele für KLAR: ‘Office 365’, ‘AWS S3’”
Explizite Strenge-Vorgaben: “Nur Antworten mit Clarity Score > 0.7 akzeptieren. Sei streng in der Bewertung.”
Fallback-Instruktionen: “Falls Bewertung nicht möglich, verwende clarity_score: 0.5, needs_followup: true”
6.3 Architektur-Patterns für Agent-Systeme#
Single-Agent mit spezialisierten Methoden (wie in diesem Projekt) eignet sich für:
- Sequenzielle Workflows
- Klare Aufgaben-Abfolgen
- Einfache State-Verwaltung
Multi-Agent-Systeme eignen sich für:
- Parallele Verarbeitung
- Spezialisierte Teilaufgaben mit unterschiedlichen Prompts
- Komplexe Entscheidungs-Bäume
Wichtig: Die Komplexität steigt nicht-linear mit der Anzahl der Agenten. Nur bei klarem Nutzen zu Multi-Agent übergehen.
6.4 Error-Handling und Robustheit#
Kritische Bereiche:
- LLM-Timeouts: Immer mit asyncio.wait_for() und Fallback-Werten arbeiten
- JSON-Parsing: Robuste Fehlerbehandlung, nie Absturz bei invalider Response
- State-Inkonsistenzen: Threading-Locks bei parallelen Zugriffen
- Endlosschleifen: Harte Limits unabhängig von LLM-Output
Implementierungs-Prinzip: Jede LLM-Interaktion kann fehlschlagen. System muss in allen Fällen weiterlaufen können.
7. Metriken und Aufwand#
Projekt-Umfang:
- 4.000 Zeilen Code
- 15 Python-Dateien
- Modulare Struktur: src/ (5 Dateien), interface/ (4 Dateien), config/ (2 Dateien)
Entwicklungszeit:
- Spezifikation: 2 Stunden
- Implementierung: 4 Stunden (verteilt über 3 Tage)
- Gesamt: 6 Stunden
- Iterationen: 4-5 Haupt-Iterationen
- Prompt-Refinement: 5-6 Runden
Komponenten-Größe:
- Agent-Logik: ~500 Zeilen
- LLM-Client: ~300 Zeilen
- Prompt-Management: ~600 Zeilen
- UI-Interface: ~1.900 Zeilen
- Datenmodelle: ~400 Zeilen
- Monitoring/Utils: ~300 Zeilen
Effizienz-Bewertung: Die Entwicklungszeit von 6 Stunden für ein funktionales 4.000-Zeilen-System demonstriert die Effizienz von LLM-gestütztem Coding. Allerdings: Der eigentliche Lernwert lag nicht in der schnellen Code-Generierung, sondern im erworbenen Architektur-Verständnis.
8. Fazit und Ausblick#
8.1 Zentrale Erkenntnisse#
Architektur-Verständnis ist der limitierende Faktor: Bei komplexen LLM-Systemen ist nicht die Code-Generierung die Herausforderung, sondern das konzeptionelle Verständnis geeigneter Architekturmuster. Dieses Verständnis lässt sich nur durch praktisches Experimentieren aufbauen.
LLMs neigen zu Overengineering: Ohne explizite Vorgaben schlagen LLMs zu komplexe Lösungen vor. Aktive Lenkung zu KISS-Prinzipien ist notwendig.
Strukturierte JSON-Outputs sind zentral: Bei Multi-Komponenten-Workflows sind strukturierte, typsichere Schnittstellen entscheidend. Gleichzeitig erfordern sie robuste Safeguards gegen Endlosschleifen.
Iterativer Ansatz optimal: Spezifikation → Prototyp → Architektur-Learning → Verfeinerte Spezifikation → Produktiv-Implementierung.
Grenzen bei semantischer Tiefe: Automatische Kriterienableitung funktioniert bei klaren Fällen, stößt aber bei kontextabhängigen Vollständigkeits-Bewertungen an Grenzen.
8.2 Methodische Implikationen#
Für zukünftige LLM-Coding-Projekte mit ähnlicher Komplexität:
- Explizit Zeit für explorative Prototypen einplanen
- Fokus auf Architektur-Learning, nicht sofortige Produktivität
- Klare, aber nicht überdetaillierte Spezifikationen
- Systematisches Dokumentieren von Learnings
- Bewusste Einfachheit gegenüber vorzeitiger Abstraktion
8.3 Ausblick#
Das Projekt erfüllte seinen Zweck als Lernvehikel. Die gewonnenen Erkenntnisse flossen direkt in das Nachfolgeprojekt “ppt-helper” ein, das die Architekturmuster mit mehreren spezialisierten Agenten weiterentwickelt.
Die zentrale methodische Erkenntnis – dass Architektur-Verständnis der limitierende Faktor ist – hat direkte Implikationen für die Gestaltung von Lern-Curricula im Bereich LLM-gestützter Entwicklung: Statt sich primär auf Prompt-Engineering zu fokussieren, sollten systematisch Architekturmuster für verschiedene Komplexitätsstufen exploriert werden.
Zukünftige Experimente könnten gezielt weitere Architekturmuster explorieren: Event-getriebene Systeme, Streaming-Workflows, Multi-Agent-Collaboration-Patterns. Jedes Muster erfordert spezifisches Verständnis, das sich nur durch praktisches Experimentieren aufbauen lässt.