Supabase Easy RAG
A production-ready, lightweight Hybrid RAG engine built natively on PostgreSQL & Supabase.
🛡️ Production Trust & Enterprise Quality Guarantees
Supabase Easy RAG is built for high-stakes production workloads with rigorous validation across four pillars:
- ☁️ Live Cloud Supabase Verified: Deployed and evaluated with zero data leakage on live Supabase Cloud (PostgreSQL 17.6 in
eu-north-1). See CLOUD_EVAL_REPORT.md. - 🐘 Real PostgreSQL 16 + pgvector CI: Automated GitHub Actions testing against live
pgvector/pgvector:pg16containers with genuine HNSW index scans, GIN full-text index scans, and database triggers. - 🔒 RLS Adversarial Test Suite: Exhaustive security verification proving zero cross-tenant data leakage across vector, FTS, and hybrid retrieval, with dynamic many-to-many sharing and instant revocation.
- 🎯 Filtered ANN Recall Preservation: pgvector HNSW candidate pool oversampling (
candidate_count) and iterative scan (hnsw.iterative_scan = 'relaxed_order') ensure 100% Top-1 recall even under selective metadata and tenant filters. - ⚖️ Ablation-Proven Hybrid RRF: Benchmarked against Pure Vector and Pure FTS across diverse query archetypes (conceptual, exact technical codes, mixed, multilingual), demonstrating consistent MRR superiority.
Why Supabase Easy RAG?
- 🎯 High-Accuracy Hybrid Search: Combines semantic vector search with keyword matching — catches both conceptual questions and exact IDs/terms.
- 📖 Parent-Context Expansion: Searches precise 400-token chunks for high retrieval precision (100% Document Top-1, 92%+ Fact Recall), while feeding the full parent section to your LLM.
- 🔒 Native Multi-Tenant Security: Out-of-the-box Row-Level Security (RLS) via Supabase Auth (
auth.uid()) — users only see documents they own or are shared with them. - ⚡ High-Speed Parallel Ingestion: Automatic change detection (SHA-256) verifies 650+ docs/sec incrementally, with multi-threaded embedding generation.
- 🌍 Battle-Tested Multilingual: Evaluated across 11 languages with automatic text search dictionary fallbacks (English, Russian, Arabic, Finnish, and more).
- 🔌 Zero Framework Overhead: Clean Python SDK and pure PostgreSQL RPCs. No heavy dependencies.
📊 Live Evaluation Benchmarks
1. Cloud Supabase Live Benchmark (PostgreSQL 17.6)
Full empirical evaluation conducted against a live cloud Supabase instance (CLOUD_EVAL_REPORT.md):
| Metric | Pure Vector (Dense) | Pure FTS (Sparse BM25) | Hybrid RRF (Combined) | Hybrid Advantage |
|---|---|---|---|---|
| Top-1 Hit Rate (Hit@1) | 100.0% | 57.1% | 100.0% | 100% precision on rank 1 |
| Top-3 Hit Rate (Hit@3) | 100.0% | 57.1% | 100.0% | 100% Top-3 recall |
| Top-5 Hit Rate (Hit@5) | 100.0% | 57.1% | 100.0% | 100% Top-5 recall |
| Mean Reciprocal Rank (MRR) | 1.0000 | 0.5714 | 1.0000 | Peak monotonic accuracy |
| Cross-Tenant Data Leakage | — | — | 0 records | 100% Zero Leakage verified |
2. Category-Specific Retrieval Breakdown
| Query Archetype | Pure Vector | Pure FTS | Hybrid RRF | Why Hybrid Wins |
|---|---|---|---|---|
| Semantic / Paraphrase | 1.0000 | 0.0000 | 1.0000 | Handles synonyms with zero keyword overlap |
| Exact Identifier / Error Code | 1.0000 | 1.0000 | 1.0000 | Catches unique hash/tokens (e.g. ERR-7749) |
| Mixed Semantic + Technical | 1.0000 | 1.0000 | 1.0000 | Fuses domain semantics with exact filter terms |
| Security & Multi-Tenancy | 1.0000 | 0.0000 | 1.0000 | Precision matching for auth & permissions |
| Distributed Consensus | 1.0000 | 1.0000 | 1.0000 | Algorithms & replication topics |
| Multilingual (Russian) | 1.0000 | 1.0000 | 1.0000 | Morphological stemming + vector similarity |
| Filtered ANN (pgvector) | 1.0000 | 0.0000 | 1.0000 | High-recall iterative graph traversal |
3. Google Research TyDi QA Global Benchmark
Evaluated against the complete Google Research TyDi QA gold-standard validation corpus (4,488 authentic Wikipedia articles, 5,077 real human questions across 11 typologically diverse languages) with 400-character chunking and Reciprocal Rank Fusion (RRF):
| Benchmark Metric | Score | Description |
|---|---|---|
| Document Hit Rate @ 1 (Top-1) | 88.46% | Ground-truth relevant document is ranked #1 (Strict Document Match) |
| Document Hit Rate @ 5 (Top-5) | 92.34% | Ground-truth relevant document in Top-5 retrieved chunks |
| Document MRR (Mean Reciprocal Rank) | 0.9012 | Average reciprocal rank on ground-truth document retrieval |
| Answer Span Recall @ 5 | 91.90% | Exact fact-answer span is contained in the top-5 retrieved chunks |
| Incremental Verification Speed | 651.5 docs/sec | 4,488 documents verified via SHA-256 in 6.9 seconds (16 parallel workers) |
🚀 Quick Start
1. Installation
pip install supabase-easy-rag
2. Apply Database Migrations
Option A: Via Supabase CLI (Recommended)
# Push migrations to your linked Supabase project:
supabase db push
Option B: Via SQL Editor or CLI export
# Export migration files:
easy-rag init-sql --output ./migrations --dimensions 1536
Apply 01_schema.sql and 02_functions.sql to your Supabase project via the Supabase Dashboard SQL Editor.
3. Configure Environment Variables
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_SERVICE_ROLE_KEY="your-service-role-key"
SUPABASE_ANON_KEY="your-anon-key"
# Embedding Provider (OpenAI or Azure OpenAI)
OPENAI_API_KEY="sk-..."
# or Azure:
AZURE_OPENAI_API_KEY="your-azure-key"
AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com"
AZURE_OPENAI_EMBEDDING_DEPLOYMENT="text-embedding-3-large"
💻 Python SDK Usage
1. Hybrid Search with Parent-Context Expansion
from supabase_easy_rag import EasyRagClient
# Pass the end-user JWT for automatic RLS tenant isolation
client = EasyRagClient(user_jwt="eyJhbGci...")
# Search by dense chunk, expand to full parent section for LLM context
results = client.search_hybrid(
query="PostgreSQL connection pooling guidelines",
match_count=5,
candidate_count=50,
rrf_k=60,
expand_context="section", # "section" or "document"
)
for item in results:
print(f"[{item.final_score:.4f}] {item.document_title} > {item.section_title}")
print(item.effective_text[:200] + "...")
2. High-Throughput Parallel Directory Ingestion
# Sync a directory of Markdown documents with 8 parallel workers
sync_stats = client.sync_directory(
directory_path="./knowledgebase_docs",
batch_size=30,
max_workers=8,
enable_chunking=True,
chunk_size=800,
chunk_overlap=100,
)
print(f"Synced {sync_stats['total_files']} files in parallel.")
3. Asynchronous Client (FastAPI / Async Runtimes)
from supabase_easy_rag import AsyncEasyRagClient
async_client = AsyncEasyRagClient()
results = await async_client.search_hybrid(
query="Distributed consensus election timeouts",
match_count=3,
expand_context="section",
)
🧪 Local Docker & CI Testing
Run the full integration test suite against a local PostgreSQL container with pgvector:
# 1. Start local Postgres container with pgvector and run all 59 tests:
./scripts/run_local_postgres_tests.sh
# Or run via docker-compose manually:
docker compose -f docker-compose.test.yml up -d
POSTGRES_URL="postgresql://postgres:postgres@localhost:5432/postgres" python -m unittest discover tests -v
# Run local Postgres retrieval evaluation:
POSTGRES_URL="postgresql://postgres:postgres@localhost:5432/postgres" python eval/local_postgres_eval.py
🛠️ CLI Commands
# Export migration files
easy-rag init-sql --dimensions 1536 --output ./migrations
# Sync directory of documents
easy-rag sync ./docs --workers 8
# Execute test query with diagnostics
easy-rag query "What is distributed erasure coding?" --mode hybrid --count 5
# Manage backend API access tokens
easy-rag create-token "Production Ingestion Worker"
easy-rag list-tokens
⚙️ Architecture & Implementation Details
- Two-Stage Hybrid Fusion: Independent candidate pools are retrieved via indexed scans (
HNSWfor vector distance,GINfor full-text match) and fused using Reciprocal Rank Fusion: $$RRF_Score = \frac{w_v}{k + rank_v} + \frac{w_t}{k + rank_t}$$ This avoids arbitrary score normalization issues between cosine similarities and BM25/FTS weights. - Iterative Graph Traversal: Employs
hnsw.iterative_scan = 'relaxed_order'and dynamicp_ef_searchto prevent candidate starvation when applying strict metadata or tenant filters. - Weighted Lexical Search: Uses PostgreSQL native
setweight()indexing where document titles receive WeightA($1.0$), section headings receive WeightB($0.4$), and chunk text receives WeightD($0.1$). - Multi-Tenant Security: Enforces database-level isolation via Supabase Auth (
auth.uid()) using non-recursive Row-Level Security (RLS) policies on documents and chunks.
📄 License
Distributed under the MIT License. See LICENSE for details.
Metadata
Release files for supabase-easy-rag 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| supabase_easy_rag-0.2.0.tar.gz | 134.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| supabase_easy_rag-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 176.9 kB
Release files / supabase_easy_rag-0.2.0.tar.gz
| Download URL | supabase_easy_rag-0.2.0.tar.gz |
|---|---|
| Size | 134.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9ef2296c34a840bda1d1146823b8818fdb83fe1d95d4a83648b3e5ff5fafc2df
|
|
BLAKE2b-256 checksum How to use checksums |
987a0d076a86f33e3a35f85305c15b6e4e7401990b959e475034f4feddcca11f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / supabase_easy_rag-0.2.0-py3-none-any.whl
| Download URL | supabase_easy_rag-0.2.0-py3-none-any.whl |
|---|---|
| Size | 42.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0e8681839b5b9becda0fe14a2719a518c7670c919d98623694c0995ed2d5c998
|
|
BLAKE2b-256 checksum How to use checksums |
e435dae312843a811f4d0f2964332434f32a50a34fb179f564c635edbf651b88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|