qwen3 vs nomic: замена эмбеддингов с реальными цифрами
Это продолжение предыдущей статьи, где я внедрил Hybrid RAG в чатбот на сайте. RAG работал, токены экономились на 80%, бот отвечал на английские вопросы нормально. Но одна проблема не давала покоя: русские запросы находили не те чанки. Бот рассказывал про BPM вместо RAG, путал статьи между собой, и я не мог понять - проблема в промпте, в retrieval, или в чем-то глубже.
Вопрос, который я задал себе: может ли замена одной модели эмбеддингов исправить retrieval quality без изменения всей архитектуры? Или проблема фундаментальнее и нужно менять подход?

Проблема
После запуска RAG я проверил, как бот отвечает на вопрос “Расскажи про статью о Hybrid RAG”. Бот ответил: “Hybrid RAG: лучшее из Agile и Waterfall”. Статья про оптимизацию токенов превратилась в методологию проектного управления. Для пользователя это выглядит как галлюцинация модели, но на самом деле модель честно ответила на основе тех чанков, которые ей подсунул retrieval. Проблема была не в LLM, а в поиске.
Посмотрел в логи Qdrant. Чанк blog_hybrid_rag с правильным текстом лежит в коллекции. Но при поиске по запросу “Hybrid RAG оптимизация токенов” он оказался на 44-м месте из 48 со score 0.583. Первые 7 позиций - окно retrieval, которое передается в промпт модели - заняли случайные статьи про IT-трансформации и BPM. Модель получила нерелевантный контекст и добросовестно сгенерировала ответ на его основе.
Проблема оказалась в nomic-embed-text - модели эмбеддингов, которая конвертирует текст в векторы для поиска. nomic обучена преимущественно на английских данных. Русский текст она превращает в вектор, но семантика теряется: “оптимизация токенов” и “эволюция управления” для нее примерно одинаковы - набор кириллических символов с похожей структурой. Это объясняет, почему английские запросы работали нормально, а русские - нет.
Выбор замены
Критерии определялись инфраструктурой. Чатбот работает на VPS с 4 GB RAM, где одновременно крутятся Qdrant, Ollama и сам бот. Внешние API для эмбеддингов я не рассматривал принципиально - это лишняя зависимость, latency и стоимость на каждый запрос. Значит, модель должна:
- Нативно поддерживать русский, английский и казахский (не “понимать кириллицу”, а реально различать семантику)
- Работать в Ollama (у нас всё локально)
- Влезать в доступную RAM вместе с остальным стеком
qwen3-embedding подходил идеально: #1 в MTEB multilingual leaderboard на момент выбора, обучена на 100+ языках, три размера на выбор (0.6B / 4B / 8B), есть в Ollama. Взял 0.6B - 639 MB, что в 2.3 раза тяжелее nomic (274 MB), но всё ещё вписывается в бюджет RAM.
Миграция
Замена эмбеддинг-модели - это не просто смена имени в конфиге. Каждая модель генерирует векторы разной размерности: nomic - 768 измерений, qwen3 - 1024. Коллекция в Qdrant создана под конкретную размерность, и вектор из 1024 чисел физически не ляжет в коллекцию, рассчитанную на 768. Значит, все коллекции нужно пересоздать и все 48 чанков переиндексировать с нуля.
Хорошо, что я заранее параметризировал код через env vars:
EMBED_MODEL = os.environ.get("EMBED_MODEL", "nomic-embed-text")
VECTOR_DIM = int(os.environ.get("VECTOR_DIM", "768"))
Добавил автоматическое пересоздание коллекции при смене размерности:
def ensure_collection():
client = get_client()
collections = [c.name for c in client.get_collections().collections]
if COLLECTION in collections:
info = client.get_collection(COLLECTION)
existing_dim = info.config.params.vectors.size
if existing_dim != VECTOR_DIM:
logger.info("Dimension changed %d -> %d, recreating",
existing_dim, VECTOR_DIM)
client.delete_collection(COLLECTION)
else:
return
client.create_collection(
COLLECTION,
VectorParams(size=VECTOR_DIM, distance=Distance.COSINE),
)
Деплой:
# На сервере
docker exec ollama ollama pull qwen3-embedding:0.6b
# В .env
EMBED_MODEL=qwen3-embedding:0.6b
VECTOR_DIM=1024
# Перезапуск (CI/CD или вручную)
docker compose up -d --build chatbot
В логах при старте:
Vector dimension changed 768 -> 1024, recreating collection
Created Qdrant collection: knowledge (dim=1024)
Knowledge ingestion complete: 48/48 chunks
Все 48 чанков переиндексированы автоматически. Даунтайм - несколько секунд, пока бот перезапускается и ingestion отрабатывает. Для production-чатбота с десятками запросов в день это допустимо.
Бенчмарк
Методология простая: 12 запросов на трех языках (8 русских, 3 английских, 1 казахский). Для каждого запроса я знаю, какой чанк должен быть найден. Замеряю rank (позицию в результатах) и score (cosine similarity) из Qdrant. Одни и те же 48 чанков, одни и те же search_text, меняется только модель эмбеддингов. Это не MTEB с тысячами запросов - это бенчмарк на живых данных конкретного продукта.
Русский
| Запрос | Ожидаемый чанк | nomic | qwen3 |
|---|---|---|---|
| Расскажи про опыт в банке | career_bank_head | #5 0.636 | #1 0.658 |
| опыт работы в крупном банке | career_bank_head | #1 0.715 | #1 0.683 |
| какие услуги предлагает | services_overview | #2 0.688 | #1 0.612 |
| где учился Ильяс | education_certs | #2 0.666 | #1 0.561 |
| Hybrid RAG оптимизация | blog_hybrid_rag | #44 0.583 | #1 0.719 |
| как устроен чатбот | blog_hybrid_rag | #14 0.613 | #5 0.636 |
| где работал Ильяс | career_overview | #11 0.661 | #1 0.663 |
| статья про 4 бага | blog_four_bugs | #19 0.599 | #3 0.553 |
Ключевая строка: “Hybrid RAG оптимизация”. nomic поставил нужный чанк на 44-е место из 48 - то есть фактически на дно результатов. qwen3 поставил на 1-е. Это не косметическое улучшение, это разница между “бот отвечает правильно” и “бот несет чушь”.
Английский
| Запрос | Ожидаемый чанк | nomic | qwen3 |
|---|---|---|---|
| What services does Ilyas offer | services_overview | #1 0.719 | #1 0.825 |
| banking career experience | career_bank_head | #2 0.589 | #1 0.733 |
| AI agents and LLM | service_ai_agents | #1 0.715 | #1 0.823 |
На английском обе модели находят нужный чанк - nomic здесь на своей территории, обучающие данные были английскими. Но разница в score показательна: qwen3 дает 0.82-0.83, nomic - 0.59-0.72. Почему это важно? Выше score нужного чанка - больше дистанция до шума, меньше шанс подмешать нерелевантный чанк в окно retrieval. При score 0.72 нужный чанк и мусор лежат рядом; при 0.83 - четко разделены.
Казахский
| Запрос | Ожидаемый чанк | nomic | qwen3 |
|---|---|---|---|
| Ильястың банктегі тәжірибесі | career_bank_head | #14 0.575 | #6 0.503 |
Казахский остается самым сложным для обеих моделей - всего один тестовый запрос, но он показателен. nomic поставил нужный чанк на 14-е место - далеко за пределами окна retrieval (top-7). qwen3 поднял его на 6-е - на границе, но внутри окна. Бот хотя бы получит правильный чанк в контекст и сможет на него опереться. Идеальным казахский retrieval пока не назовешь, но разница между “чанк есть в контексте” и “чанка нет” - это разница между ответом и галлюцинацией.
Сводка
nomic находил нужный чанк в окне retrieval (top-7) в 42% случаев. Это значит, что в 58% запросов бот получал нерелевантный контекст и отвечал на его основе - по сути галлюцинировал, но не по своей вине. qwen3 - 100%. Каждый запрос из бенчмарка попал в окно retrieval. Это та разница, ради которой стоило менять модель.
Скорость
Latency на запрос - почти одинаковая, qwen3 даже на 10ms быстрее (134 vs 144 ms). Это неожиданно для модели в 2.3 раза тяжелее, но объясняется, видимо, более эффективной архитектурой. Ingestion медленнее (9.5 vs 5.4 сек за 48 чанков), но это разовая операция при старте контейнера - пользователь её не замечает.
Главное: переход на qwen3 не добавил latency к ответам бота. Пользователь ждет столько же, но получает правильный ответ.
Почему nomic проигрывает на русском
Причина не в том, что nomic “плохая” модель. Для английского она работает достойно - #1 и #2 в бенчмарке выше. Проблема в обучающих данных: nomic-embed-text обучена преимущественно на английском корпусе. Русский текст она обрабатывает, но не различает семантику на уровне, достаточном для точного retrieval. Для нее “оптимизация токенов” и “эволюция управления” - примерно одно и то же: набор кириллических символов с похожей длиной и структурой.
qwen3-embedding обучена на 100+ языках, включая русский и казахский. Она понимает, что “оптимизация токенов” семантически ближе к “token cost reduction”, чем к “project management evolution”. Это не магия - это результат обучения на мультиязычном корпусе, где модель видела достаточно русских текстов, чтобы построить адекватное семантическое пространство.
Визуально разница выглядит так: nomic дает scores 0.58-0.72 для всех 48 чанков - узкий коридор, где сигнал (нужный чанк) теряется в шуме (остальные чанки). Все чанки “похожи” друг на друга. qwen3 дает 0.50-0.83 - разброс в полтора раза шире, нужный чанк четко выделяется на фоне остальных. Это и есть суть quality retrieval: не абсолютный score важен, а разница между нужным результатом и шумом.
Ограничения бенчмарка
Этот бенчмарк - не MTEB и не претендует на универсальность. 48 чанков, 12 запросов, один use case. Я не тестировал long-form queries, не проверял edge cases, не мерял recall@k для разных значений k. Результаты показывают конкретное улучшение для конкретного продукта: мультиязычный чатбот на персональном сайте с русскими, английскими и казахскими запросами, с базой знаний из 48 чанков.
Для чисто английского RAG nomic может оказаться достаточным - на английских запросах она показывает приемлемые результаты. Для любого проекта с русским или другими не-английскими языками - qwen3-embedding однозначно лучше. Разница не косметическая, она принципиальная: 42% vs 100% retrieval accuracy.
Как попробовать у себя
Если у вас уже есть RAG на Ollama + Qdrant (или вы собрали его по предыдущей статье):
# Скачать модель
docker exec ollama ollama pull qwen3-embedding:0.6b
# Добавить в .env
EMBED_MODEL=qwen3-embedding:0.6b
VECTOR_DIM=1024
# Перезапустить
docker compose up -d --build
Если ваш код пересоздает коллекцию при смене размерности (как в примере выше) - данные переиндексируются автоматически при перезапуске. Если нет - удалите коллекцию вручную через Qdrant API (DELETE /collections/{name}) и перезапустите ingestion.
Главный совет: прежде чем менять модель, подготовьте набор тестовых запросов с ожидаемыми результатами. Без этого вы не узнаете, стало ли лучше или хуже. Мой набор из 12 запросов - минимум, но даже он показал проблему, которую я бы не заметил вручную.
Бот работает на qwen3-embedding прямо сейчас - кнопка чата в правом нижнем углу. Попробуйте спросить что-нибудь по-русски и сравните с тем, как работало раньше. Или напишите, если хотите подобную систему для своего продукта.
Читайте также


