BGE-M3 — открытая мультиязычная модель для семантического и гибридного поиска. Она поддерживает тексты более чем на 100 языках, вход до 8192 токенов и три режима представления: dense, sparse и multi-vector.
Оглавление
- Что представляет собой BGE-M3
- Характеристики и режимы поиска
- Когда модель подходит
- Запуск локального сервиса
- Проверка результата
- Полезные сценарии
- Типичные ошибки
- Источники и документация
Что представляет собой BGE-M3
BGE-M3 — модель из семейства BGE, опубликованная под именем BAAI/bge-m3. Первая запись о выпуске BGE-M3 в репозитории FlagEmbedding датирована февралем 2024 года. Название M3 объединяет три свойства модели:
- Multi-Linguality — семантический поиск более чем на 100 языках. В документации также указано, что обучающие наборы охватывали до 170+ языков, но объём данных по языкам различался, поэтому качество следует проверять отдельно для своего корпуса.
- Multi-Functionality — dense, sparse и multi-vector retrieval в одной модели.
- Multi-Granularity — обработка входов от коротких предложений до документов длиной 8192 токена.
Техническая статья авторов описывает self-knowledge distillation: сигналы от разных режимов поиска используются совместно при обучении. Для длинных текстов модель применяет увеличенный позиционный контекст и метод Multiple CLS.
Характеристики и режимы поиска
| Параметр | Значение |
| Модель | BAAI/bge-m3 |
| Количество параметров | 569 млн |
| Размер модели | 2,27 ГБ |
| Размерность dense-вектора | 1024 |
| Максимальная длина входа | 8192 токена |
| Языки | Более 100 рабочих языков |
| Режимы поиска | Dense, sparse и multi-vector |
Одна модель возвращает разные представления текста:
| Режим | Результат | Практическое применение |
| Dense | Один нормализованный вектор размерности 1024 | Семантический поиск и базовый RAG |
| Sparse | Обученные веса токенов | Точные термины, имена, артикулы и версии |
| Multi-vector | Набор токенных векторов с поздним взаимодействием в стиле ColBERT | Более детальное ранжирование кандидатов |
Официальная документация рекомендует гибридный поиск с последующим переранжированием. Multi-vector-режим требует больше вычислений, поэтому его разумно применять к ограниченному набору кандидатов, найденных dense- или sparse-поиском.
max_length сокращает задержку. Длину входа, размер чанка и режимы поиска подбирайте по измерениям на собственных документах.Когда модель подходит
BGE-M3 стоит проверить, если:
- база знаний содержит документы на нескольких языках;
- запрос и найденный документ могут быть написаны на разных языках;
- нужен локальный сервис без обязательного внешнего API;
- семантический поиск требуется дополнить точным лексическим совпадением;
- нужно обрабатывать длинные входы, а альтернативы в вашем стеке ограничены 512 токенами.
Модель может оказаться избыточной, если важнее минимальная задержка, небольшой индекс или работа на слабом устройстве. Поддержка 8192 токенов также не означает, что целый документ всегда следует превращать в один вектор: длинный фрагмент может охватывать несколько тем и давать менее точные результаты.
Выбор модели и размера чанка проверяйте на наборе реальных запросов. Сравнивайте хотя бы recall@k или долю запросов, для которых правильный фрагмент попал в первые результаты.
Запуск локального сервиса
По состоянию на 9 сентября 2026 года страница релизов FlagEmbedding показывает v1.4.2 как последний релиз. В описании этого релиза указано исправление совместимости токенизатора с Transformers 5. Для воспроизводимого развёртывания зафиксируйте проверенную версию после локального теста.
Установка
python3 -m venv .venv
source .venv/bin/activate
pip install -U "FlagEmbedding==1.4.2" fastapi uvicorn pydanticОфициальный интерфейс загрузки и кодирования выглядит так:
from FlagEmbedding import BGEM3FlagModel
model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=False)
output = model.encode(
['Пример документа'],
batch_size=8,
max_length=8192,
return_dense=True,
return_sparse=False,
return_colbert_vecs=False,
)
vector = output['dense_vecs'][0]use_fp16=True показан в официальном примере для CUDA и ускоряет вычисления с небольшим ухудшением качества. На CPU оставьте False, если не проверяли иной режим.
Минимальный HTTP-адаптер
Следующий пример повторяет основные поля ответа OpenAI Embeddings API. Это пользовательский адаптер, а не официальный сервер BAAI; совместимость с конкретным клиентом нужно проверить отдельно.
from typing import List, Union
from fastapi import FastAPI
from FlagEmbedding import BGEM3FlagModel
from pydantic import BaseModel
app = FastAPI()
model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=False)
class EmbeddingRequest(BaseModel):
input: Union[str, List[str]]
model: str = 'bge-m3'
@app.post('/v1/embeddings')
def embeddings(req: EmbeddingRequest):
texts = [req.input] if isinstance(req.input, str) else req.input
output = model.encode(
texts,
batch_size=8,
max_length=8192,
return_dense=True,
return_sparse=False,
return_colbert_vecs=False,
)
return {
'object': 'list',
'model': req.model,
'data': [
{
'object': 'embedding',
'index': index,
'embedding': vector.tolist(),
}
for index, vector in enumerate(output['dense_vecs'])
],
'usage': {'prompt_tokens': 0, 'total_tokens': 0},
}
@app.get('/health')
def health():
return {'status': 'ok', 'model': 'BAAI/bge-m3'}Поле usage в этом минимальном адаптере заполнено нулями и не является подсчётом токенов. Если клиент использует эти значения для биллинга или лимитов, добавьте подсчёт через токенизатор.
Запустите сервис только на локальном интерфейсе:
uvicorn server:app --host 127.0.0.1 --port 8080Автозапуск через systemd
# /etc/systemd/system/bge-m3.service
[Unit]
Description=BGE-M3 Embeddings Server
After=network.target
[Service]
Type=simple
User=embeddings
WorkingDirectory=/opt/bge-m3
Environment="PATH=/opt/bge-m3/.venv/bin"
ExecStart=/opt/bge-m3/.venv/bin/uvicorn server:app --host 127.0.0.1 --port 8080
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now bge-m3
sudo systemctl status bge-m3Проверка результата
Сначала проверьте доступность процесса:
curl http://127.0.0.1:8080/healthОжидаемый ответ:
{"status":"ok","model":"BAAI/bge-m3"}Затем запросите два вектора:
curl -s http://127.0.0.1:8080/v1/embeddings \
-H 'Content-Type: application/json' \
-d '{"input":["Привет, мир","Hello, world"],"model":"bge-m3"}' \
| jq '{count: (.data | length), dimensions: (.data[0].embedding | length)}'Ожидаемая структура результата:
{"count":2,"dimensions":1024}Эта проверка подтверждает работу HTTP-слоя и размерность вектора, но не качество поиска. Для проверки retrieval соберите небольшой контрольный набор из запросов, релевантных документов и заведомо нерелевантных фрагментов. Затем измерьте, попадают ли правильные документы в top-k.
Полезные сценарии
Поиск по русско-английской базе знаний
Исходное условие: документы и запросы встречаются на русском и английском. Проиндексируйте все фрагменты одной моделью и отправляйте запросы через тот же dense-режим. Проверяемый результат — релевантный документ попадает в top-k и при запросе на другом языке. Это проверяйте отдельно по размеченному контрольному набору, потому что качество может различаться между языками.
Гибридный поиск по смыслу и точным терминам
Dense-представление помогает находить переформулировки, а sparse-веса учитывают совпадения терминов. Получите оба представления через return_dense=True и return_sparse=True, затем объедините результаты в поисковой системе, которая поддерживает гибридное ранжирование. Универсальных весов нет: официальная документация указывает, что они зависят от сценария. Результат проверяйте отдельно на смысловых запросах и запросах с артикулами, именами или версиями.
Переранжирование ограниченного набора кандидатов
Сначала получите кандидатов дешёвым dense- или sparse-поиском. Затем вычислите multi-vector score только для этого набора. Проверяемый результат — сравните порядок top-N до и после более детального сопоставления токенов. Ограничение: multi-vector-режим требует больше вычислений и увеличивает объём хранения токенных представлений.
Поиск по длинным материалам
Контекст 8192 токена позволяет экспериментировать с крупными фрагментами, но размер чанка остаётся параметром поиска. Сравните несколько вариантов нарезки на одинаковом наборе запросов. Результатом должен быть измеримый рост полноты или точности, а не только уменьшение числа чанков.
Типичные ошибки
| Симптом | Что проверить | Действие |
| Текст неожиданно обрезается | Значение max_length | Передайте нужный лимит явно; максимум модели — 8192 токена |
| Процессу не хватает памяти | Размер батча и длину входов | Уменьшите batch_size и max_length, затем измерьте снова |
| Ответ не принимает клиент | Требуемую клиентом схему | Сверьте поля, типы, обработку ошибок и способ подсчёта usage |
| Поиск плохо работает на конкретном языке | Контрольный набор для этого языка | Измерьте качество отдельно и сравните с альтернативной моделью |
| Индекс занимает слишком много места | Включённые режимы представления | Оставьте dense-режим как базовый и добавляйте остальные по результатам тестов |
BGE-M3 не требует обязательной инструкции-префикса для поисковых запросов. Это прямо указано в актуальной документации проекта. Не переносите на неё рекомендации для старых моделей BGE автоматически.
Также не смешивайте векторы разных моделей в одном поисковом пространстве: их координаты напрямую несопоставимы. При смене модели создайте новый индекс и повторно закодируйте документы.
Источники и документация
Проверено 9 сентября 2026 года:
- Документация и примеры BGE-M3 в FlagEmbedding
- Техническое описание BGE-M3
- Релизы FlagEmbedding
- Карточка модели BAAI/bge-m3
- Статья M3-Embedding, arXiv:2402.03216
Следующий шаг
После запуска соберите 30–50 реальных запросов и сравните dense-поиск с гибридным вариантом. Для сравнения с другой локальной embedding-моделью можно посмотреть EmbeddingGemma. Такой тест поможет отделить особенности модели от влияния нарезки текста и настроек поиска.
Связанные материалы
Подходящих дополнительных материалов по BGE-M3 среди проверенных публичных ссылок нет.
Если вы проектируете локальный RAG-контур и хотите подобрать модель, размер чанка и схему поиска под свои документы, конфигурацию полезно обсудить на реальной нагрузке и контрольных запросах.
Если захотите обсудить, как это применить у себя или в команде — пишите в Telegram @pimenov
