ENSUREOK
← 返回 Blog
E0 · design or editorial contextSource ↗

Debug Diary: BM25 Found It, Hybrid Ranked It First

I wanted to know what “semantic search” meant in this repository, so I followed the code instead of the label.

First pass: BM25

BM25 uses k1=1.2 and b=0.75. Non-CJK text is tokenized by word; CJK text is tokenized in a way that preserves character-level matching. It is fast and explainable, but paraphrases with little lexical overlap can miss.

Second pass: hash vectors

The built-in embedder is not a neural model. It hashes character n-grams into a deterministic, normalized vector. That gives a zero-dependency similarity signal and supports CJK text, with an obvious tradeoff: hash collisions and shallow features limit discrimination.

Third pass: hybrid

Hybrid mode runs both searches and combines rankings with Reciprocal Rank Fusion.

semantix search --query "fix the failing Go test" --retriever bm25
semantix search --query "fix the failing Go test" --retriever vector
semantix search --query "fix the failing Go test" --retriever hybrid

Repository tests use a small repair-related fixture and assert that vector and hybrid modes return the repair slice. That is a valid regression test, not a general relevance benchmark.

Debugging rule

When hybrid surprises you, print the BM25 rank, vector rank, and fused rank separately. Do not tune a threshold from one anecdote. Build a labeled set with misses, near-misses, CJK queries, and cross-scope negatives. The public M0 gate still lists “70% real-session relevance as pending, so the current implementation should be described as available and testable—not proven superior.

Sources and limitations