IDas Argument gegen generierten SQL

Das Modell sollte nicht
das SQL schreiben.

Text-to-SQL ist der naheliegende Weg, einen Agenten auf eine Datenbank anzusetzen, und die Demo ist durchaus beeindruckend. Im Produktivbetrieb zeigt sich das Problem: Dieselbe Frage kompiliert zu unterschiedlichem SQL, ein stiller Join-Fehler verschiebt den Umsatz um 15 %, und die Ausgabe des Modells wird zur Angriffsfläche. Es gibt einen anderen Weg.

IIZuerst das Lob

Text-to-SQL hat den Hype verdient. In seinem Bereich.

Wo es das richtige Werkzeug ist

  • Prototypen mit wegwerfbaren Daten
  • Erkundung eines unbekannten Schemas unter Aufsicht
  • Einmalige Fragen, die jemand gegencheckt
  • Die Demo — sie überzeugt wirklich in der Demo

Wo es versagt

  • Zahlen, auf die jemand handelt
  • Nicht vertrauenswürdiger Text irgendwo im Kontext
  • Produktions-Credentials auf der Verbindung
  • Antworten, die reproduzierbar oder auditierbar sein müssen
  • Agenten, die unbeaufsichtigt laufen

Das Muster ist nicht falsch. Der Schadensradius schon. Jede Gefahr auf dieser Seite geht auf eine einzige Designentscheidung zurück: Die Ausgabe des Modells wird als Code ausgeführt.

IIIDie zwei Wege

Dieselbe Frage. Zwei Architekturen.

Verfolgen Sie eine Frage durch beide Wege — links ein freier SQL-String, rechts ein typisierter Plan. Nummerierte Markierungen verweisen auf das Gefahrenregister unten.

die Frage

Welche Region hat den höchsten Gesamtumsatz?

Weg A

Das Modell schreibt SQL

  1. das Modell improvisiert einen String 010304

    Alles, was das Modell gelesen hat — eine Nutzernachricht, eine abgerufene Zeile — kann diesen String beeinflussen.

    Durchlauf 1SELECT region, SUM(total) FROM orders GROUP BY region;Durchlauf 2 · dieselbe FrageSELECT o.region, SUM(i.amount) FROM orders o LEFT JOIN order_items i ON i.order_id = o.id GROUP BY 1;
  2. Ihre Verbindung führt ihn aus 05

    Mit der vollen Berechtigung der Verbindung. Lesen, Joinen — und sofern niemand das Flag gesetzt hat, auch Schreiben.

die Antwort

run 1 → east · 2130.50

run 2 → east · 2450.08+15% — Join-Fan-out 02

Zwei Durchläufe, zwei Zahlen. Beide plausibel. Kein Hinweis, welche — wenn überhaupt eine — stimmt.

Weg B

Das Modell reicht einen typisierten Plan ein

  1. typisierte Absicht

    Kein String — ein Wert mit Schema. Er kann nur Operationen benennen, die der Vertrag definiert.

    { "kind": "query", "version": "1", "source": "revenue", "op": "sum", "group_by": "region" }
  2. Vertragscheck

    Hash-gesichert. Eine unbekannte Operation gibt unsupported_operation mit nächsten Treffern zurück — niemals eine Vermutung.

  3. Richtliniencheck

    Ihre code-seitige Erlaubnisliste. Eine Anfrage kann die Oberfläche einschränken, niemals erweitern.

  4. deterministische Ausführung

    float64, Single-Thread, gepinnter Runtime. Gleicher Plan, gleiche Bytes, gleiche Antwort.

die Antwort

east · 2130.50

plan_hash f87610d8afeb…

decision_path "exact_spec"

Eine Antwort, mit den Hashes zur Wiederholung — nächste Woche, nächstes Quartal, in beiden Sprachen.

IVDas Gefahrenregister

Fünf Wege, wie generiertes SQL scheitert

  1. 01

    P2SQLarXiv 2308.01990

    Injection verlagert sich in den Ausgabekanal

    Eingabe-Sanitierung prüft, was ins Modell gelangt. P2SQL-Angriffe kommen in dem heraus, was es ausgibt: wohlgeformtes, bösartiges SQL, zusammengesetzt aus Anweisungen, die in einer Nutzernachricht oder einer abgerufenen Zeile versteckt sind. Kein Eingabefilter sieht es je — der Angriff ist die Ausgabe.

  2. 02

    −15%das Dashboard, das log

    Falsche Joins scheitern lautlos

    Ein Fan-out-Join zählt Zeilen doppelt, und der Umsatz weicht um 15% ab. Keine Exception, keine Warnung — falsches SQL stürzt nicht ab, es berichtet. Das Ergebnis ist immer eine Zahl, und eine plausible Zahl gibt kein Signal, dass sie falsch ist.

  3. 03

    1 → neine Frage, n Abfragen

    Dieselbe Frage, unterschiedliches SQL

    Zweimal gefragt, kann das Modell die Frage auf zwei verschiedene Arten übersetzen — manchmal zu zwei verschiedenen Antworten. Es gibt keine kanonische Abfrage zum Prüfen, Cachen oder Wiederholen. Die gestrige Zahl lässt sich nicht reproduzieren, selbst nicht zur bloßen Kontrolle.

  4. 04

    91,2 → 21,3% korrekt · Benchmark → Enterprise-Schema

    Der Genauigkeitsabgrund

    Auf sauberen Benchmark-Schemas schrieb ein führendes Modell in 91,2% der Fälle korrektes SQL. Auf realen Enterprise-Schemas: 21,3%. In derselben Forschungswelle scheiterten rund 40% der Text-to-SQL-Agenten-Läufe vollständig oder lieferten falsche Ergebnisse. Benchmarks sind ordentlich. Ihr Schema nicht.

  5. 05

    1 Prod-DBvon einem Agenten gelöscht — der Replit-Vorfall

    Der Schreibpfad war immer da

    Replits Coding-Agent löschte eine Produktionsdatenbank — trotz ausdrücklicher Anweisung, sie nicht anzufassen. Die Lehre daraus: Eine Read-only-Anweisung ist eine Bitte. Wenn die Verbindung schreiben kann, existiert der Schreibpfad — und irgendwann findet ihn eine fehlerhafte Ausgabe. Read-only muss eine Eigenschaft des Werkzeugs sein, nicht eine Zeile im Prompt.

Nicht die Ausgabe filtern.
Nicht erzeugen.

Kein SQL-String, keine Injection · keine Vermutung, kein Drift

VDas Zertifikat

Fünf Dimensionen im Vergleich

Kein LLM-zu-SQL-GeneratorEngine-README

Zertifikat der Unterschiede

Erstellungsoberflächegeneriertes SQLein freier SQL-Stringtypisierter Planeine typisierte, versionierte Absicht
Ausführungsoberflächegeneriertes SQLalles, was die Verbindung erlaubttypisierter Plan4.574 read-only-Fähigkeiten
Schreibpfadgeneriertes SQLvorhanden, sofern nicht blockierttypisierter Plankeiner, konstruktionsbedingt
Governancegeneriertes SQLPrompt-Ebene, Best-Efforttypisierter PlanCode-seitige Allow-Lists, die das Modell nicht erweitern kann
Reproduzierbarkeitgeneriertes SQLkeinetypisierter Planein Replay-Hash für jedes Ergebnis

rechte Spalte am Vertrag verankertsha256:79f1c5a6…924be9a1

Das Kleingedruckte hält stand: Die einzige Hintertür der Engine — getUnsafeRuntime — ist auf keiner modellseitigen Oberfläche vorhanden; ein Modell kann sie nicht erreichen. Und das README formuliert die Doktrin klar: Dies ist kein LLM-zu-SQL-Generator.

VIFragen

Aus dem Produktivbetrieb

Wie blockiere ich DELETE und DROP in LLM-generiertem SQL?

Das SQL nicht filtern — aufhören, es zu erzeugen. Denylists prüfen Strings, und Modelle sind endlos erfinderisch darin, neue zu produzieren. SQAI beseitigt die Klasse: Das Modell reicht einen typisierten Plan gegen 4.574 read-only-Fähigkeiten ein — eine Schreibfähigkeit, die ein Plan benennen könnte, existiert nicht.

Was ist P2SQL-Injection?

Prompt-to-SQL-Injection: schadhaftes SQL, das in der Ausgabe des Modells erscheint — zusammengesetzt aus Anweisungen, die in der gelesenen Eingabe verborgen waren: einer Nutzernachricht, einem Dokument, einer abgerufenen Zeile. Eingabe-Sanitierung erkennt es nicht, weil der Angriff im Ausgabekanal stattfindet. Dokumentiert in arXiv 2308.01990.

Ist Text-to-SQL jemals die richtige Wahl?

Ja — für Prototypen und beaufsichtigte Exploration auf Nicht-Produktionsdaten ist es schnell und genuinen Nutzen bringend. Die falsche Wahl ist es, sobald auf das Ergebnis gehandelt wird, der Kontext nicht vertrauenswürdigen Text enthält oder die Antwort reproduzierbar sein muss.

Wie gebe ich einem KI-Agenten read-only-Zugriff auf eine Datenbank?

Read-only strukturell verankern, nicht konfiguriert. Ein Read-only-Flag auf einer Verbindung ist eine Einstellung, die jemand ändern kann. Die Ausführungsoberfläche von SQAI enthält ausschließlich Lesefähigkeiten — der Schreibpfad fehlt konstruktionsbedingt, und selbst die Hintertür der Engine ist von keinem modellseitigen Werkzeug erreichbar.

Worin unterscheidet sich ein typisierter Plan von generiertem SQL?

Ein SQL-String kann alles ausdrücken, was die Grammatik erlaubt. Ein typisierter Plan kann nur aussagen, was der Vertrag definiert. Jeder Plan wird gegen einen hash-verankerten Vertrag validiert, gegen die Allow-List-Richtlinie geprüft und auf einer deterministischen Engine ausgeführt — mit einem Replay-Hash für jedes Ergebnis.

Den anderen Weg nehmen.

Kein Konto. Kein Schlüssel. Lokale Daten bleiben lokal.