BM25 hybrid reranking for Hermes Agent session search — inspired by MemPalace searcher.py
This module extends Hermes Agent's SessionDB.search_messages() with Okapi-BM25 reranking. When FTS5 returns results, BM25 re-orders them by keyword match quality, so exact-term matches surface first instead of relying solely on FTS5's positional ranking.
FTS5 query → initial results → BM25 scoring → hybrid rank (50% FTS5 + 50% BM25) → final results
Example: Searching for "python" — a message containing both "python" and "machine learning" will rank above a message that only mentions "python" once in a later position.
| Parameter | Value | Description |
|---|---|---|
k1 |
1.5 | Term-frequency saturation |
b |
0.75 | Length normalization |
BM25_WEIGHT |
0.5 | BM25 contribution to final score |
VECTOR_WEIGHT |
0.5 | FTS5 rank contribution (semantic proxy) |
Parameters are MemPalace's proven defaults.
| File | Description |
|---|---|
hermes_state.py |
Modified SessionDB class with BM25 methods added |
test_hermes_state.py |
Unit + integration tests (16 new test cases) |
LICENSE |
MIT License |
Copy the BM25 methods from hermes_state.py into your SessionDB class:
# In SessionDB class (hermes_state.py):
# Constants (add to class)
_TOKEN_RE = re.compile(r"[\w\u0080-\U0000FFFF]{2,}", re.UNICODE)
_BM25_K1 = 1.5
_BM25_B = 0.75
_VECTOR_WEIGHT = 0.5
_BM25_WEIGHT = 0.5
# Methods to add (see hermes_state.py for full implementation):
@staticmethod
def _tokenize(text: str) -> list[str]: ...
@staticmethod
def _bm25_scores(query: str, documents: list[str]) -> list[float]: ...
@staticmethod
def _bm25_rerank(matches: list[dict], query: str) -> list[dict]: ...
# In search_messages(): call _bm25_rerank(matches, query) after FTS5 results
# and before context enrichment (both FTS5 and LIKE fallback paths)- Zero external dependencies — pure Python stdlib (
math,re) - Python 3.10+
- SQLite with FTS5 enabled
pytest tests/test_hermes_state.py::TestBM25RerankUnit -v
pytest tests/test_hermes_state.py::TestBM25RerankIntegration -vAll 16 BM25 tests pass. Full suite: 210 tests, 0 failures.
| Approach | External deps | Index needed | Best for |
|---|---|---|---|
| This (BM25 rerank) | None | No | Small corpus, Hermes-scale (~20 msgs/query) |
| rank_bm25 | numpy | Yes | Medium corpus |
| bm25s | numpy+numba | Yes | Large corpus |
| knowledge-rag | rank_bm25+ChromaDB | Yes | Full RAG pipelines |
MIT — same as Hermes Agent and MemPalace.