Чат-бот с векторной базой Qdrant ищет ответ не по совпадению слов, а по смыслу запроса - это первое, что меняется, когда переходишь с обычного full-text поиска на эмбеддинги. За последний год собрал на Qdrant три RAG-бота: для интернет-магазина на WooCommerce с базой по возврату и доставке через СДЭК, для B2B-сервиса на n8n и телеграм-бота поддержки на aiogram. В статье - как разворачивал базу, что грузил в коллекции и на каких шагах терял время зря.
Зачем чат-боту векторная база данных вместо поиска по ключевым словам
Обычный поиск по базе знаний работает через совпадение слов: если в вопросе клиента нет тех же терминов, что в документе, ответ не найдётся. Проверял это на реальном кейсе - в базе FAQ для магазина был раздел «возврат товара», а клиент писал «как вернуть деньги за заказ». Full-text поиск по PostgreSQL с tsvector такие запросы пропускал в 30-40% случаев, потому что «деньги» и «товар» - не те слова, что в тексте документа.
Эмбеддинги решают это иначе: текст превращается в вектор чисел, и близость векторов отражает смысловую близость, а не совпадение символов. Фраза «вернуть деньги за заказ» и заголовок «оформление возврата» в векторном пространстве окажутся рядом даже без общих слов. Qdrant хранит эти векторы и по запросу находит ближайшие через косинусное сходство или евклидово расстояние - обычно за 20-50 мс на базе в 100-200 тысяч записей на паре виртуальных ядер.
Что такое Qdrant и почему я беру его для RAG-ботов
Qdrant - векторная база на Rust с открытым исходным кодом, gRPC и REST API из коробки. Для чат-бота важны три вещи, которые в Qdrant сделаны без костылей:
- Фильтрация по payload прямо во время векторного поиска - можно искать «похоже на запрос» и одновременно «только из раздела доставка» одним запросом, без постобработки на стороне бота.
- HNSW-индекс с настраиваемым балансом скорость/точность - на боевых объёмах до полумиллиона векторов это ощутимо быстрее полного перебора.
- Snapshot и репликация из коробки для self-host, если база растёт и нужен бэкап без ручных скриптов.
В конце статьи сравню Qdrant с Pinecone, Weaviate и pgvector - но если коротко, я выбираю Qdrant за то, что его можно развернуть на своём VPS в России без завязки на зарубежный биллинг, а API при этом не уступает облачным конкурентам.
Разворачиваю Qdrant: Docker, облако, коллекция
Самый быстрый способ поднять базу локально или на VPS - через Docker:
docker run -p 6333:6333 -p 6334:6334
-v $(pwd)/qdrant_storage:/qdrant/storage
qdrant/qdrant
Порт 6333 - REST API, 6334 - gRPC, том нужен, чтобы данные не терялись при рестарте контейнера. Для продакшена добавляю docker-compose с healthcheck и лимитами памяти - на коллекцию в 100 тысяч векторов размерностью 1536 хватает 2 ГБ RAM, VPS такого класса на практике обходится от 500-700 ₽ в месяц у большинства российских провайдеров.
Есть и облачный вариант - Qdrant Cloud с бесплатным тестовым кластером на 1 ГБ, этого достаточно для прототипа на 50-100 тысяч записей. Для боевого бота с трафиком я всё же ставлю self-host: меньше задержка сети между ботом и базой, если оба висят на одном сервере, и нет риска блокировки зарубежного биллинга.
После запуска создаю коллекцию - это как таблица в обычной БД, только с параметрами вектора:
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams
client = QdrantClient(url="http://localhost:6333")
client.create_collection(
collection_name="faq_base",
vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
)
Размерность 1536 - под модель эмбеддингов text-embedding-3-small от OpenAI, для других моделей меняю на их размерность (у bge-m3, например, 1024).
Бесплатный материал
🎁 Полезный скрипт в подарок
Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.
Без спама. Отписка в 1 клик.
Загружаю базу знаний: эмбеддинги, чанкинг, upsert
Перед загрузкой текст режу на чанки по 300-500 токенов с перекрытием 50-100 токенов - если резать без перекрытия, смысл на границе абзаца теряется и поиск промахивается мимо нужного куска. Для документа на 40 страниц типично получается 150-250 чанков.
Эмбеддинги считаю либо через OpenAI (text-embedding-3-small - около 0,02 $ за миллион токенов, для базы в 500 страниц это копейки), либо через открытые модели вроде bge-m3, если данные нельзя отправлять за рубеж - этот вариант ставлю локально через sentence-transformers, но требует GPU или терпения на CPU.
Загрузка в Qdrant - через upsert, каждая точка это вектор плюс payload с оригинальным текстом и метаданными:
from qdrant_client.models import PointStruct
client.upsert(
collection_name="faq_base",
points=[
PointStruct(
id=idx,
vector=embedding,
payload={"text": chunk, "source": "return_policy.pdf", "category": "returns"},
)
for idx, (chunk, embedding) in enumerate(chunks_with_vectors)
],
)
Поле category потом использую для фильтрации - если бот точно знает, что вопрос про доставку, можно искать только среди чанков с category=“delivery” и не смешивать с разделом оплаты. Готовый скрипт для загрузки PDF и docx в Qdrant с чанкингом и повтором запросов при таймаутах я выкладывал в библиотеке готовых скриптов - можно взять за основу и адаптировать под свои данные.
Подключаю Qdrant к чат-боту: aiogram и n8n
В телеграм-боте на aiogram поиск по базе встраивается в обработчик сообщений: превращаю вопрос пользователя в вектор, ищу ближайшие чанки, собираю из них контекст и отдаю в LLM вместе с вопросом.
@dp.message()
async def handle_message(message: Message):
query_vector = get_embedding(message.text)
hits = client.search(
collection_name="faq_base",
query_vector=query_vector,
limit=5,
)
context = "n".join(hit.payload["text"] for hit in hits)
answer = await ask_llm(question=message.text, context=context)
await message.answer(answer)
limit=5 обычно достаточно - брал больше чанков и заметил, что модель начинает путаться в избыточном контексте и отвечать более расплывчато, а не точнее.
В n8n схема без единой строчки кода: HTTP Request нода дергает POST /collections/faq_base/points/search у Qdrant с телом запроса, содержащим вектор вопроса (его предварительно считает нода вызова embeddings API), дальше Function нода собирает найденные payload.text в один контекст, и он уходит в ноду LLM. Для клиентов, которым дешевле автоматизация без разработки бота с нуля, такая связка на n8n закрывает задачу за пару дней вместо нескольких недель на кастомном коде.
Qdrant vs Pinecone vs Weaviate vs pgvector - что выбрать
Сравнение по опыту работы с каждым вариантом на реальных проектах:
| Критерий | Qdrant | Pinecone | Weaviate | pgvector |
|---|---|---|---|---|
| Self-host в России | да, без ограничений | нет, только облако | да, но тяжелее в настройке | да, это расширение Postgres |
| Фильтры по метаданным при поиске | встроены, быстро | есть, с ограничениями по типам | есть | через SQL WHERE, медленнее на больших объёмах |
| Порог входа | низкий, один docker run | низкий, но нужна карта для оплаты | средний, больше конфигов | низкий, если уже есть Postgres |
| Стоимость на рынке (не мои цены) | self-host - цена VPS, облако от бесплатного тарифа | от 70-280 $/мес на платных планах у большинства провайдеров | от 25-100 $/мес в облаке или self-host бесплатно | бесплатно, если Postgres уже оплачен |
| Когда беру | боты и RAG с фильтрами и трафиком | если проект уже на зарубежном стеке и оплата не проблема | если нужна встроенная гибридная схема с классами объектов | если база маленькая и не хочется разворачивать отдельный сервис |
pgvector беру для проектов, где база знаний до 10-20 тысяч записей и уже есть Postgres под рукой - разворачивать отдельную векторную БД ради этого объёма избыточно. Как только записей становится больше или нужны сложные фильтры на лету, перехожу на Qdrant - разница в скорости поиска на 100+ тысячах векторов становится заметна на глаз.
Отдельно стоит сказать про грабли, на которые я наступал сам. Первая - забывал переиндексировать коллекцию после массового обновления payload, из-за чего бот несколько дней отвечал по старым данным о ценах. Вторая - при выборе размерности вектора экономил и брал модель с 384 измерениями вместо 1536, чтобы сэкономить на памяти, а потом переделывал всю базу заново, потому что точность поиска на нюансированных вопросах заметно проседала. Третья - на VPS с 1 ГБ RAM Qdrant начинал тормозить уже на 50 тысячах векторов, так что для боевого бота закладываю минимум 2 ГБ.
Чат-бот с базой знаний
AI / RAG
от 50 000 ₽
Подробнее →Частые вопросы
Сколько документов выдержит бесплатный тариф Qdrant Cloud?
Бесплатный кластер даёт около 1 ГБ хранилища, чего хватает примерно на 100-150 тысяч векторов размерностью 1536 вместе с payload. Для прототипа или базы знаний небольшого магазина этого достаточно, для боевого проекта с ростом базы обычно перехожу на self-host или платный план.
Обязательно ли использовать OpenAI для эмбеддингов или можно бесплатные модели?
Нет, не обязательно. Открытые модели вроде bge-m3 или multilingual-e5 считают эмбеддинги локально без обращения к внешнему API и неплохо работают с русским языком. Минус - их нужно где-то запускать, и на CPU без GPU расчёт эмбеддингов для большой базы займёт часы вместо минут.
Подойдёт ли Qdrant для маленького бота на 50 вопросов или это избыточно?
Для 50 фиксированных вопросов векторная база действительно избыточна - проще держать словарь вопрос-ответ или простой fuzzy-поиск. Qdrant оправдан, когда база растёт, вопросы формулируются по-разному и нужен поиск по смыслу, а не по точному совпадению.
Сколько стоит подключить Qdrant к готовому чат-боту под ключ?
Зависит от объёма базы знаний и того, есть ли уже готовый бот. Чат-бот с базой знаний на RAG с нуля, включая настройку Qdrant, чанкинг и загрузку данных, у меня стоит от 50 000 ₽ - цена растёт, если нужна интеграция с CRM, эквайрингом или несколькими источниками данных.