Skip to main content

A library for building natural-language database query agents

Project description

AskMeDB

A Python library for building natural-language database query agents. Ask questions in plain English, get SQL-powered answers.

AskMeDB connects an LLM to your database, generates SQL from natural language, executes it safely, self-corrects on errors, and synthesizes human-readable answers — all in a few lines of code.

Features

  • Natural Language to SQL — Converts plain English questions into SQL queries
  • Self-Correction — Automatically retries and fixes failed SQL queries, learning from mistakes
  • Multi-Turn Conversations — Follow-up questions maintain context ("Break that down by plan")
  • Multi-Database Support — SQLite out of the box, PostgreSQL/MySQL/others via SQLAlchemy
  • LLM-Agnostic — Works with 100+ models via LiteLLM (OpenAI, Anthropic, Groq, Ollama, etc.)
  • Auto Schema Detection — Introspects your database schema automatically
  • Context Layers — Enrich prompts with business rules, query patterns, and accumulated learnings
  • Event Hooks — Monitor the full pipeline (reasoning, SQL generation, corrections, results)
  • Pluggable Architecture — Extend with custom DB connectors, LLM providers, or schema sources

Installation

pip install askmedb

Or with uv:

uv add askmedb

Optional Dependencies

# For PostgreSQL, MySQL, and other databases via SQLAlchemy
pip install askmedb[sql]

# For running the included examples
pip install askmedb[examples]

Quick Start

from askmedb import AskMeDBEngine, SQLiteConnector, AutoSchemaProvider

# Connect to your database
db = SQLiteConnector("my_database.db")

# Auto-detect schema
schema = AutoSchemaProvider(db)

# Create the engine and ask a question
engine = AskMeDBEngine(db=db, schema=schema)
result = engine.ask("How many customers do we have?")

print(result.answer)   # "There are 150 customers in the database."
print(result.sql)      # "SELECT COUNT(*) FROM customers"

Configuration

from askmedb import AskMeDBEngine, AskMeDBConfig, SQLiteConnector, AutoSchemaProvider

config = AskMeDBConfig(
    model="anthropic/claude-haiku-4-5-20251001",  # Any LiteLLM-supported model
    sql_temperature=0.0,           # Deterministic SQL generation
    answer_temperature=0.3,        # Slightly creative answers
    max_correction_attempts=3,     # Self-correction retries
    max_conversation_turns=10,     # Multi-turn history window
    max_result_rows=30,            # Rows sent to LLM for answer synthesis
    enable_learnings=True,         # Learn from self-corrections
    learnings_path="learnings.json",  # Persist learnings to file
)

engine = AskMeDBEngine(
    db=SQLiteConnector("my_database.db"),
    schema=AutoSchemaProvider(db),
    config=config,
)

Schema Providers

AskMeDB supports multiple ways to provide your database schema:

from askmedb import AutoSchemaProvider, JSONSchemaProvider, DictSchemaProvider

# Auto-detect from database (easiest)
schema = AutoSchemaProvider(db)

# Load from a JSON file
schema = JSONSchemaProvider("schema.json")

# Pass a dictionary directly
schema = DictSchemaProvider({
    "database": "mydb",
    "tables": [
        {
            "name": "customers",
            "description": "Customer accounts",
            "columns": [
                {"name": "id", "type": "INTEGER", "primary_key": True},
                {"name": "name", "type": "TEXT", "description": "Company name"},
            ],
        }
    ],
})

Enriching Context

Add business rules, query patterns, and a custom agent description for better results:

engine = AskMeDBEngine(
    db=db,
    schema=schema,
    config=config,
    business_rules="business_rules.json",    # Metric definitions and gotchas
    query_patterns="query_patterns.sql",     # Example SQL patterns
    agent_description="You are a data analyst for an e-commerce company.",
)

Business Rules (JSON)

{
  "metrics": [
    {
      "name": "MRR",
      "definition": "Monthly Recurring Revenue — sum of mrr from active subscriptions",
      "sql_hint": "SUM(mrr) FROM subscriptions WHERE status = 'active'"
    }
  ],
  "gotchas": [
    "Always filter subscriptions by status='active' for current metrics",
    "Use DATE() for date comparisons in SQLite"
  ]
}

Query Patterns (SQL)

-- name: Total MRR
-- keywords: mrr, monthly recurring revenue, total mrr
SELECT SUM(s.mrr) AS total_mrr
FROM subscriptions s
WHERE s.status = 'active';

Multi-Turn Conversations

Follow-up questions automatically reference previous context:

result = engine.ask("What is our total MRR?")
# Answer: "Your total MRR is $45,200."

result = engine.ask("Break that down by plan")
# Answer: "MRR by plan: Starter $5,800, Growth $18,400, Enterprise $21,000"

result = engine.ask("Which plan has the most customers?")
# Answer: "The Starter plan has the most customers with 85 subscriptions."

# Reset conversation when switching topics
engine.reset_conversation()

Event Hooks

Monitor every step of the pipeline:

engine.on_reasoning = lambda r: print(f"Reasoning: {r}")
engine.on_sql_generated = lambda sql: print(f"SQL: {sql}")
engine.on_sql_error = lambda err, sql, attempt: print(f"Error (attempt {attempt}): {err}")
engine.on_sql_corrected = lambda sql, reason: print(f"Corrected: {reason}")
engine.on_results = lambda cols, rows: print(f"Got {len(rows)} rows")
engine.on_warning = lambda w: print(f"Warning: {w}")
engine.on_answer = lambda a: print(f"Answer: {a}")
engine.on_learning_saved = lambda: print("Learned from this correction")

Working with Results

result = engine.ask("Top 5 customers by revenue")

# Access structured data
print(result.question)            # Original question
print(result.sql)                 # Generated SQL
print(result.answer)              # Human-readable answer
print(result.columns)             # Column names
print(result.rows)                # Raw row tuples
print(result.row_count)           # Number of rows
print(result.correction_attempts) # How many retries were needed
print(result.warnings)            # Heuristic warnings

# Convert to pandas DataFrame
df = result.to_dataframe()

# Convert to list of dicts
records = result.to_dicts()

Database Connectors

SQLite (built-in)

from askmedb import SQLiteConnector

db = SQLiteConnector("path/to/database.db")

SQLAlchemy (PostgreSQL, MySQL, etc.)

pip install askmedb[sql]
from askmedb.db.sqlalchemy_connector import SQLAlchemyConnector

# PostgreSQL
db = SQLAlchemyConnector("postgresql://user:pass@localhost/mydb")

# MySQL
db = SQLAlchemyConnector("mysql+pymysql://user:pass@localhost/mydb")

Custom Connector

from askmedb import BaseDBConnector

class MyConnector(BaseDBConnector):
    def execute(self, sql: str) -> tuple[list[str], list[tuple]]:
        # Execute SQL, return (column_names, rows)
        ...

    def get_dialect(self) -> str:
        return "postgresql"  # For dialect-specific SQL hints

Custom LLM Provider

from askmedb import BaseLLMProvider

class MyLLMProvider(BaseLLMProvider):
    def generate(self, messages: list[dict], temperature: float = 0.0, max_tokens: int = 2048) -> str:
        # Call your LLM and return the response text
        ...

Pass it to the engine:

engine = AskMeDBEngine(db=db, schema=schema, llm=MyLLMProvider())

Running the Examples

The repo includes a sample CloudMetrics SaaS database with 5 tables (customers, plans, subscriptions, invoices, support_tickets) and ~200 customers of synthetic data.

Step 1: Set up the database

pip install faker
python examples/setup_db.py

This creates examples/cloudmetrics.db with realistic synthetic data.

Step 2: Run the quickstart

export ANTHROPIC_API_KEY=sk-ant-...
pip install askmedb python-dotenv

python examples/quickstart.py

Step 3: Run the full CLI app (with Rich UI)

pip install askmedb[examples]

python examples/cloudmetrics/app.py

Type questions in plain English, use samples to see example queries, or reset to clear conversation history.

Try it on Google Colab

Open In Colab

The Colab notebook walks through the full setup: installing dependencies, creating the database, configuring knowledge files, and asking questions interactively.

Project Structure

askmedb/
├── askmedb/                        # Python package
│   ├── core/                       # Engine, config, result, exceptions
│   ├── db/                         # Database connectors (SQLite, SQLAlchemy)
│   ├── llm/                        # LLM providers (LiteLLM)
│   ├── context/                    # Schema, prompt building, context layers
│   └── pipeline/                   # Conversation, parsing, validation, self-correction
├── examples/
│   ├── setup_db.py                 # Creates sample CloudMetrics SQLite database
│   ├── quickstart.py               # Minimal usage example
│   ├── askmedb_colab_demo.ipynb    # Google Colab notebook
│   └── cloudmetrics/               # Full CLI app with Rich UI
│       ├── app.py
│       ├── sample_queries.py
│       └── knowledge/              # Schema, business rules, query patterns
├── pyproject.toml
└── README.md

Environment Variables

Variable Description Example
ANTHROPIC_API_KEY Anthropic API key (for Claude models) sk-ant-...
OPENAI_API_KEY OpenAI API key (for GPT models) sk-...
LLM_MODEL Override default model groq/llama-3.3-70b-versatile

Any API key supported by LiteLLM works.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

askmedb-0.1.0.tar.gz (32.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

askmedb-0.1.0-py3-none-any.whl (25.8 kB view details)

Uploaded Python 3

File details

Details for the file askmedb-0.1.0.tar.gz.

File metadata

  • Download URL: askmedb-0.1.0.tar.gz
  • Upload date:
  • Size: 32.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.3

File hashes

Hashes for askmedb-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e5feeb17e66662a59a67fa20541d96e518b848de9235b30398d0c7a0d05aa8ef
MD5 e6ef49a3d94d8e40e47a9c5cce4bb11e
BLAKE2b-256 f85f523b2edc5b22d9460d96c21c698b55105c438f13022969c0f7f15a9e9aad

See more details on using hashes here.

File details

Details for the file askmedb-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: askmedb-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.3

File hashes

Hashes for askmedb-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d8385a88112277a9cd4e905e8af65854aa39678f944cdab0f713b617ef23adba
MD5 5293cddddc45bdcc3a9e2c45023c5f60
BLAKE2b-256 87e131dfe93854fa133aa2e6e0c8682b288c9cad3c8be27204529cd9dcbed1db

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page