2026-09-25
Why BGE-M3? (And why we left it)
We picked BGE-M3 for one reason: dense, sparse, and ColBERT-style multi-vectors in a single forward pass. Three signals for the price of one. Then we measured — and moved.
What BGE-M3 got right
One model, 100+ languages, 8192-token context, and a hybrid output that covered semantics and exact match together. For two years it was the default answer to "which embedding model self-hosts well," and it earned that.
What the leaderboard said
By late 2026 the live MTEB board had BGE-M3 at rank 86 on the multilingual suite — beaten by models half its size. Leaderboards aren't workloads, though, so we spiked two finalists on our own MovieLens-shaped data: 1,000 docs, 20 graded queries.
What our spike said
F2LLM-v2-0.6B beat Qwen3-Embedding-0.6B on nDCG@10, 0.771 to 0.726, winning 11 queries to 7 — including our own production head query by a wide margin. Same 1024 dimensions, so the stored format didn't change; only the space got better. We swapped the default, served it from a Rust ONNX sidecar, and reindexed.
The lesson
Pick the model on your data, not the leaderboard — and re-run the comparison yearly. The half-life of "best default" in embeddings is about eighteen months.