TL;DR: Прежде чем ставить отдельную векторную БД, проверьте, не хватает ли вам pgvector в существующем PostgreSQL или FAISS/hnswlib в памяти при перестроении индекса по расписанию. Если специализированный движок всё же нужен: Chroma — для прототипов и embedded-сценариев, Qdrant — для продакшена, где важны фильтрация по метаданным и контроль над данными, Pinecone — когда вы сознательно покупаете отсутствие DevOps и готовы платить за managed-сервис.
Проект начинается одинаково: появляется RAG или семантический поиск, и кто-то говорит «нам нужна векторная база». Дальше обычно ставят то, что чаще встречается в туториалах. Это плохой способ принимать решение: у каждого варианта есть чёткие границы применимости, и ошибка выбора проявляется месяцы спустя — в стоимости инфраструктуры, в невозможности отфильтровать выдачу так, как нужно бизнесу, или в лишнем компоненте, который кто-то должен администрировать. Разберём выбор по порядку, начиная с вопроса, который часто вообще не задают.
Нужна ли вообще отдельная векторная БД
Честный ответ: не всегда. Специализированный движок — это отдельный сервис, который надо разворачивать, мониторить, бэкапить и обновлять. Есть два сценария, где без него можно обойтись.
Сценарий 1: pgvector в существующем PostgreSQL
Если у вас уже есть PostgreSQL и эмбеддингов немного (порядок сотен тысяч — единиц миллионов), расширение pgvector закрывает большинство задач. Оно поддерживает два ANN-индекса:
- HNSW — более точный и быстрый на поиске, но требует больше памяти и дольше строится.
- IVFFlat — строится быстрее, легче, но требует предварительного обучения индекса (lists) и уступает HNSW по recall.
Ограничения, о которых стоит знать до принятия решения: тип vector индексируется до 2000 измерений, тип halfvec (half-precision) — до 4000. Для большинства open-source эмбеддинг-моделей (768–1536 измерений) это не проблема. Фильтрация по метаданным выполняется обычными SQL-условиями — но ANN-поиск и фильтр комбинируются не всегда оптимально, при сильно селективных фильтрах recall проседает, и это приходится компенсировать настройками.
Главный аргумент за pgvector — не скорость, а отсутствие нового компонента: векторы живут рядом с данными, транзакции и бэкапы уже решены, джойны с бизнес-таблицами бесплатны.
Сценарий 2: FAISS или hnswlib в памяти
Если корпус документов статичен или меняется редко, а чтений много, вариант «FAISS/hnswlib в памяти процесса + перестроение индекса по расписанию» часто рациональнее любой БД. Нет сетевого хопа на поиске, нет сервиса, который надо поддерживать, индекс — это файл, который версионируется и выкатывается вместе с релизом. Типовые грабли: индекс нельзя обновлять инкрементально без пересборки (у FAISS есть IndexIVF с добавлением, но удаление записей всё равно неудобное), и при нескольких репликах сервиса каждая держит индекс в памяти. Подробнее про устройство таких контуров памяти я писал в статье про память AI-систем.
Когда отдельный движок оправдан
Специализированная векторная БД оправдана, когда выполняется хотя бы пара условий:
- Данные пишутся и обновляются часто (реалтайм-индексация новых документов).
- Запросы идут от нескольких независимых сервисов — нужен сетевой доступ с аутентификацией.
- Поиск должен комбинировать близость векторов со сложной фильтрацией по метаданным.
- Объём не помещается в память одного узла или требуется репликация.
Если это ваш случай — дальше выбираем между тремя вариантами.
Qdrant: контроль и фильтрация
Qdrant — open-source векторная БД, лицензия Apache 2.0, доступна в self-hosted варианте и как Qdrant Cloud. Вокруг неё удобно строить полноценный RAG-пайплайн для корпоративных документов, потому что фильтры и индексы настраиваются явно.
Ключевые возможности
- Индекс HNSW с настраиваемыми параметрами графа (
m,ef_construct), опциональное сжатие векторов: scalar quantization и product quantization плюс поддержкаfloat16. На больших коллекциях квантизация даёт заметную экономию RAM при приемлемой потере recall — проверяйте на своих данных, а не на чужих бенчмарках. - Фильтрация по payload: условия
must,should,must_not, диапазоны, гео, вложенные объекты, полнотекстовый индекс по текстовым полям. Для Qdrant фильтр — первоклассная часть запроса, а не постобработка. - Гибридный и разреженный поиск: поддержка sparse-векторов (BM25-подобные представления) и гибридных запросов со слиянием результатов.
- Кластерность: шардирование и репликация коллекций, снапшоты для бэкапов.
Когда выбирать Qdrant
- Данные и инфраструктура должны оставаться под вашим контролем (on-prem, свой VPC).
- Запросы активно фильтруются по метаданным — например, по тенанту, языку, дате документа.
- Нужна возможность перейти из self-hosted в облако без смены API.
Пример (актуальный qdrant-client, Python)
from qdrant_client import QdrantClient
from qdrant_client.models import (
Distance, VectorParams, PointStruct,
Filter, FieldCondition, MatchValue,
)
client = QdrantClient(url="http://localhost:6333")
# В облаке: QdrantClient(url="https://<cluster>.qdrant.io", api_key="...")
COLLECTION = "docs"
if not client.collection_exists(COLLECTION):
client.create_collection(
collection_name=COLLECTION,
vectors_config=VectorParams(size=1024, distance=Distance.COSINE),
)
client.upsert(
collection_name=COLLECTION,
points=[
PointStruct(
id=1,
vector=[0.1, 0.2, 0.3], # ваш эмбеддинг
payload={"text": "Политика возвратов", "category": "policy", "lang": "ru"},
),
],
)
result = client.query_points(
collection_name=COLLECTION,
query=[0.15, 0.25, 0.35], # эмбеддинг запроса
limit=3,
query_filter=Filter(
must=[FieldCondition(key="lang", match=MatchValue(value="ru"))]
),
)
for point in result.points:
print(point.score, point.payload["text"])
Обратите внимание: поиск в актуальном клиенте — это query_points, а не старый search. Старый метод оставлен для обратной совместимости, новый код пишите на query_points.
Chroma: минимальный порог входа
Chroma — open-source векторная БД (Apache 2.0), изначально ориентированная на прототипирование RAG прямо из Python-кода. В версиях 1.x ядро переписано на Rust, помимо embedded-режима есть серверный (chroma run) и управляемый Chroma Cloud, так что «Chroma — это только in-process на Python» уже неактуальная характеристика. Есть и JavaScript-клиент.
Ключевые возможности
- Быстрый старт: одна строка — и у вас персистентная локальная БД в каталоге проекта.
- Embedded и клиент-сервер: можно начать in-process, а затем поднять тот же код против
chroma run --path ./chroma_dbбез переписывания логики. - Индекс HNSW с выбором метрики расстояния через метаданные коллекции (
hnsw:space:cosine,l2,ip). - Фильтрация по метаданным операторами
$eq,$ne,$gt,$in,$and,$or— для прототипа достаточно, хотя выразительность уступает Qdrant. - Встроенные эмбеддинг-функции: коллекция умеет сама вызывать провайдера эмбеддингов, если передать конфигурацию при создании.
Ограничения, которые стоит знать
Chroma сознательно не даёт низкоуровневой настройки HNSW (m, ef_construct), нет родного шардирования коллекции на несколько узлов в open-source. Для нагруженных продакшен-систем с десятками миллионов векторов это потолок — либо вертикальное масштабирование одного узла, либо Chroma Cloud.
Когда выбирать Chroma
- Прототипы, MVP, демо — туда, где скорость разработки важнее тюнинга.
- Embedded-сценарии: десктопные приложения, CLI-утилиты, тесты.
- Команда без DevOps, которой пока хватает одного узла. Кстати, про бюджетную сторону таких решений — в разборе реальных бюджетов на AI-MVP.
Пример (актуальный chromadb, Python)
import chromadb
# Embedded + персистентность на диске
client = chromadb.PersistentClient(path="./chroma_db")
# Против сервера: chromadb.HttpClient(host="localhost", port=8000)
collection = client.get_or_create_collection(
name="docs",
metadata={"hnsw:space": "cosine"},
)
collection.add(
ids=["doc1", "doc2"],
embeddings=[[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]],
documents=["Политика возвратов", "Регламент отпусков"],
metadatas=[{"category": "policy"}, {"category": "hr"}],
)
results = collection.query(
query_embeddings=[[0.15, 0.25, 0.35]],
n_results=2,
where={"category": {"$eq": "hr"}},
)
print(results["ids"], results["distances"])
Pinecone: покупка отсутствия DevOps
Pinecone — закрытый, полностью управляемый облачный сервис. Кода и языка реализации у него нет в публичном доступе; вы работаете только с API. Всё администрирование — индексы, реплики, обновления, бэкапы — на стороне провайдера.
Ключевые возможности
- Serverless-индексы: хранение и вычисления разделены, данные лежат в объектном хранилище провайдера, оплата зависит от потребления. Подовые (pod-based) индексы остаются как legacy-опция; для новых проектов берите serverless-архитектуру.
- Автомасштабирование под нагрузку и рост коллекции без ручных операций.
- Фильтрация по метаданным с операторами
$eq,$in,$ltи т.д. Напоминание: из-за архитектуры индекса сильно селективные фильтры могут влиять на recall — это ограничение любого ANN с post-filtering, не специфика Pinecone. - Namespace для логического разделения данных внутри одного индекса (удобно для мультитенантности).
- Интеграции с основными LLM-фреймворками. Если выбираете между ними, взгляните на сравнение LangChain vs LlamaIndex.
Ограничения
Производительность и поведение индекса — чёрный ящик. Низкоуровневого тюнинга ANN нет. Vendor lock-in присутствует: миграция означает выгрузку векторов и метаданных целиком.
Когда выбирать Pinecone
- Требуется вывести в продакшен систему с жёсткими требованиями к доступности, а DevOps-компетенции в команде нет и нанимать её не планируется.
- Нагрузка непредсказуема, и автомасштабирование важнее контроля над тюнингом индекса.
- Регуляторные требования допускают хранение векторов и метаданных у внешнего провайдера.
Пример (актуальный pinecone SDK, Python)
from pinecone import Pinecone, ServerlessSpec
pc = Pinecone(api_key="YOUR_API_KEY")
INDEX = "docs"
DIM = 1024
if not pc.has_index(INDEX):
pc.create_index(
name=INDEX,
dimension=DIM,
metric="cosine",
spec=ServerlessSpec(cloud="aws", region="us-east-1"),
)
index = pc.Index(INDEX)
index.upsert(
vectors=[
{"id": "doc1", "values": [0.1, 0.2, 0.3],
"metadata": {"category": "policy", "lang": "ru"}},
],
namespace="kb",
)
results = index.query(
vector=[0.15, 0.25, 0.35],
top_k=3,
namespace="kb",
filter={"lang": {"$eq": "ru"}},
include_metadata=True,
)
for match in results["matches"]:
print(match["score"], match["metadata"])
Старый стиль pinecone.init() и pinecone.Index(...) как глобальные функции давно удалён из SDK — актуальный интерфейс только через объект Pinecone, как в примере выше.
Сравнительная таблица
| Критерий | Qdrant | Chroma | Pinecone |
|---|---|---|---|
| Лицензия | Apache 2.0 | Apache 2.0 | Проприетарный сервис |
| Форма поставки | Self-hosted бинарь/Docker, Qdrant Cloud | Embedded-библиотека, сервер (chroma run), Chroma Cloud | Только managed cloud |
| Индекс | HNSW (настраиваемый m, ef_construct), sparse-векторы | HNSW (метрика через metadata коллекции) | Управляемый провайдером, детали закрыты |
| Фильтрация по метаданным | must/should/must_not, диапазоны, гео, полнотекст | $eq, $in, $gt, $and, $or | $eq, $in, $lt и др., плюс namespace |
| Квантизация | Scalar, product, float16 | Нет | Управляется провайдером |
| Что администрируете | Узлы, диски, снапшоты, обновления (self-hosted) | Процесс сервера и диск; в embedded — ничего | Ничего |
| Модель оплаты | Бесплатно self-hosted; облако — по ресурсам | Бесплатно open-source; облако — по потреблению | По потреблению (serverless) |
Моя рекомендация
Считайте сверху вниз и остановитесь на первом подходящем уровне:
- Уже есть PostgreSQL и эмбеддингов до единиц миллионов? Ставьте pgvector с HNSW. Не приносите новый сервис, пока его отсутствие не стало измеримой проблемой.
- Корпус статичен, чтений много? FAISS или hnswlib в памяти с перестроением индекса по расписанию. Дешевле и надёжнее любой БД.
- Прототип или embedded-приложение? Chroma. Переход на серверный режим — вопрос смены клиента, а не архитектуры.
- Продакшен под вашим контролем, богатая фильтрация, частые записи? Qdrant. Это мой вариант по умолчанию для корпоративных RAG: предсказуемое поведение, честная настройка индекса, отсутствие vendor lock-in.
- Жёсткий SLA, нет и не будет DevOps? Pinecone. Вы платите деньгами за то, чтобы не платить временем и риском эксплуатации.
Ошибка, которую я встречаю чаще всего, — выбор Pinecone «потому что так в туториале» у проекта, где данные нельзя отдавать внешнему провайдеру, или выбор Qdrant-кластера у команды из двух человек, которые потом полгода страдают с его эксплуатацией. Оба решения обратимы, но миграция между векторными БД — это всегда полная переиндексация, закладывайте её стоимость заранее.
FAQ
Можно ли использовать несколько векторных БД в одном проекте?
Можно, но внутри одного кейса это редко оправдано. Нормальная практика — разные инструменты на разных стадиях: Chroma локально у разработчиков, Qdrant или pgvector в продакшене. Держать два движка для одной и той же задачи — двойная стоимость синхронизации и расхождение поведения индексов.
Что быстрее: Qdrant, Chroma или Pinecone?
Универсального ответа нет: latency зависит от объёма коллекции, параметров HNSW, селективности фильтров и железа. Честный способ выбрать — поднять пилот на своих данных и своих запросах и измерить. Чужие бенчмарки используйте только для отсева явных неподходящих вариантов, а не для финального решения.
Qdrant или pgvector?
pgvector — если векторы по объёму и QPS укладываются в ваш PostgreSQL и фильтрация простая. Qdrant — когда появляются сложные условия по метаданным, частые записи, потребность в sparse/гибридном поиске или кластерности. Граница проходит примерно там, где ANN-запросы начинают конкурировать с транзакционной нагрузкой за ресурсы одной БД.
Нужна ли векторная БД, если я просто вызываю API большой LLM?
Да, если модель должна отвечать на основе ваших документов, которых нет в её обучающей выборке. Это и есть RAG: эмбеддинг запроса, поиск ближайших чанков, подстановка их в контекст. Без векторного хранилища ретривер не работает, а контекстные окна всё равно ограничены.
Что хранить в метаданных?
Минимум — исходный текст чанка (или ссылку на него), ID документа и поля, по которым будете фильтровать: тенант, язык, дату, категорию. Большие бинарные данные и полные документы держите в основном хранилище, в векторной БД оставляйте ссылки — так индексы легче, а снапшоты быстрее.
Не уверены, какое хранилище выживет под вашей нагрузкой и требованиями к данным? Напишите мне — разберём архитектуру конкретно под ваш проект.