Skip to content

Retrieval and reranking

Hybrid retrieval

from persian_rag import HybridRetriever

retriever = HybridRetriever(embedder, rrf_k=60, dense_weight=1.0, sparse_weight=1.0)
retriever.add_chunks(chunks)
hits = retriever.retrieve("حافظ اهل کجا بود؟", k=5, mode="hybrid")
Mode Ranking Score
hybrid Reciprocal rank fusion of BM25 and dense lists Weighted RRF
dense Vector store search Store score (cosine by default)
sparse Okapi BM25 over Persian tokens BM25

Each RetrievalResult has chunk_id, document_id, text, score, character offsets, metadata, and the 1-based dense_rank and sparse_rank inside the candidate pool.

Reranking

A reranker reorders a larger candidate pool with a more expensive model. Plug one into the pipeline:

from persian_rag import CrossEncoderReranker, RAGPipeline

pipeline = RAGPipeline(
    retriever,
    llm,
    reranker=CrossEncoderReranker(),  # BAAI/bge-reranker-v2-m3
    rerank_candidates=20,
)
answer = pipeline.query("پرسش", k=4)

The retriever fetches max(k, rerank_candidates) chunks, and the reranker returns the best k. Reranked results carry the new score in score and the first-stage score in retrieval_score.

Cross-encoder

pip install "persian-rag[rerank]"

CrossEncoderReranker(model_name=..., device=None, batch_size=16, max_length=512) scores each (query, passage) pair. The default model is multilingual and handles Persian. Pass model= to reuse a loaded encoder.

LLM reranker

from persian_rag import LLMReranker

reranker = LLMReranker(llm, max_candidates=20, max_passage_chars=1200)

The model sees the query and numbered passages and returns an order such as [3, 1, 2]. Replies wrapped in prose or code fences are accepted, unknown or repeated numbers are ignored, and passages the model leaves out keep their original order at the end. Scores fall linearly with the final rank.

Your own reranker

Any object with this method works:

def rerank(
    self, query: str, results: Sequence[RetrievalResult], top_k: int | None = None
) -> list[RetrievalResult]: ...

Use arerank(reranker, query, results) to run a synchronous reranker from async code.