Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Векторные базы данных
vector_databases

Векторные базы данных

Обзор векторных баз данных: Chroma, FAISS, Qdrant — хранение и поиск векторов

Векторные базы данных

Embeddings бесполезны, если вы не можете быстро искать среди миллионов векторов.

#Зачем нужна векторная база данных

В предыдущей теме мы научились превращать текст в векторы. Теперь нужно понять, как их хранить и искать. Можно ли хранить embeddings в обычном списке и перебирать все векторы при поиске? Для 10 документов — да. Для 100 000 — нет: линейный поиск будет слишком медленным.

Векторная база данных — это специализированное хранилище, оптимизированное для быстрого поиска ближайших векторов (nearest neighbor search). Она использует индексные структуры (HNSW, IVF, Flat), чтобы находить похожие векторы за миллисекунды даже среди миллионов записей.

В RAG векторная БД — это «память» системы: здесь хранятся все чанки документов в виде embeddings.

#ChromaDB: простая встраиваемая база

ChromaDB — самый простой вариант для начала. Это встраиваемая (embedded) база данных — она работает внутри вашего Python-процесса, не требует отдельного сервера.

#Установка

pip install chromadb

#Создание коллекции и добавление документов

Коллекция в Chroma — это аналог таблицы в реляционной БД. В одну коллекцию вы добавляете документы с их embeddings.

import chromadb from chromadb.utils import embedding_functions # Создаём клиент — документы сохраняются на диск client = chromadb.PersistentClient(path="./chroma_db") # Создаём embedding-функцию embedder = embedding_functions.SentenceTransformerEmbeddingFunction( model_name="intfloat/multilingual-e5-small" ) # Создаём или получаем коллекцию collection = client.get_or_create_collection( name="hr_documents", embedding_function=embedder, metadata={"hnsw:space": "cosine"} # Метрика сравнения ) # Добавляем документы collection.add( documents=[ "Отпуск оформляется через HR-портал за 2 недели", "Больничный лист нужно отнести в бухгалтерию", "Удалённая работа — до 3 дней в неделю" ], ids=["hr_001", "hr_002", "hr_003"], metadatas=[ {"category": "отпуск", "department": "HR"}, {"category": "больничный", "department": "бухгалтерия"}, {"category": "удалёнка", "department": "HR"} ] )

Каждый документ должен иметь уникальный id. Поле metadatas — опциональное, позволяет хранить дополнительную информацию (категорию, дату, автора), которую потом можно использовать для фильтрации.

#Поиск документов

results = collection.query( query_texts=["Как получить отпуск?"], n_results=2, where={"department": "HR"} # Фильтр по метаданным ) for doc, metadata, distance in zip( results["documents"][0], results["metadatas"][0], results["distances"][0] ): print(f"Документ: {doc}") print(f"Метаданные: {metadata}") print(f"Расстояние: {distance:.4f}") print("---")

ChromaDB автоматически создаёт embedding запроса через embedding_function и ищет ближайшие документы. Поле distances содержит расстояние до каждого найденного документа — чем меньше, тем лучше.

#Фильтрация по метаданным

Chroma поддерживает фильтрацию при поиске:

# Только документы категории "отпуск" results = collection.query( query_texts=["Когда можно уйти в отпуск?"], n_results=1, where={"category": "отпуск"} ) # Комбинированный фильтр results = collection.query( query_texts=["Документы HR"], n_results=5, where={ "$and": [ {"department": "HR"}, {"category": {"$ne": "удалёнка"}} ] } )

Операторы: $eq (равно), $ne (не равно), $gt (больше), $lt (меньше), $and, $or.

#FAISS: быстрая библиотека от Facebook

FAISS (Facebook AI Similarity Search) — библиотека от Meta для эффективного поиска векторов. В отличие от Chroma, это не полноценная БД с метаданными, а специализированный индекс.

#Установка

pip install faiss-cpu # или для GPU: # pip install faiss-gpu

#Типы индексов FAISS

IndexFlatL2 — простой плоский индекс с поиском по евклидову расстоянию. Точный (находит абсолютный ближайший), но медленный на больших данных:

import faiss import numpy as np # Размерность должна совпадать с embedding-моделью dimension = 384 # Создаём плоский индекс (евклидово расстояние) index = faiss.IndexFlatL2(dimension) # Добавляем векторы embeddings = np.random.random((100, dimension)).astype("float32") index.add(embeddings) print(f"Количество векторов в индексе: {index.ntotal}")

IndexFlatIP — поиск по скалярному произведению (inner product). Подходит для нормализованных векторов (эквивалентно косинусному сходству):

# Индекс по скалярному произведению index_ip = faiss.IndexFlatIP(dimension) # Нормализуем векторы (обязательно для IP) faiss.normalize_L2(embeddings) index_ip.add(embeddings)

IndexIVFFlat — индекс с инвертированным файлом (Inverted File with Flat storage). Быстрее Flat на больших данных, но приближённый поиск (может пропустить ближайший):

# IVF-индекс n_clusters = 10 # Количество кластеров (квантизация) quantizer = faiss.IndexFlatL2(dimension) index_ivf = faiss.IndexIVFFlat(quantizer, dimension, n_clusters) # IVF нужно обучить на данных перед добавлением index_ivf.train(embeddings) index_ivf.add(embeddings) # Для поиска нужно задать nprobe (сколько кластеров проверять) index_ivf.nprobe = 3 # Поиск query = np.random.random((1, dimension)).astype("float32") distances, indices = index_ivf.search(query, k=5)

Больше nprobe — точнее, но медленнее. Меньше — быстрее, но менее точно.

#Поиск в FAISS

# Поиск k ближайших k = 3 distances, indices = index.search(query, k) print(f"Индексы ближайших: {indices[0]}") print(f"Расстояния: {distances[0]}")

FAISS возвращает индексы векторов в массиве — вам нужно самостоятельно связать их с оригинальными документами (например, хранить список документов параллельно).

#Сохранение и загрузка

# Сохраняем индекс на диск faiss.write_index(index, "my_index.faiss") # Загружаем loaded_index = faiss.read_index("my_index.faiss")

#Qdrant: облачная векторная база

Qdrant — более мощная система, поддерживает как локальный режим, так и облачный. Удобна для продакшена.

#Установка

pip install qdrant-client

#Локальный режим

from qdrant_client import QdrantClient from qdrant_client.models import Distance, VectorParams, PointStruct # Локальный клиент (in-memory) client = QdrantClient(":memory:") # Создаём коллекцию client.create_collection( collection_name="documents", vectors_config=VectorParams(size=384, distance=Distance.COSINE) ) # Добавляем точки points = [ PointStruct( id=1, vector=[0.1] * 384, # Ваш embedding payload={"text": "Отпуск через HR-портал", "category": "HR"} ), PointStruct( id=2, vector=[0.2] * 384, payload={"text": "Больничный в бухгалтерию", "category": "finance"} ) ] client.upsert(collection_name="documents", points=points)

#Поиск с фильтрацией

from qdrant_client.models import Filter, FieldCondition, MatchValue # Поиск с фильтром results = client.search( collection_name="documents", query_vector=[0.15] * 384, # Embedding вопроса query_filter=Filter( must=[FieldCondition(key="category", match=MatchValue(value="HR"))] ), limit=2 ) for hit in results: print(f"ID: {hit.id}, Score: {hit.score}, Payload: {hit.payload}")

score в Qdrant — это схожесть (чем больше, тем лучше), в отличие от Chroma/FAISS, где возвращается расстояние (чем меньше, тем лучше).

#Сравнение векторных баз данных

ХарактеристикаChromaDBFAISSQdrant
Сложность настройкиМинимальнаяСредняяСредняя
Встроенные embeddingsДаНетНет
Метаданные и фильтрацияДаНет (только ID)Да
Облачный режимНет (только локально)НетДа
МасштабируемостьСредняя (до ~1M)Высокая (до ~1B)Высокая
Для прототипаОтличноХорошоХорошо
Для продакшенаСреднеСреднеОтлично

#Когда что выбирать

ChromaDB — лучший выбор для прототипа и небольших проектов. Прост в установке, есть встроенная embedding-функция, удобные метаданные. Если у вас до 100 000 документов и не нужен облачный режим — Chroma идеален.

FAISS — когда нужна максимальная скорость поиска на очень больших объёмах (миллионы векторов). Но нужно самостоятельно управлять метаданными и embedding-логикой.

Qdrant — для продакшен-систем с облачным развёртыванием. Поддержка фильтрации, масштабирования, мониторинга. Если ваш RAG будет работать с тысячами пользователей — Qdrant даст нужную инфраструктуру.

#Практический пример: полный цикл с ChromaDB

Вот полный пример индексации и поиска с использованием ChromaDB:

import chromadb from chromadb.utils import embedding_functions # 1. Инициализация client = chromadb.PersistentClient(path="./rag_store") embedder = embedding_functions.SentenceTransformerEmbeddingFunction( model_name="intfloat/multilingual-e5-small" ) collection = client.get_or_create_collection( name="company_docs", embedding_function=embedder ) # 2. Индексация документов documents = [ "Политика компании по удалённой работе обновлена в январе 2026", "Процедура оформления отпуска: заявление за 2 недели через HR-портал", "Инструкция по охране труда: носить каску на производстве обязательно", "Порядок сдачи больничных: лист нетрудоспособности в бухгалтерию за 3 дня" ] collection.add( documents=documents, ids=[f"doc_{i}" for i in range(len(documents))] ) # 3. Поиск query = "Что делать если я заболел?" results = collection.query(query_texts=[query], n_results=2) for doc, dist in zip(results["documents"][0], results["distances"][0]): print(f"[dist={dist:.4f}] {doc}")

Далее: Стратегии разделения текста