How to choose an embedding model for RAG and semantic search
BGE-M3 and Qwen3 Embedding: how they differ, how vector dimensionality matters, and why multilingual support is essential for Russian.
Yenisei team
How to choose an embedding model for RAG and semantic search
An embedding turns text into a vector, a set of numbers where texts close in meaning end up close in space. Everything rests on this: semantic search, RAG, clustering, deduplication, recommendations. The model here is chosen once and for a long time; switching later is painful because the entire base has to be reindexed. So it is worth choosing carefully.
What is in the catalog
- BGE-M3 (
bge-m3, BAAI) is multilingual, works well with Russian, has a reasonable dimensionality, and is open. The default choice if in doubt. - Qwen3 Embedding 8B (
qwen3-embedding-8b) is a strong multilingual model for when you need maximum accuracy. - Qwen3 Embedding 4B (
qwen3-embedding-4b) is the same lineup, lighter.
All three have open weights. Closed embedding models (text-embedding-3 from OpenAI, Gemini Embedding from Google) are not in the Yenisei catalog.
Vector dimensionality: what you pay for
Dimensionality is the length of the vector (for example, 1024 or 3072 numbers). More is usually more accurate, but:
- Memory and speed. There are millions of vectors in the base; every extra dimension is memory in storage and time spent searching.
- Index cost. Vector databases consume resources roughly linearly with dimensionality.
Some models are trained so that the vector can be truncated: take only the first dimensions with almost no loss in quality. If you use this, decide by measurement: compute the quality at full length, then at the truncated length, and compare.
Multilingual support: mandatory for Russian
The main trap for Russian-language projects is taking a model trained mostly on English. It shines on an English benchmark, but Russian retrieval degrades: Russian phrases close in meaning end up farther apart in space than they should. For a Russian base, take a model that is multilingual by design: BGE-M3 or Qwen3 Embedding. Whether search works at all depends on this.
How to compute embeddings
Through the standard /v1/embeddings endpoint:
curl https://api.yenisei.ru/v1/embeddings \ -H "Authorization: Bearer $YENISEI_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "bge-m3", "input": ["first text fragment", "second text fragment"] }'In Python, in batches, so you do not send them one at a time:
from openai import OpenAIclient = OpenAI(base_url="https://api.yenisei.ru/v1", api_key="YENISEI_KEY")def embed(texts, model="bge-m3"): r = client.embeddings.create(model=model, input=texts) return [d.embedding for d in r.data]# batches of 64-256 texts per request: cheaper and fastervectors = embed(chunks_batch)Rules that will save you a reindex
- One model for the index and for the query. The query vector and the base vectors must be computed by the same model, otherwise they are not comparable and search breaks silently.
- Normalize and measure cosine. For most embeddings, cosine similarity is the right proximity metric.
- Do not mix versions. Updated the embedding model: reindex everything, not half.
- Test on your own data. Collect 30 to 50 "query, correct document" pairs and see at what rank the right one shows up. This is more honest than any external benchmark.
What to take by default
For Russian-language RAG, start with BGE-M3: multilingual, open, predictable, no surprises on price. Need higher accuracy: try Qwen3 Embedding 8B and compare it with BGE-M3 on your 30 pairs. Need a lighter model for large volume: Qwen3 Embedding 4B. Make the final choice by measurement on your own data, not by benchmarks.