中文翻译暂不可用,显示俄语原文。

Как вы индексируете видео-контент в RAG-системе?

Краткий тезис

Индексация видео в RAG — это мультимодальная задача, требующая обработки как аудиодорожки, так и визуальных кадров. Типовой пайплайн: извлекаем аудио → транскрибируем через Whisper → получаем текстовые чанки с временными метками; параллельно делаем frame sampling (выбор ключевых кадров), пропускаем их через CLIP для получения визуальных эмбеддингов. Затем оба типа эмбеддингов индексируются (часто в отдельных векторных пространствах) и комбинируются на этапе поиска через fusion strategy (например, взвешенная сумма или реранжирование). Результат — поиск по содержимому видео, включая и речь, и визуальные сцены.


1. Почему видео — сложный формат для RAG

Видео — это мультимодальный контент: он содержит визуальный поток (кадры, сцены), аудиодорожку (речь, звуки), часто субтитры и метаданные. Просто взять субтитры как текст — недостаточно, потому что визуальная информация (жесты, графики, демонстрация кода) теряется. С другой стороны, все кадры видео обрабатывать невозможно (30 fps → 1800 кадров на минуту), поэтому нужны методы сжатия. Главная цель индексации — так преобразовать видеоданные в поисковые эмбеддинги (векторные представления), чтобы по текстовому запросу можно было найти релевантный момент в видео.

Ключевые вызовы

  • Большой объём — даже короткое видео содержит гигабайты данных.
  • Временная привязка — результат должен указывать на конкретный таймкод.
  • Разнородность модальностей — текст запроса может быть про сцену («покажите синюю диаграмму») или про речь («что сказал лектор про loss function»). Система должна уметь отвечать на оба типа.

2. Пайплайн индексации видео

Общая схема:

Видеофайл
  ├── Извлечение аудиодорожки (FFmpeg)
  │   └── Распознавание речи (Whisper) → текстовые чанки + таймкоды
  └── Извлечение ключевых кадров (frame sampling)
      └── Получение визуальных эмбеддингов (CLIP, ViT)
          └── Индексация в векторной БД (FAISS, Qdrant)

Ниже каждый этап подробно.


3. Аудиодорожка: транскрибация через Whisper

Whisper — модель OpenAI для распознавания речи. Даёт точный текст с временными метками (start, end).

Процесс

  • Из видео извлекаем аудио (библиотеки FFmpeg, pydub).
  • Разбиваем на сегменты (например, по паузам) или обрабатываем целиком.
  • Whisper возвращает текст сегментов; мы сохраняем метаданные: [start_sec, end_sec, text.

Формирование чанков для текстового поиска

  • Текст Вики/Whisper|Whisper может быть длинным; мы дополнительно чанкуем (например, по 512 токенов) с наложением, чтобы не разрывать предложения.
  • Каждому чанку присваиваем нормализованный эмбеддинг (через text-encoder CLIP или другое embedding model, например, text-embedding-3-small).
  • Индексируем в векторной БД вместе с полем start_time, end_time.
import whisper
model = whisper.load_model("medium")
result = model.transcribe("lecture.mp4", word_timestamps=True)
for segment in result["segments"]:
    start = segment["start"]
    end = segment["end"]
    text = segment["text"]
    # ... chunking, embedding, indexing

Преимущества простая интеграция, поддержка многих языков. Недостатки не видит визуальный контент; если в видео музыка без речи — ничего не получаем.


4. Ключевые кадры (Frame Sampling)

Визуальный контент требует выбора репрезентативных кадров. Подходы:

  • Uniform sampling — каждый N-ый кадр (например, 1 кадр в секунду). Просто, но может пропустить быстрые сцены.
  • Scene detection — детекция смены сцены (по гистограмме, через PySceneDetect). Берётся первый/центральный кадр каждой сцены.
  • Adaptive sampling — на основе изменения движения или ключевых объектов.
  • Keyframe extraction на основе CLIP — берём кадры, которые максимально информативны по CLIP-скору (например, кадры с минимальной энтропией или с максимальным отличием от предыдущего).

Рекомендуемый минимум детектор сцен + один кадр на сцену. Это сжимает 30-минутное видео до 50–200 кадров.

import cv2, scenedetect
cap = cv2.VideoCapture("video.mp4")
detector = scenedetect.ContentDetector(threshold=30)
scenes = scenedetect.detect_scenes(cap, detector)
for (start, end) in scenes:
    # extract middle frame
    cap.set(cv2.CAP_PROP_POS_MSEC, (start.get_seconds() + end.get_seconds())/2 * 1000)
    ret, frame = cap.read()
    # save or embed

5. Визуальные эмбеддинги (CLIP, ViT)

Ключевые кадры нужно превратить в вектор. Основная модель — CLIP (Contrastive Language–Image Pre-training). Она обучена на парах (текст, изображение), поэтому эмбеддинги текста и изображения находятся в общем пространстве. Это позволяет выполнять text-to-image retrieval: запрос «синяя диаграмма» сравнивается с эмбеддингами кадров.

Альтернативы

  • ViT (Vision Transformer) — только изображения, не выровнен с текстом (нужно дообучать).
  • SigLIP — улучшенный CLIP от Google.
  • BLIP-2 — может генерировать текстовые описания кадров, что даёт гибридный поиск.

Сохранение визуальных эмбеддингов храним вектор embedding для каждого кадра, привязанный к временной метке. Индексируем отдельно от аудио-эмбеддингов.

import clip
model, preprocess = clip.load("ViT-B/32")
image = preprocess(Image.open("frame_001.jpg")).unsqueeze(0)
embed = model.encode_image(image) / model.logit_scale  # нормализация

6. Индексация и хранение

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

БазаПлюсыМинусы
FAISSВысокая скорость, GPU-ускорениеТолько in-memory, сложная репликация
QdrantПоддержка фильтров, гибридный поискНет нативных мультимодальных фич
MilvusМасштабируемость, облачная версияБольшая сложность
ChromaПростота, питон-интеграцияНе подходит для больших объёмов

Рекомендация использовать отдельные коллекции (или префиксы) для аудио- и видео-эмбеддингов, с полем modality: "audio" | "video". Это позволит на этапе поиска выбирать стратегию.

Метаданные к каждому эмбеддингу

  • start_time, end_time
  • video_id
  • modality
  • (для визуальных) описание кадра (caption) от BLIP-2, если нужно

7. Объединённый поиск (Fusion Strategy)

При поиске пользователь отправляет текстовый запрос. Мы получаем вектор запроса (через тот же CLIP text-encoder) и выполняем два поиска:

  1. По аудио-эмбеддингам (текст–текст, если у аудио отдельная модель или также CLIP text-encoder? — обычно для аудио мы использовали текстовые эмбеддинги, поэтому можно использовать ту же CLIP-text: для аудио-чанков мы получаем текстовые эмбеддинги через CLIP text encoder).
  2. По визуальным эмбеддингам (текст–изображение).

Далее нужно объединить результаты. Стратегии:

  • Weighted fusion — взвешенная сумма скоров: score = w1 * score_audio + w2 * score_video, где веса подбираются эмпирически (например, 0.6/0.4).
  • Reranking — взять top-k от каждого списка, объединить и пересортировать через более тяжёлую модель (например, кросс-энкодер с текстом и конкатенацией текста+описания кадра).
  • Late fusion — сначала ищем отдельно, потом подаём в LLM все найденные фрагменты (с меткой модальности) и просим выбрать релевантные (Self-RAG-like).
  • Dense-sparse fusion — можно добавить BM25 по субтитрам для дополнительного покрытия.
# пример weighted fusion
query_embed = clip_text_model.encode(query)
audio_scores = faiss_index_audio.search(query_embed, k=20)
video_scores = faiss_index_video.search(query_embed, k=20)
combined = []
for a in audio_scores:
    combined.append((a.id, 0.6 * a.score, "audio"))
for v in video_scores:
    combined.append((v.id, 0.4 * v.score, "video"))
combined.sort(key=lambda x: x[1], reverse=True)
top_k = combined[:10]

8. Временная привязка и поиск точного фрагмента

Поскольку каждый чанк (аудио- или визуальный) имеет временные метки, мы можем возвращать не только идентификатор видео, но и точный интервал. Для этого в метаданных храним start_sec, end_sec. При выводе пользователю можно показывать плеер с таймкодом.

Для длинных видео может потребоваться slide-level search: когда несколько соседних чанков ссылаются на один большой отрезок, их нужно группировать. Используйте Maximal Marginal Relevance (MMR) или просто слияние по времени.


9. Оценка качества индексации видео

Метрики оценки Video Retrieval:

МетрикаОписание
Recall@kДоля релевантных фрагментов среди топ-k результатов
mAPСредняя точность по запросам (учитывает рейтинг)
Temporal IoU (tIoU)Для задачи moment retrieval — пересечение по времени предсказанного интервала с ground-truth
NDCGДля учёта нескольких релевантных моментов

Для создания gold standard нужно вручную разметить пары (запрос → набор таймкодов) на тестовом видео. Можно автоматически генерировать запросы из субтитров (например, брать часть фразы и проверять, что retrieval возвращает правильный интервал).


10. Сложности и лучшие практики

  • Длинные видео (>1 часа): frame sampling даст много кадров; используйте scene detection с адаптивным порогом.
  • Отсутствие речи: если видео состоит только из музыки или шума, аудиоканал бесполезен, упор только на визуал.
  • Одинаковые кадры: дедупликация (по хэшу изображения или CLIP similarity) уменьшит индекс и улучшит качество.
  • Зависимость от CLIP: CLIP хорошо работает на естественных изображениях, но хуже на скриншотах кода или схем. Здесь может помочь fine-tuning на доменных данных или добавление OCR (извлечение текста с кадров через PaddleOCR) и индексация извлечённого текста вместе с CLIP.
  • Эффективность хранения: для больших коллекций используйте Product Quantization (сжатие векторов) с компромиссом по точности.

Расширенная архитектура (Multi-vector index):

Query
  → CLIP text encoder
  → search audio-index (text embeddings from Whisper chunks)
  → search video-index (CLIP image embeddings from keyframes)
  → merge & rerank
  → LLM takes top fragments (text + maybe image)

Для улучшения можно добавить caption generation (BLIP-2) для каждого кадра и сохранить текстовое описание в полнотекстовом индексе (Elasticsearch) — это даст гибридный поиск (векторный + BM25).


Пет-проект для закрепления

Задача Создайте RAG-систему для скринкастов по настройке Linux-сервера (видео 10 мин). Пользователь может задать вопрос вроде «как изменить права доступа к папке» и получить ответ с таймкодом.

Инструменты

Шаги:

  1. Скачайте любое обучающее видео (с YouTube) по Linux.
  2. Извлеките аудио -> Whisper -> текстовые чанки с таймкодами.
  3. Выполните scene detection, сохраните по одному ключевому кадру на сцену.
  4. Для каждого чанка и каждого кадра получите CLIP-эмбеддинги (для текста — через CLIP text encoder).
  5. Индексируйте в FAISS: отдельные индексы для аудио и видео.
  6. Напишите функцию поиска: запрос -> CLIP-текст -> поиск в обоих индексах -> weighted fusion -> вывод топ-5 с указанием времени.
  7. UI: пользователь вводит запрос, показывает таблицу результатов (время, текст из аудио, миниатюра кадра).
  8. Добавьте плеер, который стартует с нужного таймкода (через &t=xx для YouTube или локально через seek).

Ожидаемый результат Рабочее приложение, которое по запросу «как открыть порт в фаерволе» находит момент в видео, где это показывается, и выводит расшифровку речи. Вы сможете оценить, насколько лучше fusion по сравнению с использованием только аудио.


Связь с другими вопросами

ВопросТема
117Как вы обрабатываете изображения в RAG?
118Как вы объединяете результаты поиска из разных модальностей?
3Какие стратегии chunking'а вы знаете? (применимо к тексту из Whisper)
4Как вы выбираете модели эмбеддингов? (выбор CLIP vs специализированные)
5Как вы оцениваете качество retrieval'а? (те же метрики для видео)
10Что такое Self-RAG? (может применяться для фильтрации результатов разных модальностей)

Навигация