DEV Community

Datta Kharad
Datta Kharad

Posted on

NL2SQL Tutorial 2026 — Building a Schema-Grounded Natural Language to SQL Agent with Few-Shot Prompting

Natural Language to SQL (NL2SQL) has become a cornerstone technology for data-driven enterprises in 2026, enabling analysts, PMs, and operational teams to query databases directly using conversational language. With the rise of large language models (LLMs), few-shot prompting, and schema grounding, it’s possible to create intelligent NL2SQL agents that understand database structures, maintain correctness, and generate executable SQL queries.
This tutorial walks through building a schema-aware NL2SQL agent, using best practices in prompt engineering, few-shot learning, and integration with LLMs.
Why Schema-Grounded NL2SQL Matters
Traditional Challenges:
• Ambiguity in natural language
• Risk of invalid SQL due to missing schema context
• Complexity with joins and nested queries
Advantages of Schema-Grounded Approach:
• Database-awareness: Agent knows table names, columns, relationships
• Reduced errors: Generates syntactically correct and semantically valid queries
• Dynamic prompting: Few-shot examples teach the model correct SQL patterns
Step 1 — Prepare Your Database Schema
Before querying, the agent must understand the database schema:

  1. Extract metadata: -- Example: Postgres tables and columns SELECT table_name, column_name, data_type FROM information_schema.columns WHERE table_schema = 'public';
  2. Structure schema context as JSON for the LLM: { "tables": { "users": ["id", "name", "email", "created_at"], "orders": ["id", "user_id", "amount", "order_date"] }, "relationships": [ {"from": "orders.user_id", "to": "users.id"} ] } This schema JSON will be passed to the agent to ground SQL generation. Step 2 — Design Few-Shot Prompts Few-shot prompting teaches the LLM how to map natural language queries to SQL. Prompt Structure:
  3. Instruction: “Convert the user’s question into SQL using this schema.”
  4. Schema context: JSON representation of tables, columns, relationships
  5. Examples: 3–5 question → SQL pairs
  6. User query placeholder: {user_query} Example Prompt: Instruction: Convert the user question into SQL. Schema: {"tables": {"users": ["id","name","email"], "orders": ["id","user_id","amount"]}} Examples: Q: How many orders did each user place? SQL: SELECT user_id, COUNT(*) FROM orders GROUP BY user_id;

Q: List all users with their emails.
SQL: SELECT name, email FROM users;

User Question: {user_query}
SQL:
This ensures LLM output aligns with schema, reduces hallucination, and allows generalization.
Step 3 — Implement NL2SQL Agent

  1. Choose LLM backend: OpenAI GPT-5, Claude 3, or self-hosted LLaMA derivatives.
  2. Load schema context dynamically: Pull table/column info at runtime.
  3. Inject few-shot examples dynamically depending on question type.
  4. Send prompt to LLM and parse the output. Python Example: import openai

prompt = f"""
Instruction: Convert the user question into SQL.
Schema: {schema_json}
Examples:
{few_shot_examples}
User Question: {user_question}
SQL:
"""

response = openai.ChatCompletion.create(
model="gpt-5-mini",
messages=[{"role": "user", "content": prompt}],
temperature=0
)

sql_query = response.choices[0].message.content.strip()
Step 4 — Validate Generated SQL
Always validate SQL before execution:
• Check table & column existence
• Optionally run EXPLAIN plan to detect syntax issues
• Restrict queries for read-only access in production
try:
cursor.execute(sql_query)
results = cursor.fetchall()
except Exception as e:
results = f"Error: {e}"
Validation avoids runtime errors and ensures enterprise safety.
Step 5 — Handle Complex Queries
Schema-grounded agents can support:
• Joins across multiple tables
• Aggregations and grouping
• Nested subqueries
• Filters and conditions extracted from natural language
Few-shot examples should include these patterns to improve generalization.
Step 6 — Optional: Feedback Loop and Memory
Enhance agent over time:
• Store user query → SQL → result in a vector database
• Use RAG (Retrieval-Augmented Generation) to reference past queries for suggestions or corrections
• Enable auto-tuning few-shot examples based on historical performance

Top comments (0)