← All models

reranker (text-classification) · text · WASM · ~571 MB

BGE-reranker-v2-m3 — rank passages by relevance, across 100+ languages

BAAI's second-generation multilingual cross-encoder. Where the original bge-reranker-base used an XLM-RoBERTa-base backbone, v2-m3 is built on the larger M3 backbone (XLM-RoBERTa-large, trained across 100+ languages) — a stronger, broader reranker. Instead of turning a query and a passage into separate vectors and comparing them, it reads both together and outputs a single relevance score, so it ranks a Chinese or Spanish passage against an English query as easily as an English one. Give it a query and candidates and watch it re-sort them; then look inside at the raw logit per pair. Nothing leaves your device.

At a glance

Modelonnx-community/bge-reranker-v2-m3-ONNX (ONNX of BAAI/bge-reranker-v2-m3)
Task / pipelinetext-classification used as a cross-encoder reranker (num_labels = 1)
Inputa (query, passage) pair encoded together → one relevance logit
ArchitectureXLM-RoBERTa-large (the M3 backbone, 100+ languages) fine-tuned for passage reranking — v2 of the BGE reranker family
vs. v1bge-reranker-base = XLM-RoBERTa-base (~270 MB q8); v2-m3 = the larger M3/large backbone (~571 MB q8) — more capacity, broader language reach
Quantizationq8 (8-bit) ONNX
BackendWebAssembly (runs anywhere; no WebGPU needed)
Download~571 MB, cached after first load
LicenseApache-2.0
Web APIsWebAssembly, Web Workers — all Baseline widely available

Run it

Type a query and one candidate passage per line. The model scores each passage against the query and re-sorts them by relevance logit (higher = more relevant). The default set mixes English, Chinese and Spanish so you can see cross-language ranking.

See inside — before vs after, and why it isn't word-matching

The one number the model emits per pair is a relevance logit — unbounded, higher is more relevant (we also show its sigmoid as a 0–100% probability). First, the before/after view: the candidates in their original (retrieval) order on the left, and the cross-encoder's reordering on the right — arrows mark what moved. Then a second contrast ranks the same passages by naive shared-word overlap; where the columns disagree, the cross-encoder is using meaning, and it does so across languages — a word-overlap score can't match an English query to a Chinese or Spanish answer at all, but the M3 backbone can.

Rerank some passages above to compare.

Cross-encoder vs. lexical overlap

Why it matters

Rerankers are the precision stage of modern search. A fast retriever (a keyword index or embeddings) casts a wide net and returns, say, the top 50 candidates; a cross-encoder then reads each candidate against the query and reorders them with far higher accuracy. BGE-reranker-v2-m3 pairs that precision with the widest language reach in the family — one model that ranks relevance across 100+ languages, so a query in one language surfaces the best answer written in another. At ~571 MB it runs in a tab, so the precise, expensive step happens on-device with nothing sent anywhere.

Use cases

Basics

Rank a handful of passages against a query by cross-encoder relevance.

Practical

Two-stage RAG: retrieve a multilingual shortlist, then rerank with v2-m3.

Wild

Cross-lingual hard negatives: distractors that fool keyword and embedding search across languages.

Multi-model

Multilingual E5 embeddings retrieve, BGE-reranker-v2-m3 reorders — the classic retrieve-then-rerank.

Contrast with the first-generation BGE-reranker-base: same cross-encoder idea, but v2-m3 uses the larger M3 backbone for stronger accuracy and broader language coverage — at roughly double the download.

How the API works

A cross-encoder scores query–passage pairs; we read the raw logit off the model directly:

import { AutoTokenizer, AutoModelForSequenceClassification } from "@huggingface/transformers";

const model_id = "onnx-community/bge-reranker-v2-m3-ONNX";
const tokenizer = await AutoTokenizer.from_pretrained(model_id);
const model = await AutoModelForSequenceClassification.from_pretrained(model_id, { dtype: "q8" });

// Encode the query with each passage AS A PAIR — [CLS] query [SEP] passage [SEP]:
const inputs = tokenizer(
  passages.map(() => query),
  { text_pair: passages, padding: true, truncation: true },
);
const { logits } = await model(inputs); // one relevance logit per pair — higher = more relevant
// sort the passages by logits.data — that's your reranking (works even when query and passage
// are in different languages, because the M3 backbone is multilingual XLM-RoBERTa-large)

This page loads the model through the shared loader as a text-classification pipeline, then reuses pipe.model + pipe.tokenizer to read the raw logits (the pipeline would squash them through a sigmoid). All inference runs in a Web Worker so ranking never janks the page.

References