feat: built-in query expansion for recall() #16
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Recall quality is significantly limited when the query phrasing doesn't closely match how information was originally stored. A question like "What degree did I graduate with?" scores poorly against a session that says "I studied Business Administration at university" — the vocabulary is different even though the meaning is the same.
The current workaround is to implement query expansion in the calling client, generating multiple search variants and unioning the results. This works but pushes complexity onto every caller.
Evidence from LongMemEval benchmark
Without query expansion, even with good turn-pair chunking, some questions fail to retrieve anything because the question phrasing and stored content don't share vocabulary. With query expansion generating 3 variants per question, recall coverage improves substantially — we went from needing to write ~50 lines of client-side expansion logic to a single flag.
Example:
All 4 queries are run, results are unioned by key and re-ranked by top score.
Proposed solution
Add an
expand_queriesflag torecall()andrecall_index():When
expand_queries=True:ANTHROPIC_API_KEYintegration) to generate N variant queriestop_kConfiguration
Why in OmniMem rather than the client
recall()call instead of a loop over variantsCost consideration
Each expansion call adds ~1 Claude API call (Haiku is sufficient, ~0.01p per expansion). Only fires when
expand_queries=Trueor the env var is set, so it's opt-in.Related
remember_document()) — both issues stem from the LongMemEval benchmark projectClosing — shipped in v5.0.0.
recall()andrecall_index()take anexpand_queriesflag (default followsRECALL_EXPAND_QUERIES, count viaRECALL_EXPAND_COUNT): Claude Haiku generates alternative phrasings, results are unioned across variants and deduplicated, and variants are cached in Valkey underqexp:<sha1>with a 24h TTL so repeated queries don't re-bill the API.Two refinements since: v5.3.0 gave variant searches the same query-side state/project filter push-down and candidate over-fetch as the main query, and v5.3.1 fixed variants not applying the temporal boost (date-anchored memories ranked lower when found via a variant than via the original query).