RankLLM
repository·main·Indexed 20 days ago
https://github.com/castorini/rank_llmA suite of rerankers for high-efficiency information retrieval using pointwise (e.g., MonoT5), pairwise (e.g., DuoT5), and listwise (e.g., RankGPT, RankZephyr) models. It supports both open-source LLMs via vLLM and SGLang, and proprietary models from providers like OpenAI and Gemini. The package includes a CLI for reranking, evaluation, and serving models via HTTP or MCP, as well as tools for fine-tuning models with generation, ranking, or combined objectives.
What's inside rank-llm
- FIRST (Faster Improved Listwise Reranking with Single Token Decoding) is a reranking approach designed for higher inference efficiency. Unlike traditional listwise reranking, which prompts an LLM to generate a full text-based ranking (e.g., "[3] > [1] > [2]"), FIRST examines the probability that each document will be ranked as the top document by analyzing the LLM's logits. This avoids the bottleneck of waiting for full text generation, potentially improving inference speed by up to 42%.
How Listwise Reranking with Sliding Windows works
mainListwise reranking involves presenting an LLM with a query and a list of candidate documents, asking it to output a ranked ordering of those documents.
Because LLMs have finite context lengths (e.g., 4096 tokens), a sliding window approach is used to rank long lists of documents:
- A window size and a stride are defined.
- The algorithm scans the list (often from back to front) using the window.
- In each iteration, the LLM reorders the documents within the current window.
- The window then advances by the stride amount, and the process repeats.
While the final ranking might not be a perfect global optimum, this method effectively pushes the most relevant documents toward the top of the list. Common practical settings are a window size of 20 and a stride of 10.
Understand Multi-stage Retrieval
mainMulti-stage retrieval is a technique used to improve retrieval quality while managing computational costs. It consists of two main phases:
- First-stage retrieval: A computationally efficient method (e.g., sparse or dense retrieval) used to narrow down a massive collection of documents to a manageable number of candidates (e.g., reducing 8 million documents to 1,000).
- Reranking: A more computationally expensive algorithm applied only to the small set of candidates from the first stage to refine their order and improve metrics like nDCG or AP.
This approach allows for the use of high-quality but slow models (like LLMs) that would be impractical to run against an entire corpus.
Install Gemini provider extra
mainTo use Gemini models (like
gemini-3-flash-preview) with RankLLM, you must first install thegenaiextra usinguvorpip.After installation, run the model using the
run_rank_llm.pyscript with the appropriate--model_pathand--prompt_template_path.# Using uv uv sync --group dev --extra genai # Or using pip pip install -e ".[genai]"Install RankLLM for Development
mainFor development or to access the latest features, clone the repository and use
uvto set up a local virtual environment with development dependencies.git clone https://github.com/castorini/rank_llm.git cd rank_llm uv python install 3.11 uv venv --python 3.11 source .venv/bin/activate uv sync --group devCompare FIRST speed with traditional listwise reranking
mainTo compare the speed of the FIRST approach against traditional listwise reranking using therun_rank_llm.pyscript, run the command without the--use_logitsand--use_alphaflags.Fine-tune a model using train_rankllm.py
mainTo fine-tune a model for RankLLM, use the
accelerate launch train_rankllm.pycommand. You can choose between three training objectives via the--objectiveflag:generation: Traditional language modelling objective.ranking: Learning-to-rank objective.combined: A combination of both objectives.
Required and common arguments:
--model_name_or_path: Path to the model to fine-tune.--train_dataset_path: Path to the training dataset.--num_train_epochs: Number of training epochs.--seed: Random seed.--per_device_train_batch_size: Batch size per device.--gradient_accumulation_steps: Number of gradient accumulation steps.--num_warmup_steps: Number of warmup steps.--gradient_checkpointing: Enable gradient checkpointing.--output_dir: Directory to save the output.--noisy_embedding_alpha: Alpha value for noisy embeddings.--objective: The training objective (generation,ranking, orcombined).
DS_SKIP_CUDA_CHECK=1 NCCL_IB_DISABLE=1 NCCL_P2P_DISABLE=1 PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True accelerate launch train_rankllm.py \ --model_name_or_path <path-to-model> \ --train_dataset_path <path-to-train-dataset> \ --num_train_epochs <num-epochs> \ --seed <seed> \ --per_device_train_batch_size <batch-size> \ --gradient_accumulation_steps <gradient-accumulation-steps> \ --num_warmup_steps <num-warmup-steps> \ --gradient_checkpointing \ --output_dir <output-dir> \ --noisy_embedding_alpha <noisy-embedding-alpha> \ --objective <objective>Integrate RankLLM with Llama Index
mainRankLLM can be used as a post-processor in Llama Index to rerank nodes retrieved from a vector index.
Installation:
pip install llama-index-core llama-index-embeddings-huggingface llama-index-postprocessor-rank-llm rank_llm transformers requestsUsage Pattern:
- Build a standard Llama Index
VectorStoreIndexusingHuggingFaceEmbedding. - Retrieve nodes using a
VectorIndexRetriever. - Pass the retrieved nodes to
RankLLMRerank.postprocess_nodes(). - Memory Management: If using
rank_zephyr, calldel rerankerandtorch.cuda.empty_cache()after post-processing to free the ~16GB of VRAM required.
from llama_index.core import VectorStoreIndex, Settings from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.postprocessor.rankllm_rerank import RankLLMRerank from llama_index.core.retrievers import VectorIndexRetriever from llama_index.core import QueryBundle import torch # Setup Index Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5") index = VectorStoreIndex.from_documents(documents) # Retrieval and Reranking query_bundle = QueryBundle("Which date did Paul Gauguin arrive in Arles?") retriever = VectorIndexRetriever(index=index, similarity_top_k=50) retrieved_nodes = retriever.retrieve(query_bundle) # Apply RankLLM reranker = RankLLMRerank(model="rank_zephyr", top_n=3, window_size=15) reranked_nodes = reranker.postprocess_nodes(retrieved_nodes, query_bundle) # Cleanup del reranker torch.cuda.empty_cache()- Build a standard Llama Index
Run end-to-end reranking with FirstMistral
mainFirstMistral is an LLM fine-tuned for the FIRST approach. You can run an end-to-end multi-stage retrieval pipeline using the
run_rank_llm.pyscript. This example performs first-stage retrieval withSPLADE++_EnsembleDistil_ONNXto retrieve 100 candidates, followed by listwise reranking using FIRST with theFirstMistralmodel.Note: This requires that the necessary
rank_llminstallation steps for RankZephyr have already been completed.python src/rank_llm/scripts/run_rank_llm.py --model_path=castorini/first_mistral --top_k_candidates=100 --dataset=dl20 --retrieval_method=SPLADE++_EnsembleDistil_ONNX --prompt_template_path=src/rank_llm/rerank/prompt_templates/rank_zephyr_alpha_template.yaml --context_size=4096 --variable_passages --use_logits --use_alpha --num_gpus 1Integrate RankLLM with LangChain
mainTo use RankLLM within a LangChain workflow, install the necessary dependencies and use the
RankLLMRerankcompressor with aContextualCompressionRetriever. This allows you to take a base retriever (like FAISS) and apply RankLLM reranking to the retrieved documents.Installation:
pip install langchain-community faiss-gpu torch transformers sentence-transformers huggingface-hub rank_llmUsage Pattern:
- Set up a standard LangChain retriever (e.g., using
FAISSandHuggingFaceEmbeddings). - Initialize
RankLLMRerankwith your desiredtop_nandmodel_path. - Wrap the base retriever in a
ContextualCompressionRetrieverusing the RankLLM compressor. - Note: If using
rank_zephyr, it consumes approximately 16GB of GPU VRAM. It is recommended todel compressorand calltorch.cuda.empty_cache()after use to free memory.
from langchain_community.document_loaders import TextLoader from langchain_community.vectorstores import FAISS from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain.retrievers import ContextualCompressionRetriever from rank_llm import RankLLMRerank import torch # 1. Setup base retriever documents = TextLoader("state_of_the_union.txt").load() text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100) texts = text_splitter.split_documents(documents) embedding = HuggingFaceEmbeddings(model_name="BAAI/bge-small-en", model_kwargs={'device': 'cuda'}) retriever = FAISS.from_documents(texts, embedding).as_retriever(search_kwargs={"k": 20}) # 2. Setup Reranker torch.cuda.empty_cache() compressor = RankLLMRerank(top_n=3, model_path="rank_zephyr") compression_retriever = ContextualCompressionRetriever( base_compressor=compressor, base_retriever=retriever ) # 3. Use query = "What was done to Russia?" compressed_docs = compression_retriever.invoke(query) # 4. Cleanup del compressor- Set up a standard LangChain retriever (e.g., using
Install RankLLM via PyPI
mainTo install the published
rank-llmpackage in an isolated virtual environment, useuv. This is the recommended method for users who do not need to develop on the source code directly.uv venv --python 3.11 source .venv/bin/activate uv pip install rank-llmIntegrate RankLLM with Rerankers
mainThe
rerankerslibrary provides a streamlined way to use RankLLM by specifyingmodel_type="rankllm".Installation:
pip install "rerankers[rankllm]"Usage: Initialize the
Rerankerclass with the model name and the specificmodel_type.Configuration Arguments for Reranker (model_type="rankllm"):
model: str (default: "rank_zephyr")window_size: int (default: 20)context_size: int (default: 4096)prompt_template_path: strnum_few_shot_examples: int (default: 0)few_shot_file: Optional[str] (default: None)num_gpus: int (default: 1)variable_passages: bool (default: False)use_logits: bool (default: False)use_alpha: bool (default: False)stride: int (default: 10)use_azure_openai: bool (default: False)
from rerankers import Reranker ranker = Reranker('rank_zephyr', model_type="rankllm") results = ranker.rank( query="I love you", docs=["I hate you", "I really like you"], doc_ids=[0, 1] ) print(results)