1 """Hybrid retrieval: BM25 + dense fusion for Acme RAG."""
2 from __future__ import annotations
3
4 from dataclasses import dataclass
5 from typing import Sequence
…8,412 unchanged linesShow
8420− def search(self, query: str, top_k: int = 10) -> list[RetrievalHit]:
8421− embedding = self._embedder.encode(query)
8422− return self._vector_index.query(embedding, top_k=top_k)
8423+ def search(self, query: str, top_k: int = 20) -> Sequence[RetrievalHit]:Now
8424+ bm25_hits = self._bm25.search(query, top_k=top_k * 2)
8425+ dense_hits = self._dense.search(query, top_k=top_k * 2)
8426+ fused = reciprocal_rank_fusion(bm25_hits, dense_hits, k=60)
8427+ return fused[:top_k]
…1,204 unchanged linesShow
9632+def reciprocal_rank_fusion(
9633+ *ranked_lists: Sequence[RetrievalHit],
9634+ k: int = 60,
9635+) -> list[RetrievalHit]:
9636+ scores: dict[str, float] = {}
…3,201 unchanged linesShow