Skip to main content

Why hybrid

Vector search alone misses exact identifiers (file name (e.g. pg_hba.conf), a ticket number, or a specific concept) because embeddings blur precise strings into approximate meaning. Keyword search alone misses the meaning, so memloom runs both (plus an entity arm) inside the database, in a single SQL function (memloom_fuse), and fuses the rankings. There’s no reranker service and no second round trip: one query, one fused result list. All arms rank saved memories and context chunks together in one pool, so “search my memories” and “search my files” are the same operation.

The three arms

The entity arm has an abstention gate: it only fires when the query is clearly about a known entity (query ↔ entity cosine ≥ 0.60). A vague query anchors to nothing and the arm contributes nothing, so it never drags in unrelated results. The keyword arm abstains the same way: no lexical match, no votes.

Reciprocal-rank fusion

Each arm produces a ranking; fusion combines ranks rather than scores (cosine distances and FTS ranks aren’t comparable):
Default weights: vector 1.0, keyword 2.0, entity 0.5. Keyword is up-weighted because it abstains when it has nothing, so its votes are cheap and precise; the entity arm is half-weighted so it works as a tiebreaker between arms rather than a winner on its own (both eval-tuned on a real corpus). A result that two arms agree on beats a result that tops one arm alone. Each recall result carries both numbers:
  • rrfScore: the fused rank score. This is the order results arrive in.
  • similarity: the raw cosine signal alone, useful as a “how semantically close” query is to the result.

What makes results good in practice

  • Exact identifiers are excellent queries. The keyword arm makes memloom recall "pg_hba.conf" precise in a way pure-vector systems can’t be.
  • Chunks embed their breadcrumb. A markdown chunk is stored as Guide > Setup > Postgres\n\n<text>: the heading path is prepended to the text, so both the vector and the keyword arm see the heading context along with the paragraph.
  • Index your store. The entity arm only works over what memloom index has processed. An unindexed store still recalls fine on the other two arms.
  • Stale never surfaces. Every arm filters status = 'active', so superseded versions of a belief can’t shadow the current one.
In offline mode (no API key) the vector arm runs on deterministic hash embeddings, which makes texts sharing words score as similar, which is a real but low signal compared to cloud embedding. The keyword arm works at full quality offline; the entity arm needs indexing, which needs the LLM. For production recall quality, just configure a key here.