A production-ready, model-agnostic Text-to-SQL agent CLI. This tool allows users to query SQLite databases using natural language directly from their terminal, formatting results in clean ASCII tables, providing real-time token streaming, and explaining the queries in plain English.
- 100% Provider Agnostic: Out-of-the-box support for OpenAI (
gpt-4o,gpt-4o-mini), Google Gemini, DeepSeek, local Ollama models, or any OpenAI-compatible API endpoint via standard environment variables. - Real-Time Token Streaming (
query_stream): Renders generated SQL tokens chunk-by-chunk in real-time, bringing perceived Time-To-First-Token (TTFT) latency under 1.0 second. - Database Agnostic (
--db): Point the CLI at any arbitrary SQLite database file (python -m src.cli --db custom.db). - Multi-Turn Conversation Memory: Preserves context across queries. You can ask follow-up questions (e.g., "show only the top 3" or "filter to 2021") without re-specifying the entire request.
- Full-Schema Injection: Auto-injects database DDL structures and realistic sample rows for all tables into the system prompt, reducing table/column hallucinations to near zero.
- Self-Correcting Execution Retry Loop: If generated SQL fails SQLite execution, the agent feeds the error message back to the LLM for automatic self-correction (up to 2 retries).
- Security & Read-Only Guardrails: Enforces
PRAGMA query_only = ON;and application-level SQL parsing to block non-SELECT / destructive statements (DROP,DELETE,UPDATE,INSERT). - CSV Export (
export <file.csv>): Export active query results to CSV directly from the terminal. - Evaluation Framework: Measures Execution Accuracy (EX) and Result Accuracy (RA) against gold-standard SQL and answers (
--dataset dev|extended|all). - Automated Unit Tests: Built-in test suite (
python -m unittest tests/test_agent.py).
┌──────────────────────┐
│ python -m │
│ src.cli │
└──────────┬───────────┘
│ user question
▼
┌──────────────────────┐
│ TextToSQLAgent │
│ (src/agent.py) │
└──────────┬───────────┘
│
┌───────────────────────┼───────────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌────────────────┐
│ Injects DDL │ │ Execs query │ │ Queries LLM │
│ & Samples │ │ & Guardrails │ │ Client (via │
│ (src/utils) │ │ (SQLite3) │ │ OpenAI SDK) │
└──────────────┘ └──────────────┘ └────────────────┘
Execute the setup script to create a Python virtual environment, install dependencies, and download the sample SQLite database (Chinook.db):
./setup.shCopy .env.example to .env:
cp .env.example .envFill in your API credentials:
OPENAI_API_KEY=your-openai-api-key-here
LLM_MODEL=gpt-4o # or gpt-4o-miniLLM_PROVIDER=gemini
LLM_MODEL=gemini-2.5-flash # or gemini-1.5-pro, gemini-2.5-pro
LLM_API_KEY=your-gemini-api-key
LLM_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/LLM_PROVIDER=openai
LLM_MODEL=deepseek-chat
LLM_API_KEY=your-api-key
LLM_BASE_URL=https://api.deepseek.com/v1 # or http://localhost:11434/v1 for OllamaLaunch the terminal query assistant:
# 1. Activate virtual environment
source .venv/bin/activate
# 2. Run CLI against sample Chinook database
python -m src.cli
# 3. Point CLI at a custom SQLite database file
python -m src.cli --db path/to/your_database.db| Command | Description |
|---|---|
<your question> |
Convert natural language to SQL, stream response, execute query, and format ASCII results. |
schema or schema <table> |
Print database schema structure and column definitions. |
export <file.csv> |
Export active query results to a CSV file. |
reset |
Clear multi-turn conversation history and start a fresh session. |
exit / quit |
End terminal session. |
Evaluate the agent's Execution Accuracy (EX) and Result Accuracy (RA) against benchmark question sets:
# Evaluate on public dev questions (10 questions)
python -m src.evals --dataset dev
# Evaluate on extended edge-case questions (10 questions)
python -m src.evals --dataset extended
# Run full evaluation suite
python -m src.evals --dataset all --output eval_results.json
# Skip baseline comparison
python -m src.evals --no-baselineMeasure system latency (P50/P95/Mean) and token consumption metrics:
python -m src.perf --runs 3 --output perf_report.jsonRun the built-in test suite:
python -m unittest tests/test_agent.pyRe-run the agent over all dev questions to update dev_answers.json:
python scripts/generate_answers.pyAn architecture analysis was conducted to determine whether to rewrite this codebase using LangChain or LangGraph versus maintaining the current Vanilla Python + OpenAI SDK structure.
| Criteria | Vanilla Python (Current) | LangChain | LangGraph |
|---|---|---|---|
| Architecture | Direct, imperative Python | Linear DAG chain abstractions | State machine graph loops |
| Dependency Bloat | Low (only openai & python-dotenv) |
High (large nested packages) | High (requires graph runtimes) |
| Self-Correction Retry Loop | Simple try-except retry loops |
Clumsy (cycles hard to model in LCEL) | Native (cycles are first-class edges) |
| Debuggability | Trivial (normal stack traces) | Hard (complex nested trace stacks) | Medium (visual traces via LangSmith) |
| Latency / Execution Overhead | Near-zero | Medium (abstraction wrappers) | Medium-High (state graph overhead) |
We recommend keeping the current Vanilla Python architecture. For single/multi-database querying with structured JSON parsing, real-time streaming, and a self-correcting retry loop, the simplicity, minimal latency, and zero dependency bloat of vanilla Python vastly outweigh the overhead of LangChain or LangGraph.