βββ ββββββ ββββββββββ βββββββ ββββββββββ βββββββ ββββββ βββββββ
βββ βββββββ βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββ βββββββ ββββββββββββββββββββββ ββββββββββββββββββββββ ββββ
ββββββββ βββββ ββββββββββββββββββββββ ββββββββββββββββββββββ βββ
βββ βββ βββ βββββββββββ βββββββββββββββββ ββββββ ββββββββββββ
βββ βββ βββ βββββββ βββ βββββββββββββ βββ ββββββ βββ βββββββ
HybridRAG is a backend-first Python starter for MongoDB-native AI applications with real live validation on a blessed stack.
Features β’ MongoDB 8.2 β’ Quick Start β’ Documentation β’ Contributing
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β THE FRAGMENTED WAY β
β β
β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β
β β Pinecone β β Neo4j β β Redis β β Postgres β β
β β Vectors β β Graph β β Cache β β Metadata β β
β ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ β
β β β β β β
β βββββββββββββββ΄ββββββββββββββ΄ββββββββββββββ β
β β β
β SYNC HELL π± β
β If one write fails, your RAG returns β
β vectors for deleted text β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
VS
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β THE HYBRIDRAG WAY β
β β
β βββββββββββββββββββββββ β
β β MongoDB Atlas β β
β β βββββ βββββ βββββ β β
β β β V β β G β β K β β β
β β βββββ βββββ βββββ β β
β β Vector Graph KV β β
β βββββββββββββββββββββββ β
β β β
β ONE DOCUMENT = ATOMIC β
β
β All or nothing. Never inconsistent. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DATABASE β EMBEDDINGS β LLM β SURFACE β
β ββββββββββββ β βββββββββββββ β ββββββββββββ β ββ β
β β MongoDB 8.2+ β β Voyage AI β β OpenAI API β β Python API β
β β atlas-local β β voyage-4-large β β Compatible β β REST API β
β β Atlas cloud β β Reranking β endpoints β β Rich CLI β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
HybridRAG supports multiple integrations internally, but the public reference path is intentionally narrow:
- MongoDB: Atlas 8.2+ or
mongodb/mongodb-atlas-local:previewonmongodb://localhost:27018/?directConnection=true - Embeddings/Rerank: Voyage
- LLM: OpenAI API or an OpenAI-compatible endpoint
- Product shape: Python library + FastAPI + CLI
That is the stack exercised by the release gate. Unsupported capabilities on this path should fail explicitly rather than silently degrading.
HybridRAG is built for MongoDB 8.2 with native support for the latest search operators.
from hybridrag import (
# 1. Vector Search Filters (MQL - for $vectorSearch)
VectorSearchFilterConfig,
build_vector_search_filters,
# 2. Atlas Search Filters (for $search compound queries)
AtlasSearchFilterConfig,
build_atlas_search_filters,
# 3. Lexical Prefilters (NEW - for $search.vectorSearch)
LexicalPrefilterConfig,
build_lexical_prefilters,
TextFilter, FuzzyFilter, PhraseFilter, WildcardFilter, GeoFilter,
)The game-changer: Apply Atlas Search operators (fuzzy, phrase, wildcard, geo) BEFORE vector search.
from hybridrag import LexicalPrefilterConfig, HybridRAG
# Create a lexical prefilter config
filter_config = LexicalPrefilterConfig(
# Fuzzy text matching (typo-tolerant)
fuzzy_filters=[{"path": "content", "query": "machin lerning", "maxEdits": 2}],
# Exact phrase matching
phrase_filters=[{"path": "title", "query": "vector database"}],
# Wildcard patterns
wildcard_filters=[{"path": "tags", "query": "tech*"}],
# Date range filtering
range_filters={"timestamp": {"gte": "2024-01-01"}},
# Geospatial (find docs near a location)
geo_filters=[{"path": "location", "geometry": {"type": "Point", "coordinates": [-73.9, 40.7]}}],
)
# Use with hybrid search
results = await rag.query(
query="machine learning best practices",
mode="hybrid",
lexical_filter_config=filter_config,
)| Scenario | Legacy $vectorSearch | New $search.vectorSearch |
|---|---|---|
| "Find docs about machin lerning" | β No fuzzy support | β
fuzzy: {maxEdits: 2} |
| "Exact phrase 'machine learning'" | β Vector similarity only | β
phrase: {slop: 0} |
| "Tags matching tech*" | β No wildcards | β
wildcard: {query: "tech*"} |
| "Docs within 10km of NYC" | β No geo filtering | β
geoWithin |
| "Combined filters" | β MQL only ($eq, $gte) | β Full Atlas Search syntax |
# $vectorSearch and $search use operator-specific $meta keywords.
# $rankFusion and $scoreFusion both expose the combined score via "score".
OPERATOR_SCORE_FIELDS = {
"$vectorSearch": "vectorSearchScore", # legacy $vectorSearch stage
"$search.vectorSearch": "searchScore", # MongoDB 8.2+ $search.vectorSearch
"$rankFusion": "score", # MongoDB 8.0+ (also "scoreDetails")
"$scoreFusion": "score", # MongoDB 8.3+ (also "scoreDetails")
} βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β $rankFusion (MongoDB 8.2 Native) β
β β
β βββββββββββββββββββββββββ βββββββββββββββββββββββββ β
β β VECTOR PIPELINE β β TEXT PIPELINE β β
β β $search.vectorSearch β β $search.compound β β
β β β β β β
β β βββββββββββββββββββ β β βββββββββββββββββββ β β
β β β Lexical Prefilterβ β β β Fuzzy Matching β β β
β β β (fuzzy/phrase/ β β β β β β β
β β β wildcard/geo) β β β β β β β
β β ββββββββββ¬βββββββββ β β ββββββββββ¬βββββββββ β β
β β β β β β β β
β β βββββββββββββββββββ β β βββββββββββββββββββ β β
β β β Vector Similarityβ β β β BM25 Scoring β β β
β β ββββββββββ¬βββββββββ β β ββββββββββ¬βββββββββ β β
β βββββββββββββΌββββββββββββ βββββββββββββΌββββββββββββ β
β β β β
β ββββββββββββββββ¬ββββββββββββββββββββ β
β β β
β βββββββββββββββββββββββββ β
β β Weighted Fusion β β
β β vector: 0.6 β β
β β text: 0.4 β β
β β scoreDetails: true β β
β βββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β KNOWLEDGE GRAPH ($graphLookup) β
β β
β Entity Boosting: KG relationships enhance reranking scores β
β Mix Mode: Combines vector + text + graph for comprehensive RAG β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Prerequisites: Python 3.11+ and Docker Desktop (running).
git clone https://github.com/romiluz13/Hybrid-Search-RAG.git
cd Hybrid-Search-RAG
# Create a virtual environment and install (one-time)
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[all]" # or just run: make first-time-setup
make demo # starts local MongoDB + runs the showcasemake demo brings up a local MongoDB (mongodb/mongodb-atlas-local:preview via
Docker) and runs the real MongoDB 8.2+ native hybrid-search pipeline against
seeded data β no Voyage key, no LLM key, no Atlas account. You see:
$vectorSearchβ semantic nearest neighbors (cosine)$searchβ lexical / BM25$rankFusionβ native hybrid search merging vector + lexical via RRF$graphLookupβ knowledge-graph traversal in one pipeline
The demo uses sample vectors (labeled). In production, embeddings come from Voyage AI β that's the
make demo-fullpath below.
# 1. Configure API keys
cp .env.example .env # MONGODB_URI defaults to local; add your keys
# Required: VOYAGE_API_KEY (https://dash.voyageai.com/)
# Required: one LLM key β set LLM_PROVIDER to match:
# - anthropic (default) β ANTHROPIC_API_KEY
# - openai β OPENAI_API_KEY
# - gemini β GEMINI_API_KEY
# - grove β GROVE_API_KEY + GROVE_BASE_URL
# (MongoDB internal OpenAI-compatible gateway; for SAs
# without an OpenAI/Anthropic key)
# 2. Run full RAG (ingests real Voyage embeddings + generates an answer)
make demo-full
# 3. Or start a server
make run-api # FastAPI β http://localhost:8000 (/health, /docs)
make run-ui # Chainlit β http://localhost:8001
make run-cli # interactive CLImacOS + Atlas SSL note: if you hit
SSL: CERTIFICATE_VERIFY_FAILEDagainst Atlas (common with python.org Python, which doesn't bundle CA certs), HybridRAG now automatically usescertifi's CA bundle formongodb+srv://connections. No action needed. For a corporate/custom CA, setMONGODB_TLS_CA_FILE=/path/to/your-ca.pem.
# Simple answer
answer = await rag.query("How does hybrid search work?", mode="mix")
# Source-aware response
result = await rag.query_with_sources(
"How does hybrid search work?",
mode="mix",
top_k=5,
)
print(result["answer"])
print(result["references"])
# Streaming response
stream = await rag.stream_query(
"What should a production RAG boilerplate expose?",
mode="mix",
include_context=True,
include_references=True,
)
async for chunk in stream["response_iterator"]:
print(chunk, end="")The repo is considered publish-ready only when the blessed stack passes:
- fast PR checks
- API contract tests
- example smoke tests
- deterministic live seeded validation on
atlas-local:preview - no skipped release tests
- no silent fallback on the blessed path
import asyncio
from hybridrag import create_hybridrag, LexicalPrefilterConfig
async def main():
# Initialize
rag = await create_hybridrag()
# Ingest documents
await rag.ingest_files("./documents/")
# Simple query
result = await rag.query_with_memory(
query="What are the key findings?",
mode="mix", # Vector + Graph + Keyword
)
print(result["answer"])
# Advanced: Query with lexical prefilters
filter_config = LexicalPrefilterConfig(
fuzzy_filters=[{"path": "content", "query": "machin lerning", "maxEdits": 2}],
range_filters={"timestamp": {"gte": "2024-01-01"}},
)
result = await rag.query(
query="machine learning trends",
mode="hybrid",
lexical_filter_config=filter_config,
)
asyncio.run(main())# Launch interactive CLI
hybridrag chat
# Or use Typer commands
hybridrag ingest ./documents/
hybridrag query "What is MongoDB Atlas?"
hybridrag status
hybridrag benchmark| Mode | Description | Use Case |
|---|---|---|
mix |
KG + Vector + Keyword | Recommended - General queries |
hybrid |
Vector + Keyword ($rankFusion) | Fast hybrid search |
local |
Entity-focused retrieval | Specific entities |
global |
Community summaries | High-level overview |
naive |
Vector search only | Simple similarity |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β HybridRAG β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββββββββββββββββββ β
β β Voyage AI β β Claude/GPT/ β β MongoDB Atlas 8.2 β β
β β Embeddings β β Gemini β β β β
β β + Reranking β β β β ββββββββββββββββββββββββ β β
β ββββββββββββββββββ ββββββββββββββββββ β β $rankFusion β β β
β β β $scoreFusion β β β
β β β $search.vectorSearch β β β
β β β $graphLookup β β β
β β ββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β FILTER SYSTEMS ββ
β β VectorSearchFilterConfig β AtlasSearchFilterConfig β LexicalPrefilterββ
β β (MQL: $eq, $gte, $in) β (Atlas: range, equals) β (fuzzy,phrase) ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β ENHANCEMENTS ββ
β β Entity Boosting β Query Optimizer β Self-Compacting Memory ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β INTERFACES ββ
β β Chainlit UI β Typer CLI β REST API β Python SDK ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Document | Description |
|---|---|
| Cookbook | 8 production recipes for building AI apps |
| Installation Guide | Setup and configuration |
| Architecture Decisions | ADRs for key decisions |
| Enhanced Search | Graph traversal, mix mode |
| Notebooks | Interactive tutorials (5) |
| Examples | Code examples (8) |
| Recipe | Topic | Description |
|---|---|---|
| 01 | Hybrid Search | MongoDB $rankFusion implementation |
| 02 | Lexical Prefilters | MongoDB 8.2 fuzzy/phrase/wildcard/geo |
| 03 | Conversation Memory | Multi-turn chat with self-compaction |
| 04 | Vector Optimization | numCandidates, quantization, tuning |
| 05 | Knowledge Graph | $graphLookup for entity relationships |
| 06 | Filtering Strategies | Three filter systems explained |
| 07 | Agent Memory | Long-term, working, episodic memory |
| 08 | Production | Scaling, monitoring, security |
- ADR-001: MongoDB Single Database
- ADR-002: Voyage AI Embeddings
- ADR-003: Hybrid Search RRF
- ADR-004: Prompts Module
- ADR-005: Filter Builder Systems
- ADR-006: Lexical Prefilters
# Setup development environment
make first-time-setup
# Run tests
make test # All tests
make test-quick # Fast unit tests
make test-cov # With coverage
# Code quality
make lint # Ruff linting
make format # Auto-format
make typecheck # MyPy
# Full CI suite
make ci| Task | Postgres + pgvector | HybridRAG + MongoDB |
|---|---|---|
| Add metadata field | ALTER TABLE + backfill + reindex |
Just add it |
| Change embedding model | Rewrite entire table (MVCC bloat) | Bulk update, no rewrite |
| Hybrid search | Manual result merging in app code | Single $rankFusion pipeline |
| Lexical prefilters | Not supported | $search.vectorSearch native |
| Filter vectors by metadata | Separate index, query planner struggles | Compound index, native |
| Time to first query | Hours (extensions, schema, indexes) | 30 minutes (Atlas free tier) |
We welcome contributions! See CONTRIBUTING.md for guidelines.
# Development setup
git clone https://github.com/romiluz13/Hybrid-Search-RAG.git
cd Hybrid-Search-RAG
make first-time-setup
# Run tests before submitting
make ciApache License 2.0 - see LICENSE for details.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β MongoDB 8.0+ Native: $rankFusion β’ $scoreFusion(8.3+) β’ $search.vectorSearch β
β β
β Three Filter Systems: Vector (MQL) β’ Atlas β’ Lexical Prefilters β
β β
β One MongoDB document. Atomic updates. Never inconsistent. β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Built with MongoDB 8.2 β’ Voyage AI β’ Claude