Skip to content

feat(rag): enable MMR/BM25/relevance-floor + benchmark RLM refinement & reranker #10600

Closed

Description

@mrveiss

Task 4 — RAG retrieval-quality flips & hybrid search

Theme: Precision. Several retrieval-quality features are fully built but disabled by default; the hybrid path uses naive substring matching instead of the existing BM25.

Problem

  • MMR diversity disabled: knowledge/search_components/reranking.py:49 mmr_lambda=0.0; with reranking ON the crude _diversify_results is also skipped (advanced_rag_optimizer.py:799-800) → top-k can be near-duplicate chunks.
  • RLM adaptive query refinement off: services/rag_config.py:92 enable_rlm_refinement=False; full loop exists (advanced_rag_optimizer.py:945, rag_service.py:198-213) and refinement history is logged-then-discarded.
  • Hybrid keyword half uses substring TF, not BM25: advanced_rag_optimizer.py:734-740 loads all facts into memory per query and scores via _calculate_keyword_score (:365) — while knowledge/search_components/bm25.py exists unused.
  • No relevance floor on optimizer hybrid path: advanced_rag_optimizer.py:648-715 applies no min score; non-chat callers (cag_service.py:130, graph_rag_service.py:486) ingest low-relevance chunks.
  • Advanced-search feature flags never enabled: knowledge/search.py:645-647 enable_query_expansion/relevance_scoring/clustering all default False; only enable_reranking=True is passed (services/knowledge/service.py:151).
  • Dated reranker: services/rag_config.py:47 pins cross-encoder/ms-marco-MiniLM-L-6-v2 (2021).

Subtasks

  • 4.1 Enable MMR diversity — reranking.py:49, advanced_rag_optimizer.py:799
    • Step: set a sensible mmr_lambda default; benchmark via knowledge/rag_benchmarks.py
  • 4.2 Replace substring keyword scan with BM25 index — advanced_rag_optimizer.py:365,734-740, knowledge/search_components/bm25.py
    • Step: route hybrid keyword half through BM25; remove full-corpus in-memory scan
  • 4.3 Add a uniform relevance floor to advanced_search — advanced_rag_optimizer.py:648-715
    • Step: configurable min_score; protects all callers
  • 4.4 Enable advanced-search quality flags in chat retrieval — services/knowledge/service.py:151
    • Step: pass enable_query_expansion/enable_relevance_scoring (benchmark clustering separately)
  • 4.5 Benchmark + enable RLM refinement — services/rag_config.py:92
    • Step: A/B via rag_benchmarks.py; flip default only if recall improves without latency regression
  • 4.6 Benchmark a stronger reranker — services/rag_config.py:47
    • Step: try bge-reranker / larger ms-marco; config-only swap; keep if precision lifts
  • 4.7 Surface reranker-active metric — reranking.py:383-440
    • Step: emit health signal when reranking silently falls back (no sentence_transformers)

Verification

  • Run knowledge/rag_benchmarks.py before/after each flip; record precision/recall deltas in the issue
  • Confirm no latency regression on chat retrieval

Notes

Every flip is config-gated and benchmarked — no blind enabling. Reuse existing BM25/MMR/reranker code; do not reimplement.

Activity

  1. mrveiss commented on Jun 28, 2026

    @mrveiss
    OwnerAuthor

    Part of umbrella #10603 (AutoBot Efficiency & Precision).

  2. mrveiss commented on Jun 29, 2026

    @mrveiss
    OwnerAuthor

    Decision doc — RAG quality flips (blocked on a missing eval, needs your call)

    These flips can't follow the issue's "benchmark then flip" plan as written, because knowledge/rag_benchmarks.py is a performance-timing harness (vector-similarity speed, top-k latency, chunking throughput) — not a precision/recall quality eval. There is no labeled-query quality benchmark in the repo, so retrieval-quality changes can't be measured objectively today.

    The flips, by risk

    Flip Flag / location Risk Notes
    MMR diversity rag_config.py:51 mmr_lambda (0.0=off) Low Reorders top-k for diversity; reversible; no recall loss
    Relevance floor on optimizer hybrid path advanced_rag_optimizer.advanced_search (no min) Low Pure precision guard; only drops sub-threshold chunks
    Query expansion / relevance scoring knowledge/search.py flags (default False) Low-med Recall aid; more terms = more context
    BM25 hybrid (replace substring scan) search_components/bm25.py (built, unused) Med Structural; needs A/B to confirm it beats substring
    RLM adaptive refinement rag_config.py:92 enable_rlm_refinement=False Med Iterative re-query; latency + quality tradeoff
    Reranker swap (ms-marco-MiniLM → bge) rag_config.py:47 reranking_model Med Config swap; needs quality A/B

    Your decision (pick one)

    • A — Build a quality eval first (effort: moderate): a small labeled query→relevant-doc set + precision@k/recall@k script, then flip each with evidence. Most rigorous; unblocks all six.
    • B — Enable low-risk now, defer the rest: turn on MMR + relevance-floor + query-expansion (all config-gated, reversible, no recall loss); leave BM25/RLM/reranker-swap until a quality eval exists. (Recommended — captures the safe wins without guessing on quality.)
    • C — Leave as-is until the eval harness is prioritized.

    I can implement B immediately (config-gated PRs) if you approve — no eval needed for those three. The rest stay tracked here pending the eval decision.

  3. mrveiss commented on Jul 6, 2026

    @mrveiss
    OwnerAuthor

    Delivered via PR #10985 — MMR + BM25 hybrid + relevance-floor wired into the optimizer chat retrieval path behind config flags (all default OFF, no blind flips); reranker health metric added. 42 tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions