Beliebte Suchanfragen
//

Closing the Loop: Ein Prompt-Iteration Workflow für Databricks Genie

10.8.2026 | 12 Minuten Lesezeit

Teil 03 beschrieb den Verbesserungszyklus in einem einzigen Satz: schwache Kategorien identifizieren, die Fehlschläge analysieren, die Korrektur anwenden, erneut ausführen, vergleichen. Das war soweit richtig, aber „die Korrektur anwenden" verbirgt einen erheblichen Teil der eigentlichen Arbeit. In der Praxis bedeutet das, zwischen vier Konfigurationshebeln zu wählen, die jeweils unterschiedlich weit reichen und einen unterschiedlichen Wirkungsradius haben. Wird der falsche Hebel gewählt, lässt sich zwar der betrachtete Fehlschlag beheben, gleichzeitig werden aber möglicherweise drei andere Abfragen beeinträchtigt, ohne dass dies unmittelbar auffällt.

Dieser Artikel arbeitet diese Entscheidung systematisch durch, sodass Verbesserungen nachvollziehbar bleiben, Regressionen auf eine Ursache zurückgeführt werden können und die Konfiguration am Ende wie eine bewusste Spezifikation wirkt und nicht wie eine Ansammlung angehäufter Vermutungen.

Die vier Hebel

Die SQL-Generierung eines Genie Agents wird durch vier Arten von Konfiguration geprägt. Spaltenkonfiguration, Join-Spezifikationen und Beispiel-SQL liegen im Knowledge Store des Agents, Anweisungen werden separat als freitextliche Direktiven festgelegt. Bevor einer dieser Hebel verändert wird, lohnt es sich zu wissen, wie weit jeder einzelne tatsächlich reicht.

Die Spaltenkonfiguration ist der am engsten begrenzte Hebel. Beschreibungen, Synonyme und Beispielwerte, die einer einzelnen Spalte zugeordnet sind, wirken sich nur auf Abfragen aus, die diese Spalte betreffen. Das macht sie zur richtigen ersten Anlaufstelle, wenn Genie einen Feldnamen falsch interpretiert, bei einem Filter den falschen Literalwert wählt oder ein Synonym übersieht, das ein Nutzer tatsächlich verwendet hat.

Join-Spezifikationen liegen auf einer ähnlichen Ebene. Wird explizit festgelegt, wie zwei Tabellen zusammenhängen, über welche Spalten, in welcher Richtung, lassen sich Fehler bei Multi-Table-Joins beheben, ohne dass sonst etwas verändert wird. Die meisten fehlerhaften Joins lassen sich auf eine Beziehung zurückführen, die Genie nie mitgeteilt wurde.

Beispiel-SQL setzt eine Ebene höher an, nicht bei der Spalte, sondern beim Muster. Eine Frage, gepaart mit der zugehörigen korrekten Abfrage, vermittelt Genie die Struktur einer ganzen Klasse von Fragen, ohne etwas über Abfragen außerhalb dieser Klasse festzulegen. Dieser Hebel eignet sich, wenn Genie bereits die richtige Tabelle wählt, aber bei der Aggregation, der GROUP BY-Klausel oder dem Join-Ansatz danebenliegt.

Anweisungen bilden die Ausnahme: Freitext, global angewendet, auf jede Abfrage, die der Agent bearbeitet. Sie sind zugleich der mit Abstand mächtigste Hebel, eine einzelne, gut platzierte Anweisung, die eine Zeitkonvention definiert oder festlegt, welche Tabelle für ein bestimmtes Konzept zuständig ist, kann ein Dutzend Fehlschläge auf einmal beheben, und gleichzeitig der gefährlichste, weil dieselbe Reichweite auch das Verhalten für Abfragen verändern kann, die mit dem ursprünglichen Problem nichts zu tun hatten. Anweisungen sollten daher als Letztes eingesetzt werden.

Im Moment der Entscheidung fühlt sich das selten so an. Anweisungen sind der Hebel, zu dem viele zuerst greifen, weil sie sich wie normale Sprache lesen und wie die schnellste verfügbare Lösung wirken. Tatsächlich sind sie meist die langsamste Lösung, sobald die Zeit eingerechnet wird, die später aufgewendet werden muss, um herauszufinden, was dadurch beschädigt wurde.

Die Ausgabe des Test-Harnesses lesen

Bevor irgendeine Konfiguration verändert wird, sollte die Aufschlüsselung nach Kategorien betrachtet werden. Der Gesamtscore zeigt, wie es insgesamt läuft, die Kategorieansicht zeigt, wo genauer hingeschaut werden sollte, und die einzelnen Fehlschläge zeigen, warum.

Jeder Fehlschlag lässt sich genau einem der vier Hebel zuordnen, und diese Zuordnung vor dem Schreiben jeglicher Konfiguration zu finden, ist im Grunde die eigentliche Aufgabe. Wird sie falsch getroffen, wird häufig ein Problem gelöst und gleichzeitig, unbemerkt, ein neues geschaffen.

FehlermusterGrundursacheHier ansetzen
Falsche Tabelle ausgewähltGenie weiß nicht, welche Tabelle für ein Konzept zuständig istAnweisung, die den Zweck der Tabelle benennt
Falscher Filterwert oder LiteralKeine Beispielwerte für diese Spalte hinterlegtSpaltenkonfiguration: Beispielwerte hinzufügen
Richtige Tabelle, richtige Struktur, falsche AggregationErwartetes Muster nicht demonstriertBeispiel-SQL-Paar
Zeitraum falsch interpretiertKeine Konvention für Begriffe wie „letztes Quartal" oder „YTD" definiertAnweisung, die die eigenen Zeitkonventionen definiert
Mehrdeutiger Begriff falsch aufgelöstMehrere gültige Interpretationen, keine explizite KlärungSpaltenkonfiguration-Synonym oder gezielte Anweisung
Multi-Table-Join fehlt oder ist falschJoin-Schlüssel unbekannt oder Beziehung nicht explizitJoin-Spezifikation
Korrektes SQL, falsches ErgebnisDer Erwartungswert des Testfalls ist möglicherweise veraltetTestfall aktualisieren, nicht Genie

Diese letzte Zeile lässt sich leicht übersehen, verdient aber, zuerst geprüft zu werden. Bevor Genie für irgendetwas verantwortlich gemacht wird, sollte zunächst geklärt werden, ob der Testfall selbst noch die Realität widerspiegelt, Tabellen werden umbenannt, Spalten kommen hinzu, Werte verschieben sich nach einem Reload. Dreißig Sekunden, die investiert werden, um dies auszuschließen, sparen häufig viel Zeit, die sonst in die Suche nach einer Lösung für ein nicht existierendes Problem fließen würde.

Es lohnt sich außerdem, über einzelne Fälle hinweg zu lesen, nicht nur innerhalb eines Falls. Ein fehlgeschlagener Test in einer Kategorie ist ein einzelner Datenpunkt. Vier von fünf fehlgeschlagenen Multi-Table-Join-Tests sind ein Muster und deuten fast immer auf eine einzelne fehlende Join-Spezifikation hin statt auf vier voneinander unabhängige Fehler, die Diagnose sollte auf dieser Ebene erfolgen, nicht Testfall für Testfall. Der Schwierigkeitsgrad liefert eine zweite Achse: Häufen sich Fehlschläge bei schwierigen Fällen mit mehreren Verknüpfungsschritten, deutet das meist auf fehlende Join-Spezifikationen hin, während gleichmäßig über leichte und mittlere Fragen verteilte Fehlschläge auf ein grundlegenderes Problem hindeuten, etwa eine fehlende Tabellenbeschreibung oder einen Begriff, den Genie bereits falsch interpretiert, bevor überhaupt mit dem Schreiben von SQL begonnen wird.

Ein anderes Signal ist ein gleichzeitiger Rückgang der Genauigkeit über mehrere Kategorien hinweg, nachdem eine Änderung eingespielt wurde. Das sind nicht vier neue Probleme, sondern eine einzige Änderung, die mit etwas bereits Bestehendem in Konflikt geraten ist. In diesem Fall sollte die Änderung zurückgenommen, die Rückkehr zur Ausgangsbasis bestätigt und das ursprüngliche Problem anschließend mit einem enger gefassten Hebel angegangen werden. Weitere Anweisungen aufzuschichten löst eine kategorienübergreifende Regression nicht, sondern ist häufig der Auslöser für die nächste.

Das Regressionsproblem

Anweisungen bleiben nicht isoliert. Sie wirken zusammen mit allem, was bereits in der Konfiguration des Agents vorhanden ist, und dieses Zusammenwirken kann zu Verhalten führen, das niemand tatsächlich beabsichtigt hat.

Ein Beispiel, wie sich das in der Praxis auswirkt. Ein Genie Agent, der auf einem Franchise-Datenmodell aufbaut, verfügt über eine Tabelle transactions und eine Tabelle franchises, verknüpft über franchiseID. Frühe Harness-Läufe zeigen, dass Multi-Table-Joins durchgängig fehlschlagen, Genie fragt weiterhin nur transactions ab, statt mit franchises zu verknüpfen, sobald eine Frage die Franchise-Ebene betrifft. Die naheliegende Lösung ist eine Anweisung: „Beim Analysieren von Umsatz nach Franchise die Tabelle transactions mit der Tabelle franchises über franchiseID verknüpfen." Das funktioniert. Die Join-Genauigkeit in der Multi-Table-Kategorie steigt.

Beim nächsten vollständigen Lauf bricht dann etwas anderes. Einfache Aggregationen, die zuvor allein auf der Tabelle transactions basierten, Abfragen, die nichts mit Franchise-Auswertungen zu tun haben, enthalten nun einen unnötigen Join. Genie hat die Anweisung weiter verallgemeinert als beabsichtigt, und der Wirkungsradius hat Abfragen erreicht, die zuvor unproblematisch waren.

Das ist das Regressionsproblem, und es handelt sich nicht um einen Sonderfall, sondern um die gewöhnlichen Kosten, breit angelegte Konfiguration zu einem System hinzuzufügen, in dem Anweisungen miteinander interagieren. Ein Harness mit Abdeckung beider Abfragetypen erkennt das sofort. Ein Harness, der nur die zuvor fehlschlagende Kategorie abdeckt, zeigt die Verbesserung und übersieht den Schaden vollständig.

Die Absicherung besteht darin, sich vor dem Schreiben von irgendetwas zu fragen, welcher der am engsten gefasste Hebel ist, der das Problem dennoch löst:

  • Spaltenkonfiguration oder Join-Spezifikation, wirkt nur auf diese eine Spalte oder Beziehung, kein kategorienübergreifendes Risiko
  • Beispiel-SQL, betrifft Abfragen, die strukturell ähnlich zum Beispiel sind, begrenzter Wirkungsradius
  • Gezielte Anweisung, auf einen bestimmten Kontext beschränkt, etwa „wenn nach einer Franchise-Aufschlüsselung gefragt wird…"
  • Breite Anweisung, gilt überall, sollte erst eingesetzt werden, wenn nichts Engeres funktioniert, und danach sofort die vollständige Testsuite ausgeführt werden Für das Franchise-Beispiel bedeutet das, auf die breite Anweisung zu verzichten und stattdessen eine Join-Spezifikation zu verwenden, die die Beziehung über franchiseID direkt benennt. Sie gibt Genie den Join-Schlüssel, ohne festzulegen, wann er zu verwenden ist, die Entscheidung, ob ein Join notwendig ist, bleibt bei Genie, basierend auf der tatsächlichen Frage, statt durch eine Anweisung erzwungen zu werden, die die beiden Abfragetypen nicht unterscheiden kann.

Das Iterationsprotokoll

Aus dem oben beschriebenen Regressionsproblem ergeben sich drei Regeln unmittelbar.

Eine Änderung pro Iteration. Zwei fehlschlagende Kategorien sollten nicht im selben Lauf behoben werden. Verbessern sich beide Änderungen, lässt sich nicht feststellen, welche dafür verantwortlich war, sinkt die Genauigkeit, lässt sich nicht feststellen, welcher Änderung das anzulasten ist. Das macht die einzelne Iteration langsamer, insgesamt aber schneller, weil sich jedes Ergebnis, positiv wie negativ, auf etwas Konkretes zurückführen lässt.

Die vollständige Testsuite bei jedem Lauf ausführen, nicht nur die gerade bearbeitete Kategorie. Kategorienübergreifende Schäden bleiben ohne vollständige Abdeckung unsichtbar: Eine Änderung, die zehn Punkte bei Joins gewinnt und gleichzeitig unbemerkt acht Punkte bei Aggregationen verliert, ist kein Erfolg, und ein Teillauf zeigt diesen Verlust niemals.

Läufe in MLflow vergleichen, bevor irgendetwas entschieden wird. Die Regel ist binär, keine Ermessensfrage: Hat sich die Zielkategorie verbessert, und sind alle übrigen Kategorien stabil geblieben oder haben sich ebenfalls verbessert? Wenn beides zutrifft, bleibt die Änderung bestehen. Ist irgendetwas anderes gesunken, gab es einen Konflikt, und es braucht erneut eine engere Lösung.

1runs = mlflow.search_runs(experiment_names=[EXPERIMENT_NAME])
2comparison = runs[[
3    "run_id",
4    "start_time",
5    "params.change_description",
6    "metrics.sql_semantic_correctness/rating/average",
7    "metrics.category_joins/accuracy",
8    "metrics.category_aggregations/accuracy",
9]]
10display(comparison.sort_values("start_time", ascending=False))

Ein Parameter change_description bei jedem Lauf ist eine kleine Ergänzung, die sich schnell auszahlt. Ohne ihn sind Run-IDs bedeutungslos und man ist auf die eigene Erinnerung angewiesen, um zu wissen, was jeweils getestet wurde. Mit ihm dient die Tabelle zugleich als Entscheidungsprotokoll, jede Änderung, ihre Auswirkung auf jede Kategorie, ob sie sich bewährt hat.

Wird dies konsequent durchgehalten, summiert sich der Effekt auf positive Weise. Eine Reihe kleiner, gezielter Korrekturen, die jeweils eine Kategorie verbessern, ohne die übrigen zu beeinträchtigen, addiert sich über die Zeit sauber. Eine Reihe breiter Anweisungen, die jeweils ein Problem lösen und dabei unbemerkt ein anderes untergraben, bewirkt das Gegenteil: eine Konfiguration, die niemand mehr vollständig erklären kann, und die sich später kaum noch sicher vereinfachen lässt.

Wann die Testsuite erweitert werden sollte

Die Testsuite, mit der man startet, deckt nur ab, was zuvor bedacht wurde. Der produktive Betrieb bringt immer weitere Fälle zutage.

Zwei Momente erfordern, sofort einen Testfall hinzuzufügen. Der erste ist jede von Nutzern gemeldete falsche Antwort, sie sollte umgehend in einen Testfall mit der korrekten SQL als erwartetem Ergebnis überführt werden, damit der Harness genau dieses Fehlermuster von da an erkennt. Der zweite ist eine Korrektur, die zwar funktioniert, sich aber unsicher anfühlt, in diesem Fall lohnt es sich, eine Variante der Frage hinzuzufügen, die dasselbe Verhalten aus einem leicht veränderten Blickwinkel prüft. Eine belastbare Korrektur besteht auch diese Variante, eine fragile nicht, und das sollte lieber jetzt auffallen als später im produktiven Betrieb.

Es gibt zudem eine langsamer wirkende Quelle: den eigenen Gesprächsverlauf von Genie. Fragen, die häufig auftauchen, aber nicht in der Testsuite enthalten sind, sollten ergänzt werden. Gleiches gilt für Fragen, die Nutzer unmittelbar umformulieren, ein Hinweis darauf, dass die erste Antwort nicht überzeugt hat. Auch Folgefragen sind aufschlussreich, da sie häufig eine Annahme über Konventionen offenlegen, die die Testsuite bislang nie geprüft hat.

Die Testsuite sollte versioniert und zusammen mit der Konfiguration des Agents gepflegt werden. Ändert sich etwas an den zugrunde liegenden Daten, eine Umbenennung, eine entfernte Spalte, ein aktualisierter Schlüssel, erkennt eine aktuelle Testsuite die Abweichung, bevor ein Nutzer sie bemerkt.

Konfiguration als Code

Wird diese Disziplin lange genug durchgehalten, wirkt die Konfiguration des Agents nicht mehr wie eine Ansammlung einzelner punktueller Korrekturen. Sie wird zu einer Spezifikation, bei der jede Anweisung, jede Beispielabfrage, jede Join-Spezifikation, jede bewusst gesetzte Spaltenbeschreibung auf einen Testfall zurückgeführt werden kann, der ihre Aufnahme gerechtfertigt hat. Konfiguration und Testsuite werden zu zwei Hälften desselben Artefakts: die eine beschreibt, was das System tut, die andere, was es tun soll.

Dieses Zusammenspiel bringt zwei Vorteile, die Konfiguration allein nicht bietet.

Der erste ist sicheres Löschen. Eine Anweisung ohne zugehörigen Testfall lässt sich ohne größeres Risiko entfernen, entweder war sie nie notwendig, oder ihre Wirkung wurde nie tatsächlich überprüft, in beiden Fällen gibt es nichts zu verlieren. Selbst eine Anweisung mit verknüpftem Testfall lässt sich in gewissem Sinn sicher entfernen: War sie tatsächlich unverzichtbar, zeigt der Harness das umgehend.

Der zweite Vorteil ist sicheres Onboarding. Wer neu zu einem Projekt hinzukommt, kann die Testsuite ausführen, um den aktuellen Stand zu sehen, und anschließend die Konfiguration lesen, um zu verstehen, wie es dazu gekommen ist. Zusammen fungieren beide als ausführbare Spezifikation, kein Dokument, das lediglich eine Absicht beschreibt, sondern etwas, das Verhalten tatsächlich überprüft, derselbe Wert, den Unit-Tests in der klassischen Softwareentwicklung liefern, hier angewendet auf das Verhalten eines KI-Agents.

Das begleitende Repository zeigt das konkret: ein Ordner genie-ontology/ mit instructions.md, example_queries.sql und join_specs.md, eine Datei pro Hebel, versioniert direkt neben der Testsuite. Ein Git-Diff auf einer dieser Dateien zeigt, was sich geändert hat, wann, und, weil der verknüpfte Testfall unmittelbar daneben liegt, warum.

Es ist dieselbe Idee von Semantik als Code aus Teil 01, nur eine Ebene höher angewendet. Dort war das versionierte Artefakt eine Metrikdefinition. Hier ist es ein Verhaltensvertrag: was Genie tut, wenn jemand eine Frage stellt. Dies mit derselben Sorgfalt bei Review und Versionskontrolle zu behandeln wie Code, macht es zu etwas, dem tatsächlich vertraut werden kann.

Fazit

Über vier Teile hinweg hat diese Serie ein Argument in Etappen entwickelt. Teil 01 bildete das Fundament: eine semantische Schicht, die geschäftliche Bedeutung so codiert, dass Menschen und KI-Systeme mit denselben Definitionen arbeiten. Teil 02 benannte die Disziplinen, die verhindern, dass ein GenAI-System auf diesem Fundament allmählich verfällt, schlankes Tooling, fokussierte Prompts, beobachtbare Pipelines, ein Feedback-Loop, der sich tatsächlich schließt. Teil 03 machte aus diesem Feedback-Loop lauffähigen Code: einen Harness, der Genie befragt, das SQL bewertet und die Ergebnisse protokolliert. Dieser Artikel ist die andere Hälfte, was zu tun ist, sobald diese Ergebnisse vorliegen.

Die dahinterliegende Regel ist einfach, auch wenn ihre Anwendung Disziplin erfordert: den am engsten gefassten Hebel wählen, der das Problem löst, in dieser Reihenfolge, zuerst Spaltenkonfiguration, dann Join-Spezifikationen, dann Beispiel-SQL, dann Anweisungen, und erst zuletzt die breite Anweisung als letztes Mittel. Eine Änderung nach der anderen. Jedes Mal die vollständige Testsuite. Wird das konsequent befolgt, wird die entstehende Konfiguration nicht nur genauer, sie wird zu etwas, das auch jemand anderes noch in einem Jahr öffnen und tatsächlich verstehen kann.

Ein unevaluierter Genie Agent läuft auf Hoffnung. Einer mit Harness und einer disziplinierten Art, dessen Ergebnisse zu nutzen, läuft stattdessen auf Evidenz, nicht weil er aufhört, Fehler zu machen, sondern weil jeder Fehler erkannt, jede Korrektur gemessen und der gesamte Verlauf irgendwo festgehalten wird, statt sich nur auf Erinnerung zu verlassen.

//

Weitere Artikel in diesem Themenbereich

Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.

//
Jetzt für unseren Newsletter anmelden

Alles Wissenswerte auf einen Klick:
Unser Newsletter bietet dir die Möglichkeit, dich ohne großen Aufwand über die aktuellen Themen bei codecentric zu informieren.