Multi-Agenten Systeme in Text-to-SQL: Zukunft der Datenanalyse?
Multi-Agenten Systeme in Text-to-SQL: Zukunft der Datenanalyse?
Übermäßige Datenmengen können User in Unternehmen oft überfordern. Deswegen bleiben die tieferen Erkenntnisse, die diese Daten bieten, leider oft verborgen. Hier setzt Multi-Agent Text-to-SQL an: Durch den Einsatz moderner KI-Agenten können auch nicht-technische Nutzer Daten über natürliche Sprache abfragen und präzise Queries generieren.
Zugängliche Verarbeitungsmethoden, die auch nicht-technischen Nutzern Zugriff auf diese Erkenntisse bieten, beinhalten oft Techniken mittels generativer AI (GenAI).
GenAI bedient sich dabei zumeist Large Language Models (LLMs), die aus bereitgestelltem Kontext probabilistisch Text, Bilder oder auch Musik erzeugen können.
Allerdings halluzinieren LLMs häufig Fakten und präsentieren nicht akkurat die Erkenntnisse der zugehörigen Datenbank.
Hier schaffen neue Ansätze Abhilfe, indem sie die Aufgaben auf mehrere KI-Agenten verteilen. Beispielsweise werden faktenbasierte Antworten geliefert, indem eine Datenbank mittels Text-to-SQL (Structured Query Language) abgefragt wird und der zuständige Agent diese Erkenntnisse in seiner Antwort nutzt.
Damit wird auch nicht-technischen Usern die Möglichkeit geboten, auf direktem Level Erkenntnisse aus einer Datenbank zu extrahieren.
Grenzen klassicher LLM Ansätze:
Bisher verließen sich viele KI-Architekturen auf Retrieval-Augmented Generation (RAG) mittels Vektordatenbanken.
Während diese Ansätze effektiv Daten mit ähnlichen Stichworten finden, scheitern sie oft an fortgeschrittenen Anfragen, die weiterführenden Kontext oder Logik erfordern. Beispielsweise erfordern tiefergehende SQL Queries oft Aggregate und Verknüpfungen mehrerer Tabellen mithilfe von Joins anhand bestimmter Spalten.
Darüberhinaus führen rein probabilistische Ansätze oft zu Halluzinationen, weswegen ein deterministischer Ansatz für belastbare Aussagen unumgänglich ist.
Der deterministische Ausweg: Text-to-SQL
Im Multi-Agent Text-to-SQL Ansatz werden die Grenzen der LLMs mittels deterministischer Leitplanken erweitert.
Die Arbeitsschritte werden auf verschiedene KI-Agenten aufgeteilt:
- Ein LLM wird nur dazu angehalten, eine SQL-Query zu erzeugen.
- Die Validierung der erstellten Logik und das Erzeugen des Resultats erfolgt direkt gegen die zugrundeliegende Datenbank. Halluzinationen von Fakten sind damit ausgeschlossen.
Um eine einfachere Handhabung der Daten und LLMs zu gewährleisten, eröffnen moderne Technologien wie das Model Context Protocol (MCP) Möglichkeiten, um KI-Agenten direkt mit den Datenbanken zu verknüpfen.
Architektur eines modernen Multi-Agenten-Systems
Durch gesteigerte Komplexitäten im Arbeitsalltag werden auch die zugehörigem Daten immer vielschichtiger. Deswegen lassen sich reale Datenbanken von modernen Unternehmen sich nicht mehr als einfache Tabelle darstellen, sondern enthalten eine Vielzahl von verzahnten Objekten.
Daher müssen oft Informationen aus verschiedenen Quellen kombiniert werden, um Anfragen vollumfänglich zu beantworten.
Dabei würde es das Kontextfenster überladen, einem LLM die Gesamtheit der Datenstruktur mitzuteilen.
Der hier vorgestellte Ausweg ist eine Architektur, die mehrere KI-Agenten hintereinander schaltet, um die Aufgaben und Herausforderung aufzuteilen. Darüberhinaus ermöglichen Technologien, fehlerhafte Queries direkt zu korrigieren oder bei bedenklichen Queries den User nach einer Freigabe zu fragen (Human-in-the-loop).

Kontextfilter
Ein vorgeschalteter Agent fungiert als „Skimmer“. Seine Aufgabe ist es, die gestellte Anfrage zu verstehen und nur die für die Antwort benötigten Tabellen und Spalten zu identifizieren.
Hierbei finden die bereits erwähnten RAG-basierten Vektorsuchen weiterhin Anwendung, diese werden nicht ersetzt sondern erweitert im Multi-Agenten-System. Durch das bessere Verständnis der Datenbank kann im nächsten Schritt eine bessere Abfrage erzeugt werden.
Integrierte Korrekturloops
Moderne Systeme nutzen Agenten-Frameworks wie LangGraph, um strategische Pläne zu formulieren. Sollte eine generierte Query fehlschlagen, analysiert das System den Fehler, nutzt den bisherigen Kontext und startet einen automatischen Korrekturloop ohne eine erneute Anfrage zu benötigen. Dadurch wird der gesamte Workflow stabiler ohne zusätzliche menschliche Inputs zu erfordern.
Semantische Schicht
Da menschliche Anfragen oft vage oder mehrdeutig formuliert sind („Was ist das beste Produkt?“), hilft eine vorgefertigte semantische Schicht, die für derlei Anfragen weiteren Kontext bereitstellt („Metrik für Produkte: Umsatz, Absatzzahlen“). Daraus können vom zuständigen Agenten dann konkrete Abfragen abgeleitet werden („Summiere Spalte Umsatz für Tabelle Verkäufe“), die idealerweise die tatsächliche Intention des Fragenden abbilden.
Universalität durch MCP
Das MCP Protokoll erlaubt die Anbindung von Agenten an diverse verfügbare Tools. Hierbei fungiert das MCP Protokoll als eine standardisierte Brücke unter Benutzung einer universellen Schnittstelle. Dadurch ist die Architektur nicht auf ein bestimmtes LLM als Agenten festgesetzt, sondern es kann für jede Ebene der passende Agent eingesetzt werden. (MCP-Webinar)
Sicherheit via Human-in-the-loop
Übereifrige KI-Agenten könnten in produktiven Datenbanken erheblichen Schaden anrichten, wenn beispielsweise Daten ungewollt gelöscht werden. Hier schafft eine „Human-in-the-Loop“-Architektur Sicherheit. Kritische Befehle oder die Veröffentlichung sensibler Daten werden erst nach expliziter Freigabe durch einen Menschen ausgeführt. Wie im Beispiel unten aufgeführt, erkennt das Sicherheitslayer gefährliche Syntax in den Abfragen, bricht die Ausführung ab und wartet auf eine explizite menschliche Erlaubnis.
Vergleich LLM gegen Mensch
Als belastbare Metrik für die Performance von Text-to-SQL Ansätzen hat sich Bird-SQL (Big Bench for large-scale Database-grounded Text-to-SQL) bewährt.
Diese vergleicht die Performance von SQL Abfragen unter Berücksichtigung von Datenbankstruktur, Größe und Effizienz auf unaufgeräumten, realen Datenbanken, die Verknüpfung mehrerer Tabellen erfordern.
Quantifiziert wird die Performance unter anderem mit:
1. Execution Accuracy (EX): Stimmt das Ergebnis der KI-Query mit der hinterlegten „Gold-Standard“-Abfrage überein?
2. Reward-based Valid Efficiency Score (R‑VES): Verbraucht die Query unangemessen viel Zeit oder Speicherressourcen.
In einer Studie erreichten menschliche Experten Scores von ca. 92%, während verschiedene AI Systeme maximal ~80% erreichten.
Technisches Beispiel:
Im Folgenden wird einmal beispielhaft die Architektur eines Multi-Agenten Systems gezeigt, welches auf einer Dummy-Datenbank aus natürlichem Text über SQL Abfragen deterministische Ergebnisse erzielt.

Datenbank
Zunächst wird eine Datenbank mit einer künstlichen Unternehmensdaten mittels sqlite3 erstellt.
Diese enthält klassische Elemente wie Produkte, Kunden und Bestellungen.
Die Einträge sind derart angelegt, dass zur vollständigen Beantwortung von Anfragen Verknüpfungen zwischen diesen Tabellen vonnöten sind.
– 1. Categories Table
CREATE TABLE categories (
category_id INTEGER PRIMARY KEY AUTOINCREMENT,
category_name TEXT NOT NULL,
description TEXT
);
– 2. Products Table
CREATE TABLE products (
product_id INTEGER PRIMARY KEY AUTOINCREMENT,
product_name TEXT NOT NULL,
category_id INTEGER,
list_price REAL NOT NULL,
stock_quantity INTEGER,
FOREIGN KEY (category_id) REFERENCES categories(category_id)
);
– 3. Customers Table
CREATE TABLE customers (
customer_id INTEGER PRIMARY KEY AUTOINCREMENT,
company_name TEXT NOT NULL,
country TEXT,
segment TEXT – e.g., Enterprise, SMB, Startup
);
– 4. Orders Table
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY AUTOINCREMENT,
customer_id INTEGER,
order_date DATE,
status TEXT, – e.g., Shipped, Pending, Cancelled
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
– 5. Order Items Table (The bridging table for Many-to-Many between Orders and Products)
CREATE TABLE order_items (
item_id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id INTEGER,
product_id INTEGER,
quantity INTEGER NOT NULL,
unit_price REAL NOT NULL, – Price at the time of sale (might differ from list_price)
FOREIGN KEY (order_id) REFERENCES orders(order_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
– ==========================================
– INSERT DUMMY DATA
– ==========================================
– Insert Categories
INSERT INTO categories (category_name, description) VALUES
(‚Workstations‘, ‚High-performance desktop computers‘),
(‚Peripherals‘, ‚Monitors, keyboards, and mice‘),
(‚Server Hardware‘, ‚Rack mounts and enterprise networking‘);
– Insert Products
INSERT INTO products (product_name, category_id, list_price, stock_quantity) VALUES
(‚DevBox Pro‘, 1, 2500.00, 50),
(‚UltraWide Monitor 34″‘, 2, 800.00, 120),
(‚Mechanical Keyboard‘, 2, 150.00, 300),
(‚Rack Server 2U‘, 3, 5500.00, 20),
(‚Cloud Switch 48-Port‘, 3, 1200.00, 45);
– Insert Customers
INSERT INTO customers (company_name, country, segment) VALUES
(‚Acme Corp‘, ‚Germany‘, ‚Enterprise‘),
(‚Globex Solutions‘, ‚USA‘, ‚SMB‘),
(‚Initech‘, ‚USA‘, ‚Enterprise‘),
(‚Soylent Analytics‘, ‚UK‘, ‚Startup‘);
– Insert Orders
INSERT INTO orders (customer_id, order_date, status) VALUES
(1, ‚2026–03-10‘, ‚Shipped‘),
(1, ‚2026–04-05‘, ‚Pending‘),
(2, ‚2026–04-12‘, ‚Shipped‘),
(3, ‚2026–04-18‘, ‚Shipped‘),
(4, ‚2026–04-20‘, ‚Pending‘);
– Insert Order Items (Linking Orders to Products)
– Order 1 (Acme Corp): 10 DevBox Pros, 10 Monitors
INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES
(1, 1, 10, 2400.00), – Discounted price
(1, 2, 10, 800.00);
– Order 2 (Acme Corp): 2 Rack Servers
INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES
(2, 4, 2, 5500.00);
– Order 3 (Globex): 5 Keyboards
INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES
(3, 3, 5, 150.00);
– Order 4 (Initech): 20 DevBox Pros, 1 Cloud Switch
INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES
(4, 1, 20, 2500.00),
(4, 5, 1, 1200.00);
– Order 5 (Soylent): 2 Monitors
INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES
(5, 2, 2, 800.00);
Implementierung der Agenten-Logik
Agent 1: Skimmer
Zur Verarbeitung von user-Anfragen wird als erster Agent („Skimmer“) zum Analysieren der Anfrage, durchsuchen der Databank und Veranschaulichung des Kontextes kreiert.
Dieser hat nur die Aufgabe, alle Tabellen zusammenzutragen, die im Nachgang benötigt werden, um den Kontext für die SQL Abfrage zu erstellen.
Per Prompt gibt der Skimmer nur eine Liste von Tabellen zurück.
def agent_1_skimmer(state: AgentState):
print(„🕵️ Agent 1 (Skimmer): Reviewing database tables…“)
all_tables = get_all_table_names()
system_prompt = „You are a database architect. Your ONLY job is to identify which tables are needed to answer the user’s question.“
user_prompt = f“““
Available tables: {‚, ‚.join(all_tables)}
User Question: {state[‚question‘]}
Return ONLY a comma-separated list of the required table names. No explanation. No markdown.
„““
response = call_your_llm(system_prompt, user_prompt)
# Parse the list and clean up
selected_tables = [t.strip() for t in response.split(„,“)]
filtered_schema = get_specific_table_schemas(selected_tables)
print(f“ -> Tables selected: {selected_tables}“)
return {„selected_tables“: selected_tables, „filtered_schema“: filtered_schema}
Agent 2: Erstellen der SQL Query
Ein zweiter Agent ist der SQL Experte und erhält die Anfrage sowie die Liste der Tabellen vom Skimmer.
Daraufhin wird die Query erstellt. Um sicherzugehen, dass nicht unfreiwillig Daten gelöscht werden, ist eine Liste an Keywords hinterlegt, die eine menschliche Freigabe erfordern.
def agent_2_coder(state: AgentState):
print(„💻 Agent 2 (Coder): Generating SQL from filtered schema…“)
system_prompt = „You are a SQLite expert. Write the SQL query to answer the question. Return ONLY raw SQL. No markdown wrappers.“
user_prompt = f“““
Schema for relevant tables:
{state[‚filtered_schema‘]}
User Question: {state[‚question‘]}
„““
sql = call_your_llm(system_prompt, user_prompt)
# Clean up SQL formatting if LLM includes markdown
if sql.startswith(„„ ‚sql“):
sql = sql[6:-3].strip()
elif sql.startswith(„„ ‚“):
sql = sql[3:-3].strip()
# — SAFETY CHECK LOGIC —
dangerous_keywords = [
„DROP“,
„TRUNCATE“,
„DELETE“,
„UPDATE“,
„INSERT“,
„ALTER“,
„REPLACE“,
]
requires_approval = any(
re.search(rf“\b{word}\b“, sql.upper()) for word in dangerous_keywords
)
return {„sql_query“: sql, „requires_approval“: requires_approval}
Sicherheitslayer: Human-in-the-loop
Wenn eine destruktive Query entdeckt wird, wird direkt eine Warnung gesendet und der Nutzer muss diese Query erst freigeben, bevor diese gegen die Datenbank ausgeführt wird.
Die Kriterien, ab denen eine generierte Query menschliche Freigabe erfordert, können je nach Compliance-Kriterien und Anforderungen an den Usecase angepasst werden.
def human_approval_node(state: AgentState):
„“„This node handles the interactive Human-in-the-Loop step.“““
print(„\n“ + „⚠️ “ * 15)
print(„🚨 WARNING: POTENTIALLY DESTRUCTIVE QUERY DETECTED 🚨“)
print(f„Generated SQL:\n{state[’sql_query‘]}“)
print(„⚠️ “ * 15)
while True:
choice = input(„\nDo you approve executing this query? (y/n): “).strip().lower()
if choice in [„y“, „yes“]:
print(„Approval granted. Proceeding to execution…“)
return {} # State remains unchanged, proceeds to execution
elif choice in [„n“, „no“]:
print(„Execution aborted by human.“)
return {
„db_results“: „Execution aborted by human administrator due to safety concerns.“
}
Der Usecase: Interaktion von User und Agenten
In unserem Beispiel erfolgt die Interaktion mittels ausgeführtem Python Script und Interaktion im CLI wie unten dargestellt.
Am Anfang wird die Useranfrage (How many products do we have?) verarbeitet.
Daruafhin sucht der Skimmer die benötigten Tabellen aus der Datenbank heraus (‚Tables selected: [‚products‘]‚) und gibt diese weiter.
Der nächste Agent, der Coder, formuliert daraus eine Abfrage (SELECT COUNT(product_id) FROM products), welche keine gefährlichen Schlüsselwörter enthält.
Um die gefundene Antwort in menschliche Sprache zu übersetzen, ist hier noch ein Interpreter-Agent geschaltet, damit auch nicht technische User direkt Erkenntnisse aus der gefundenden Antwort ziehen können.
Im Gegensatz dazu wird im zweiten Beispiel eine destruktive Anfrage gesendet (Delete all orders).
Der Skimmer und der Coder erzeugen die korrekte Liste an Tabellen (Tables selected: ['orders', 'order_items', 'customers']) sowie eine richtige Query (DELETE FROM orders😉 um die Anfrage des Users richtig in SQL zu übersetzen.
Da diese Query Daten löschen würde, wird eine Warnung ausgelöst und der Human-in-the-loop wird gefragt, ob er diese Query freigeben möchte.
Nach der Ablehnung erhält der User kein Ergebnis für seine Anfrage, stattdessen erscheint die Warnung The deletion of all orders was not completed. The execution was aborted by a human administrator due to safety concerns, indicating that the action may have had unintended or potentially harmful consequences .
============================================================
🕸️ LangGraph Multi-Agent SQL System (Safe Mode)
============================================================
User Question: How many products do we have?
————————————————————
🕵️ Agent 1 (Skimmer): Reviewing database tables…
-> Tables selected: [‚products‘]
💻 Agent 2 (Coder): Generating SQL from filtered schema…
⚡ System: Executing SQL query…
🗣️ Agent 3 (Interpreter): Formulating final response…
==================== FINAL OUTPUT ====================
Generated SQL : SELECT COUNT(product_id) FROM products
Final Answer : We have 5 products.
======================================================
User Question: Delete all orders
————————————————————
🕵️ Agent 1 (Skimmer): Reviewing database tables…
-> Tables selected: [‚orders‘, ‚order_items‘, ‚customers‘]
💻 Agent 2 (Coder): Generating SQL from filtered schema…
⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️
🚨 WARNING: POTENTIALLY DESTRUCTIVE QUERY DETECTED 🚨
Generated SQL:
DELETE FROM orders;
⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️
Do you approve executing this query? (y/n): n
Execution aborted by human.
🗣️ Agent 3 (Interpreter): Formulating final response…
==================== FINAL OUTPUT ====================
Generated SQL : DELETE FROM orders;
Final Answer : The deletion of all orders was not completed. The execution was aborted by a human administrator due to safety concerns, indicating that the action may have had unintended or potentially harmful consequences.
======================================================
MCP: Auslagern der Datenbank in die Cloud
Dieses Beispiel erfolgte der Einfachheit halber nur auf einer lokalen Datenbank.
Über das MCP Protkoll lassen sich auch einfach nicht nur andere LLM Agenten, sondern auch beispielsweise Cloud SQL Datenbanbken wie Snowflake anbinden.
# Connect to Snowflake
def init_snowflake():
user = os.getenv(„SNOWFLAKE_USER“)
password = os.getenv(„SNOWFLAKE_PASSWORD“)
account = os.getenv(„SNOWFLAKE_ACCOUNT“)
warehouse = os.getenv(„SNOWFLAKE_WAREHOUSE“)
database = os.getenv(„SNOWFLAKE_DATABASE“)
schema = os.getenv(„SNOWFLAKE_SCHEMA“)
role = os.getenv(„SNOWFLAKE_ROLE“)
conn = snowflake.connector.connect(
user=user,
password=password,
account=account,
warehouse=warehouse,
database=database,
schema=schema,
role=role,
)
print(„✅ Connected to Snowflake“, sys.stderr, file=sys.stderr)
return conn
send(
snow_proc,
{
„jsonrpc“: „2.0“,
„id“: msg_id_snow,
„method“: „tools/call“,
„params“: {
„name“: „query_snowflake“,
„arguments“: {„query“: sql_query},
},
},
)
result = recv(snow_q, timeout=30)
msg_id_snow += 1
Fazit
Die vorgestellte Architektur eines Multi-Agenten-Systems für Text-to-SQL markiert einen Übergang weg von probabilistischen LLM Ansätzen, die Fakten trotz zugrundeliegender Datanbank halluzinieren hin zu einem deterministischen Ansatz, bei dem alle Anfragen aus funktionierenden Queries gegen eine Datenbank beantwortet werden.

Hinweis: AI generiert.
Der Einsatz von LangGraph für komplexe Korrekturschleifen und MCP als universelle Schnittstelle schafft Architekturen, welche
- Weniger halluzinieren, da sie auf echten Datenbank-Fakten basieren.
- Effizienter arbeiten, indem der vorgeschaltete Skimmer den Kontext bereinigt.
- Sicherer sind, da durch Human-in-the-Loop und Sicherheits-Layer kritische Fehler vermieden werden.
- Skalierbar und flexibel sind, da über MCP als universale Schnittstelle direkt andere LLM Agenten und Datenbanken angebunden werden können.
Zukünftig können auch nicht-technische User problemlos Erkenntnisse aus Datenbanken ziehen, ohne dass die Gefahr von Halluzinationen oder Datenverlust besteht.
