0Pricing
AI Agents · Lektion

Funktionsweise von NL-to-SQL-Agenten

Schema-Injektion, Query-Generierung, Ausführung und Formatierung der Ergebnisse.

Funktionsweise von NL-to-SQL-Agenten ist eine kostenlose AI Agents-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Agents-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Agents-Kurs umfasst insgesamt 4 Lektionen.

Was ist ein NL-to-SQL-Agent?

Ein Agent zur Umwandlung natürlicher Sprache in SQL übersetzt Fragen in natürlicher Sprache in SQL-Abfragen, führt diese in einer Datenbank aus und gibt verständliche Antworten zurück.

Statt SELECT COUNT(*) FROM orders WHERE status='pending' zu schreiben, fragen Sie einfach: „Wie viele ausstehende Bestellungen haben wir?“

Die Kernarchitektur

Jeder NL-to-SQL-Agent folgt derselben Pipeline:

  1. Schema-Injektion – DB-Struktur in den Prompt einfügen
  2. LLM generiert SQL – das Modell erstellt eine Abfrage
  3. Ausführen – die Abfrage in der Datenbank ausführen
  4. Ergebnisse formatieren – Zeilen in lesbaren Text umwandeln
  5. Antwort zurückgeben – dem Nutzer antworten
# High-level pipeline
def nl_to_sql_agent(user_question, db_connection):
    schema = get_schema(db_connection)
    sql = llm_generate_sql(user_question, schema)
    rows = execute_query(db_connection, sql)
    answer = format_results(rows, user_question)
    return answer

Schema-Injektion erklärt

Das LLM kennt die Struktur Ihrer Datenbank nicht. Sie müssen das Schema in jeden Prompt einfügen, damit das Modell weiß, welche Tabellen und Spalten vorhanden sind.

Eine kompakte Schemabeschreibung teilt dem Modell mit: „Die Tabelle orders enthält die Spalten: id, user_id, status, total, created_at.“

def build_schema_prompt(schema_info):
    lines = []
    for table in schema_info:
        cols = ', '.join(
            f"{c['name']} ({c['type']})"
            for c in table['columns']
        )
        lines.append(f"Table {table['name']}: {cols}")
    return '\n'.join(lines)

# Output:
# Table users: id (INT), email (VARCHAR), created_at (TIMESTAMP)
# Table orders: id (INT), user_id (INT), status (VARCHAR), total (FLOAT)

if __name__ == '__main__':
    demo_schema = [
        {'name': 'users', 'columns': [{'name': 'id', 'type': 'INT'}, {'name': 'email', 'type': 'VARCHAR'}]},
        {'name': 'orders', 'columns': [{'name': 'id', 'type': 'INT'}, {'name': 'user_id', 'type': 'INT'}]},
    ]
    print(build_schema_prompt(demo_schema))

Prompt zur SQL-Generierung durch das LLM

Der Prompt muss dem LLM drei Dinge vorgeben: das Schema, die Frage und die ausdrückliche Anweisung, ausschließlich gültiges SQL zurückzugeben.

Klare Vorgaben für SELECT-only sowie für den Zieldialekt (PostgreSQL, MySQL, SQLite) sind für Sicherheit und Korrektheit entscheidend.

SYSTEM_PROMPT = '''You are a SQL expert. Given a database schema and a question,
generate a valid {dialect} SELECT query. Return ONLY the SQL query, no explanation.
Do not use INSERT, UPDATE, DELETE, or DROP.

Schema:
{schema}
'''

def llm_generate_sql(question, schema, dialect='PostgreSQL'):
    prompt = SYSTEM_PROMPT.format(schema=schema, dialect=dialect)
    response = client.chat.completions.create(
        model='gpt-4o',
        messages=[
            {'role': 'system', 'content': prompt},
            {'role': 'user', 'content': question}
        ]
    )
    return response.choices[0].message.content.strip()

Generiertes SQL ausführen

Nachdem das LLM SQL zurückgegeben hat, führen Sie es in der echten Datenbank aus. Verwenden Sie nach Möglichkeit parametrisierte Abfragen und fangen Sie Ausnahmen immer ab – das LLM kann ungültiges SQL erzeugen.

Wenn Sie die Ausführung in einen try/except-Block einschließen, können Sie es mit einem an das LLM zurückgesendeten Fehlerhinweis erneut versuchen.

import psycopg2

def execute_query(conn, sql):
    try:
        with conn.cursor() as cur:
            cur.execute(sql)
            columns = [desc[0] for desc in cur.description]
            rows = cur.fetchmany(100)  # limit rows
            return {'columns': columns, 'rows': rows}
    except psycopg2.Error as e:
        return {'error': str(e), 'sql': sql}

Ergebnisse für Nutzer formatieren

Rohe Datenbankzeilen sind nicht benutzerfreundlich. Der Agent muss sie in eine Antwort in natürlicher Sprache umwandeln.

Bei kleinen Ergebnismengen können Sie die Zeilen zur Interpretation an das LLM zurückgeben. Bei großen Ergebnismengen berechnen Sie zuerst zusammenfassende Statistiken.

def format_results(result, original_question):
    if 'error' in result:
        return f'Query failed: {result["error"]}'

    rows = result['rows']
    columns = result['columns']

    if not rows:
        return 'No results found.'

    # For simple counts/aggregates — just return the value
    if len(columns) == 1 and len(rows) == 1:
        return f'Result: {rows[0][0]}'

    # For multi-row results — summarize
    summary = f'Found {len(rows)} rows.\n'
    for row in rows[:5]:  # show first 5
        summary += ', '.join(f'{columns[i]}: {row[i]}' for i in range(len(columns))) + '\n'
    return summary

if __name__ == '__main__':
    demo_result = {'rows': [[42]], 'columns': ['count']}
    print(format_results(demo_result, 'How many users signed up?'))
    demo_result2 = {'rows': [], 'columns': ['id']}
    print(format_results(demo_result2, 'Any orders today?'))

Warum NL-to-SQL schwierig ist: Mehrdeutigkeit

Mehrdeutigkeit ist die größte Herausforderung. Betrachten Sie die Frage: „Zeigen Sie mir die besten Kunden.“

  • Die besten nach Umsatz, Bestellanzahl oder Aktualität?
  • Im letzten Monat oder über den gesamten Zeitraum?
  • Die besten 10 oder die besten 100?

Menschen verstehen den Kontext, LLMs treffen Annahmen. Agenten benötigen Strategien, um mit mehrdeutigen Fragen umzugehen oder diese zu präzisieren.

AMBIGUITY_PROMPT = '''If the question is ambiguous, respond with JSON:
{"needs_clarification": true, "question": "your clarifying question"}

If clear, respond with the SQL query directly.

User question: {question}
'''

def generate_or_clarify(question, schema):
    response = llm_call(AMBIGUITY_PROMPT.format(
        question=question, schema=schema
    ))
    if '"needs_clarification"' in response:
        import json
        return json.loads(response)
    return {'sql': response}

Warum NL-to-SQL schwierig ist: Schemastruktur

Unternehmensdatenbanken können Hunderte von Tabellen und Tausende von Spalten enthalten. Das vollständige Schema einzufügen, würde das Kontextfenster des LLM überschreiten.

Zu den Lösungen gehören: Schema-Suche (Tabellenbeschreibungen einbetten und relevante Beschreibungen abrufen), Tabellenfilterung (das LLM zuerst fragen, welche Tabellen benötigt werden) und Schemakomprimierung (Index- und Auditspalten weglassen).

# Two-phase approach for large schemas
def get_relevant_tables(question, all_tables):
    prompt = f'''Given these tables: {all_tables}
Which 3-5 tables are most relevant to answer: "{question}"?
Return a JSON list of table names only.'''
    response = llm_call(prompt)
    import json
    return json.loads(response)

def nl_to_sql_large_db(question, conn):
    all_tables = list_all_tables(conn)  # just names
    relevant = get_relevant_tables(question, all_tables)
    schema = get_schema_for_tables(conn, relevant)
    return llm_generate_sql(question, schema)

Warum NL-to-SQL schwierig ist: Unterschiede zwischen SQL-Dialekten

SQL ist nicht überall gleich. LIMIT in PostgreSQL/MySQL wird in SQL Server zu TOP. Datumsfunktionen unterscheiden sich je nach Datenbank. Das LLM muss wissen, welchen Dialekt es verwenden soll.

Geben Sie den Zieldialekt immer in Ihrem System-Prompt an und erwägen Sie, dialektspezifische Beispiele in Few-Shot-Prompting aufzunehmen.

DIALECT_EXAMPLES = {
    'postgresql': 'Use LIMIT for row limits. Use NOW() for current time.',
    'mysql': 'Use LIMIT for row limits. Use NOW() for current time.',
    'sqlite': 'Use LIMIT. Use datetime("now") for current time.',
    'mssql': 'Use TOP N for row limits. Use GETDATE() for current time.',
    'bigquery': 'Use LIMIT. Use CURRENT_TIMESTAMP() for current time. Use backtick for table names.'
}

def get_dialect_hint(dialect):
    return DIALECT_EXAMPLES.get(dialect.lower(), '')

if __name__ == '__main__':
    for dialect in ['postgresql', 'sqlite', 'mssql']:
        print(f'{dialect}: {get_dialect_hint(dialect)}')

Schleife zur Fehlerbehebung

Generiertes SQL schlägt beim ersten Versuch häufig fehl. Ein robuster Agent implementiert eine Fehlerbehebungsschleife: Senden Sie das fehlgeschlagene SQL und die Fehlermeldung an das LLM zurück und bitten Sie es, die Abfrage zu korrigieren.

Beschränken Sie die Wiederholungsversuche auf 2–3, um Endlosschleifen bei nicht korrigierbaren Abfragen zu vermeiden.

def nl_to_sql_with_retry(question, schema, conn, max_retries=3):
    sql = llm_generate_sql(question, schema)
    for attempt in range(max_retries):
        result = execute_query(conn, sql)
        if 'error' not in result:
            return format_results(result, question)
        # Ask LLM to fix the error
        fix_prompt = f'The SQL query failed with error: {result["error"]}\n'\
                     f'Original SQL: {sql}\n'\
                     f'Please fix the SQL query.'
        sql = llm_call(fix_prompt)
        print(f'Retry {attempt + 1} with fixed SQL')
    return 'Could not generate a valid query after retries.'

Alles zusammenführen

Ein produktiver NL-to-SQL-Agent kombiniert alle Bausteine: Schemaabruf, Prompt-Erstellung, SQL-Generierung, Validierung, Ausführung, Fehlerbehebung und Ergebnisformatierung.

Das Hinzufügen von Abfrage-Caching (dieselbe Frage → dasselbe SQL) reduziert bei wiederholten Abfragen die Latenz und die LLM-Kosten erheblich.

import hashlib

query_cache = {}

def cached_nl_to_sql(question, schema_hash, conn):
    cache_key = hashlib.md5((question + schema_hash).encode()).hexdigest()
    if cache_key in query_cache:
        print('Cache hit!')
        sql = query_cache[cache_key]
    else:
        schema = get_schema(conn)
        sql = llm_generate_sql(question, schema)
        query_cache[cache_key] = sql

    result = execute_query(conn, sql)
    return format_results(result, question)

Wissenscheck

Wie lautet die richtige Reihenfolge der Schritte in der Pipeline eines NL-to-SQL-Agenten?

Zusammenfassung: NL-to-SQL-Architektur

NL-to-SQL-Agenten wandeln Fragen in natürlicher Sprache über eine strukturierte Pipeline in ausführbare SQL-Abfragen um: Schema einfügen → SQL generieren → ausführen → formatieren → zurückgeben.

Zu den wichtigsten Herausforderungen gehören Mehrdeutigkeiten in Nutzerfragen, große Schemas, die Kontextfenster überschreiten, und Unterschiede zwischen SQL-Dialekten in verschiedenen Datenbanken. Fehlerbehebungsschleifen behandeln vom LLM erzeugtes SQL, das bei der ersten Ausführung fehlschlägt.

Häufig gestellte Fragen

Ist die Lektion „Funktionsweise von NL-to-SQL-Agenten“ kostenlos?

Ja — der vollständige Text von „Funktionsweise von NL-to-SQL-Agenten“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Agents-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Agents-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Funktionsweise von NL-to-SQL-Agenten“?

Schema-Injektion, Query-Generierung, Ausführung und Formatierung der Ergebnisse. Du übst AI Agents mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um AI Agents zu starten?

Keine Vorkenntnisse erforderlich. AI Agents auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.

Wie lange dauert die Lektion „Funktionsweise von NL-to-SQL-Agenten“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser AI Agents-Lektion Code schreiben und ausführen?

Ja. Jede AI Agents-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Funktionsweise von NL-to-SQL-Agenten
  2. Schemaverständnis und -injektion
  3. SQL-Queries generieren und validieren
  4. Mehrdeutige Datenbankfragen verarbeiten
← Zurück zu AI Agents