QMD-style query expansion has been successfully implemented in lobs-memory.
- Query expansion using LM Studio chat API
- LRU cache (500 entries) for expanded queries
- Graceful fallback when LLM doesn't return valid expansions
- Parses
lex:,vec:, andhyde:expansion types
- Integrated query expansion into search pipeline
- Strong signal detection: Skips expansion when BM25 finds a clear winner (fast path ~15-30ms)
- Multi-query search: Each expansion type routes to appropriate backend:
lex→ BM25vec/hyde→ vector search
- RRF (Reciprocal Rank Fusion): Combines multiple ranked lists when expansion is used
- Timing tracking:
expansionMsadded to search response - Logging of expanded queries (when successful)
- Added
strongSignalThresholdtoSearchConfig.queryExpansion - Added
expansionMstoSearchResponse.timings - Added
expandedQueriestoSearchResponse
- Calls
initExpander(config)during startup
- Query expansion enabled by default
strongSignalThreshold: 0.8configured
1. Initial BM25 probe (original query)
2. Strong signal check:
- If top BM25 result score ≥ 0.8 AND significantly better than #2 → skip expansion (fast path)
- Otherwise → expand query via LM Studio
3. If expanding:
a. Generate lex/vec/hyde variants via chat API
b. Run searches for each variant (lex→BM25, vec/hyde→vector)
c. Fuse all result lists via RRF
4. Apply reranking, temporal decay, MMR (existing pipeline)
5. Return results with timing breakdown
- Total: 15-30ms
- No expansion overhead
- Most queries with exact keyword matches use this path
- Total: 200-2000ms+ (depends on LLM speed)
- Breakdown:
- BM25: 1-2ms
- Vector: 200-250ms
- Expansion: 200-2000ms (LLM generation)
The current chat model (qwen/qwen3.5-9b) generates verbose "thinking process" text instead of directly outputting the requested format. This causes:
- Slow expansion (1-2 seconds instead of 200-500ms)
- Low success rate (fallback to basic vec expansion most of the time)
Workaround implemented: Graceful fallback that uses the original query for vector search when LLM fails to parse.
Recommended fix: Use a different chat model:
- Claude (via API)
- GPT-4 (via API)
- A smaller, instruction-tuned local model (e.g., Phi-3, Mistral-7B-Instruct)
- Or configure LM Studio to suppress chain-of-thought reasoning
The current prompt is simple and directive. May need tuning for specific models. Few-shot examples were tried but the model still generates verbose output.
All core functionality verified:
- ✅ Expansion triggers when BM25 signal is weak
- ✅ Fast path works (skips expansion for strong matches)
- ✅ Timing tracked correctly (
expansionMsin response) - ✅ Expanded queries logged (when successful)
- ✅ Fallback works when LLM fails
- ✅ RRF fusion combines multiple search results
- ✅ Cache works (same query = instant expansion)
[2026-03-12 23:53:13] SEARCH "Discord bot permissions" → expanding...
No valid expansions parsed from LLM response for query: "Discord bot permissions"
vec: "Discord bot permissions"
[2026-03-12 23:53:13] SEARCH "Discord bot permissions" → 2 results in 2009ms (bm25:1ms vec:230ms expand:1765ms)
#1 [0.05] /Users/lobs/.lobs/workspace/AGENTS.md:151-205
#2 [0.03] /Users/lobs/.lobs/workspace/drafts/consumer-group-chat-LOBS-0.md:149-211
{
"results": [...],
"query": "original query",
"expandedQueries": ["vec:expanded query 1", "lex:expanded query 2"],
"timings": {
"totalMs": 2009,
"bm25Ms": 1,
"vectorMs": 230,
"expansionMs": 1765
}
}- Model selection: Use a better chat model or configure qwen to skip reasoning
- Prompt optimization: Fine-tune prompts for the specific model being used
- Expansion quality metrics: Track how often expansions improve results
- Adaptive threshold: Learn optimal
strongSignalThresholdfrom query patterns - Parallel expansion: Generate lex/vec/hyde expansions concurrently instead of sequentially
- ✅ CREATE:
~/lobs-memory/server/expander.ts - ✅ MODIFY:
~/lobs-memory/server/search.ts - ✅ MODIFY:
~/lobs-memory/server/types.ts - ✅ MODIFY:
~/lobs-memory/server/index.ts - ✅ MODIFY:
~/lobs-memory/config.json
The QMD-style query expansion system is fully implemented and functional. The core architecture is solid - the only issue is that the specific LLM model being used is too chatty. With a better-behaved model, this system should deliver the expected 200-600ms expansion times and significantly improved semantic search results.
The fallback mechanism ensures the system remains fast and reliable even when expansion doesn't work perfectly.