Skip to main content

sqlmind

LangGraph-native NL→SQL agent library — drop your database query pipeline directly into an existing agent graph as a composable node.

Python 3.10+ License: MIT


Why sqlmind?

Most NL→SQL tools are standalone apps or ChatGPT wrappers. sqlmind is a library — designed to be dropped into your existing LangGraph agent as a composable node. No hosting, no vendor lock-in, no new service to manage.

Feature sqlmind Most alternatives
LangGraph-native nodes ✅ First-class ❌ Standalone only
Pluggable guardrails ✅ Full interface ❌ Fixed policies
Semantic glossary ✅ YAML/dict/custom ❌ None
Canonical metric defs ✅ Injected into LLM ❌ LLM guesses
Self-correction loop ✅ Up to N retries ❌ One-shot
Read-only by default ✅ Session-level ⚠️ Convention only
Any LLM ✅ Protocol + adapters ❌ OpenAI only

Installation

# Core + PostgreSQL + LangGraph/LangChain
pip install sqlmind[langgraph,postgres]

# Add OpenAI or Anthropic direct adapters
pip install sqlmind[openai]
pip install sqlmind[anthropic]

# Everything
pip install sqlmind[all]

Quick Start

Shape A — Single drop-in node

from sqlmind import SQLAgent, SQLAgentConfig
from sqlmind.core import PostgresConnection
from sqlmind.guardrails import ReadOnlyGuardrail, RowLimitGuardrail, BlockedColumnsGuardrail
from sqlmind.semantic import Glossary, MetricRegistry
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, END

# 1. Connect (read-only enforced at DB session level)
conn = PostgresConnection(url="postgresql://user:pass@host/mydb")

# 2. Semantic layer — eliminates LLM guessing about your business terms
glossary = Glossary.from_yaml("glossary.yaml")
metrics = MetricRegistry()
metrics.define("mrr", "Monthly Recurring Revenue", formula="SUM(amount) WHERE cycle='monthly'", unit="USD")

# 3. Guardrails — fail closed, explainable violations
guardrails = [
    ReadOnlyGuardrail(),                              # Block INSERT/UPDATE/DELETE/DROP
    RowLimitGuardrail(max_rows=500),                  # Inject LIMIT clause
    BlockedColumnsGuardrail(columns=["ssn", "password_hash"]),  # PII protection
]

# 4. Build agent — any LLM works
agent = SQLAgent(
    connection=conn,
    llm=ChatOpenAI(model="gpt-4o"),    # or OpenAIAdapter, AnthropicAdapter, or any custom LLM
    guardrails=guardrails,
    glossary=glossary,
    metrics=metrics,
)

# 5. Drop into your LangGraph graph — ONE LINE
graph = StateGraph(dict)
graph.add_node("db", agent.as_node())
graph.set_entry_point("db")
graph.add_edge("db", END)
app = graph.compile()

result = app.invoke({"user_query": "How many active users signed up last month?"})
# → {"success": True, "sql_result": [...], "row_count": 1, "sql_executed": "SELECT ...", ...}

Shape B — Exploded sub-graph (power users)

Individual nodes for full control flow — route to human-in-the-loop on low confidence, add custom steps between pipeline stages.

from sqlmind.integrations import clarify_node, generate_node, validate_node, execute_node

graph = StateGraph(MyState)
graph.add_node("clarify",  clarify_node(agent))
graph.add_node("generate", generate_node(agent))
graph.add_node("validate", validate_node(agent))
graph.add_node("execute",  execute_node(agent))

# Your own routing
def route_after_clarify(state):
    return "human_in_loop" if state.get("needs_clarification") else "generate"

graph.add_conditional_edges("clarify", route_after_clarify, {...})

Use outside LangGraph

result = agent.query("Show me top 10 customers by revenue this quarter")
print(result["sql"])         # The executed SQL
print(result["rows"])        # Query result as list of dicts
print(result["explanation"]) # Human-readable explanation

Custom LLM Integration

Any LLM works. Three ways:

# Option 1: Any LangChain model (ChatOpenAI, ChatAnthropic, ChatOllama, etc.)
from langchain_openai import ChatOpenAI
agent = SQLAgent(connection=conn, llm=ChatOpenAI(model="gpt-4o"))

# Option 2: Direct OpenAI (no LangChain dep)
from sqlmind.llm import OpenAIAdapter
agent = SQLAgent(connection=conn, llm=OpenAIAdapter(api_key="sk-...", model="gpt-4o"))

# Option 3: Direct Anthropic
from sqlmind.llm import AnthropicAdapter
agent = SQLAgent(connection=conn, llm=AnthropicAdapter(model="claude-3-5-sonnet-20241022"))

# Option 4: Fully custom — implement 2 methods
class MyCustomLLM:
    def complete(self, messages, **kwargs):
        ...  # return LLMResponse(content="...")
    def complete_structured(self, messages, schema, **kwargs):
        ...  # return dict

agent = SQLAgent(connection=conn, llm=MyCustomLLM())

Custom Guardrails

from sqlmind.guardrails import Guardrail, GuardrailResult
import datetime

class NoDeleteOnWeekendsGuardrail(Guardrail):
    def check(self, query, context):
        is_weekend = datetime.date.today().weekday() >= 5
        has_delete = "DELETE" in query.sql.upper()
        if is_weekend and has_delete:
            return GuardrailResult(
                passed=False,
                guardrail_name=self.name,
                reason="DELETE queries are blocked on weekends per data policy.",
            )
        return GuardrailResult(passed=True, guardrail_name=self.name)

agent = SQLAgent(
    connection=conn,
    llm=llm,
    guardrails=[ReadOnlyGuardrail(), NoDeleteOnWeekendsGuardrail()],
)

Glossary YAML Format

# glossary.yaml
amt_cents:
  description: "Revenue in USD cents. Always divide by 100 before display."
  example: "SELECT SUM(amt_cents) / 100.0 AS revenue_usd FROM orders"
  tags: [finance, revenue]

status:
  description: "User status: 1=active, 2=trial, 3=churned, 4=suspended"
  tags: [user, lifecycle]

# Shorthand
mrr: "Monthly Recurring Revenue. See metric definitions for formula."

Configuration

from sqlmind import SQLAgentConfig

config = SQLAgentConfig(
    max_retries=3,                # Self-correction attempts on execution error
    confidence_threshold=0.65,    # Below this → trigger clarification step
    max_rows=1000,                # Hard row cap
    query_timeout_seconds=30,     # Wall-clock execution timeout
    memory_window=10,             # Multi-turn context turns kept
    input_state_key="user_query", # LangGraph state key for the question
    output_state_key="sql_result",# LangGraph state key for the result
    verbose=False,                # Debug logging
    llm_temperature=0.0,          # Deterministic generation
)

LangGraph State Contract

The sqlmind node reads and writes these keys on the shared LangGraph state:

Key Direction Type Description
user_query Read str The NL question
sql_result Write list[dict] Query result rows
sql_executed Write str Final SQL (after any guardrail rewrites)
row_count Write int Number of rows returned
success Write bool Whether execution succeeded
error Write str|None Error message if failed
clarification_question Write str|None Set if question was ambiguous
sql_confidence Write float Model confidence 0.0–1.0
execution_attempts Write int Number of self-correction attempts

Architecture

sqlmind/
├── core/           # DB connection + schema introspection + embedding index
├── semantic/       # Glossary (YAML/dict) + MetricRegistry
├── agent/          # clarify → generate → validate → execute → memory
├── guardrails/     # Abstract interface + 5 built-ins + custom registry
├── integrations/   # langgraph_node.py (as_node + exploded nodes)
└── llm/            # LLMProvider protocol + LangChain/OpenAI/Anthropic adapters

Running Tests

pip install sqlmind[dev]
pytest tests/ -v

License

MIT

Download files

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

Source Distribution

sqlmind-0.1.1.tar.gz (45.7 kB view details)

Uploaded Source

Built Distribution

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

sqlmind-0.1.1-py3-none-any.whl (50.5 kB view details)

Uploaded Python 3

File details

Details for the file sqlmind-0.1.1.tar.gz.

File metadata

  • Download URL: sqlmind-0.1.1.tar.gz
  • Upload date:
  • Size: 45.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for sqlmind-0.1.1.tar.gz
Algorithm Hash digest
SHA256 7744a060977694d2505daf7394632eb5b14de19d65d45dca8db1701dc48a1a83
MD5 f57b92717b26e1fee6371e1883ae87a0
BLAKE2b-256 462a90ea4eba1e110ca7ec3b6fb6a420010f9a0c89a20d66aab6b65366482ee6

See more details on using hashes here.

File details

Details for the file sqlmind-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: sqlmind-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 50.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for sqlmind-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e4ce7c2c273f5864cd0de7a7be3c8a9c5d4fb8620d7d89b060d2ccdb3ef479f0
MD5 99b6b7c18c558dff493f726aa4abf640
BLAKE2b-256 423ebfd5e91649be6b2d21dacfa43b72a83582adad737440f385ef0a2aaf6640

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 Sentry Error logging StatusPage Status page