数据截至 (上游 commit c412a093a820)
VideoRAG — 架构与原理
30 秒导读: VideoRAG 让你「和视频聊天」——哪怕是几百小时的素材。它先把视频离线蒸馏成两份索引(一份文字知识图谱、一份视觉向量库),查询时两条通道并行召回相关片段,再用视觉语言模型对命中片段「精读」一遍,最后生成带时间戳引用的回答。论文 arXiv:2502.01549;本仓库还含一个基于它的桌面应用 Vimo。
1. 这是什么(零基础也能懂)
一句话定义: VideoRAG 是一个「长视频检索增强生成」框架——把视频当成知识库,用自然语言提问,它去视频里找答案。
解决什么问题 / 给谁用:
想象你有一套 100 小时的网课录像,想问「老师在哪一节讲了反向传播,怎么讲的?」。
- 直接把 100 小时喂给大模型——上下文窗口塞不下,token 费用爆炸。
- 只对字幕做普通 RAG——丢掉了画面信息(板书、演示、图表)。
VideoRAG 的做法是:离线时把视频压缩成紧凑的「知识」,在线时只检索并精读真正相关的几个 30 秒片段。这样单张 RTX 3090(24GB)就能处理几百小时素材(README「Technical Highlights」)。
它能做什么:
- 索引任意长度、任意数量的视频(
insert_video)。 - 用自然语言查询,返回带「视频名 + 起止时间戳」引用的答案(
query,mode="videorag")。 - 回答多选题(
mode="videorag_multiple_choice",用于 benchmark 评测)。 - 跨多个视频联合理解(图谱天然把多视频的实体连在一起)。
用起来什么样:
索引和查询是两步,分别是一段极简脚本(来自 examples/):
# 示意,浓缩自 examples/process_videos_deepseek.py + query_videos_deepseek.py
from videorag import VideoRAG, QueryParam
from videorag._llm import deepseek_bge_config
# 第一步:索引(离线,慢,吃 GPU)
rag = VideoRAG(llm=deepseek_bge_config, working_dir="./videorag-workdir")
rag.insert_video(video_path_list=["/path/lecture.mp4"])
# 第二步:查询(在线,快)
rag = VideoRAG(llm=deepseek_bge_config, working_dir="./videorag-workdir")
rag.load_caption_model(debug=False) # 加载视觉语言模型用于「精读」
param = QueryParam(mode="videorag")
print(rag.query("老师怎么讲反向传播的?", param=param))
一句话直觉/类比: 把它想成给视频做了一个「双层目录」——一层是文字大纲(知识图谱),一层是画面指纹(视觉向量)。提问时两层目录一起翻,找到候选页码(片段)后,再派一个「会看视频的助理」(视觉语言模型)去逐页精读,最后助理写报告并标注「第几页第几行」(时间戳)。
2. 顶层全景(它大概怎么转)
VideoRAG 分两个生命周期:离线索引(insert_video)和 在线查询(query)。中间隔着磁盘上的 working_dir——索引把知识写进去,查询从里面读。
全景图(从左 到右是数据流,上半离线、下半在线)
┌──────────────── 离线索引 insert_video() ────────────────┐
原始视频 ─▶ ① 切片 ─▶ ② Whisper 转写 ─▶ ③ 视觉语言模型 字幕 ─┐
(mp4) 30s/段 (字幕文本) (画面描述) │
│ ▼
└─▶ ⑤ ImageBind 编码每段 ──────────┐ ④ 合并「字幕+转写」为段文本
(视觉向量) │ │
▼ ▼
【视频片段向量库】 【文字分块 → 实体抽取 → 知识图谱】
vdb_video_segment_feature chunk_entity_relation(graphml)
└─────────────────────── 都落到 working_dir/ ───────────────┘
┌──────────────── 在线查询 query() ──────────────────────────┐
提问 ─┬─▶ 改写成「实体检索句」 ─▶ 查实体向量库 ─▶ 图谱反查 ─▶ 相关片段集 A ─┐
├─▶ 改写成「视觉检索句」 ─▶ 查片段向量库 ──────────────▶ 相关片段集 B ─┤
└─▶ 同时:查 chunk 向量库拿「文字上下文」 │
A ∪ B = 候选片段 ▼
候选片段 ─▶ ⑥ LLM 逐段过滤(留相关) ─▶ ⑦ 视觉语言模型「精读」每段 ─▶ ⑧ 组装上下文
│
带时间戳引用的答案 ◀┘
怎么读这张图:离线把一份视频拆成「文字」和「视觉」两套索引;在线时提问同时走「图谱通道」和「视觉通道」两路召回,合并后再精读。这就是论文说的 dual-channel(双通道) 架构。
部件一句话职责
| 部件 | 干什么 | 在哪个文件 |
|---|---|---|
VideoRAG(dataclass) | 总编排器:装配所有存储/模型,提供 insert_video / query | videorag/videorag.py:60 |
split_video | 把视频按 30 秒切片,抽音轨,采样帧时间点 | videorag/_videoutil/split.py:10 |
speech_to_text | 用 faster-whisper 给每段转写字幕 | videorag/_videoutil/asr.py:8 |
segment_caption | 用 MiniCPM-V 视觉语言模型给每段生成画面描述 | videorag/_videoutil/caption.py:17 |
encode_video_segments | 用 ImageBind 把每段视频编码成视觉向量 | videorag/_videoutil/feature.py:10 |
extract_entities | 从段文本抽实体/关系,建知识图谱 | videorag/_op.py:356 |
videorag_query | 在线查询主流程(双通道召回→过滤→精读→作答) | videorag/_op.py:580 |
NanoVectorDBStorage 等 | 向量库 / KV / 图存储后端 | videorag/_storage/ |
LLMConfig | 把「最强模型/便宜模型/嵌入模型」抽象成可替换 provider | videorag/_llm.py:44 |
主线走一遍(高层)
索引: insert_video 对每个视频跑 Step0–7(videorag.py:202)——切片、转写、字幕、编码、存片段信息;最后统一调 ainsert(videorag.py:344)把段文本分块、抽实体、写图谱。
查询: query 转给 aquery,按 param.mode 分发到 videorag_query(videorag.py:307)。该函数三路并行召回(实体图谱 / 视觉相似 / naive chunk),合并候选片段,LLM 逐段判相关性过滤,视觉语言模型对留下的片段精读,最后塞进 videorag_response 提示词作答。
阅读地图
建议顺序(由浅入深):
01-indexing-pipeline.md— 一段视频如何变成两套索引(切片/转写/字幕/编码的七步)。先读这章,因为查询依赖它产出的数据结构。02-dual-channel-retrieval.md— 查询 时双通道怎么召回、怎么过滤、怎么精读重述、怎么带时间戳引用。本框架的「价值核心」。03-knowledge-graph.md— 知识图谱怎么建(实体抽取 + gleaning + 合并)、怎么从实体一跳邻居反查到视频片段。04-storage-and-llm.md— 存储后端家族、LLM 多 provider 抽象、缓存。给要改后端/换模型的人。
每章末尾都有「代码地图」表,可直接 grep 符号名跳进源码。