Man verfeinert einen Prompt, testet ihn, bekommt marginal bessere Ergebnisse – und stößt an eine harte Grenze. Die Logik im Kopf des Modells bleibt eine Blackbox. Was, wenn die KI nicht nur Anweisungen, sondern auch den Programmcode umschreiben könnte? Genau diese Frage stellt Michael Isaac, Doktorand an der Carnegie Mellon University, in einem Gastbeitrag für cmpnd. Sein Modul Flex für das DSPy-Framework verändert den Optimierungsprozess. Statt nur den Prompt zu optimieren, gibt Flex dem Optimierer die Kontrolle über den ausführbaren Code. Das betrifft alle, die KI nicht nur als Chat-Spielzeug, sondern als Baustein in Produktivsystemen nutzen.
Der Paradigmenwechsel von der Anweisung zur Architektur
Die Entwicklungsgeschichte von DSPy lässt sich laut Isaac direkt an den Fähigkeiten der zugrunde liegenden Modelle ablesen. 2022 musste man Modellen noch zeigen, wie eine Aufgabe aussieht. Optimierer wie BootstrapFewShot wählten automatisch passende Beispiel-Paare aus, um das Verhalten zu steuern. Als Modelle lernten, selbst gute Prompts zu schreiben, übernahmen Optimierer wie MIPROv2 oder GEPA diese Aufgabe und verbesserten die Anweisungen iterativ. Jetzt sind Modelle zu exzellenten Programmierern geworden. Flex nutzt diese Fähigkeit: Das Modell bekommt nicht mehr nur das Skript der Anweisungen, sondern den gesamten Programmcode. Der Optimierer kann Funktionen zerlegen, Hilfsroutinen schreiben, Routing-Logik implementieren und gleichzeitig die Prompts verfeinern. Das ist kein Add-on, sondern eine neue Ebene der Automatisierung. Prompt-Engineering ist nicht mehr der entscheidende Hebel. Es ist die Architektur.
So funktioniert Flex in DSPy
Die Integration ist unkompliziert. Man ersetzt den bestehenden Predict- oder ReAct-Baustein durch dspy.Flex(YourSignature). Bis zur Optimierung verhält sich Flex wie ein normales Predict-Modul, optional mit Werkzeugen für einen ReAct-Agenten. Der Unterschied zeigt sich, wenn man Flex an den GEPA-Optimierer übergibt. GEPA erhält Zugriff auf den ausführbaren Quellcode des Moduls, nicht nur auf dessen Parameter. Der Reflexionsprozess kann nun eigene Funktionen schreiben, Bedingungen einbauen und entscheiden, ob ein Schritt überhaupt ein Modell benötigt. Sicherheit ist dabei zentral: Code, den ein Modell geschrieben hat, gilt als unvertrauenswürdig. Deshalb führt Flex den generierten Quellcode standardmäßig in einer Sandbox aus. Nur die explizit definierten Predictor-Aufrufe und übergebenen Werkzeuge dürfen zurück in den Hauptprozess. Die Obergrenze max_predictor_calls begrenzt, wie oft diese Brücke pro Vorwärtslauf überschritten wird. So bleibt die Kontrolle beim Entwickler, während das Modell kreativ in der Sandbox arbeitet.
Der harte Praxis-Test: Geospatiale Konflationsaufgabe
Für die Evaluation nutzte der Autor eine Aufgabe vom Data + AI Summit: die geospatiale Konflationsaufgabe. Es geht darum, anhand von zwei Ortsangaben zu entscheiden, ob es sich um denselben physischen Ort handelt. Simpel auf den ersten Blick, tückisch im Detail. KIN CAFE und KIN an derselben Adresse sind eindeutig derselbe Ort. Bei CONCESSION #2 KEN MERCER SPORTS PARK und KEN MERCER SPORTS PARK derselben Adresse handelt es sich jedoch um zwei getrennte Einrichtungen. Mit 1.029 gelabelten Paaren und 240 gehaltenen Datensätzen ist die Benchmark anspruchsvoll, die Zufallswahrscheinlichkeit liegt bei 50 Prozent. Das Baseline-System, ein einfacher dspy.Predict mit einem Modellaufruf pro Datensatz, erreicht 90,4 Prozent Genauigkeit bei Kosten von 0,98 Dollar pro tausend Datensätzen. Optimiert man nur den Prompt mit GEPA, steigt die Genauigkeit auf 92,5 Prozent. Doch der Prompt wird deutlich länger, und jeder Datensatz kostet zusätzliche Tokens. Das Ergebnis: 2,88 Dollar pro tausend Datensätzen, fast dreimal so teuer wie die Basislinie und 48 Prozent langsamer.
Flex bietet dem Optimierer einen zweiten Hebel: den Modul-Code. Als GEPA unverändert auf das Flex-Programm losgelassen wurde, stieg die Genauigkeit von 90,4 auf 95,0 Prozent – bei gesunkenen Kosten von 0,70 Dollar pro tausend Datensätzen. Das ist 28 Prozent günstiger und 40 Prozent schneller als die ursprüngliche Baseline. Möglich wird das, weil viele Vergleiche rein deterministisch gelöst werden können. Das Reflexionsmodell schrieb Code, um einfache Fälle zu identifizieren und direkt an Python-Funktionen weiterzuleiten. Dadurch reduzierten sich die LLM-Aufrufe um 75 Prozent. Das System ruft seltener an, und wenn, dann präziser, weil die Sandbox bereits Arbeit geleistet hat.
Die Metrik als Steuerungselement
Isaac zeigt, dass man dieses Verhalten gezielt steuern kann, indem man die Metrik anpasst. Eine GEPA-Metrik liefert nicht nur einen finalen Score, sondern auch sprachliches Feedback an den Optimierer. Mit Flex kann diese Metrik zusätzlich sehen, wie viele Sprachmodell-Aufrufe ein generiertes Programm pro Datensatz macht. Der Autor baute eine Strafe in den Score ein: score = max(0.0, correct – PENALTY * n_llm_calls). Bei Lambda gleich null sind Aufrufe gratis, der Optimierer jagt nur der Genauigkeit hinterher. Steigt Lambda, muss jeder LLM-Aufruf mehr an Genauigkeit zurückbringen, als er kostet. Der Optimierer löst dann Fälle in Python und reserviert das Modell für wirklich unklare Fälle. Ab Lambda 1,0 kann sich ein Aufruf nie mehr amortisieren; das System ruft das Modell praktisch nie mehr auf.
Der Autor hat Lambda über die Werte 0, 0.05, 0.1, 0.2 und 0.4 gesweept. Das Programm lief auf Haiku 4.5, dem schwächsten und günstigsten Claude-Modell, während Opus 5 als Reflexionsmodell den Code umschrieb. Bei Lambda null erreichte das System 95 Prozent Genauigkeit mit 0,25 Modellaufrufen pro Datensatz und Kosten von 0,70 Dollar. Bei Lambda 0,4 sank die Genauigkeit auf 92,1 Prozent – statistisch nicht unterscheidbar von der Baseline, die immer das Modell nutzt. Aber die Kosten betrugen nur noch 0,01 Dollar pro tausend Datensätzen, und die Latenz sank von 1.924 Millisekunden auf 65 Millisekunden. Hohe Strafen landen durchweg auf demselben Niveau: Parität mit der Baseline bei einem Bruchteil des Preises. Diesen Kompromiss gehen die meisten Produktionssysteme bereitwillig ein.
Was die KI tatsächlich in den Code geschrieben hat
Ein Blick auf den generierten Quellcode lohnt sich. Bei Lambda 0,4 entstand ein Programm von etwa zweihundert Zeilen Python, komplett vom Reflexionsmodell geschrieben. Der Kopf des Codes trägt den Kommentar: „Die LLM ist ein LAST-RESORT-Fallback.“ Die Logik ist in drei Stufen organisiert. Zuerst normalisiert das System die Namen: Großbuchstaben, Entfernung von Franchise-Nummern, Rechtsnachfolger und etwa vierzig generische Geschäftswörter wie CAFE, RESTAURANT oder GRILL. Was übrig bleibt, ist der charakteristische Teil des Namens – bei KIN CAFE eben nur KIN. Adressen werden in Hausnummer und Straßenkern zerlegt, Einheitenangaben und Straßentyppräfixe werden verworfen. Danach vergleicht das System die charakteristischen Namens-Tokens per Fuzzy-Similarity und ordnet sie in drei Kategorien ein: sichere Treffer, sichere Fehlschläge, Unsicherheiten. Hausnummern werden getrennt von Straßennamen behandelt, weil das Modell herausfand, dass die Hausnummer ein starkes Signal ist. In der dritten Stufe, der Entscheidung, greifen kombinierte Regeln für Namen, Adresse und Distanz zwischen zwei Geocodes. Zum Beispiel: Stimmen Name und Adresse überein und liegen sie unter 400 Metern, handelt es sich um denselben Ort. Gleicher Name, aber verschiedene Hausnummern mit über 120 Metern Abstand? Das sind zwei Filialen einer Marke.
Nur wenn keine der Entscheidungsregeln greift, wird das Modell gerufen. Und selbst dann geht es nicht allein. Das Modul hängt seine eigene Analyse an: die geparsten Hausnummern, die Straßenkerne, die Ähnlichkeitswerte. Zusätzlich werden die Anweisungen des Richters mitgeführt, die die gelernten Domänenregeln komprimiert zusammenfassen. Bei Lambda 0,4 wurde dieser Fallback in 240 Datensätzen genau einmal aktiviert. Der Optimierer hat gelernt, die einfachen Fälle besser zu lösen als ein kleines Modell, und die KI sieht nur noch die Fälle, die wirklich Urteilsvermögen brauchen.
Vier Muster, die in der eigenständigen Optimierung auftauchen
Ein weiteres Experiment zeigt, dass das kein Einzelfall ist. Der Autor hat Flex und GEPA auf SWE-bench Pro gerichtet, einem Coding-Benchmark mit realen GitHub-Issues. Die Aufgabe: ein Issue lesen und eine Lösung generieren. Haiku 4.5 löste ohne Optimierung null von zwölf Problemen. Nach einer Modifikation der Metrik und einer Beschränkung der Metrik-Aufrufe auf 60 löste das optimierte Programm vier von zwölf Problemen. Das System entwarf selbstständig einen Software-Engineering-Workflow, der Python und LLM-Aufrufe mischt, um zu recherchieren, Entwürfe zu erstellen, zu evaluieren, zu reparieren und eine endgültige Antwort abzugeben. Isaac warnt, dass dies ein Pilotexperiment ist. Doch es ist beeindruckend, wie ein Harness in wenigen Durchläufen vier von zwölf Problemen löst, während Haiku in einem ausgereiften, manuell gebauten Harness laut Autor 39 Prozent erreicht.
Betrachtet man alle Experimente, fallen vier wiederkehrende Muster auf. Erstens die Zerlegung: Eine Aufgabe wird in Schritte unterteilt, die jeweils eigene Implementierungen erhalten. Zweitens die Methodenauswahl: Für jeden Schritt wird entschieden, ob deterministischer Code oder ein Modellaufruf besser geeignet ist. Drittens das Routing: Unterschiedliche Eingaben sind unterschiedliche Aufgaben, klare Fälle gehen den billigen Weg, mehrdeutige den aufwendigen. Viertens die Evolution: Sobald die Struktur steht, werden die inneren Details verfeinert – Signaturen, Anweisungen, Code. Handgeschriebene Harnesses machen diese Schritte auch, aber sie entwickeln sich nicht von selbst weiter. Sobald neue Modelle, Daten oder Taktiken verfügbar sind, muss ein Mensch das Skript umschreiben. Flex kompiliert diese Harnesses kontinuierlich. Entwickler können so über Modelle und Metriken hinweg Kosten, Latenz und Genauigkeit ausbalancieren, ohne das Fundament neu zu bauen. Das ist keine Zukunftsmusik, sondern eine funktionierende Werkzeugkiste.
Quelle: cmpnd.ai
