An AI-powered agentic system that converts plain English business questions into safe, optimized SQL queries β with a full Streamlit UI, FastAPI backend, and PostgreSQL demo database.
- 2-stage AI pipeline β intent extraction β SQL generation with chain-of-thought reasoning
- Self-correction loop β automatically retries up to 2 times if SQL fails to execute
- Clarification agent β asks for clarification when the question is ambiguous
- Security layer β SELECT-only enforcement, dangerous keyword blocklist, auto LIMIT injection
- Live schema introspection β agent always reads the real DB schema at query time
- Evaluation framework β tracks latency, token usage, self-corrections, and error rate per query
- Human feedback β rate any query result via API or UI
- Demo e-commerce DB β auto-seeded with 50 customers, 20 products, 200 orders
User Question
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β Stage 1: IntentExtraction β
β β
β LLaMA 3.3 70B extracts: β
β β’ intent_type (aggregation/join/β¦) β
β β’ entities (tables/columns) β
β β’ time_range β
β β’ ambiguity_flags β
β β
β ambiguity_flags non-empty? β
β β return ClarificationRequest β
ββββββββββββββββ¬βββββββββββββββββββββββ
β QueryIntent
βΌ
βββββββββββββββββββββββββββββββββββββββ
β Stage 2: SQLGeneration β
β β
β 1. Fetch live DB schema β
β 2. LLaMA reasons step-by-step: β
β Step 1 β identify tables β
β Step 2 β determine joins β
β Step 3 β write SQL β
β Step 4 β self-review β
β 3. Security validation β
β 4. Execute SQL β
β 5. Self-correction loop (β€ 2Γ) β
ββββββββββββββββ¬βββββββββββββββββββββββ
β GeneratedSQL + Results
βΌ
QueryResponse
sql Β· explanation Β· results
latency Β· tokens Β· cost Β· corrections
- Docker Desktop
- A free Groq API key β console.groq.com (no credit card required)
git clone https://github.com/jenish0908/nl2sql.git
cd nl2sql
cp .env.example .envOpen .env and set your key:
GROQ_API_KEY=gsk_xxxxxxxxxxxxxxxxxxxxdocker-compose up --buildOn first boot the app will:
- Create all database tables
- Seed the demo e-commerce dataset
- Start the FastAPI backend
- Start the Streamlit UI
| Service | URL |
|---|---|
| π₯οΈ Streamlit UI | http://localhost:8501 |
| β‘ FastAPI docs | http://localhost:8001/docs |
| ποΈ PostgreSQL | localhost:5433 |
Which category had the highest revenue last month?
Show me the top 5 customers by total order value
Which products are running low on stock?
What is the average order value by city?
How many orders were placed last week by status?
Which supplier has the best-rated products?
Show total revenue per month for the last 3 months
What is the profit margin per product category?
Which customers placed more than 3 orders?
Show me cancelled orders from the last 30 days
{
"question": "Which city had the highest order value last month?"
}Response:
{
"query_id": 1,
"sql": "SELECT delivery_city, SUM(total_amount) AS total ...",
"explanation": "This query groups orders by delivery city ...",
"results": [{"delivery_city": "New York", "total": 14230.50}],
"row_count": 5,
"intent": {"intent_type": "aggregation", "time_range": "last month"},
"latency_ms": 1240,
"tokens_used": 980,
"cost_usd": 0.0,
"self_corrections": 0
}Re-run with extra context when the agent asks for clarification.
{
"question": "Show me sales",
"clarification": "I mean total revenue by product category for last month"
}Returns the full live database schema (tables, columns, types, foreign keys).
Returns the last 20 queries with SQL, results summary, and metrics.
{
"total_queries": 47,
"avg_latency_ms": 1340,
"avg_cost_usd": 0.0,
"self_correction_rate": 0.04,
"clarification_rate": 0.06,
"error_rate": 0.02
}{
"sql_correct": true,
"result_correct": true,
"rating": 5,
"comment": "perfect"
}| Layer | Detail |
|---|---|
| SELECT-only | Non-SELECT statements are rejected immediately |
| Keyword blocklist | DROP, DELETE, UPDATE, INSERT, ALTER, CREATE, EXEC, TRUNCATE, XP_, SP_ |
| Comment stripping | -- and /* */ comments removed before validation |
| Auto LIMIT | LIMIT 100 appended if no LIMIT clause present |
| Parameterized execution | All queries run through SQLAlchemy's safe layer |
Every query automatically records:
| Metric | Description |
|---|---|
latency_ms |
Total wall-clock time from question to response |
tokens_used |
Combined input + output tokens across both agent stages |
cost_usd |
$0 on Groq free tier |
self_corrections |
SQL retry count (0β2) |
clarification_requested |
Whether the intent stage flagged ambiguity |
execution_error |
Whether all retries were exhausted |
nl2sql-agent/
βββ app/
β βββ main.py FastAPI app + lifespan
β βββ config.py Settings (pydantic-settings)
β βββ agents/
β β βββ intent_extraction.py Stage 1 β Groq intent parsing
β β βββ sql_generation.py Stage 2 β Groq SQL + self-correction
β β βββ clarification.py Clarification subagent
β βββ api/
β β βββ query.py POST /query, POST /query/clarify
β β βββ schema.py GET /schema
β β βββ evaluations.py GET /history, /evaluations/summary, feedback
β βββ services/
β β βββ db.py Async SQLAlchemy engine + session
β β βββ schema_inspector.py Live schema introspection
β β βββ sql_executor.py Safe SQL execution + security checks
β βββ models/
β βββ database.py SQLAlchemy ORM models
β βββ schemas.py Pydantic v2 request/response schemas
βββ streamlit_app.py Streamlit demo UI
βββ scripts/
β βββ seed_demo_data.py Demo e-commerce data seeder
βββ docker-compose.yml
βββ Dockerfile
βββ entrypoint.sh
βββ requirements.txt
βββ .env.example
# Start only Postgres via Docker
docker run -d \
-e POSTGRES_USER=nl2sql \
-e POSTGRES_PASSWORD=nl2sql \
-e POSTGRES_DB=nl2sql_db \
-p 5432:5432 \
postgres:15-alpine
# Install dependencies
pip install -r requirements.txt
# Configure env (use localhost URLs)
cp .env.example .env
# Create tables + seed data
python scripts/seed_demo_data.py
# Start API
uvicorn app.main:app --reload
# Start UI (separate terminal)
streamlit run streamlit_app.py| Layer | Technology |
|---|---|
| LLM | Groq β LLaMA 3.3 70B Versatile (free) |
| Backend | FastAPI + Uvicorn |
| Database | PostgreSQL 15 + SQLAlchemy (async) |
| UI | Streamlit |
| Validation | Pydantic v2 |
| Infra | Docker + Docker Compose |