Skip to content

Repository files navigation

rerank-lite

Lightweight retrieval reranker for JavaScript and TypeScript -- zero dependencies, three scoring modes, one API.

npm versionnpm downloadslicensenode


Description

rerank-lite takes a query and a list of candidate documents from a first-stage retriever (vector search, BM25, or fusion) and reorders them by relevance. It is the second stage of a two-stage retrieval pipeline: stage one retrieves candidates quickly with approximate methods, stage two reranks them precisely for the final result set.

The package ships three scoring modes that share a single rerank() API and return the same RerankResult[] output:

  • Heuristic -- BM25 + TF-IDF + position-based scoring with zero external dependencies. Works immediately after install.
  • LLM -- Delegates scoring to a caller-supplied judge function. Bring any LLM provider (OpenAI, Anthropic, local Ollama, etc.).
  • Hybrid -- A 50/50 blend of heuristic and LLM scores for balanced accuracy and cost.

All scores are normalized to the [0, 1] range. The output is ready to pass to a context packer, fusion ranker, or directly into an LLM prompt.


Installation

npm install rerank-lite

Requires Node.js 18 or later.


Quick Start

import{rerank}from'rerank-lite'constdocuments=[{id: 'doc-0',text: 'Machine learning model training with neural networks'},{id: 'doc-1',text: 'Quick sort algorithm and data structures'},{id: 'doc-2',text: 'Deep learning transformer architecture for NLP'},]constresults=awaitrerank('machine learning neural network',documents)for(constresultofresults){console.log(`[rank ${result.newRank}] ${result.document.id} -- score: ${result.score.toFixed(4)}`)}

Features

  • Three scoring modes -- heuristic, LLM-as-judge, and hybrid, all behind one function signature.
  • Zero runtime dependencies -- heuristic mode is pure TypeScript with no external packages.
  • BM25 scoring -- corpus-aware term frequency / inverse document frequency with configurable k1 and b parameters, normalized via sigmoid.
  • TF-IDF cosine similarity -- builds TF-IDF vectors for the query and each document, scores by cosine similarity against the corpus.
  • Position bias -- original retrieval rank feeds into the composite score, preserving signal from the first-stage retriever.
  • Configurable weights -- tune the relative contribution of BM25, TF-IDF, and position scoring.
  • Top-K and minimum score filtering -- limit output to the top K results and filter below a score threshold.
  • Pluggable LLM judge -- pass any async function that scores a (query, document) pair. No SDK lock-in.
  • Factory pattern -- createReranker() returns a preconfigured instance for repeated use across many queries.
  • Full TypeScript support -- ships with declaration files and source maps. All types are exported.

API Reference

rerank(query, documents, options?)

Reranks an array of documents against a query. Returns a Promise<RerankResult[]> sorted by relevance score descending.

import{rerank}from'rerank-lite'constresults=awaitrerank('machine learning',documents,{mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},})

Parameters:

ParameterTypeRequiredDescription
querystringYesThe search query to rank documents against.
documentsDocument[]YesArray of candidate documents from a first-stage retriever.
optionsRerankOptionsNoConfiguration for scoring mode, filtering, and weights.

Returns:Promise<RerankResult[]> -- results sorted by score descending, with newRank assigned as 0-based indices.

Behavior with empty input: Returns an empty array when documents is empty.


createReranker(config?)

Factory that returns a configured Reranker instance. Preset options are applied to every rerank() call; per-call options override the preset.

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,weights: {bm25: 0.6,tfidf: 0.3,position: 0.1},})constresults=awaitreranker.rerank('first query',docs)// Override topK for this call onlyconsttop3=awaitreranker.rerank('second query',docs,{topK: 3})

Parameters:

ParameterTypeRequiredDescription
configRerankerConfigNoDefault configuration applied to all calls.

Returns:Reranker -- an object with a rerank() method and a read-only config property.


Types

Document

Represents a candidate document to be scored.

interfaceDocument{id: string// Unique identifier for the documenttext: string// The text content to score against the queryscore?: number// Optional original retrieval scoremetadata?: Record<string,unknown>// Optional pass-through metadata}

RerankResult

A scored and ranked document returned by rerank().

interfaceRerankResult{document: Document// The original document object, including metadatascore: number// Relevance score in [0, 1]originalRank: number// 0-based index in the input arraynewRank: number// 0-based rank after reranking (0 = most relevant)explanation?: string// Optional debug information}

RerankOptions

Options for a single rerank() call.

interfaceRerankOptions{topK?: number// Return only the top K results (default: all)minScore?: number// Filter out results with a score below this thresholdmode?: RerankMode// Scoring mode (default: 'heuristic')judgeFn?: JudgeFn// Required when mode is 'llm' or 'hybrid'weights?: ScoringWeights// Custom weights for heuristic scoring components}

RerankMode

typeRerankMode='heuristic'|'llm'|'hybrid'
ModeDescription
heuristicBM25 + TF-IDF + position weighted scoring. Zero dependencies. Default.
llmDelegates scoring entirely to the caller-supplied judgeFn.
hybrid50/50 blend of heuristic scores and judgeFn scores.

JudgeFn

The function signature for LLM-as-judge scoring.

typeJudgeFn=(query: string,document: string)=>Promise<number>

Must return a numeric relevance score. Called once per document when mode is llm or hybrid.

ScoringWeights

Weights for the three heuristic scoring signals. All are optional and default to the values shown.

interfaceScoringWeights{bm25?: number// Default: 0.5tfidf?: number// Default: 0.3position?: number// Default: 0.2}

RerankerConfig

Configuration for the createReranker() factory. Same shape as RerankOptions.

interfaceRerankerConfig{mode?: RerankModetopK?: numberminScore?: numberjudgeFn?: JudgeFnweights?: ScoringWeights}

Reranker

The instance returned by createReranker().

interfaceReranker{rerank(query: string,documents: Document[],options?: RerankOptions): Promise<RerankResult[]>readonlyconfig: RerankerConfig}

Configuration

Scoring Weights

The heuristic composite score is computed as:

score = (bm25_weight * bm25_score) + (tfidf_weight * tfidf_score) + (position_weight * position_score)

Default weights:

SignalDefault WeightDescription
bm250.5BM25 term frequency / inverse document frequency score, normalized to [0, 1] via sigmoid.
tfidf0.3TF-IDF cosine similarity between query and document vectors.
position0.2Position bias: 1 - (originalRank / totalDocuments). Preserves signal from the first-stage retriever.

Override weights to tune for your retrieval domain:

// Favor lexical match, ignore original orderingconstresults=awaitrerank('exact keyword query',docs,{weights: {bm25: 0.7,tfidf: 0.3,position: 0.0},})// Trust the first-stage retriever, use reranking as a tiebreakerconstresults=awaitrerank('semantic query',docs,{weights: {bm25: 0.2,tfidf: 0.2,position: 0.6},})

BM25 Parameters

The BM25 scorer accepts standard tuning parameters k1 (term frequency saturation, default 1.5) and b (document length normalization, default 0.75). These are set internally and follow the Robertson/Zaragoza BM25 formulation.


Error Handling

rerank() handles edge cases gracefully without throwing:

  • Empty documents array -- returns an empty array [].
  • No matching terms -- all documents receive a baseline score (sigmoid of zero for BM25, zero for TF-IDF). Documents are still ranked by position bias.
  • Empty query or document text -- TF-IDF returns 0 for empty strings. BM25 returns the sigmoid baseline (0.5).

When using llm or hybrid mode, errors from the judgeFn propagate as-is. Wrap your judge function with try/catch if you need graceful degradation:

constsafejudgeFn=async(query: string,doc: string): Promise<number>=>{try{returnawaityourLLMScorer(query,doc)}catch{return0// Fallback score on failure}}constresults=awaitrerank('query',docs,{mode: 'llm',judgeFn: safejudgeFn})

Advanced Usage

LLM-as-Judge Mode

Pass any async function that returns a relevance score. The function is called once per document.

import{rerank}from'rerank-lite'importOpenAIfrom'openai'constopenai=newOpenAI()constjudgeFn=async(query: string,document: string): Promise<number>=>{constresponse=awaitopenai.chat.completions.create({model: 'gpt-4o-mini',messages: [{role: 'user',content: `Rate the relevance of this document to the query on a scale from 0 to 1.\nQuery: ${query}\nDocument: ${document}\nRespond with only a number between 0 and 1.`,},],})returnparseFloat(response.choices[0].message.content??'0')}constresults=awaitrerank('machine learning',docs,{mode: 'llm', judgeFn })

Hybrid Mode

Combines heuristic scoring with LLM judgment. The final score is a 50/50 blend:

hybrid_score = 0.5 * heuristic_score + 0.5 * llm_score
constresults=awaitrerank('machine learning',docs,{mode: 'hybrid',
judgeFn,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},// Applies to heuristic half})

RAG Pipeline Integration

Use reranking as stage two after vector search or BM25 retrieval:

// Stage 1: Retrieve candidates from your vector databaseconstcandidates=awaitvectorDB.query(embedding,{topK: 50})// Stage 2: Rerank for precisionconstreranked=awaitrerank(query,candidates,{topK: 10,minScore: 0.4})// Stage 3: Pass to LLM contextconstcontext=reranked.map(r=>r.document.text).join('\n\n')

Reusable Reranker Instance

For applications that rerank many queries with the same configuration:

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.6,tfidf: 0.25,position: 0.15},})// Use across multiple queriesconstresults1=awaitreranker.rerank('first query',docs1)constresults2=awaitreranker.rerank('second query',docs2)// Override per-call when neededconstresults3=awaitreranker.rerank('third query',docs3,{topK: 5})

Filtering with minScore and topK

minScore is applied first, then topK limits the output:

// Return at most 5 results, all with score >= 0.5constresults=awaitrerank('query',docs,{topK: 5,minScore: 0.5})

TypeScript

rerank-lite is written in TypeScript and ships with declaration files (.d.ts) and source maps. All types are exported from the package entry point:

import{rerank,createReranker,typeDocument,typeRerankResult,typeRerankOptions,typeRerankMode,typeJudgeFn,typeScoringWeights,typeRerankerConfig,typeReranker,}from'rerank-lite'

The package targets ES2022 and emits CommonJS modules. It is compatible with both require() and bundlers that resolve the exports field.


License

MIT

About

Lightweight retrieval reranker using cross-encoder scoring

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - SiluPanda/rerank-lite: Lightweight retrieval reranker using cross-encoder scoring · GitHub
Skip to content

Repository files navigation

rerank-lite

Lightweight retrieval reranker for JavaScript and TypeScript -- zero dependencies, three scoring modes, one API.

npm versionnpm downloadslicensenode


Description

rerank-lite takes a query and a list of candidate documents from a first-stage retriever (vector search, BM25, or fusion) and reorders them by relevance. It is the second stage of a two-stage retrieval pipeline: stage one retrieves candidates quickly with approximate methods, stage two reranks them precisely for the final result set.

The package ships three scoring modes that share a single rerank() API and return the same RerankResult[] output:

  • Heuristic -- BM25 + TF-IDF + position-based scoring with zero external dependencies. Works immediately after install.
  • LLM -- Delegates scoring to a caller-supplied judge function. Bring any LLM provider (OpenAI, Anthropic, local Ollama, etc.).
  • Hybrid -- A 50/50 blend of heuristic and LLM scores for balanced accuracy and cost.

All scores are normalized to the [0, 1] range. The output is ready to pass to a context packer, fusion ranker, or directly into an LLM prompt.


Installation

npm install rerank-lite

Requires Node.js 18 or later.


Quick Start

import{rerank}from'rerank-lite'constdocuments=[{id: 'doc-0',text: 'Machine learning model training with neural networks'},{id: 'doc-1',text: 'Quick sort algorithm and data structures'},{id: 'doc-2',text: 'Deep learning transformer architecture for NLP'},]constresults=awaitrerank('machine learning neural network',documents)for(constresultofresults){console.log(`[rank ${result.newRank}] ${result.document.id} -- score: ${result.score.toFixed(4)}`)}

Features

  • Three scoring modes -- heuristic, LLM-as-judge, and hybrid, all behind one function signature.
  • Zero runtime dependencies -- heuristic mode is pure TypeScript with no external packages.
  • BM25 scoring -- corpus-aware term frequency / inverse document frequency with configurable k1 and b parameters, normalized via sigmoid.
  • TF-IDF cosine similarity -- builds TF-IDF vectors for the query and each document, scores by cosine similarity against the corpus.
  • Position bias -- original retrieval rank feeds into the composite score, preserving signal from the first-stage retriever.
  • Configurable weights -- tune the relative contribution of BM25, TF-IDF, and position scoring.
  • Top-K and minimum score filtering -- limit output to the top K results and filter below a score threshold.
  • Pluggable LLM judge -- pass any async function that scores a (query, document) pair. No SDK lock-in.
  • Factory pattern -- createReranker() returns a preconfigured instance for repeated use across many queries.
  • Full TypeScript support -- ships with declaration files and source maps. All types are exported.

API Reference

rerank(query, documents, options?)

Reranks an array of documents against a query. Returns a Promise<RerankResult[]> sorted by relevance score descending.

import{rerank}from'rerank-lite'constresults=awaitrerank('machine learning',documents,{mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},})

Parameters:

ParameterTypeRequiredDescription
querystringYesThe search query to rank documents against.
documentsDocument[]YesArray of candidate documents from a first-stage retriever.
optionsRerankOptionsNoConfiguration for scoring mode, filtering, and weights.

Returns:Promise<RerankResult[]> -- results sorted by score descending, with newRank assigned as 0-based indices.

Behavior with empty input: Returns an empty array when documents is empty.


createReranker(config?)

Factory that returns a configured Reranker instance. Preset options are applied to every rerank() call; per-call options override the preset.

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,weights: {bm25: 0.6,tfidf: 0.3,position: 0.1},})constresults=awaitreranker.rerank('first query',docs)// Override topK for this call onlyconsttop3=awaitreranker.rerank('second query',docs,{topK: 3})

Parameters:

ParameterTypeRequiredDescription
configRerankerConfigNoDefault configuration applied to all calls.

Returns:Reranker -- an object with a rerank() method and a read-only config property.


Types

Document

Represents a candidate document to be scored.

interfaceDocument{id: string// Unique identifier for the documenttext: string// The text content to score against the queryscore?: number// Optional original retrieval scoremetadata?: Record<string,unknown>// Optional pass-through metadata}

RerankResult

A scored and ranked document returned by rerank().

interfaceRerankResult{document: Document// The original document object, including metadatascore: number// Relevance score in [0, 1]originalRank: number// 0-based index in the input arraynewRank: number// 0-based rank after reranking (0 = most relevant)explanation?: string// Optional debug information}

RerankOptions

Options for a single rerank() call.

interfaceRerankOptions{topK?: number// Return only the top K results (default: all)minScore?: number// Filter out results with a score below this thresholdmode?: RerankMode// Scoring mode (default: 'heuristic')judgeFn?: JudgeFn// Required when mode is 'llm' or 'hybrid'weights?: ScoringWeights// Custom weights for heuristic scoring components}

RerankMode

typeRerankMode='heuristic'|'llm'|'hybrid'
ModeDescription
heuristicBM25 + TF-IDF + position weighted scoring. Zero dependencies. Default.
llmDelegates scoring entirely to the caller-supplied judgeFn.
hybrid50/50 blend of heuristic scores and judgeFn scores.

JudgeFn

The function signature for LLM-as-judge scoring.

typeJudgeFn=(query: string,document: string)=>Promise<number>

Must return a numeric relevance score. Called once per document when mode is llm or hybrid.

ScoringWeights

Weights for the three heuristic scoring signals. All are optional and default to the values shown.

interfaceScoringWeights{bm25?: number// Default: 0.5tfidf?: number// Default: 0.3position?: number// Default: 0.2}

RerankerConfig

Configuration for the createReranker() factory. Same shape as RerankOptions.

interfaceRerankerConfig{mode?: RerankModetopK?: numberminScore?: numberjudgeFn?: JudgeFnweights?: ScoringWeights}

Reranker

The instance returned by createReranker().

interfaceReranker{rerank(query: string,documents: Document[],options?: RerankOptions): Promise<RerankResult[]>readonlyconfig: RerankerConfig}

Configuration

Scoring Weights

The heuristic composite score is computed as:

score = (bm25_weight * bm25_score) + (tfidf_weight * tfidf_score) + (position_weight * position_score)

Default weights:

SignalDefault WeightDescription
bm250.5BM25 term frequency / inverse document frequency score, normalized to [0, 1] via sigmoid.
tfidf0.3TF-IDF cosine similarity between query and document vectors.
position0.2Position bias: 1 - (originalRank / totalDocuments). Preserves signal from the first-stage retriever.

Override weights to tune for your retrieval domain:

// Favor lexical match, ignore original orderingconstresults=awaitrerank('exact keyword query',docs,{weights: {bm25: 0.7,tfidf: 0.3,position: 0.0},})// Trust the first-stage retriever, use reranking as a tiebreakerconstresults=awaitrerank('semantic query',docs,{weights: {bm25: 0.2,tfidf: 0.2,position: 0.6},})

BM25 Parameters

The BM25 scorer accepts standard tuning parameters k1 (term frequency saturation, default 1.5) and b (document length normalization, default 0.75). These are set internally and follow the Robertson/Zaragoza BM25 formulation.


Error Handling

rerank() handles edge cases gracefully without throwing:

  • Empty documents array -- returns an empty array [].
  • No matching terms -- all documents receive a baseline score (sigmoid of zero for BM25, zero for TF-IDF). Documents are still ranked by position bias.
  • Empty query or document text -- TF-IDF returns 0 for empty strings. BM25 returns the sigmoid baseline (0.5).

When using llm or hybrid mode, errors from the judgeFn propagate as-is. Wrap your judge function with try/catch if you need graceful degradation:

constsafejudgeFn=async(query: string,doc: string): Promise<number>=>{try{returnawaityourLLMScorer(query,doc)}catch{return0// Fallback score on failure}}constresults=awaitrerank('query',docs,{mode: 'llm',judgeFn: safejudgeFn})

Advanced Usage

LLM-as-Judge Mode

Pass any async function that returns a relevance score. The function is called once per document.

import{rerank}from'rerank-lite'importOpenAIfrom'openai'constopenai=newOpenAI()constjudgeFn=async(query: string,document: string): Promise<number>=>{constresponse=awaitopenai.chat.completions.create({model: 'gpt-4o-mini',messages: [{role: 'user',content: `Rate the relevance of this document to the query on a scale from 0 to 1.\nQuery: ${query}\nDocument: ${document}\nRespond with only a number between 0 and 1.`,},],})returnparseFloat(response.choices[0].message.content??'0')}constresults=awaitrerank('machine learning',docs,{mode: 'llm', judgeFn })

Hybrid Mode

Combines heuristic scoring with LLM judgment. The final score is a 50/50 blend:

hybrid_score = 0.5 * heuristic_score + 0.5 * llm_score
constresults=awaitrerank('machine learning',docs,{mode: 'hybrid',
judgeFn,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},// Applies to heuristic half})

RAG Pipeline Integration

Use reranking as stage two after vector search or BM25 retrieval:

// Stage 1: Retrieve candidates from your vector databaseconstcandidates=awaitvectorDB.query(embedding,{topK: 50})// Stage 2: Rerank for precisionconstreranked=awaitrerank(query,candidates,{topK: 10,minScore: 0.4})// Stage 3: Pass to LLM contextconstcontext=reranked.map(r=>r.document.text).join('\n\n')

Reusable Reranker Instance

For applications that rerank many queries with the same configuration:

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.6,tfidf: 0.25,position: 0.15},})// Use across multiple queriesconstresults1=awaitreranker.rerank('first query',docs1)constresults2=awaitreranker.rerank('second query',docs2)// Override per-call when neededconstresults3=awaitreranker.rerank('third query',docs3,{topK: 5})

Filtering with minScore and topK

minScore is applied first, then topK limits the output:

// Return at most 5 results, all with score >= 0.5constresults=awaitrerank('query',docs,{topK: 5,minScore: 0.5})

TypeScript

rerank-lite is written in TypeScript and ships with declaration files (.d.ts) and source maps. All types are exported from the package entry point:

import{rerank,createReranker,typeDocument,typeRerankResult,typeRerankOptions,typeRerankMode,typeJudgeFn,typeScoringWeights,typeRerankerConfig,typeReranker,}from'rerank-lite'

The package targets ES2022 and emits CommonJS modules. It is compatible with both require() and bundlers that resolve the exports field.


License

MIT

About

Lightweight retrieval reranker using cross-encoder scoring

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - SiluPanda/rerank-lite: Lightweight retrieval reranker using cross-encoder scoring · GitHub
Skip to content

Repository files navigation

rerank-lite

Lightweight retrieval reranker for JavaScript and TypeScript -- zero dependencies, three scoring modes, one API.

npm versionnpm downloadslicensenode


Description

rerank-lite takes a query and a list of candidate documents from a first-stage retriever (vector search, BM25, or fusion) and reorders them by relevance. It is the second stage of a two-stage retrieval pipeline: stage one retrieves candidates quickly with approximate methods, stage two reranks them precisely for the final result set.

The package ships three scoring modes that share a single rerank() API and return the same RerankResult[] output:

  • Heuristic -- BM25 + TF-IDF + position-based scoring with zero external dependencies. Works immediately after install.
  • LLM -- Delegates scoring to a caller-supplied judge function. Bring any LLM provider (OpenAI, Anthropic, local Ollama, etc.).
  • Hybrid -- A 50/50 blend of heuristic and LLM scores for balanced accuracy and cost.

All scores are normalized to the [0, 1] range. The output is ready to pass to a context packer, fusion ranker, or directly into an LLM prompt.


Installation

npm install rerank-lite

Requires Node.js 18 or later.


Quick Start

import{rerank}from'rerank-lite'constdocuments=[{id: 'doc-0',text: 'Machine learning model training with neural networks'},{id: 'doc-1',text: 'Quick sort algorithm and data structures'},{id: 'doc-2',text: 'Deep learning transformer architecture for NLP'},]constresults=awaitrerank('machine learning neural network',documents)for(constresultofresults){console.log(`[rank ${result.newRank}] ${result.document.id} -- score: ${result.score.toFixed(4)}`)}

Features

  • Three scoring modes -- heuristic, LLM-as-judge, and hybrid, all behind one function signature.
  • Zero runtime dependencies -- heuristic mode is pure TypeScript with no external packages.
  • BM25 scoring -- corpus-aware term frequency / inverse document frequency with configurable k1 and b parameters, normalized via sigmoid.
  • TF-IDF cosine similarity -- builds TF-IDF vectors for the query and each document, scores by cosine similarity against the corpus.
  • Position bias -- original retrieval rank feeds into the composite score, preserving signal from the first-stage retriever.
  • Configurable weights -- tune the relative contribution of BM25, TF-IDF, and position scoring.
  • Top-K and minimum score filtering -- limit output to the top K results and filter below a score threshold.
  • Pluggable LLM judge -- pass any async function that scores a (query, document) pair. No SDK lock-in.
  • Factory pattern -- createReranker() returns a preconfigured instance for repeated use across many queries.
  • Full TypeScript support -- ships with declaration files and source maps. All types are exported.

API Reference

rerank(query, documents, options?)

Reranks an array of documents against a query. Returns a Promise<RerankResult[]> sorted by relevance score descending.

import{rerank}from'rerank-lite'constresults=awaitrerank('machine learning',documents,{mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},})

Parameters:

ParameterTypeRequiredDescription
querystringYesThe search query to rank documents against.
documentsDocument[]YesArray of candidate documents from a first-stage retriever.
optionsRerankOptionsNoConfiguration for scoring mode, filtering, and weights.

Returns:Promise<RerankResult[]> -- results sorted by score descending, with newRank assigned as 0-based indices.

Behavior with empty input: Returns an empty array when documents is empty.


createReranker(config?)

Factory that returns a configured Reranker instance. Preset options are applied to every rerank() call; per-call options override the preset.

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,weights: {bm25: 0.6,tfidf: 0.3,position: 0.1},})constresults=awaitreranker.rerank('first query',docs)// Override topK for this call onlyconsttop3=awaitreranker.rerank('second query',docs,{topK: 3})

Parameters:

ParameterTypeRequiredDescription
configRerankerConfigNoDefault configuration applied to all calls.

Returns:Reranker -- an object with a rerank() method and a read-only config property.


Types

Document

Represents a candidate document to be scored.

interfaceDocument{id: string// Unique identifier for the documenttext: string// The text content to score against the queryscore?: number// Optional original retrieval scoremetadata?: Record<string,unknown>// Optional pass-through metadata}

RerankResult

A scored and ranked document returned by rerank().

interfaceRerankResult{document: Document// The original document object, including metadatascore: number// Relevance score in [0, 1]originalRank: number// 0-based index in the input arraynewRank: number// 0-based rank after reranking (0 = most relevant)explanation?: string// Optional debug information}

RerankOptions

Options for a single rerank() call.

interfaceRerankOptions{topK?: number// Return only the top K results (default: all)minScore?: number// Filter out results with a score below this thresholdmode?: RerankMode// Scoring mode (default: 'heuristic')judgeFn?: JudgeFn// Required when mode is 'llm' or 'hybrid'weights?: ScoringWeights// Custom weights for heuristic scoring components}

RerankMode

typeRerankMode='heuristic'|'llm'|'hybrid'
ModeDescription
heuristicBM25 + TF-IDF + position weighted scoring. Zero dependencies. Default.
llmDelegates scoring entirely to the caller-supplied judgeFn.
hybrid50/50 blend of heuristic scores and judgeFn scores.

JudgeFn

The function signature for LLM-as-judge scoring.

typeJudgeFn=(query: string,document: string)=>Promise<number>

Must return a numeric relevance score. Called once per document when mode is llm or hybrid.

ScoringWeights

Weights for the three heuristic scoring signals. All are optional and default to the values shown.

interfaceScoringWeights{bm25?: number// Default: 0.5tfidf?: number// Default: 0.3position?: number// Default: 0.2}

RerankerConfig

Configuration for the createReranker() factory. Same shape as RerankOptions.

interfaceRerankerConfig{mode?: RerankModetopK?: numberminScore?: numberjudgeFn?: JudgeFnweights?: ScoringWeights}

Reranker

The instance returned by createReranker().

interfaceReranker{rerank(query: string,documents: Document[],options?: RerankOptions): Promise<RerankResult[]>readonlyconfig: RerankerConfig}

Configuration

Scoring Weights

The heuristic composite score is computed as:

score = (bm25_weight * bm25_score) + (tfidf_weight * tfidf_score) + (position_weight * position_score)

Default weights:

SignalDefault WeightDescription
bm250.5BM25 term frequency / inverse document frequency score, normalized to [0, 1] via sigmoid.
tfidf0.3TF-IDF cosine similarity between query and document vectors.
position0.2Position bias: 1 - (originalRank / totalDocuments). Preserves signal from the first-stage retriever.

Override weights to tune for your retrieval domain:

// Favor lexical match, ignore original orderingconstresults=awaitrerank('exact keyword query',docs,{weights: {bm25: 0.7,tfidf: 0.3,position: 0.0},})// Trust the first-stage retriever, use reranking as a tiebreakerconstresults=awaitrerank('semantic query',docs,{weights: {bm25: 0.2,tfidf: 0.2,position: 0.6},})

BM25 Parameters

The BM25 scorer accepts standard tuning parameters k1 (term frequency saturation, default 1.5) and b (document length normalization, default 0.75). These are set internally and follow the Robertson/Zaragoza BM25 formulation.


Error Handling

rerank() handles edge cases gracefully without throwing:

  • Empty documents array -- returns an empty array [].
  • No matching terms -- all documents receive a baseline score (sigmoid of zero for BM25, zero for TF-IDF). Documents are still ranked by position bias.
  • Empty query or document text -- TF-IDF returns 0 for empty strings. BM25 returns the sigmoid baseline (0.5).

When using llm or hybrid mode, errors from the judgeFn propagate as-is. Wrap your judge function with try/catch if you need graceful degradation:

constsafejudgeFn=async(query: string,doc: string): Promise<number>=>{try{returnawaityourLLMScorer(query,doc)}catch{return0// Fallback score on failure}}constresults=awaitrerank('query',docs,{mode: 'llm',judgeFn: safejudgeFn})

Advanced Usage

LLM-as-Judge Mode

Pass any async function that returns a relevance score. The function is called once per document.

import{rerank}from'rerank-lite'importOpenAIfrom'openai'constopenai=newOpenAI()constjudgeFn=async(query: string,document: string): Promise<number>=>{constresponse=awaitopenai.chat.completions.create({model: 'gpt-4o-mini',messages: [{role: 'user',content: `Rate the relevance of this document to the query on a scale from 0 to 1.\nQuery: ${query}\nDocument: ${document}\nRespond with only a number between 0 and 1.`,},],})returnparseFloat(response.choices[0].message.content??'0')}constresults=awaitrerank('machine learning',docs,{mode: 'llm', judgeFn })

Hybrid Mode

Combines heuristic scoring with LLM judgment. The final score is a 50/50 blend:

hybrid_score = 0.5 * heuristic_score + 0.5 * llm_score
constresults=awaitrerank('machine learning',docs,{mode: 'hybrid',
judgeFn,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},// Applies to heuristic half})

RAG Pipeline Integration

Use reranking as stage two after vector search or BM25 retrieval:

// Stage 1: Retrieve candidates from your vector databaseconstcandidates=awaitvectorDB.query(embedding,{topK: 50})// Stage 2: Rerank for precisionconstreranked=awaitrerank(query,candidates,{topK: 10,minScore: 0.4})// Stage 3: Pass to LLM contextconstcontext=reranked.map(r=>r.document.text).join('\n\n')

Reusable Reranker Instance

For applications that rerank many queries with the same configuration:

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.6,tfidf: 0.25,position: 0.15},})// Use across multiple queriesconstresults1=awaitreranker.rerank('first query',docs1)constresults2=awaitreranker.rerank('second query',docs2)// Override per-call when neededconstresults3=awaitreranker.rerank('third query',docs3,{topK: 5})

Filtering with minScore and topK

minScore is applied first, then topK limits the output:

// Return at most 5 results, all with score >= 0.5constresults=awaitrerank('query',docs,{topK: 5,minScore: 0.5})

TypeScript

rerank-lite is written in TypeScript and ships with declaration files (.d.ts) and source maps. All types are exported from the package entry point:

import{rerank,createReranker,typeDocument,typeRerankResult,typeRerankOptions,typeRerankMode,typeJudgeFn,typeScoringWeights,typeRerankerConfig,typeReranker,}from'rerank-lite'

The package targets ES2022 and emits CommonJS modules. It is compatible with both require() and bundlers that resolve the exports field.


License

MIT

About

Lightweight retrieval reranker using cross-encoder scoring

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - SiluPanda/rerank-lite: Lightweight retrieval reranker using cross-encoder scoring · GitHub
Skip to content

Repository files navigation

rerank-lite

Lightweight retrieval reranker for JavaScript and TypeScript -- zero dependencies, three scoring modes, one API.

npm versionnpm downloadslicensenode


Description

rerank-lite takes a query and a list of candidate documents from a first-stage retriever (vector search, BM25, or fusion) and reorders them by relevance. It is the second stage of a two-stage retrieval pipeline: stage one retrieves candidates quickly with approximate methods, stage two reranks them precisely for the final result set.

The package ships three scoring modes that share a single rerank() API and return the same RerankResult[] output:

  • Heuristic -- BM25 + TF-IDF + position-based scoring with zero external dependencies. Works immediately after install.
  • LLM -- Delegates scoring to a caller-supplied judge function. Bring any LLM provider (OpenAI, Anthropic, local Ollama, etc.).
  • Hybrid -- A 50/50 blend of heuristic and LLM scores for balanced accuracy and cost.

All scores are normalized to the [0, 1] range. The output is ready to pass to a context packer, fusion ranker, or directly into an LLM prompt.


Installation

npm install rerank-lite

Requires Node.js 18 or later.


Quick Start

import{rerank}from'rerank-lite'constdocuments=[{id: 'doc-0',text: 'Machine learning model training with neural networks'},{id: 'doc-1',text: 'Quick sort algorithm and data structures'},{id: 'doc-2',text: 'Deep learning transformer architecture for NLP'},]constresults=awaitrerank('machine learning neural network',documents)for(constresultofresults){console.log(`[rank ${result.newRank}] ${result.document.id} -- score: ${result.score.toFixed(4)}`)}

Features

  • Three scoring modes -- heuristic, LLM-as-judge, and hybrid, all behind one function signature.
  • Zero runtime dependencies -- heuristic mode is pure TypeScript with no external packages.
  • BM25 scoring -- corpus-aware term frequency / inverse document frequency with configurable k1 and b parameters, normalized via sigmoid.
  • TF-IDF cosine similarity -- builds TF-IDF vectors for the query and each document, scores by cosine similarity against the corpus.
  • Position bias -- original retrieval rank feeds into the composite score, preserving signal from the first-stage retriever.
  • Configurable weights -- tune the relative contribution of BM25, TF-IDF, and position scoring.
  • Top-K and minimum score filtering -- limit output to the top K results and filter below a score threshold.
  • Pluggable LLM judge -- pass any async function that scores a (query, document) pair. No SDK lock-in.
  • Factory pattern -- createReranker() returns a preconfigured instance for repeated use across many queries.
  • Full TypeScript support -- ships with declaration files and source maps. All types are exported.

API Reference

rerank(query, documents, options?)

Reranks an array of documents against a query. Returns a Promise<RerankResult[]> sorted by relevance score descending.

import{rerank}from'rerank-lite'constresults=awaitrerank('machine learning',documents,{mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},})

Parameters:

ParameterTypeRequiredDescription
querystringYesThe search query to rank documents against.
documentsDocument[]YesArray of candidate documents from a first-stage retriever.
optionsRerankOptionsNoConfiguration for scoring mode, filtering, and weights.

Returns:Promise<RerankResult[]> -- results sorted by score descending, with newRank assigned as 0-based indices.

Behavior with empty input: Returns an empty array when documents is empty.


createReranker(config?)

Factory that returns a configured Reranker instance. Preset options are applied to every rerank() call; per-call options override the preset.

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,weights: {bm25: 0.6,tfidf: 0.3,position: 0.1},})constresults=awaitreranker.rerank('first query',docs)// Override topK for this call onlyconsttop3=awaitreranker.rerank('second query',docs,{topK: 3})

Parameters:

ParameterTypeRequiredDescription
configRerankerConfigNoDefault configuration applied to all calls.

Returns:Reranker -- an object with a rerank() method and a read-only config property.


Types

Document

Represents a candidate document to be scored.

interfaceDocument{id: string// Unique identifier for the documenttext: string// The text content to score against the queryscore?: number// Optional original retrieval scoremetadata?: Record<string,unknown>// Optional pass-through metadata}

RerankResult

A scored and ranked document returned by rerank().

interfaceRerankResult{document: Document// The original document object, including metadatascore: number// Relevance score in [0, 1]originalRank: number// 0-based index in the input arraynewRank: number// 0-based rank after reranking (0 = most relevant)explanation?: string// Optional debug information}

RerankOptions

Options for a single rerank() call.

interfaceRerankOptions{topK?: number// Return only the top K results (default: all)minScore?: number// Filter out results with a score below this thresholdmode?: RerankMode// Scoring mode (default: 'heuristic')judgeFn?: JudgeFn// Required when mode is 'llm' or 'hybrid'weights?: ScoringWeights// Custom weights for heuristic scoring components}

RerankMode

typeRerankMode='heuristic'|'llm'|'hybrid'
ModeDescription
heuristicBM25 + TF-IDF + position weighted scoring. Zero dependencies. Default.
llmDelegates scoring entirely to the caller-supplied judgeFn.
hybrid50/50 blend of heuristic scores and judgeFn scores.

JudgeFn

The function signature for LLM-as-judge scoring.

typeJudgeFn=(query: string,document: string)=>Promise<number>

Must return a numeric relevance score. Called once per document when mode is llm or hybrid.

ScoringWeights

Weights for the three heuristic scoring signals. All are optional and default to the values shown.

interfaceScoringWeights{bm25?: number// Default: 0.5tfidf?: number// Default: 0.3position?: number// Default: 0.2}

RerankerConfig

Configuration for the createReranker() factory. Same shape as RerankOptions.

interfaceRerankerConfig{mode?: RerankModetopK?: numberminScore?: numberjudgeFn?: JudgeFnweights?: ScoringWeights}

Reranker

The instance returned by createReranker().

interfaceReranker{rerank(query: string,documents: Document[],options?: RerankOptions): Promise<RerankResult[]>readonlyconfig: RerankerConfig}

Configuration

Scoring Weights

The heuristic composite score is computed as:

score = (bm25_weight * bm25_score) + (tfidf_weight * tfidf_score) + (position_weight * position_score)

Default weights:

SignalDefault WeightDescription
bm250.5BM25 term frequency / inverse document frequency score, normalized to [0, 1] via sigmoid.
tfidf0.3TF-IDF cosine similarity between query and document vectors.
position0.2Position bias: 1 - (originalRank / totalDocuments). Preserves signal from the first-stage retriever.

Override weights to tune for your retrieval domain:

// Favor lexical match, ignore original orderingconstresults=awaitrerank('exact keyword query',docs,{weights: {bm25: 0.7,tfidf: 0.3,position: 0.0},})// Trust the first-stage retriever, use reranking as a tiebreakerconstresults=awaitrerank('semantic query',docs,{weights: {bm25: 0.2,tfidf: 0.2,position: 0.6},})

BM25 Parameters

The BM25 scorer accepts standard tuning parameters k1 (term frequency saturation, default 1.5) and b (document length normalization, default 0.75). These are set internally and follow the Robertson/Zaragoza BM25 formulation.


Error Handling

rerank() handles edge cases gracefully without throwing:

  • Empty documents array -- returns an empty array [].
  • No matching terms -- all documents receive a baseline score (sigmoid of zero for BM25, zero for TF-IDF). Documents are still ranked by position bias.
  • Empty query or document text -- TF-IDF returns 0 for empty strings. BM25 returns the sigmoid baseline (0.5).

When using llm or hybrid mode, errors from the judgeFn propagate as-is. Wrap your judge function with try/catch if you need graceful degradation:

constsafejudgeFn=async(query: string,doc: string): Promise<number>=>{try{returnawaityourLLMScorer(query,doc)}catch{return0// Fallback score on failure}}constresults=awaitrerank('query',docs,{mode: 'llm',judgeFn: safejudgeFn})

Advanced Usage

LLM-as-Judge Mode

Pass any async function that returns a relevance score. The function is called once per document.

import{rerank}from'rerank-lite'importOpenAIfrom'openai'constopenai=newOpenAI()constjudgeFn=async(query: string,document: string): Promise<number>=>{constresponse=awaitopenai.chat.completions.create({model: 'gpt-4o-mini',messages: [{role: 'user',content: `Rate the relevance of this document to the query on a scale from 0 to 1.\nQuery: ${query}\nDocument: ${document}\nRespond with only a number between 0 and 1.`,},],})returnparseFloat(response.choices[0].message.content??'0')}constresults=awaitrerank('machine learning',docs,{mode: 'llm', judgeFn })

Hybrid Mode

Combines heuristic scoring with LLM judgment. The final score is a 50/50 blend:

hybrid_score = 0.5 * heuristic_score + 0.5 * llm_score
constresults=awaitrerank('machine learning',docs,{mode: 'hybrid',
judgeFn,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},// Applies to heuristic half})

RAG Pipeline Integration

Use reranking as stage two after vector search or BM25 retrieval:

// Stage 1: Retrieve candidates from your vector databaseconstcandidates=awaitvectorDB.query(embedding,{topK: 50})// Stage 2: Rerank for precisionconstreranked=awaitrerank(query,candidates,{topK: 10,minScore: 0.4})// Stage 3: Pass to LLM contextconstcontext=reranked.map(r=>r.document.text).join('\n\n')

Reusable Reranker Instance

For applications that rerank many queries with the same configuration:

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.6,tfidf: 0.25,position: 0.15},})// Use across multiple queriesconstresults1=awaitreranker.rerank('first query',docs1)constresults2=awaitreranker.rerank('second query',docs2)// Override per-call when neededconstresults3=awaitreranker.rerank('third query',docs3,{topK: 5})

Filtering with minScore and topK

minScore is applied first, then topK limits the output:

// Return at most 5 results, all with score >= 0.5constresults=awaitrerank('query',docs,{topK: 5,minScore: 0.5})

TypeScript

rerank-lite is written in TypeScript and ships with declaration files (.d.ts) and source maps. All types are exported from the package entry point:

import{rerank,createReranker,typeDocument,typeRerankResult,typeRerankOptions,typeRerankMode,typeJudgeFn,typeScoringWeights,typeRerankerConfig,typeReranker,}from'rerank-lite'

The package targets ES2022 and emits CommonJS modules. It is compatible with both require() and bundlers that resolve the exports field.


License

MIT

About

Lightweight retrieval reranker using cross-encoder scoring

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - SiluPanda/rerank-lite: Lightweight retrieval reranker using cross-encoder scoring · GitHub
Skip to content

Repository files navigation

rerank-lite

Lightweight retrieval reranker for JavaScript and TypeScript -- zero dependencies, three scoring modes, one API.

npm versionnpm downloadslicensenode


Description

rerank-lite takes a query and a list of candidate documents from a first-stage retriever (vector search, BM25, or fusion) and reorders them by relevance. It is the second stage of a two-stage retrieval pipeline: stage one retrieves candidates quickly with approximate methods, stage two reranks them precisely for the final result set.

The package ships three scoring modes that share a single rerank() API and return the same RerankResult[] output:

  • Heuristic -- BM25 + TF-IDF + position-based scoring with zero external dependencies. Works immediately after install.
  • LLM -- Delegates scoring to a caller-supplied judge function. Bring any LLM provider (OpenAI, Anthropic, local Ollama, etc.).
  • Hybrid -- A 50/50 blend of heuristic and LLM scores for balanced accuracy and cost.

All scores are normalized to the [0, 1] range. The output is ready to pass to a context packer, fusion ranker, or directly into an LLM prompt.


Installation

npm install rerank-lite

Requires Node.js 18 or later.


Quick Start

import{rerank}from'rerank-lite'constdocuments=[{id: 'doc-0',text: 'Machine learning model training with neural networks'},{id: 'doc-1',text: 'Quick sort algorithm and data structures'},{id: 'doc-2',text: 'Deep learning transformer architecture for NLP'},]constresults=awaitrerank('machine learning neural network',documents)for(constresultofresults){console.log(`[rank ${result.newRank}] ${result.document.id} -- score: ${result.score.toFixed(4)}`)}

Features

  • Three scoring modes -- heuristic, LLM-as-judge, and hybrid, all behind one function signature.
  • Zero runtime dependencies -- heuristic mode is pure TypeScript with no external packages.
  • BM25 scoring -- corpus-aware term frequency / inverse document frequency with configurable k1 and b parameters, normalized via sigmoid.
  • TF-IDF cosine similarity -- builds TF-IDF vectors for the query and each document, scores by cosine similarity against the corpus.
  • Position bias -- original retrieval rank feeds into the composite score, preserving signal from the first-stage retriever.
  • Configurable weights -- tune the relative contribution of BM25, TF-IDF, and position scoring.
  • Top-K and minimum score filtering -- limit output to the top K results and filter below a score threshold.
  • Pluggable LLM judge -- pass any async function that scores a (query, document) pair. No SDK lock-in.
  • Factory pattern -- createReranker() returns a preconfigured instance for repeated use across many queries.
  • Full TypeScript support -- ships with declaration files and source maps. All types are exported.

API Reference

rerank(query, documents, options?)

Reranks an array of documents against a query. Returns a Promise<RerankResult[]> sorted by relevance score descending.

import{rerank}from'rerank-lite'constresults=awaitrerank('machine learning',documents,{mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},})

Parameters:

ParameterTypeRequiredDescription
querystringYesThe search query to rank documents against.
documentsDocument[]YesArray of candidate documents from a first-stage retriever.
optionsRerankOptionsNoConfiguration for scoring mode, filtering, and weights.

Returns:Promise<RerankResult[]> -- results sorted by score descending, with newRank assigned as 0-based indices.

Behavior with empty input: Returns an empty array when documents is empty.


createReranker(config?)

Factory that returns a configured Reranker instance. Preset options are applied to every rerank() call; per-call options override the preset.

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,weights: {bm25: 0.6,tfidf: 0.3,position: 0.1},})constresults=awaitreranker.rerank('first query',docs)// Override topK for this call onlyconsttop3=awaitreranker.rerank('second query',docs,{topK: 3})

Parameters:

ParameterTypeRequiredDescription
configRerankerConfigNoDefault configuration applied to all calls.

Returns:Reranker -- an object with a rerank() method and a read-only config property.


Types

Document

Represents a candidate document to be scored.

interfaceDocument{id: string// Unique identifier for the documenttext: string// The text content to score against the queryscore?: number// Optional original retrieval scoremetadata?: Record<string,unknown>// Optional pass-through metadata}

RerankResult

A scored and ranked document returned by rerank().

interfaceRerankResult{document: Document// The original document object, including metadatascore: number// Relevance score in [0, 1]originalRank: number// 0-based index in the input arraynewRank: number// 0-based rank after reranking (0 = most relevant)explanation?: string// Optional debug information}

RerankOptions

Options for a single rerank() call.

interfaceRerankOptions{topK?: number// Return only the top K results (default: all)minScore?: number// Filter out results with a score below this thresholdmode?: RerankMode// Scoring mode (default: 'heuristic')judgeFn?: JudgeFn// Required when mode is 'llm' or 'hybrid'weights?: ScoringWeights// Custom weights for heuristic scoring components}

RerankMode

typeRerankMode='heuristic'|'llm'|'hybrid'
ModeDescription
heuristicBM25 + TF-IDF + position weighted scoring. Zero dependencies. Default.
llmDelegates scoring entirely to the caller-supplied judgeFn.
hybrid50/50 blend of heuristic scores and judgeFn scores.

JudgeFn

The function signature for LLM-as-judge scoring.

typeJudgeFn=(query: string,document: string)=>Promise<number>

Must return a numeric relevance score. Called once per document when mode is llm or hybrid.

ScoringWeights

Weights for the three heuristic scoring signals. All are optional and default to the values shown.

interfaceScoringWeights{bm25?: number// Default: 0.5tfidf?: number// Default: 0.3position?: number// Default: 0.2}

RerankerConfig

Configuration for the createReranker() factory. Same shape as RerankOptions.

interfaceRerankerConfig{mode?: RerankModetopK?: numberminScore?: numberjudgeFn?: JudgeFnweights?: ScoringWeights}

Reranker

The instance returned by createReranker().

interfaceReranker{rerank(query: string,documents: Document[],options?: RerankOptions): Promise<RerankResult[]>readonlyconfig: RerankerConfig}

Configuration

Scoring Weights

The heuristic composite score is computed as:

score = (bm25_weight * bm25_score) + (tfidf_weight * tfidf_score) + (position_weight * position_score)

Default weights:

SignalDefault WeightDescription
bm250.5BM25 term frequency / inverse document frequency score, normalized to [0, 1] via sigmoid.
tfidf0.3TF-IDF cosine similarity between query and document vectors.
position0.2Position bias: 1 - (originalRank / totalDocuments). Preserves signal from the first-stage retriever.

Override weights to tune for your retrieval domain:

// Favor lexical match, ignore original orderingconstresults=awaitrerank('exact keyword query',docs,{weights: {bm25: 0.7,tfidf: 0.3,position: 0.0},})// Trust the first-stage retriever, use reranking as a tiebreakerconstresults=awaitrerank('semantic query',docs,{weights: {bm25: 0.2,tfidf: 0.2,position: 0.6},})

BM25 Parameters

The BM25 scorer accepts standard tuning parameters k1 (term frequency saturation, default 1.5) and b (document length normalization, default 0.75). These are set internally and follow the Robertson/Zaragoza BM25 formulation.


Error Handling

rerank() handles edge cases gracefully without throwing:

  • Empty documents array -- returns an empty array [].
  • No matching terms -- all documents receive a baseline score (sigmoid of zero for BM25, zero for TF-IDF). Documents are still ranked by position bias.
  • Empty query or document text -- TF-IDF returns 0 for empty strings. BM25 returns the sigmoid baseline (0.5).

When using llm or hybrid mode, errors from the judgeFn propagate as-is. Wrap your judge function with try/catch if you need graceful degradation:

constsafejudgeFn=async(query: string,doc: string): Promise<number>=>{try{returnawaityourLLMScorer(query,doc)}catch{return0// Fallback score on failure}}constresults=awaitrerank('query',docs,{mode: 'llm',judgeFn: safejudgeFn})

Advanced Usage

LLM-as-Judge Mode

Pass any async function that returns a relevance score. The function is called once per document.

import{rerank}from'rerank-lite'importOpenAIfrom'openai'constopenai=newOpenAI()constjudgeFn=async(query: string,document: string): Promise<number>=>{constresponse=awaitopenai.chat.completions.create({model: 'gpt-4o-mini',messages: [{role: 'user',content: `Rate the relevance of this document to the query on a scale from 0 to 1.\nQuery: ${query}\nDocument: ${document}\nRespond with only a number between 0 and 1.`,},],})returnparseFloat(response.choices[0].message.content??'0')}constresults=awaitrerank('machine learning',docs,{mode: 'llm', judgeFn })

Hybrid Mode

Combines heuristic scoring with LLM judgment. The final score is a 50/50 blend:

hybrid_score = 0.5 * heuristic_score + 0.5 * llm_score
constresults=awaitrerank('machine learning',docs,{mode: 'hybrid',
judgeFn,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},// Applies to heuristic half})

RAG Pipeline Integration

Use reranking as stage two after vector search or BM25 retrieval:

// Stage 1: Retrieve candidates from your vector databaseconstcandidates=awaitvectorDB.query(embedding,{topK: 50})// Stage 2: Rerank for precisionconstreranked=awaitrerank(query,candidates,{topK: 10,minScore: 0.4})// Stage 3: Pass to LLM contextconstcontext=reranked.map(r=>r.document.text).join('\n\n')

Reusable Reranker Instance

For applications that rerank many queries with the same configuration:

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.6,tfidf: 0.25,position: 0.15},})// Use across multiple queriesconstresults1=awaitreranker.rerank('first query',docs1)constresults2=awaitreranker.rerank('second query',docs2)// Override per-call when neededconstresults3=awaitreranker.rerank('third query',docs3,{topK: 5})

Filtering with minScore and topK

minScore is applied first, then topK limits the output:

// Return at most 5 results, all with score >= 0.5constresults=awaitrerank('query',docs,{topK: 5,minScore: 0.5})

TypeScript

rerank-lite is written in TypeScript and ships with declaration files (.d.ts) and source maps. All types are exported from the package entry point:

import{rerank,createReranker,typeDocument,typeRerankResult,typeRerankOptions,typeRerankMode,typeJudgeFn,typeScoringWeights,typeRerankerConfig,typeReranker,}from'rerank-lite'

The package targets ES2022 and emits CommonJS modules. It is compatible with both require() and bundlers that resolve the exports field.


License

MIT

About

Lightweight retrieval reranker using cross-encoder scoring

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - SiluPanda/rerank-lite: Lightweight retrieval reranker using cross-encoder scoring · GitHub
Skip to content

Repository files navigation

rerank-lite

Lightweight retrieval reranker for JavaScript and TypeScript -- zero dependencies, three scoring modes, one API.

npm versionnpm downloadslicensenode


Description

rerank-lite takes a query and a list of candidate documents from a first-stage retriever (vector search, BM25, or fusion) and reorders them by relevance. It is the second stage of a two-stage retrieval pipeline: stage one retrieves candidates quickly with approximate methods, stage two reranks them precisely for the final result set.

The package ships three scoring modes that share a single rerank() API and return the same RerankResult[] output:

  • Heuristic -- BM25 + TF-IDF + position-based scoring with zero external dependencies. Works immediately after install.
  • LLM -- Delegates scoring to a caller-supplied judge function. Bring any LLM provider (OpenAI, Anthropic, local Ollama, etc.).
  • Hybrid -- A 50/50 blend of heuristic and LLM scores for balanced accuracy and cost.

All scores are normalized to the [0, 1] range. The output is ready to pass to a context packer, fusion ranker, or directly into an LLM prompt.


Installation

npm install rerank-lite

Requires Node.js 18 or later.


Quick Start

import{rerank}from'rerank-lite'constdocuments=[{id: 'doc-0',text: 'Machine learning model training with neural networks'},{id: 'doc-1',text: 'Quick sort algorithm and data structures'},{id: 'doc-2',text: 'Deep learning transformer architecture for NLP'},]constresults=awaitrerank('machine learning neural network',documents)for(constresultofresults){console.log(`[rank ${result.newRank}] ${result.document.id} -- score: ${result.score.toFixed(4)}`)}

Features

  • Three scoring modes -- heuristic, LLM-as-judge, and hybrid, all behind one function signature.
  • Zero runtime dependencies -- heuristic mode is pure TypeScript with no external packages.
  • BM25 scoring -- corpus-aware term frequency / inverse document frequency with configurable k1 and b parameters, normalized via sigmoid.
  • TF-IDF cosine similarity -- builds TF-IDF vectors for the query and each document, scores by cosine similarity against the corpus.
  • Position bias -- original retrieval rank feeds into the composite score, preserving signal from the first-stage retriever.
  • Configurable weights -- tune the relative contribution of BM25, TF-IDF, and position scoring.
  • Top-K and minimum score filtering -- limit output to the top K results and filter below a score threshold.
  • Pluggable LLM judge -- pass any async function that scores a (query, document) pair. No SDK lock-in.
  • Factory pattern -- createReranker() returns a preconfigured instance for repeated use across many queries.
  • Full TypeScript support -- ships with declaration files and source maps. All types are exported.

API Reference

rerank(query, documents, options?)

Reranks an array of documents against a query. Returns a Promise<RerankResult[]> sorted by relevance score descending.

import{rerank}from'rerank-lite'constresults=awaitrerank('machine learning',documents,{mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},})

Parameters:

ParameterTypeRequiredDescription
querystringYesThe search query to rank documents against.
documentsDocument[]YesArray of candidate documents from a first-stage retriever.
optionsRerankOptionsNoConfiguration for scoring mode, filtering, and weights.

Returns:Promise<RerankResult[]> -- results sorted by score descending, with newRank assigned as 0-based indices.

Behavior with empty input: Returns an empty array when documents is empty.


createReranker(config?)

Factory that returns a configured Reranker instance. Preset options are applied to every rerank() call; per-call options override the preset.

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,weights: {bm25: 0.6,tfidf: 0.3,position: 0.1},})constresults=awaitreranker.rerank('first query',docs)// Override topK for this call onlyconsttop3=awaitreranker.rerank('second query',docs,{topK: 3})

Parameters:

ParameterTypeRequiredDescription
configRerankerConfigNoDefault configuration applied to all calls.

Returns:Reranker -- an object with a rerank() method and a read-only config property.


Types

Document

Represents a candidate document to be scored.

interfaceDocument{id: string// Unique identifier for the documenttext: string// The text content to score against the queryscore?: number// Optional original retrieval scoremetadata?: Record<string,unknown>// Optional pass-through metadata}

RerankResult

A scored and ranked document returned by rerank().

interfaceRerankResult{document: Document// The original document object, including metadatascore: number// Relevance score in [0, 1]originalRank: number// 0-based index in the input arraynewRank: number// 0-based rank after reranking (0 = most relevant)explanation?: string// Optional debug information}

RerankOptions

Options for a single rerank() call.

interfaceRerankOptions{topK?: number// Return only the top K results (default: all)minScore?: number// Filter out results with a score below this thresholdmode?: RerankMode// Scoring mode (default: 'heuristic')judgeFn?: JudgeFn// Required when mode is 'llm' or 'hybrid'weights?: ScoringWeights// Custom weights for heuristic scoring components}

RerankMode

typeRerankMode='heuristic'|'llm'|'hybrid'
ModeDescription
heuristicBM25 + TF-IDF + position weighted scoring. Zero dependencies. Default.
llmDelegates scoring entirely to the caller-supplied judgeFn.
hybrid50/50 blend of heuristic scores and judgeFn scores.

JudgeFn

The function signature for LLM-as-judge scoring.

typeJudgeFn=(query: string,document: string)=>Promise<number>

Must return a numeric relevance score. Called once per document when mode is llm or hybrid.

ScoringWeights

Weights for the three heuristic scoring signals. All are optional and default to the values shown.

interfaceScoringWeights{bm25?: number// Default: 0.5tfidf?: number// Default: 0.3position?: number// Default: 0.2}

RerankerConfig

Configuration for the createReranker() factory. Same shape as RerankOptions.

interfaceRerankerConfig{mode?: RerankModetopK?: numberminScore?: numberjudgeFn?: JudgeFnweights?: ScoringWeights}

Reranker

The instance returned by createReranker().

interfaceReranker{rerank(query: string,documents: Document[],options?: RerankOptions): Promise<RerankResult[]>readonlyconfig: RerankerConfig}

Configuration

Scoring Weights

The heuristic composite score is computed as:

score = (bm25_weight * bm25_score) + (tfidf_weight * tfidf_score) + (position_weight * position_score)

Default weights:

SignalDefault WeightDescription
bm250.5BM25 term frequency / inverse document frequency score, normalized to [0, 1] via sigmoid.
tfidf0.3TF-IDF cosine similarity between query and document vectors.
position0.2Position bias: 1 - (originalRank / totalDocuments). Preserves signal from the first-stage retriever.

Override weights to tune for your retrieval domain:

// Favor lexical match, ignore original orderingconstresults=awaitrerank('exact keyword query',docs,{weights: {bm25: 0.7,tfidf: 0.3,position: 0.0},})// Trust the first-stage retriever, use reranking as a tiebreakerconstresults=awaitrerank('semantic query',docs,{weights: {bm25: 0.2,tfidf: 0.2,position: 0.6},})

BM25 Parameters

The BM25 scorer accepts standard tuning parameters k1 (term frequency saturation, default 1.5) and b (document length normalization, default 0.75). These are set internally and follow the Robertson/Zaragoza BM25 formulation.


Error Handling

rerank() handles edge cases gracefully without throwing:

  • Empty documents array -- returns an empty array [].
  • No matching terms -- all documents receive a baseline score (sigmoid of zero for BM25, zero for TF-IDF). Documents are still ranked by position bias.
  • Empty query or document text -- TF-IDF returns 0 for empty strings. BM25 returns the sigmoid baseline (0.5).

When using llm or hybrid mode, errors from the judgeFn propagate as-is. Wrap your judge function with try/catch if you need graceful degradation:

constsafejudgeFn=async(query: string,doc: string): Promise<number>=>{try{returnawaityourLLMScorer(query,doc)}catch{return0// Fallback score on failure}}constresults=awaitrerank('query',docs,{mode: 'llm',judgeFn: safejudgeFn})

Advanced Usage

LLM-as-Judge Mode

Pass any async function that returns a relevance score. The function is called once per document.

import{rerank}from'rerank-lite'importOpenAIfrom'openai'constopenai=newOpenAI()constjudgeFn=async(query: string,document: string): Promise<number>=>{constresponse=awaitopenai.chat.completions.create({model: 'gpt-4o-mini',messages: [{role: 'user',content: `Rate the relevance of this document to the query on a scale from 0 to 1.\nQuery: ${query}\nDocument: ${document}\nRespond with only a number between 0 and 1.`,},],})returnparseFloat(response.choices[0].message.content??'0')}constresults=awaitrerank('machine learning',docs,{mode: 'llm', judgeFn })

Hybrid Mode

Combines heuristic scoring with LLM judgment. The final score is a 50/50 blend:

hybrid_score = 0.5 * heuristic_score + 0.5 * llm_score
constresults=awaitrerank('machine learning',docs,{mode: 'hybrid',
judgeFn,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},// Applies to heuristic half})

RAG Pipeline Integration

Use reranking as stage two after vector search or BM25 retrieval:

// Stage 1: Retrieve candidates from your vector databaseconstcandidates=awaitvectorDB.query(embedding,{topK: 50})// Stage 2: Rerank for precisionconstreranked=awaitrerank(query,candidates,{topK: 10,minScore: 0.4})// Stage 3: Pass to LLM contextconstcontext=reranked.map(r=>r.document.text).join('\n\n')

Reusable Reranker Instance

For applications that rerank many queries with the same configuration:

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.6,tfidf: 0.25,position: 0.15},})// Use across multiple queriesconstresults1=awaitreranker.rerank('first query',docs1)constresults2=awaitreranker.rerank('second query',docs2)// Override per-call when neededconstresults3=awaitreranker.rerank('third query',docs3,{topK: 5})

Filtering with minScore and topK

minScore is applied first, then topK limits the output:

// Return at most 5 results, all with score >= 0.5constresults=awaitrerank('query',docs,{topK: 5,minScore: 0.5})

TypeScript

rerank-lite is written in TypeScript and ships with declaration files (.d.ts) and source maps. All types are exported from the package entry point:

import{rerank,createReranker,typeDocument,typeRerankResult,typeRerankOptions,typeRerankMode,typeJudgeFn,typeScoringWeights,typeRerankerConfig,typeReranker,}from'rerank-lite'

The package targets ES2022 and emits CommonJS modules. It is compatible with both require() and bundlers that resolve the exports field.


License

MIT

About

Lightweight retrieval reranker using cross-encoder scoring

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - SiluPanda/rerank-lite: Lightweight retrieval reranker using cross-encoder scoring · GitHub
Skip to content

Repository files navigation

rerank-lite

Lightweight retrieval reranker for JavaScript and TypeScript -- zero dependencies, three scoring modes, one API.

npm versionnpm downloadslicensenode


Description

rerank-lite takes a query and a list of candidate documents from a first-stage retriever (vector search, BM25, or fusion) and reorders them by relevance. It is the second stage of a two-stage retrieval pipeline: stage one retrieves candidates quickly with approximate methods, stage two reranks them precisely for the final result set.

The package ships three scoring modes that share a single rerank() API and return the same RerankResult[] output:

  • Heuristic -- BM25 + TF-IDF + position-based scoring with zero external dependencies. Works immediately after install.
  • LLM -- Delegates scoring to a caller-supplied judge function. Bring any LLM provider (OpenAI, Anthropic, local Ollama, etc.).
  • Hybrid -- A 50/50 blend of heuristic and LLM scores for balanced accuracy and cost.

All scores are normalized to the [0, 1] range. The output is ready to pass to a context packer, fusion ranker, or directly into an LLM prompt.


Installation

npm install rerank-lite

Requires Node.js 18 or later.


Quick Start

import{rerank}from'rerank-lite'constdocuments=[{id: 'doc-0',text: 'Machine learning model training with neural networks'},{id: 'doc-1',text: 'Quick sort algorithm and data structures'},{id: 'doc-2',text: 'Deep learning transformer architecture for NLP'},]constresults=awaitrerank('machine learning neural network',documents)for(constresultofresults){console.log(`[rank ${result.newRank}] ${result.document.id} -- score: ${result.score.toFixed(4)}`)}

Features

  • Three scoring modes -- heuristic, LLM-as-judge, and hybrid, all behind one function signature.
  • Zero runtime dependencies -- heuristic mode is pure TypeScript with no external packages.
  • BM25 scoring -- corpus-aware term frequency / inverse document frequency with configurable k1 and b parameters, normalized via sigmoid.
  • TF-IDF cosine similarity -- builds TF-IDF vectors for the query and each document, scores by cosine similarity against the corpus.
  • Position bias -- original retrieval rank feeds into the composite score, preserving signal from the first-stage retriever.
  • Configurable weights -- tune the relative contribution of BM25, TF-IDF, and position scoring.
  • Top-K and minimum score filtering -- limit output to the top K results and filter below a score threshold.
  • Pluggable LLM judge -- pass any async function that scores a (query, document) pair. No SDK lock-in.
  • Factory pattern -- createReranker() returns a preconfigured instance for repeated use across many queries.
  • Full TypeScript support -- ships with declaration files and source maps. All types are exported.

API Reference

rerank(query, documents, options?)

Reranks an array of documents against a query. Returns a Promise<RerankResult[]> sorted by relevance score descending.

import{rerank}from'rerank-lite'constresults=awaitrerank('machine learning',documents,{mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},})

Parameters:

ParameterTypeRequiredDescription
querystringYesThe search query to rank documents against.
documentsDocument[]YesArray of candidate documents from a first-stage retriever.
optionsRerankOptionsNoConfiguration for scoring mode, filtering, and weights.

Returns:Promise<RerankResult[]> -- results sorted by score descending, with newRank assigned as 0-based indices.

Behavior with empty input: Returns an empty array when documents is empty.


createReranker(config?)

Factory that returns a configured Reranker instance. Preset options are applied to every rerank() call; per-call options override the preset.

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,weights: {bm25: 0.6,tfidf: 0.3,position: 0.1},})constresults=awaitreranker.rerank('first query',docs)// Override topK for this call onlyconsttop3=awaitreranker.rerank('second query',docs,{topK: 3})

Parameters:

ParameterTypeRequiredDescription
configRerankerConfigNoDefault configuration applied to all calls.

Returns:Reranker -- an object with a rerank() method and a read-only config property.


Types

Document

Represents a candidate document to be scored.

interfaceDocument{id: string// Unique identifier for the documenttext: string// The text content to score against the queryscore?: number// Optional original retrieval scoremetadata?: Record<string,unknown>// Optional pass-through metadata}

RerankResult

A scored and ranked document returned by rerank().

interfaceRerankResult{document: Document// The original document object, including metadatascore: number// Relevance score in [0, 1]originalRank: number// 0-based index in the input arraynewRank: number// 0-based rank after reranking (0 = most relevant)explanation?: string// Optional debug information}

RerankOptions

Options for a single rerank() call.

interfaceRerankOptions{topK?: number// Return only the top K results (default: all)minScore?: number// Filter out results with a score below this thresholdmode?: RerankMode// Scoring mode (default: 'heuristic')judgeFn?: JudgeFn// Required when mode is 'llm' or 'hybrid'weights?: ScoringWeights// Custom weights for heuristic scoring components}

RerankMode

typeRerankMode='heuristic'|'llm'|'hybrid'
ModeDescription
heuristicBM25 + TF-IDF + position weighted scoring. Zero dependencies. Default.
llmDelegates scoring entirely to the caller-supplied judgeFn.
hybrid50/50 blend of heuristic scores and judgeFn scores.

JudgeFn

The function signature for LLM-as-judge scoring.

typeJudgeFn=(query: string,document: string)=>Promise<number>

Must return a numeric relevance score. Called once per document when mode is llm or hybrid.

ScoringWeights

Weights for the three heuristic scoring signals. All are optional and default to the values shown.

interfaceScoringWeights{bm25?: number// Default: 0.5tfidf?: number// Default: 0.3position?: number// Default: 0.2}

RerankerConfig

Configuration for the createReranker() factory. Same shape as RerankOptions.

interfaceRerankerConfig{mode?: RerankModetopK?: numberminScore?: numberjudgeFn?: JudgeFnweights?: ScoringWeights}

Reranker

The instance returned by createReranker().

interfaceReranker{rerank(query: string,documents: Document[],options?: RerankOptions): Promise<RerankResult[]>readonlyconfig: RerankerConfig}

Configuration

Scoring Weights

The heuristic composite score is computed as:

score = (bm25_weight * bm25_score) + (tfidf_weight * tfidf_score) + (position_weight * position_score)

Default weights:

SignalDefault WeightDescription
bm250.5BM25 term frequency / inverse document frequency score, normalized to [0, 1] via sigmoid.
tfidf0.3TF-IDF cosine similarity between query and document vectors.
position0.2Position bias: 1 - (originalRank / totalDocuments). Preserves signal from the first-stage retriever.

Override weights to tune for your retrieval domain:

// Favor lexical match, ignore original orderingconstresults=awaitrerank('exact keyword query',docs,{weights: {bm25: 0.7,tfidf: 0.3,position: 0.0},})// Trust the first-stage retriever, use reranking as a tiebreakerconstresults=awaitrerank('semantic query',docs,{weights: {bm25: 0.2,tfidf: 0.2,position: 0.6},})

BM25 Parameters

The BM25 scorer accepts standard tuning parameters k1 (term frequency saturation, default 1.5) and b (document length normalization, default 0.75). These are set internally and follow the Robertson/Zaragoza BM25 formulation.


Error Handling

rerank() handles edge cases gracefully without throwing:

  • Empty documents array -- returns an empty array [].
  • No matching terms -- all documents receive a baseline score (sigmoid of zero for BM25, zero for TF-IDF). Documents are still ranked by position bias.
  • Empty query or document text -- TF-IDF returns 0 for empty strings. BM25 returns the sigmoid baseline (0.5).

When using llm or hybrid mode, errors from the judgeFn propagate as-is. Wrap your judge function with try/catch if you need graceful degradation:

constsafejudgeFn=async(query: string,doc: string): Promise<number>=>{try{returnawaityourLLMScorer(query,doc)}catch{return0// Fallback score on failure}}constresults=awaitrerank('query',docs,{mode: 'llm',judgeFn: safejudgeFn})

Advanced Usage

LLM-as-Judge Mode

Pass any async function that returns a relevance score. The function is called once per document.

import{rerank}from'rerank-lite'importOpenAIfrom'openai'constopenai=newOpenAI()constjudgeFn=async(query: string,document: string): Promise<number>=>{constresponse=awaitopenai.chat.completions.create({model: 'gpt-4o-mini',messages: [{role: 'user',content: `Rate the relevance of this document to the query on a scale from 0 to 1.\nQuery: ${query}\nDocument: ${document}\nRespond with only a number between 0 and 1.`,},],})returnparseFloat(response.choices[0].message.content??'0')}constresults=awaitrerank('machine learning',docs,{mode: 'llm', judgeFn })

Hybrid Mode

Combines heuristic scoring with LLM judgment. The final score is a 50/50 blend:

hybrid_score = 0.5 * heuristic_score + 0.5 * llm_score
constresults=awaitrerank('machine learning',docs,{mode: 'hybrid',
judgeFn,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},// Applies to heuristic half})

RAG Pipeline Integration

Use reranking as stage two after vector search or BM25 retrieval:

// Stage 1: Retrieve candidates from your vector databaseconstcandidates=awaitvectorDB.query(embedding,{topK: 50})// Stage 2: Rerank for precisionconstreranked=awaitrerank(query,candidates,{topK: 10,minScore: 0.4})// Stage 3: Pass to LLM contextconstcontext=reranked.map(r=>r.document.text).join('\n\n')

Reusable Reranker Instance

For applications that rerank many queries with the same configuration:

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.6,tfidf: 0.25,position: 0.15},})// Use across multiple queriesconstresults1=awaitreranker.rerank('first query',docs1)constresults2=awaitreranker.rerank('second query',docs2)// Override per-call when neededconstresults3=awaitreranker.rerank('third query',docs3,{topK: 5})

Filtering with minScore and topK

minScore is applied first, then topK limits the output:

// Return at most 5 results, all with score >= 0.5constresults=awaitrerank('query',docs,{topK: 5,minScore: 0.5})

TypeScript

rerank-lite is written in TypeScript and ships with declaration files (.d.ts) and source maps. All types are exported from the package entry point:

import{rerank,createReranker,typeDocument,typeRerankResult,typeRerankOptions,typeRerankMode,typeJudgeFn,typeScoringWeights,typeRerankerConfig,typeReranker,}from'rerank-lite'

The package targets ES2022 and emits CommonJS modules. It is compatible with both require() and bundlers that resolve the exports field.


License

MIT

About

Lightweight retrieval reranker using cross-encoder scoring

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - SiluPanda/rerank-lite: Lightweight retrieval reranker using cross-encoder scoring · GitHub
Skip to content

Repository files navigation

rerank-lite

Lightweight retrieval reranker for JavaScript and TypeScript -- zero dependencies, three scoring modes, one API.

npm versionnpm downloadslicensenode


Description

rerank-lite takes a query and a list of candidate documents from a first-stage retriever (vector search, BM25, or fusion) and reorders them by relevance. It is the second stage of a two-stage retrieval pipeline: stage one retrieves candidates quickly with approximate methods, stage two reranks them precisely for the final result set.

The package ships three scoring modes that share a single rerank() API and return the same RerankResult[] output:

  • Heuristic -- BM25 + TF-IDF + position-based scoring with zero external dependencies. Works immediately after install.
  • LLM -- Delegates scoring to a caller-supplied judge function. Bring any LLM provider (OpenAI, Anthropic, local Ollama, etc.).
  • Hybrid -- A 50/50 blend of heuristic and LLM scores for balanced accuracy and cost.

All scores are normalized to the [0, 1] range. The output is ready to pass to a context packer, fusion ranker, or directly into an LLM prompt.


Installation

npm install rerank-lite

Requires Node.js 18 or later.


Quick Start

import{rerank}from'rerank-lite'constdocuments=[{id: 'doc-0',text: 'Machine learning model training with neural networks'},{id: 'doc-1',text: 'Quick sort algorithm and data structures'},{id: 'doc-2',text: 'Deep learning transformer architecture for NLP'},]constresults=awaitrerank('machine learning neural network',documents)for(constresultofresults){console.log(`[rank ${result.newRank}] ${result.document.id} -- score: ${result.score.toFixed(4)}`)}

Features

  • Three scoring modes -- heuristic, LLM-as-judge, and hybrid, all behind one function signature.
  • Zero runtime dependencies -- heuristic mode is pure TypeScript with no external packages.
  • BM25 scoring -- corpus-aware term frequency / inverse document frequency with configurable k1 and b parameters, normalized via sigmoid.
  • TF-IDF cosine similarity -- builds TF-IDF vectors for the query and each document, scores by cosine similarity against the corpus.
  • Position bias -- original retrieval rank feeds into the composite score, preserving signal from the first-stage retriever.
  • Configurable weights -- tune the relative contribution of BM25, TF-IDF, and position scoring.
  • Top-K and minimum score filtering -- limit output to the top K results and filter below a score threshold.
  • Pluggable LLM judge -- pass any async function that scores a (query, document) pair. No SDK lock-in.
  • Factory pattern -- createReranker() returns a preconfigured instance for repeated use across many queries.
  • Full TypeScript support -- ships with declaration files and source maps. All types are exported.

API Reference

rerank(query, documents, options?)

Reranks an array of documents against a query. Returns a Promise<RerankResult[]> sorted by relevance score descending.

import{rerank}from'rerank-lite'constresults=awaitrerank('machine learning',documents,{mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},})

Parameters:

ParameterTypeRequiredDescription
querystringYesThe search query to rank documents against.
documentsDocument[]YesArray of candidate documents from a first-stage retriever.
optionsRerankOptionsNoConfiguration for scoring mode, filtering, and weights.

Returns:Promise<RerankResult[]> -- results sorted by score descending, with newRank assigned as 0-based indices.

Behavior with empty input: Returns an empty array when documents is empty.


createReranker(config?)

Factory that returns a configured Reranker instance. Preset options are applied to every rerank() call; per-call options override the preset.

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,weights: {bm25: 0.6,tfidf: 0.3,position: 0.1},})constresults=awaitreranker.rerank('first query',docs)// Override topK for this call onlyconsttop3=awaitreranker.rerank('second query',docs,{topK: 3})

Parameters:

ParameterTypeRequiredDescription
configRerankerConfigNoDefault configuration applied to all calls.

Returns:Reranker -- an object with a rerank() method and a read-only config property.


Types

Document

Represents a candidate document to be scored.

interfaceDocument{id: string// Unique identifier for the documenttext: string// The text content to score against the queryscore?: number// Optional original retrieval scoremetadata?: Record<string,unknown>// Optional pass-through metadata}

RerankResult

A scored and ranked document returned by rerank().

interfaceRerankResult{document: Document// The original document object, including metadatascore: number// Relevance score in [0, 1]originalRank: number// 0-based index in the input arraynewRank: number// 0-based rank after reranking (0 = most relevant)explanation?: string// Optional debug information}

RerankOptions

Options for a single rerank() call.

interfaceRerankOptions{topK?: number// Return only the top K results (default: all)minScore?: number// Filter out results with a score below this thresholdmode?: RerankMode// Scoring mode (default: 'heuristic')judgeFn?: JudgeFn// Required when mode is 'llm' or 'hybrid'weights?: ScoringWeights// Custom weights for heuristic scoring components}

RerankMode

typeRerankMode='heuristic'|'llm'|'hybrid'
ModeDescription
heuristicBM25 + TF-IDF + position weighted scoring. Zero dependencies. Default.
llmDelegates scoring entirely to the caller-supplied judgeFn.
hybrid50/50 blend of heuristic scores and judgeFn scores.

JudgeFn

The function signature for LLM-as-judge scoring.

typeJudgeFn=(query: string,document: string)=>Promise<number>

Must return a numeric relevance score. Called once per document when mode is llm or hybrid.

ScoringWeights

Weights for the three heuristic scoring signals. All are optional and default to the values shown.

interfaceScoringWeights{bm25?: number// Default: 0.5tfidf?: number// Default: 0.3position?: number// Default: 0.2}

RerankerConfig

Configuration for the createReranker() factory. Same shape as RerankOptions.

interfaceRerankerConfig{mode?: RerankModetopK?: numberminScore?: numberjudgeFn?: JudgeFnweights?: ScoringWeights}

Reranker

The instance returned by createReranker().

interfaceReranker{rerank(query: string,documents: Document[],options?: RerankOptions): Promise<RerankResult[]>readonlyconfig: RerankerConfig}

Configuration

Scoring Weights

The heuristic composite score is computed as:

score = (bm25_weight * bm25_score) + (tfidf_weight * tfidf_score) + (position_weight * position_score)

Default weights:

SignalDefault WeightDescription
bm250.5BM25 term frequency / inverse document frequency score, normalized to [0, 1] via sigmoid.
tfidf0.3TF-IDF cosine similarity between query and document vectors.
position0.2Position bias: 1 - (originalRank / totalDocuments). Preserves signal from the first-stage retriever.

Override weights to tune for your retrieval domain:

// Favor lexical match, ignore original orderingconstresults=awaitrerank('exact keyword query',docs,{weights: {bm25: 0.7,tfidf: 0.3,position: 0.0},})// Trust the first-stage retriever, use reranking as a tiebreakerconstresults=awaitrerank('semantic query',docs,{weights: {bm25: 0.2,tfidf: 0.2,position: 0.6},})

BM25 Parameters

The BM25 scorer accepts standard tuning parameters k1 (term frequency saturation, default 1.5) and b (document length normalization, default 0.75). These are set internally and follow the Robertson/Zaragoza BM25 formulation.


Error Handling

rerank() handles edge cases gracefully without throwing:

  • Empty documents array -- returns an empty array [].
  • No matching terms -- all documents receive a baseline score (sigmoid of zero for BM25, zero for TF-IDF). Documents are still ranked by position bias.
  • Empty query or document text -- TF-IDF returns 0 for empty strings. BM25 returns the sigmoid baseline (0.5).

When using llm or hybrid mode, errors from the judgeFn propagate as-is. Wrap your judge function with try/catch if you need graceful degradation:

constsafejudgeFn=async(query: string,doc: string): Promise<number>=>{try{returnawaityourLLMScorer(query,doc)}catch{return0// Fallback score on failure}}constresults=awaitrerank('query',docs,{mode: 'llm',judgeFn: safejudgeFn})

Advanced Usage

LLM-as-Judge Mode

Pass any async function that returns a relevance score. The function is called once per document.

import{rerank}from'rerank-lite'importOpenAIfrom'openai'constopenai=newOpenAI()constjudgeFn=async(query: string,document: string): Promise<number>=>{constresponse=awaitopenai.chat.completions.create({model: 'gpt-4o-mini',messages: [{role: 'user',content: `Rate the relevance of this document to the query on a scale from 0 to 1.\nQuery: ${query}\nDocument: ${document}\nRespond with only a number between 0 and 1.`,},],})returnparseFloat(response.choices[0].message.content??'0')}constresults=awaitrerank('machine learning',docs,{mode: 'llm', judgeFn })

Hybrid Mode

Combines heuristic scoring with LLM judgment. The final score is a 50/50 blend:

hybrid_score = 0.5 * heuristic_score + 0.5 * llm_score
constresults=awaitrerank('machine learning',docs,{mode: 'hybrid',
judgeFn,weights: {bm25: 0.5,tfidf: 0.3,position: 0.2},// Applies to heuristic half})

RAG Pipeline Integration

Use reranking as stage two after vector search or BM25 retrieval:

// Stage 1: Retrieve candidates from your vector databaseconstcandidates=awaitvectorDB.query(embedding,{topK: 50})// Stage 2: Rerank for precisionconstreranked=awaitrerank(query,candidates,{topK: 10,minScore: 0.4})// Stage 3: Pass to LLM contextconstcontext=reranked.map(r=>r.document.text).join('\n\n')

Reusable Reranker Instance

For applications that rerank many queries with the same configuration:

import{createReranker}from'rerank-lite'constreranker=createReranker({mode: 'heuristic',topK: 10,minScore: 0.3,weights: {bm25: 0.6,tfidf: 0.25,position: 0.15},})// Use across multiple queriesconstresults1=awaitreranker.rerank('first query',docs1)constresults2=awaitreranker.rerank('second query',docs2)// Override per-call when neededconstresults3=awaitreranker.rerank('third query',docs3,{topK: 5})

Filtering with minScore and topK

minScore is applied first, then topK limits the output:

// Return at most 5 results, all with score >= 0.5constresults=awaitrerank('query',docs,{topK: 5,minScore: 0.5})

TypeScript

rerank-lite is written in TypeScript and ships with declaration files (.d.ts) and source maps. All types are exported from the package entry point:

import{rerank,createReranker,typeDocument,typeRerankResult,typeRerankOptions,typeRerankMode,typeJudgeFn,typeScoringWeights,typeRerankerConfig,typeReranker,}from'rerank-lite'

The package targets ES2022 and emits CommonJS modules. It is compatible with both require() and bundlers that resolve the exports field.


License

MIT

About

Lightweight retrieval reranker using cross-encoder scoring

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages