DSPy: Ersatz von sprödem Prompt-Engineering durch kompilierte LLM-Pipelines
Ich stoße immer wieder auf dasselbe Hindernis, wenn ich über Finanz-KI-Pipelines nachdenke: Man kann etwas bauen, das in den Testfällen wunderbar funktioniert, und dann zusehen, wie es im Stillen auseinanderfällt, wenn ein Lieferant sein Rechnungsformat ändert oder ein neuer Transaktionstyp auftaucht. Die Instabilität liegt fast immer in den Prompts – handgefertigte Strings, die niemand mehr anfassen möchte. DSPy, vorgestellt von Khattab et al. in Stanford und veröffentlicht auf der ICLR 2024, schlägt einen grundlegend anderen Weg zum Aufbau von LLM-Pipelines vor, der von jedem, der Buchhaltungsaufgaben automatisieren möchte, sorgfältig geprüft werden sollte.
Das Paper
DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines (Khattab, Singhvi, Maheshwari et al., ICLR 2024) definiert die Konstruktion von LLM-Pipelines als Programmierproblem statt als Prompt-Engineering-Problem neu. Die Kernbeobachtung ist, dass moderne LLM-Anwendungen typischerweise als Sammlungen fest kodierter Prompt-Strings – was die Autoren „Prompt-Templates“ nennen – aufgebaut sind, die mit Python-Kontrollfluss zusammengehalten werden. Wenn sich das Modell ändert oder sich die Aufgabenverteilung verschiebt, muss jemand diese Strings mühsam von Hand umschreiben.
DSPy ersetzt Prompt-Templates durch zwei Abstraktionen: Signatures (Signaturen) und Modules (Module). Eine Signatur ist eine typisierte, deklarative Spezifikation dessen, was ein LM-Aufruf tun soll, kompakt geschrieben als question -> answer oder mit expliziten Feldbeschreibungen in einer Python-Klasse. Ein Modul verpackt eine Signatur mit einer Argumentationsstrategie – ChainOfThought, ReAct, ProgramOfThought, MultiChainComparison und so weiter. Die entscheidende Ergänzung ist ein Compiler (das Paper nennt ihn einen Teleprompter), der ein DSPy-Programm, einen kleinen etikettierten Datensatz und eine Validierungsmetrik nimmt und dann automatisch Few-Shot-Demonstrationen generiert, daraus auswählt und Prompts produziert, die für diese Metrik optimiert sind. Der Compiler benötigt keine Etiketten bei jedem Zwischenschritt – er kann Demonstrationen per Bootstrapping erstellen, indem er ein Lehrer-Programm auf unbeschrifteten Eingaben ausführt und die Pfade filtert, die zu korrekten Endergebnissen führen.
Kernideen
- Signaturen entkoppeln Absicht von Implementierung. Die Angabe von
question, context -> answerreicht für DSPy aus, um zu wissen, wie der zugrunde liegende LM-Aufruf konstruiert, aufgerufen und optimiert werden muss. Der Entwickler schreibt niemals einen Prompt-String. - Kompilierung ist metrikgesteuertes Bootstrapping. Der
BootstrapFewShot-Optimierer lässt das Programm mit Trainingsdaten laufen, sammelt Eingabe-Ausgabe-Spuren, bei denen die Pipeline erfolgreich ist, und verwendet diese als Demonstrationen – eine menschliche Annotation der Zwischenschritte der Argumentation ist nicht erforderlich. - Compiler macht kleine Modelle nutzbar. Bei GSM8K (mathematische Textaufgaben) erreicht ein Standard-Llama2-13b mit Zero-Shot-Prompting 9,4 %. Nach der DSPy-Kompilierung mit Reflection- und Ensemble-Modulen erreicht es 46,9 %. T5-Large (770 Mio. Parameter), ein Modell, das die meisten für komplexe Argumentation abgeschrieben hatten, erreicht bei HotPotQA mit nur 200 beschrifteten Beispielen eine exakte Trefferquote von 39,3 %.
- Experten-Prompts sind nicht das Limit. Bei GSM8K erreicht GPT-3.5 mit Standard-Few-Shot-Prompting 25,2 %. Von Experten erstellte Chain-of-Thought-Prompts heben dies auf etwa 72–73 %. Die kompilierte Reflection-and-Ensemble-Pipeline von DSPy treibt es auf 81,6 % – ohne dass ein Mensch Prompts schreiben muss.
- Programme sind komponierbar. Eine Multi-Hop-Retrieval-QA-Pipeline in DSPy umfasst etwa 12 Zeilen Python. Das Äquivalent in LangChain, so die Autoren, enthält 50 Strings mit über 1000 Zeichen handgefertigtem Prompt-Inhalt.
- Drei Kompilierungsstufen. Der Optimierer arbeitet in den Phasen: Kandidatengenerierung (Bootstrapping von Spuren), Parameteroptimierung (Zufallssuche oder Optuna über Hyperparameter) und Optimierung höherer Ordnung (Ensembles, dynamischer Kontrollfluss).
Was Bestand hat – und was nicht
Die empirischen Ergebnisse sind real und substanziell. Die Steigerung von 9,4 % auf 46,9 % bei GSM8K mit Llama2-13b unter Verwendung von nur einer Handvoll beschrifteter Trainingsbeispiele ist nicht inkrementell – es ist die Art von Sprung, die kleine, günstige Modelle für Aufgaben rentabel macht, die zuvor GPT-4 erforderten. Die Architektur ist zudem wirklich elegant: Signaturen sind leicht zu lesen, Module sind kombinierbar und die Abstraktion wirkt für die demonstrierten Aufgaben nicht lückenhaft.
Die Einschränkungen sind jedoch real, auch wenn das Paper sie nicht in einem eigenen Abschnitt diskutiert. Die wichtigste: Der Compiler ist nur so gut wie Ihre Metrik. Wenn Ihre Validierungsmetrik unpräzise ist oder nicht mit der tatsächlichen Aufgabenqualität übereinstimmt – was in der Praxis extrem häufig vorkommt –, wird der Optimierer clevere Wege finden, sie zu maximieren, während er bei dem versagt, was Ihnen eigentlich wichtig ist. In einem strukturierten Bereich wie der Buchhaltung könnten Sie eine Metrik definieren wie „der Buchungssatz ist ausgeglichen“, aber ein ausgeglichener Eintrag kann dennoch völlig falsche Kontencodes enthalten. Die Autoren wissen, dass dieses Problem existiert, überlassen die Lösung jedoch dem Entwickler.
Eine zweite Einschränkung: Die Kompilierung erfordert immer noch einige beschriftete Daten. Das Paper behauptet, dass man mit nur 10 Beispielen mit BootstrapFewShot auskommt und dass nur Eingabewerte benötigt werden (keine Zwischenetiketten). Das stimmt im besten Fall, aber in der Praxis sinkt die Zuverlässigkeit des Bootstrappings, wenn das Startprogramm keines der Trainingsbeispiele lösen kann. Wenn Ihre Finanz-Agent-Pipeline eine Basisgenauigkeit von nahezu Null hat – was beim Aufbau von etwas Neuem üblich ist –, tritt die Kompilierung auf der Stelle.
Drittens, und etwas subtiler: DSPy optimiert Prompts und Demonstrationen, aber es optimiert nicht die Programmstruktur selbst. Wenn Sie Module auf eine Weise zusammengeschaltet haben, die für die Aufgabe grundlegend falsch ist, wird der Compiler Ihnen nicht helfen. Das Programmdesign liegt weiterhin beim Entwickler.
Warum dies für Finanz-KI wichtig ist
Die Sprödigkeit von Prompts ist vielleicht das größte praktische Hindernis für den Einsatz von Finanz-KI-Agenten in der Produktion. Eine Pipeline, die Transaktionen kategorisiert, indem sie Beschreibungen mit Kontencodes abgleicht, wird jedes Mal schlechter, wenn sich das Format der Händlerdaten ändert, eine neue Ausgabenkategorie erscheint oder der Kontenrahmen aktualisiert wird. Mit DSPy definieren Sie die Aufgabe abstrakt (transaction_description, chart_of_accounts -> account_code, confidence) und lassen den Compiler jedes Mal die optimalen Demonstrationen finden, wenn sich die Verteilung verschiebt.
Speziell für Beancount könnte ich mir eine Pipeline vorstellen, die aus drei verketteten DSPy-Modulen besteht: eines, das strukturierte Transaktionsdaten aus rohen Bankexporten extrahiert, eines, das das am besten passende Konto im bestehenden Kontenrahmen des Ledgers sucht, und eines, das den resultierenden Buchungssatz gegen die Bedingungen der doppelten Buchführung validiert. Jedes Modul erhält seine eigene Signatur; das gesamte Programm wird gegen eine Metrik kompiliert, die sowohl die buchhalterische Korrektheit als auch die Formatkonformität prüft. Das Problem der Metrikqualität wiegt hier am schwersten – man braucht eine Metrik, die falsche Kontencodes erkennt, nicht nur unausgeglichene Buchungen –, aber das ist ein lösbares technisches Problem.
Die tiefere Implikation: DSPy verlagert die Arbeit vom „Schreiben besserer Prompts“ hin zum „Schreiben besserer Metriken und Sammeln kleiner beschrifteter Datensätze“. Das ist eine wesentlich nachhaltigere Ingenieurspraxis für ein produktives Finanzsystem, das sich mit Vorschriften, Kontenrahmenstrukturen und Transaktionsformaten im Laufe der Zeit weiterentwickeln muss.
Was man als Nächstes lesen sollte
- OPRO: Large Language Models as Optimizers (Yang et al., arXiv:2309.03409) – Google DeepMinds Ansatz zur Prompt-Optimierung durch iterative, von LMs generierte Verfeinerung; ein nützlicher Kontrapunkt zum Bootstrapping-Ansatz von DSPy.
- TextGrad: Automatic "Differentiation" via Text (Yuksekgonul et al., arXiv:2406.07496) – definiert Optimierung als Backpropagation durch Text-Feedback statt als metrikgesteuertes Bootstrapping; zeigt starke Ergebnisse bei Coding- und wissenschaftlichen Aufgaben, bei denen der Ansatz von DSPy schwächer ist.
- DSPy Assertions: Computational Constraints for Self-Refining Language Model Pipelines (Singhvi et al., arXiv:2312.13382) – fügt DSPy-Programmen harte und weiche Constraints hinzu, sodass Pipelines sich selbst korrigieren können, wenn Ausgaben gegen Domänenregeln verstoßen; direkt relevant für die Durchsetzung buchhalterischer Invarianten.
