← Интерфейсы и исследования

Векторные базы для нарративного конвейера: нужны ли нам Milvus/Pinecone (2026-08-15)

Повод: в вакансии AI Tech Lead у DramaBox (dramabox-ai-roles.md) прямым текстом — «RAG и векторные БД (Milvus/Pinecone), чтобы удерживать консистентность характера персонажа и посеянные сюжетные крючки». Вопрос: копировать ли этот кусок архитектуры.

Короткий ответ: нет, и не потому что дорого, а потому что у нас другая задача. Ниже — цифры.

1. Наш масштаб в векторах

Типовой роман — около 100 000 слов; при нарезке на чанки по 300 слов это ~333 вектора на книгу.

КаталогВекторов текста+ карточки персонажейИтого
15 книг (MVP)~5 000~600~5,6 тыс.
40 книг (год)~13 300~1 600~15 тыс.
100 книг~33 300~4 000~37 тыс.

Для сравнения, пороги применимости: специализированные векторные БД (Milvus, Pinecone) проектировались под десятки миллионов векторов при высоком QPS. Мы на три порядка ниже.

Измерено локально (15.08.2026): полный перебор 15 000 векторов по 768 измерений на чистом Python без numpy и без всякой базы — 1,35 секунды на запрос, 46 МБ памяти. С numpy тот же перебор — 10–20 мс. То есть на нашем каталоге вопрос индексации технически не стоит вообще.

2. Главное: у нас другая модель консистентности

DramaBox достаёт контекст персонажа из векторной базы на лету — им приходится, потому что сценарии генерируются потоком, канон не зафиксирован и объём растёт бесконечно.

У нас канон есть и он конечный. Конвейер заранее производит структурированные артефакты: карточки персон, кастинг голосов, портреты, верифицированные по строкам цитаты (см. books-to-short-video.md §5). Библия персонажей одной книги тривиально помещается в контекст модели целиком — её незачем «искать», её нужно подставлять.

Retrieval решает задачу «корпус не влезает в контекст». У нас влезает. Более того, поиск по похожести отвечает на вопрос «что похоже», а нарративу нужен ответ «что случилось раньше и поэтому» — это уже зафиксировано в storygraph-tools.md, где графовые RAG (GraphRAG/LightRAG) отвергнуты по той же причине: их графы атемпоральны.

Важно: первая версия этого разбора называла их подход «более гибким на бесконечном потоке». Измерения это опровергают — см. §8. Векторный RAG по прозе проигрывает структурированному состоянию на нарративе с большим отрывом.

3. Где вектора нам всё-таки понадобятся

Три сценария, все — не про консистентность:

  1. 1. Инструмент сценариста: «не использовали ли мы уже такую сцену/поворот» по всему каталогу эпизодов.
  2. 2. Читательская фича «чат по книге» — если дойдём до неё.
  3. 3. Поиск по библиотеке для родителя/ребёнка: «книги про дружбу и предательство».

Во всех трёх масштаб тот же — десятки тысяч векторов.

4. Что реально брать при нашем масштабе

ИнструментСостояние на 08.2026Вердикт для нас
numpy brute force—Точка старта. 15 тыс. векторов = 10–20 мс, ноль зависимостей и ноль эксплуатации
sqlite-vecv0.1.9 (03.2026), ANN-индексы только в alpha v0.1.10; brute force <75 мс на 100k×384Кандидат №1, когда понадобится персистентность. Одна библиотека, один файл, ноль сервисов. Риск — не технологический, а bus factor: один фрилансер-мейнтейнер, 13-месячная пауза уже была в истории проекта, три месяца тишины, внимание автора на другом проекте. Смягчает то, что это чистый C без зависимостей под MIT/Apache — вендорится при необходимости
pgvectorv0.8.6 (29.07.2026); все релизы 2026 года — исправления повреждения HNSW при vacuum и параллельных сборкахБрать, если в продукте и так появится Postgres. Наш масштаб — глубоко внутри его комфортной зоны; независимый вывод исследования: «20k–500k векторов, команда 2–3 человека — просто работает, выделенную векторную БД даже не рассматривать». Важно: ставить ≥0.8.4 (в managed сейчас Supabase 0.8.0, Aurora 0.8.1, RDS 0.8.2, и только Neon на PG18 — 0.8.6)
FAISSv1.15.0 (03.08.2026), девять релизов за год, Meta/FAIRБыстрейший на своём уровне (1M×128 за 10 мс), но это библиотека, а не база: нет персистентности кроме «записать весь индекс файлом», нет CRUD, нет фильтрации по метаданным. Для батч-задач
Chromav1.5.9; embedded = SQLite + HNSW в памятиНе брать. Не process-safe (их собственная документация), потолок ~1 млн векторов, удаления не освобождают память, повреждение индекса при резком завершении процесса. Cloud вышел в GA (08.2025) с честно опубликованными тарифами, но у компании только seed $18M от 2023 и падающая доля упоминаний
LanceDBPython 0.37.1 (10.08.2026); формат Lance выделен в независимый проект (lance.org) с governance по образцу ASF/CNCFЕдинственный, кто интересен не ради поиска. Мультимодальность (блобы картинок/видео/аудио рядом с векторами) и версионирование датасетов с time-travel; $30M Series A, в проде у Midjourney, Netflix, ByteDance. Но: Cloud до сих пор в beta, публичных тарифов нет вообще — страница цен это контактная форма (проверено 15.08.2026), компакцию обслуживаешь сам, холодный старт с S3 500–1000 мс без их NVMe-кэша
Milvus / Pinecone—Не брать. Спроектированы под десятки миллионов векторов; на нашем каталоге это эксплуатация ради эксплуатации
sqlite-vssпоследний релиз 08.2023, автор сам рекомендует sqlite-vecМёртв
DuckDB VSSдва года «экспериментальный»; их документация предупреждает о потере данных при сбоеНе брать

Три цифры pgvector, которые стоит запомнить

И главная ловушка не масштаб, а фильтрация: pgvector применяет условие WHERE уже после сканирования индекса, поэтому при выборке 10% строк с дефолтным ef_search=40 в среднем найдётся всего 4 строки. Лечится частичными индексами или hnsw.iterative_scan.

5. Отдельно про LanceDB: единственный неочевидный кандидат

Аргумент в его пользу не «векторный поиск», а то, что наш конвейер производит медиа: портреты персонажей, сэмплы голосов, кадры, эпизоды. LanceDB хранит блобы рядом с векторами и версионирует датасет целиком (каждая запись = версия, откат, ветвление).

Контраргумент: эпизоды и портреты — это файлы, которые проигрывают, а не датасет, который запрашивают. Файлы + S3 + манифест в JSON решают ту же задачу проще и без 0.x-API с ломающими изменениями. Версионирование сезона у нас и так живёт в провенансе конвейера.

Вывод: не сейчас. LanceDB станет уместен, если появится задача обучать на своём материале (LoRA персонажей на своих кадрах) — вот там формат для тренировочных данных с версиями оправдан.

6. Решение

  1. 1. Консистентность персонажей делаем артефактами, не поиском. Это не компромисс, а более сильная позиция: детерминированно, воспроизводимо, проверяемо grep-ом.
  2. 2. Когда понадобится семантический поиск — начинаем с numpy brute force. На 15 тыс. векторов это 10–20 мс.
  3. 3. Персистентность — sqlite-vec, с открытыми глазами на bus factor; при появлении Postgres в стеке — pgvector.
  4. 4. Milvus, Pinecone, Chroma — не наш класс задач. Первые два переразмерены, третий небезопасен в многопроцессном режиме.
  5. 5. LanceDB — держать в поле зрения на случай обучения своих моделей.

7. А если вектора нужны не для консистентности, а чтобы писать сценарий?

Вопрос правильный — он смещает фокус со «сверить персонажа» на «достать нужный кусок книги в момент письма». Ответ: для письма по книге у нас уже есть механизм лучше векторного поиска — структурный отбор по позиции (loc).

Почему структурный отбор строго сильнее семантического

Стадия storygraph (чертёж R², ICLR 2025) строит причинный граф событий: узлы с описанием, главой и позицией в тексте, участниками, пометкой ядро/спутник. Эпизоды нарезаются обходом графа по ядрам, и в промпт письма подмешиваются исходные фрагменты по loc.

Разница принципиальная:

Векторный retrievalОтбор по loc (наш)
Отвечает на вопрос«что похоже на то, что я пишу»«что в книге происходит в этой точке причинной цепи»
Отборпо близости эмбеддинговпо структуре сюжета
Проверяемостьникакойgrep по исходнику
Ошибкатихо подсунет не тот кусокневозможна: позиция задана графом

Для сценария нужен именно второй вопрос. Похожесть тут даже вредна: она подтянет другую сцену с теми же словами (ещё одна ссора, ещё одно море) и спровоцирует смешение эпизодов — ровно та болезнь книжных саммари, которую FABLES называет главной: искажение отношений персонажей.

Плюс уже зафиксированный в storygraph-tools.md приём из 2502.00977: при письме сцен подмешивать исходный текст по loc, а не собственный пересказ — рекурсивное слияние пересказов множит галлюцинации. Вектора вернут пересказ или чанк, оторванный от структуры; loc возвращает буквальный текст, который потом проверяется grep-ом.

Третий вариант, который часто забывают: кэш промпта

Книга статична, из неё пишется десять эпизодов. Значит, её не нужно ни искать, ни перечитывать заново — её нужно закэшировать один раз:

КнигаТокенов10 эпизодов без кэшаС кэшем
Остров сокровищ (70k слов)~95 тыс.945 тыс.~190 тыс.
Три мушкетёра (230k слов)~310 тыс.3,1 млн~620 тыс.
Война и мир (587k слов)~792 тыс.7,9 млн~1,6 млн

Для книг нормального объёма это закрывает вопрос целиком: вся книга в контексте, ноль ошибок отбора, стоимость впятеро ниже наивной. RAG здесь решал бы задачу, которой нет.

Граница проходит по объёму книги. Эффективная ёмкость 1M-контекста — 60–70% номинала, то есть потолок ~600–700 тыс. токенов. «Остров сокровищ» и «Три мушкетёра» помещаются целиком; «Война и мир» (792 тыс.) — уже нет. Но и там ответ не вектора, а двухпроходность, которая в конвейере и так заложена: первый проход скользящим окном строит граф, второй пишет эпизоды по нужным loc. Это тоже retrieval — просто структурный и проверяемый.

Где вектора при письме всё-таки полезны

Одно место, и оно не про книгу, а про наш собственный накопленный вывод: после сотни эпизодов вопрос «не использовали ли мы уже этот поворот, шутку, формулировку клиффхэнгера» становится настоящей задачей поиска — там нет ни структуры, ни позиций, только похожесть. Вот это честный кандидат на вектора, и масштаб тот же (десятки тысяч векторов → numpy или sqlite-vec).

Второй, более слабый: библиотека удачных приёмов как few-shot примеры. Но подобранный вручную набор из 10–20 примеров почти всегда бьёт выдачу поиска и, в отличие от неё, аудируем.

Итог

Для письма сценария: кэш книги + отбор по loc из графа. Вектора — на проверку повторов в своём же каталоге, когда он вырастет.

8. Что оказалось важнее вопроса про БД: как индустрия реально держит консистентность

Исследование дало ответ содержательнее, чем «нам это не нужно по масштабу». Индустрия и наука сошлись не на «RAG против длинного контекста», а на третьем: явное структурированное состояние мира, которое пишется после каждой сцены и подставляется детерминированно, плюс отдельный проход-критик на противоречия.

Векторный RAG на нарративе проигрывает — это измерено

Narrative World Model, типизированный темпорально-состоянийный граф, 12 публичных книг ≥20 глав + 5 продакшн-книг по 50 глав, все в бюджете ~3k токенов:

СистемаMulti-hop
Граф состояния (NWM)0.709
Graphiti/Zep0.582
GraphRAG0.355
Векторный RAG (BGE + BM25)0.291

Ещё три подтверждения с разных сторон:

Самая высокая отдача во всём исследовании: проход-критик

ConStory-Bench (ACL Findings 2026), 200 историй с 1000 намеренно внедрённых ошибок:

F1PrecisionRecall
Автокритик0.6780.8840.550
Люди-эксперты0.2810.6600.139

Автокритик нашёл 550 ошибок из 1000, эксперты-люди — 171. Пять находок, прямо применимых к нашему QC:

  1. 1. ошибки накапливаются линейно с длиной текста;
  2. 2. кластеризуются на 40–60% нарратива — измеренная «провисающая середина», туда и наводить критика;
  3. 3. доминируют фактические и хронологические;
  4. 4. сидят в местах с повышенной энтропией (+12–19%) — дешёвый способ навести;
  5. 5. стилевые ошибки почти не коррелируют с фактическими — это отдельный проход.

Крючки решаются кодификацией, а не поиском

Codified Foreshadowing-Payoff: модели регулярно оставляют «ружьё Чехова» невыстрелившим даже когда нужный контекст есть в окне. Решение — хранить триплеты «крючок → триггер → выстрел» как исполняемые предикаты. То есть на задачу, которую DramaBox решает через RAG, отраслевой ответ — структурный.

Длинный контекст: что реально известно

Fiction.liveBench — единственный бенчмарк именно нарративного понимания. На 120 тыс. токенов лидеры дают 94–100. Но: дешёвые открытые модели рушатся между 60 и 120 тыс., а публичных нарративных цифр выше 192 тыс. токенов не существует ни у кого — заявления «миллионный контекст закрывает художку» опереть не на что. Плюс Context Rot: перемешанный «стог сена» обыгрывал связный у всех 18 моделей — связный роман есть стог наихудшей формы.

Для нас практический вывод не меняется: книга в 100 тыс. токенов влезает целиком, retrieval внутри книги не нужен — нужен хороший отбор того, что подавать.

Чего не хватает нашим артефактам

Наш character-personas.json — 5,4 КБ (~1400 токенов) на книгу, при рекомендации для писательских библий 1 500–4 000 слов и пороге деградации около 4 000. Запас есть. По науке нам не хватает двух вещей:

  1. 1. интервалов валидности фактов («Билли Бонс жив до L1420») — би-темпоральность, как в Zep: противоречащее знание не удаляется, а помечается моментом устаревания;
  2. 2. visibility-тегов «кто что знает в какой момент» — в ReverieMem это даёт +34,6 п.п.

Для сезона из 10 эпизодов это десятки записей в JSON, а не база.

И отдельно, из EntityBench (140 реальных серий, 2 491 шот): единица идентичности — не персонаж, а пара «персонаж + состояние внешности» с версионированием и полем «причина изменения». Пайплайн с одной канонической картинкой на героя не выразит «в 12-й серии она надевает куртку охраны». 62% шотов там — «тест на память».

Про слоп — научное подтверждение нашего гейта

Narrative Flattening измеряет, как post-training (instruction-tuning, DPO/RLHF) сжимает тематическую, аффективную и стилистическую вариативность: уже тематический диапазон, сглаженный эмоциональный ландшафт, потеря узнаваемости стиля. Это и есть механизм, производящий «AI slop», и он не лечится ни библией персонажей, ни RAG — только внешним отбором и человеческим редакторским гейтом. Согласуется с находкой ConStory, что стилевые ошибки не коррелируют с фактическими: две разные проблемы, два разных прохода. Прямое научное подтверждение нашей установки «финальное ревью сезона — книжный критик».

Куда вложить усилия вместо векторной БД

  1. 1. Проход-критик на консистентность — наводить по позиции 40–60% эпизода и по энтропии, целить в фактические и хронологические ошибки, стиль выносить отдельно.
  2. 2. Достроить структурированное состояние — интервалы валидности фактов и visibility-теги «кто что знает».
  3. 3. Кодифицировать крючки триплетами вместо надежды, что модель сама выстрелит.

Оговорки и источники

Цифры перебора — собственный замер 15.08.2026 (чистый Python, 15 000×768). Прозрачность цен LanceDB и Chroma проверена лично: lancedb.com/pricing отдаёт контактную форму без тарифов, trychroma.com/pricing — полный прайс ($2.50/GiB запись, $0.33/GiB·мес хранение, $0.0075/TiB запросы, $0.09/GiB исходящий трафик). Версии пакетов сверены по PyPI. Данные по sqlite-vec, FAISS, Chroma и LanceDB собраны исследовательскими агентами; бенчмарки ANN-индексов sqlite-vec — цифры автора проекта, не независимые. Отдельно помечено агентом как непроверенное и не подлежащее повторению: слух о раунде Chroma «$50M от Northstar Ventures» не подтверждается ни одним первичным источником. Цифры из статей (Fiction.liveBench, EntityBench, ConStory, NWM) приведены по первоисточникам, но независимо мной не перепроверялись. Ставка Zilliz за хранилище расходится между источниками ($0.02 против $0.04/ГБ·мес); платные тарифы Qdrant публично не публикуются вовсе.