Суть
Превращение корпуса документов в векторы — самая долгая операция конвейера RAG: даже индекс для документа в 3 строки строится ~3.5 секунды на неслабом ноутбуке. Делать это каждый запуск нелогично — индекс надо персистить.
Зачем это нужно
Логика разделения нагрузки: поднять модель эмбеддингов на мощном узле (например, spark-кластере), загрузить корпус на 1000 страниц, преобразовать в векторное представление один раз → сохранить → потом инференс (поиск) гонять хоть на ноутбуке с CPU, без GPU.
Как работает
- Chroma: параметр
persist_directoryуказывает, куда сохранить базу на диск; потом она поднимается из этой папки без переиндексации. - FAISS: объект индекса сохраняется на диск и подгружается обратно (save/load).
- Embedding-модель тоже кэшируется на диск (~100-150 МБ) — чтобы не перекачивать каждый раз; она «несёт на себе» преобразование запроса в то же пространство, в котором построен индекс.
- Критическое условие совместимости: индекс и запросы должны использовать одну и ту же модель эмбеддингов (Embeddings) — иначе пространства не совпадут и поиск сломается.
- Retrieve как функция:
retriever = f(vector_store, query)—similarity_searchсам переносит короткий запрос в пространство эмбеддингов и достаёт похожие чанки. - Для прототипа и переноса между компьютерами проще всего FAISS и Chroma (in-memory + persist); Qdrant требует развёртывания как сервис/облако (см. Vector Databases).
- Model-lock: индекс «привязан» к модели эмбеддингов — при смене модели старые векторы геометрически несовместимы с новыми запросами → нужна полная переиндексация корпуса. Выбор модели = как миграция схемы БД: дорого откатывать.
- Zero-downtime миграция (alias-based): строим «теневой» индекс новой моделью параллельно → валидируем на бенчмарк-наборе → атомарно переключаем alias → старый держим для отката. Запрос никогда не видит частичный индекс.
- Инкрементальное обновление vs пересборка: чтобы не переэмбеддить всё, используют content-hashing (хеш чанка совпал → пропускаем) и
upsertс полемvalid_from(MVCC-стиль: стейджим контент до публикации). Полная пересборка нужна только при смене модели. - Гигиена метаданных: в каждом чанке держим
doc_id, заголовок секции, timestamp, версию модели эмбеддингов (детект дрейфа) и content hash; для удаления — Document Registry (doc_id → chunk_ids), т.к. векторные БД не делают нативный update (найти chunk_ids → удалить → вставить новые).
Пример
FAISS: построить индекс один раз → сохранить на диск → поднять без переиндексации. При загрузке передаётся та же модель эмбеддингов (иначе пространства не совпадут).
vs_faiss = FAISS.from_documents(chunks, embedding=embeddings)
vs_faiss.save_local("./faiss_index") # тяжёлая offline-операция — один раз
store = FAISS.load_local(
"./faiss_index",
embeddings, # та же модель эмбеддингов!
allow_dangerous_deserialization=True, # индекс хранится через pickle
)
store.similarity_search("отпуск", k=5) # лёгкий online-инференс, хоть на CPU
Связано с
- Vector Databases — какие БД умеют persist (Chroma, FAISS) vs требуют сервиса (Qdrant)
- RAG — индексация (offline) vs поиск (online) в конвейере
- Embeddings — совместимость индекса и запроса = одна модель
- Local LLM Deployment — построить индекс в облаке/Colab, перенести на локаль