| title | Text-to-SQL Insurance Analytics |
|---|---|
| emoji | π |
| colorFrom | blue |
| colorTo | purple |
| sdk | streamlit |
| sdk_version | 1.35.0 |
| app_file | app.py |
| pinned | false |
A local, enterprise-grade Text-to-SQL application that translates natural language questions into executable SQL queries using Claude. Built with a LangGraph multi-agent pipeline, a golden dataset evaluation framework, and OPIK for experiment tracking.
text-sql/
βββ .env # API keys (never commit this)
βββ .env.example # Key template β copy to .env
βββ config.py # Central config: model names, thresholds, paths
βββ requirements.txt
β
βββ db/
β βββ schema.sql # SQLite DDL β 30 insurance/claims tables
β βββ seed_data.sql # Sample insurance data across all 30 tables
β βββ database.py # init_db(), run_query(), get_schema_str(), get_table_chunks()
β βββ schema_store.py # build_schema_store(), retrieve_schema() β ChromaDB vector store
β
βββ dataset/
β βββ seed_queries.json # 20 SME-curated ground-truth Q+SQL pairs
β βββ generate_dataset.py # Phase 1: expands seeds to 120+ variations via Claude
β βββ golden_dataset.json # Generated output (created by generate_dataset.py)
β βββ derive_needed_tables.py # Parses golden_dataset.json to populate needed_tables per entry
β
βββ agents/
β βββ graph.py # LangGraph StateGraph β wires the 3 agents together
β βββ planner.py # Agent 1: retrieves relevant schema, decomposes question into a query plan
β βββ sql_generator.py # Agent 2: converts plan to a SELECT-only SQL query
β βββ governance.py # Agent 3: blocks unsafe SQL, executes the query
β
βββ evaluation/
β βββ metrics.py # 4 scoring functions (validity, accuracy, relevance, schema_recall)
β βββ pipeline.py # Runs golden dataset through agents via opik.evaluate(), logs to OPIK
β βββ manual_pipeline.py # Alternative: sequential per-entry evaluation with @track decorators
β
βββ app.py # Streamlit UI β Query tab + Eval Dashboard tab
User Question
β
βΌ
βββββββββββββββ βββββββββββββββββββββ ββββββββββββββββββββ
β Planner ββββββΆβ SQL Generator ββββββΆβ Governance β
β (Claude) β β (Claude) β β (Heuristic) β
β β β β β β
β Decomposes β β Generates a β β Blocks non-SELECTβ
β question β β β SELECT-only β β and forbidden β
β query plan β β SQLite query β β keywords, then β
β β β β β executes the SQL β
βββββββββββββββ βββββββββββββββββββββ ββββββββββββββββββββ
β
βΌ
Result rows
Tables are grouped by domain. See db/schema.sql for full DDL.
| Domain | Tables |
|---|---|
| Core | adjusters, policies, claims, claimants, fraud_flags |
| Parties | customers, agents, underwriters |
| Coverage | coverage_types, loss_types, policy_coverages, policy_endorsements |
| Financial | premium_payments, claim_payments, reserve_estimates |
| Assets | insured_properties, insured_vehicles |
| Risk & Inspection | risk_assessments, inspection_reports |
| Claims Workflow | claim_documents, claim_assessments, claim_appeals |
| Vendors | repair_vendors, repair_estimates |
| Fraud | investigators, fraud_investigations |
| Compliance | regulatory_filings, compliance_audits |
| Performance | agent_performance, customer_risk_profiles |
| Metric | Method | Ship Threshold |
|---|---|---|
| SQL Validity | Heuristic β SQL executes without error | > 90% |
| Execution Accuracy | Row-level F1 against ground truth; LLM-as-judge fallback below threshold | > 70% |
| Answer Relevance | LLM-as-Judge β Claude scores semantic alignment of SQL + result to question | > 75% |
| Schema Recall | Heuristic β fraction of required tables covered by the vector store retrieval | > 90% |
- Designed a 30-table SQLite schema covering the Insurance/Claims domain across 11 functional areas (core, parties, coverage, financial, assets, risk, claims workflow, vendors, fraud, compliance, performance)
- Seeded realistic sample data across all 30 tables with all PII fields redacted
- Built
database.pywithinit_db(),run_query(),get_schema_str(), andget_table_chunks()β schema context is either retrieved selectively or injected in full depending onUSE_SCHEMA_RETRIEVALinconfig.py - Built
schema_store.pyusing ChromaDB to embed all 30 table descriptions as a local vector store;retrieve_schema(query, k)returns thekmost relevant tables for a given question
- Authored 20 seed queries with ground-truth SQL covering key business questions: fraud savings, risk distribution, adjuster performance, claim resolution time, vendor estimates, reserve tracking, compliance, and agent commission
- Each entry is tagged:
complexity(Simple/Medium/Complex),operations(Filter/Join/GroupBy/Subquery),risk_level,domain, andneeded_tables(required forschema_recallscoring) generate_dataset.pyuses Claude to expand each seed into 6 variations β paraphrases, temporal modifiers, typos β producing ~140 entries ingolden_dataset.jsonderive_needed_tables.pyparses each ground-truth SQL with sqlglot to populateneeded_tables; re-run whenever the dataset is regenerated
- Built a three-node
StateGraph: Planner β SQL Generator β Governance - Planner: queries the ChromaDB vector store to retrieve the
kmost relevant table descriptions for the question (or injects the full schema whenUSE_SCHEMA_RETRIEVAL=False), then uses Claude to produce a structured plan (tables, joins, filters, aggregations); retrieved schema and table names are stored inAgentStateto avoid a second vector lookup - SQL Generator: reads the schema from
AgentStateand uses Claude to generate a SELECT-only SQLite query; forbidden keywords are enforced at the prompt level - Governance: heuristic layer that blocks any non-SELECT statement and forbidden keywords (DROP, DELETE, UPDATE, INSERT, ALTER, TRUNCATE, CREATE, REPLACE), then executes the approved query
metrics.pyimplements four scoring functions:SqlValidityMetric,ExecutionAccuracyMetric(row-level F1 + LLM judge fallback),AnswerRelevanceMetric(LLM-as-judge), andSchemaRecallMetric(retrieval coverage)pipeline.pyruns the full golden dataset through the agent viaopik.evaluate(), scores each entry in parallel, logs every trace to OPIK, and prints a ship/no-ship scorecard against configurable thresholdsmanual_pipeline.pyprovides an alternative sequential runner using@trackdecorators for step-by-step OPIK tracing- Results are saved to
evaluation/results.jsonfor the UI dashboard
- Query tab: text input β agent pipeline β syntax-highlighted SQL + result table + governance badge. Thumbs up/down feedback is written to
dataset/feedback.jsonfor future dataset expansion - Eval Dashboard tab: run evaluation in-browser, view metric gauges, ship/no-ship badge, filterable per-query results table, and a drill-down inspector per entry
- Python 3.11+
- An Anthropic API key
- An OPIK (Comet) API key
cd text-sqlpython3 -m venv .venv
source .venv/bin/activate # macOS/Linux
# .venv\Scripts\activate # Windowspip install -r requirements.txtcp .env.example .envEdit .env and fill in your keys:
LLM_API_KEY=sk-ant-... # API key for whichever provider MODEL points to
OPIK_API_KEY=...
OPIK_PROJECT_NAME=text_to_sql_pm_demo
python db/database.pyExpected output:
Database ready. Total claims: <n>
Claims by risk level:
High: <n> claims, $<amount>
...
Total tables: 30
Embeds all 30 table descriptions into a local ChromaDB store (runs once, ~10 seconds on first run while the embedding model downloads):
python db/schema_store.pyExpected output:
Schema store built: 30 tables indexed at data/schema_store
The store is used by the agent pipeline to retrieve the top-k most relevant tables per query instead of injecting all 30. The value of k is set by SCHEMA_RETRIEVAL_TOP_K in config.py. Set USE_SCHEMA_RETRIEVAL = False to compare against full-schema injection β schema_recall will be trivially 1.0 in that mode.
This calls Claude ~120 times to expand 20 seed queries into ~140 variations. Takes ~3 minutes and costs a small amount in API credits.
python dataset/generate_dataset.pyOutput: dataset/golden_dataset.json
Then derive needed_tables for each entry (required for the schema_recall metric):
python dataset/derive_needed_tables.pyUse --dry-run to preview extracted tables without modifying the file. Re-run this whenever golden_dataset.json is regenerated.
streamlit run app.pyOpens at http://localhost:8501
- Query tab: type any insurance/claims question in plain English
- Eval Dashboard tab: click "Quick Run (12 seeds)" for a fast smoke test, or "Run Full Evaluation" for the complete golden dataset
# Quick run β 12 seeds only
python evaluation/pipeline.py --max 12
# Full run
python evaluation/pipeline.py.envis excluded from version control β never commit it- The Governance agent blocks all non-SELECT SQL (DROP, DELETE, UPDATE, INSERT, ALTER, TRUNCATE, CREATE, REPLACE) at the heuristic layer before any execution
- Sample data has all PII fields redacted (
full_name,contact_emailcontain only"Redacted")