Fonctionnement des agents NL-to-SQL
Injection du schéma, génération de requêtes, exécution et mise en forme des résultats.
Fonctionnement des agents NL-to-SQL est une leçon AI Agents gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Agents, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Agents comprend 4 leçons au total.
Qu’est-ce qu’un agent de langage naturel vers SQL ?
Un agent de langage naturel vers SQL traduit des questions formulées en langage courant en requêtes SQL, les exécute sur une base de données et renvoie des réponses compréhensibles.
Au lieu d’écrire SELECT COUNT(*) FROM orders WHERE status='pending', les utilisateurs demandent simplement : « Combien de commandes en attente avons-nous ? »
Architecture principale
Chaque agent de langage naturel vers SQL suit la même chaîne de traitement :
- Injection du schéma — injecter la structure de la base de données dans la consigne
- Génération du SQL par le LLM — le modèle produit une requête
- Exécution — exécuter la requête sur la base de données
- Mise en forme des résultats — transformer les lignes en texte lisible
- Retour de la réponse — répondre à l’utilisateur
# 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 answerExplication de l’injection du schéma
Le LLM ne connaît pas la structure de votre base de données. Vous devez injecter le schéma dans chaque consigne afin que le modèle sache quelles tables et quelles colonnes existent.
Une description concise du schéma indique au modèle : « La table commandes comporte les colonnes : identifiant, user_id, statut, 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))
Consigne de génération SQL du LLM
La consigne doit fournir au LLM trois éléments : le schéma, la question et des instructions explicites lui demandant de renvoyer uniquement du SQL valide.
Préciser qu’il doit utiliser SELECT uniquement ainsi que le dialecte SQL cible (PostgreSQL, MySQL ou SQLite) est essentiel pour garantir la sécurité et l’exactitude.
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()Exécuter le SQL généré
Après que le LLM a renvoyé du SQL, exécutez-le sur la base de données réelle. Utilisez si possible des requêtes paramétrées et interceptez toujours les exceptions : le LLM peut produire du SQL invalide.
Encapsuler l’exécution dans un bloc de gestion des exceptions permet de réessayer en renvoyant au LLM une indication sur l’erreur.
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}Mettre les résultats en forme pour l’utilisateur
Les lignes brutes d’une base de données ne sont pas faciles à comprendre. L’agent doit les convertir en une réponse en langage naturel.
Pour les petits ensembles de résultats, transmettez les lignes au LLM afin qu’il les interprète. Pour les grands ensembles, calculez d’abord des statistiques récapitulatives.
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?'))
Pourquoi le langage naturel vers SQL est difficile : l’ambiguïté
L’ambiguïté est le principal défi. Prenons la question suivante : « Affichez-moi les meilleurs clients. »
- Les meilleurs selon le chiffre d’affaires, le nombre de commandes ou la récence ?
- Sur le mois dernier ou sur toute la période ?
- Les 10 premiers ou les 100 premiers ?
Les humains comprennent le contexte ; les LLM formulent des suppositions. Les agents ont besoin de stratégies pour gérer les questions ambiguës ou demander des précisions.
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}Pourquoi le langage naturel vers SQL est difficile : la taille du schéma
Les bases de données d’entreprise peuvent contenir des centaines de tables et des milliers de colonnes. Injecter le schéma complet dépasserait la fenêtre de contexte du LLM.
Parmi les solutions figurent : la recherche dans le schéma (intégrer les descriptions des tables et récupérer celles qui sont pertinentes), le filtrage des tables (demander d’abord au LLM quelles tables sont nécessaires) et la compression du schéma (omettre les colonnes d’index et d’audit).
# 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)Pourquoi le langage naturel vers SQL est difficile : les différences de dialecte SQL
SQL n’est pas universel. LIMIT dans PostgreSQL ou MySQL devient TOP dans SQL Server. Les fonctions de date varient selon les bases de données. Le LLM doit savoir quel dialecte utiliser.
Indiquez toujours le dialecte cible dans votre consigne système et envisagez d’ajouter des exemples propres à chaque dialecte dans un amorçage par quelques exemples.
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)}')
Boucle de récupération après erreur
Le SQL généré échoue souvent dès la première tentative. Un agent robuste met en place une boucle de récupération après erreur : renvoyez au LLM le SQL qui a échoué ainsi que le message d’erreur, puis demandez-lui de corriger la requête.
Limitez le nombre de tentatives à 2 ou 3 afin d’éviter les boucles infinies pour les requêtes impossibles à corriger.
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.'Assembler tous les éléments
Un agent de langage naturel vers SQL destiné à la production combine tous les éléments : récupération du schéma, construction de la consigne, génération du SQL, validation, exécution, récupération après erreur et mise en forme des résultats.
Ajouter la mise en cache des requêtes (même question → même SQL) réduit considérablement la latence et les coûts du LLM pour les requêtes répétées.
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)Vérification des connaissances
Quel est l’ordre correct des étapes dans la chaîne de traitement d’un agent de langage naturel vers SQL ?
Récapitulatif : architecture du langage naturel vers SQL
Les agents de langage naturel vers SQL convertissent les questions en langage naturel en requêtes SQL exécutables grâce à une chaîne de traitement structurée : injecter le schéma → générer du SQL → exécuter → mettre en forme → renvoyer.
Les principaux défis sont l’ambiguïté des questions des utilisateurs, les schémas volumineux qui dépassent les fenêtres de contexte et les différences de dialecte SQL entre les bases de données. Les boucles de récupération après erreur traitent le SQL généré par le LLM lorsqu’il échoue lors de la première exécution.
Questions Fréquemment Posées
La leçon « Fonctionnement des agents NL-to-SQL » est-elle gratuite ?
Oui — le texte complet de « Fonctionnement des agents NL-to-SQL » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Agents, passe à CoddyKit PRO. Le cours AI Agents comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Fonctionnement des agents NL-to-SQL » ?
Injection du schéma, génération de requêtes, exécution et mise en forme des résultats. Tu pratiques AI Agents avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer AI Agents ?
Aucune expérience préalable n'est requise. AI Agents sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « Fonctionnement des agents NL-to-SQL » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon AI Agents ?
Oui. Chaque leçon AI Agents inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Fonctionnement des agents NL-to-SQL
- Comprendre et injecter un schéma
- Générer et valider des requêtes SQL
- Gérer les questions ambiguës sur les bases de données