Tutoriel : construire un endpoint NL2SQL sur Postgres
Ce tutoriel montre comment recevoir une question en français, la transformer en requête SQL validée et bornée, puis retourner le résultat — sans jamais exécuter de SQL non vérifié. Le SQL réellement généré est affiché à chaque étape, pas seulement le résultat final.
Le moteur NL2SQL d’Aurabase fait partie de l’IA native intégrée au backend : pas un service tiers à assembler. Prérequis pour suivre ce guide : un projet Aurabase existant, un schéma de base de données simple pour l’exemple, et une clé API projet.
Ce que vous allez construire
Un endpoint qui reçoit une question en langage naturel, la transforme en requête SQL validée et bornée, puis retourne le résultat. Le moteur n’exécute jamais du SQL généré sans contrôle : chaque requête passe par une validation syntaxique avant d’atteindre la base.
@aurabase/aurabase-js et l’appel HTTP brut équivalent, pour que vous puissiez suivre depuis n’importe quel langage.La question passe par un LLM configuré — OpenAI, Anthropic (Claude) ou Gemini, les trois fournisseurs natifs — qui génère un SQL candidat. Ce SQL n’est jamais exécuté tel quel : il traverse un validateur qui parse son arbre syntaxique (sqlparser), n’autorise que des requêtes SELECT simples, et ajoute un LIMIT borné s’il en manque un.
Le validateur rejette explicitement les CTE/WITH, les sous-requêtes, les UNION, les clauses de verrouillage (FOR UPDATE), et toute fonction hors d’une liste blanche (count, sum, avg, min, max, lower, upper, coalesce, date_trunc, now). Les jointures multi-tables, elles, sont supportées.
Le schéma interrogé n’est jamais fourni par votre requête : il est introspecté depuis la base réelle du projet. Un champ schema, allowed_schema ou schema_context envoyé dans le corps de la requête est explicitement refusé (erreur 400) plutôt qu’ignoré en silence — le serveur seul décide de ce qui existe réellement.
Configurer le endpoint NL2SQL
Avec le SDK JavaScript, le client Aurabase expose aura.ai.nl2sql(). L’argument schéma n’est plus accepté (il est introspecté côté serveur) : passez undefined à sa place.
En HTTP brut, l’endpoint est POST /v1/ai/{project_id}/nl2sql, authentifié par la clé API du projet.
schema, ni allowed_schema, ni schema_context dans le corps de la requête : le schéma interrogé est déterminé par le serveur, ces champs sont explicitement rejetés (400) plutôt qu’écrasés en silence.Tester avec une vraie question en français
Question envoyée : « Combien de commandes ont été passées ce mois-ci par des clients premium ? ». Voici la forme du SQL réellement rendu (noms de tables et colonnes dépendent de votre schéma) :
limit_injected indique si le LIMIT vient du modèle ou a été ajouté par le serveur. confidence est une heuristique sur la forme de la réponse (bloc SQL bien formé ou non) — pas une mesure d’exactitude sémantique du SQL généré. Une question mal formulée retourne une erreur explicite plutôt qu’un SQL halluciné : par exemple, si le SQL généré interroge une table absente de votre schéma, le message nomme les tables réellement disponibles.
Sécuriser la production
Trois vérifications avant de déployer : le plafond de lignes (LIMIT) est-il adapté à votre volumétrie, le rôle Postgres utilisé par le moteur reste-t-il restreint au schéma du projet, et les tables sensibles ont-elles une policy RLS active — le NL2SQL interroge la même base que le reste de votre application, il n’a pas de droits d’accès élargis par défaut.
- Le plafond de lignes par défaut est configurable côté serveur ; une valeur demandée au-delà du plafond serveur est refusée explicitement plutôt que silencieusement réduite.
- L’accès au catalogue système (
pg_catalog,information_schema) et aux schémas hors projet est bloqué par le validateur, indépendamment de vos policies RLS. - RLS reste votre dernière ligne de défense sur les tables sensibles : le validateur borne la forme du SQL, pas les droits métier sur les données.
Limites actuelles à connaître
Le moteur est strictement en lecture : seules les requêtes SELECT sont acceptées. Toute tentative d’INSERT, UPDATE, DELETE, DROP, CREATE ou ALTER générée par le modèle est rejetée avant exécution — ce n’est pas une convention de prompt, c’est une règle imposée au niveau de l’arbre syntaxique.
Autres limites structurelles : pas de sous-requêtes, pas de CTE/WITH, pas d’UNION, et une liste blanche fermée de dix fonctions SQL. Une question qui appelle naturellement une sous-requête (« les clients qui n’ont jamais commandé ») doit être reformulée pour tenir dans un SELECT simple, ou traitée autrement côté application.
RAG et agents
Le NL2SQL couvre les questions structurées sur vos données relationnelles. Pour des questions sur du contenu non structuré (documents, notes, tickets), le RAG natif d’Aurabase s’appuie sur pgvector et une recherche HNSW. Les deux capacités — et la manière de les combiner dans un agent — sont détaillées sur la page IA native sur Postgres.
Comment fonctionne le moteur NL2SQL