Context
Current /search uses cosine similarity only. Research shows hybrid retrieval systems cut failure rates from 15% to 5% compared to single-mode vector search.
Motivation
Vector-only search struggles with exact keyword matches, proper nouns, and short queries. BM25 excels precisely where embedding similarity fails. Combining both gives the best of both worlds.
Implementation
Three-stage retrieval pipeline:
- BM25 full-text search via PostgreSQL
tsvector/tsquery on raw_data->>'text'
- Cosine similarity via pgvector (existing)
- RRF (Reciprocal Rank Fusion) to merge both ranked lists into a single score:
score = 1/(k + rank_bm25) + 1/(k + rank_vector) where k=60
Optional fourth stage: add ColBERT-style reranker for high-stakes queries.
Notes
- pgvector already installed — no new deps needed for BM25 (use PostgreSQL native FTS)
- Add
tsvector column to mirror_engrams and populate via trigger
- Add
recall_mode=semantic|hybrid|bm25 param to /search endpoint
- Default to
hybrid — it's strictly better than semantic alone
References
Zep Memory v2 research benchmarks, pgvector hybrid search docs
Context
Current
/searchuses cosine similarity only. Research shows hybrid retrieval systems cut failure rates from 15% to 5% compared to single-mode vector search.Motivation
Vector-only search struggles with exact keyword matches, proper nouns, and short queries. BM25 excels precisely where embedding similarity fails. Combining both gives the best of both worlds.
Implementation
Three-stage retrieval pipeline:
tsvector/tsqueryonraw_data->>'text'score = 1/(k + rank_bm25) + 1/(k + rank_vector)wherek=60Optional fourth stage: add ColBERT-style reranker for high-stakes queries.
Notes
tsvectorcolumn tomirror_engramsand populate via triggerrecall_mode=semantic|hybrid|bm25param to/searchendpointhybrid— it's strictly better thansemanticaloneReferences
Zep Memory v2 research benchmarks, pgvector hybrid search docs