SentrySearch 源码解析:从视频切片、向量嵌入到检索裁剪的完整流水线
【免费下载链接】sentrysearchSemantic search over videos using Gemini Embedding 2 or Qwen3-VL.项目地址: https://gitcode.com/gh_mirrors/se/sentrysearch
SentrySearch 是一款开源的视频语义检索工具,它让「用一句话在几小时行车记录仪素材里找到想要的画面」成为可能。本文带你逐段拆解它的源码,走完从视频切片、向量嵌入、向量入库,到检索与自动裁剪的完整流水线。无论你是想学习多模态检索架构,还是打算二次开发,这份源码解析都能帮你快速建立全局认知。项目核心依赖 GoogleGemini Embedding 2或Qwen3-VL完成视频向量化,无需逐帧字幕、无需文字中间层。
一、先看懂整体架构:一条四段式流水线
打开项目根目录sentrysearch/包,你会发现每个环节都有独立模块,职责非常清晰:
| 环节 | 核心模块 | 职责 |
|---|---|---|
| ① 视频切片 | sentrysearch/chunker.py | 用 ffmpeg 把长视频切成带重叠的片段 |
| ② 向量嵌入 | sentrysearch/embedder.py及三个后端实现 | 把视频/文字/图片映射成 768 维向量 |
| ③ 向量存储与检索 | sentrysearch/store.py、search.py | 写入 ChromaDB,按余弦相似度召回 |
| ④ 结果裁剪 | sentrysearch/trimmer.py | 从原文件切出匹配片段并保存 |
CLI 入口集中在sentrysearch/cli.py,index、search、img、highlights等命令最终都汇入这条流水线。
二、第一站:视频切片——如何优雅地切出「完整事件」
视频里的事件不会刚好落在切片边界上。chunker.py的解决方案是重叠切片:默认每段 30 秒、段间重叠 5 秒。核心函数chunk_video先用 ffprobe/ffmpeg 读取总时长,再通过expected_chunk_spans计算出所有 (起, 止) 区间,最后逐段调用 ffmpeg 的-ss/-t参数完成切割(见sentrysearch/chunker.py)。
三个值得学习的设计细节:
- 断点续传优化:
cli.py中的 index 命令会先按expected_chunk_spans推算所有切片 ID,若数据库中已存在则直接跳过整文件,避免重复调用 ffmpeg。 - 静止画面跳过:
is_still_frame_chunk抽取首、中、尾 3 帧转成 JPEG,比较文件体积——大小接近说明画面几乎没变化,整段跳过不做嵌入,节省大量 API 调用。 - ffmpeg 探测:
_get_ffmpeg_executable会优先找系统 ffmpeg 并实际跑一次写入测试,再回退到包内置的imageio-ffmpeg,兼容各种沙箱环境。
三、预处理:把 19MB 缩到 1MB 的省钱妙招
在向量嵌入之前,preprocess_chunk会用 ffmpeg 把每段视频降到480p、5fps(sentrysearch/chunker.py)。为什么这样做?
- 对 API 后端:体积变小 → 上传更快、超时风险更低;
- 对本地模型:推理耗时与像素量强相关,降采样后模型要处理的像素量大幅下降,是「本地模型跑得快」的最大加速来源;
- 低帧采样:视频处理器每段最多送 32 帧,30 秒片段只取约 30 帧,而不是成百上千帧。
四、核心枢纽:三种向量嵌入后端的统一抽象
embedder.py是一个经典工厂模式:get_embedder(backend)按gemini/local/qwen-cloud三种后端返回对应实现,并用全局缓存避免重复加载模型。三者都继承自base_embedder.py的BaseEmbedder,统一提供embed_video_chunk、embed_query、embed_image三个能力。
① Gemini 后端(默认)——gemini_embedder.py调用gemini-embedding-2-preview模型,输出 768 维向量。内含两个抗抖设计:滑动窗口限流器_RateLimiter(默认 55 次/分钟)和指数退避重试_retry(对 429/503 自动重试),遇到配额耗尽还会抛出友好的GeminiQuotaError提示用户。
② 本地 Qwen3-VL 后端——local_embedder.py加载 Qwen3-VL-Embedding 系列模型(qwen8b/qwen2b),按硬件自动选择:NVIDIA 或有 24GB+ 内存的 Mac 选 8B,小内存 Mac 与纯 CPU 环境选 2B。两个关键优化:
- MRL 维度截断:只保留前 768 维并做 L2 归一化,减轻存储与距离计算压力;
- 自动 4bit 量化:显存不足时自动用 bitsandbytes 加载,8B 模型从约 18GB 降到 6–8GB。
③ DashScope 云端后端——qwen_cloud_embedder.py对接阿里云百炼的多模态嵌入,默认模型qwen3-vl-embedding。本地切片文件由官方 SDK 上传到托管 OSS 后调用,同样内置限流与重试。
五、向量入库:ChromaDB 里的存储设计
store.py的SentryStore用ChromaDB做持久化向量库,几个设计值得注意:
- 按后端+模型分集合:不同模型产出的向量互不兼容,因此集合名按
dashcam_chunks、dashcam_chunks_local_<model>、dashcam_chunks_qwen_cloud_<model>区分,绝不会混用(见sentrysearch/store.py); - 确定性切片 ID:
_make_chunk_id用 SHA-256 对「源文件+开始时间」取前 16 位,天然支持断点续传与去重; - 余弦空间:集合元数据设置
hnsw:space: cosine,检索时1.0 - distance即为相似度得分; - 自动识别索引:
detect_index按优先级扫描各集合,search命令无需手动指定后端即可从索引自动推断。
六、检索:把一句话变成「最近邻」问题
search.py的逻辑非常精简:查询文本(或图片)先经当前后端嵌入成 768 维向量,再调用store.search做余弦最近邻检索,按相似度降序返回(sentrysearch/search.py)。可选dedupe参数会把与更高排名结果过相似的条目丢弃,避免结果被几乎相同的画面刷屏。
配合--rerank参数时,reranker.py会进一步用 VLM 对候选片段逐段打分,做一轮「精排」,把嵌入检索的粗召回变成高质量排序——这也是cli.py里_get_search_reranker的设计意图。
七、不知道搜什么?用「离群点」发现精彩片段
highlights.py实现了一个很酷的功能:当你还没想好搜什么时,sentrysearch highlights会把索引中「最异常」的切片排出来——也就是向量分布偏离最大的那些片段,并自动裁剪。支持三种离群评分方法(sentrysearch/highlights.py):
- knn(默认):每个切片与其 k 个近邻的平均余弦距离,稳健、能浮出「没有很像的孪生片段」;
- centroid:与索引均值的距离,最省算力;
- lof:局部离群因子,适合索引里存在多种「常态」(白天/夜间/车库)的场景。
八、最后一步:自动裁剪,直接拿到成片
检索命中后,trimmer.py的trim_clip负责从原始文件中切出片段,而非从预处理的小文件切——保证画质无损。它还会在匹配窗口前后各加 2 秒缓冲,并依次尝试三种 ffmpeg 策略:快速流拷贝 → 重编码 → 输出端 seek 拷贝,兼容各种编码边界情况。最终文件按match_<源文件名>_<起止时间>.mp4命名保存,--save-top N还能一次保存前 N 个结果。
九、可靠性设计:DLQ 与失败重试
大规模建索引时难免遇到坏文件或网络抖动。dlq.py实现了死信队列:某切片嵌入失败达到重试上限后,会把 chunk ID、源文件、起止时间与错误原因记录到 DLQ(见sentrysearch/dlq.py),index默认跳过这些切片并提示,待问题修复后用--retry-failed一键重试。配合_embed_with_retry的指数退避(1s→2s→4s),整个流程既抗噪又不至于卡死。
十、锦上添花:特斯拉元数据叠加层
如果你用的是特斯拉行车记录仪素材,search --overlay还能从视频内嵌的 SEI 遥测中读取速度、GPS,裁剪后直接在画面上渲染 HUD 叠加层——速度、时间、城市与道路名一目了然(sentrysearch/overlay.py、sentrysearch/metadata.py):
十一、快速上手:三分钟跑通完整流水线
想亲手体验这条流水线?推荐用 uv 安装(需 Python 3.11/3.12):
git clone https://gitcode.com/gh_mirrors/se/sentrysearch cd sentrysearch uv tool install .随后初始化并建索引、搜索:
sentrysearch init # 配置 Gemini API Key sentrysearch index /path/to/footage # 切片 + 嵌入 + 入库 sentrysearch search "red truck running a stop sign" # 检索并自动裁剪无需 API Key 的场景,改用--backend local即可在本地跑 Qwen3-VL;预算敏感可用--backend qwen-cloud走阿里云百炼。
小结
SentrySearch 的源码架构非常值得借鉴:切分 → 预处理 → 嵌入 → 入库 → 检索 → 裁剪,每个环节都用独立模块封装、可替换后端、内置容错。如果你正在做视频理解、多模态检索或私有媒体库检索工具,这份源码解析可以当作一份现成的架构模板。建议重点精读sentrysearch/chunker.py、sentrysearch/embedder.py与sentrysearch/store.py,它们是整个系统的地基。
【免费下载链接】sentrysearchSemantic search over videos using Gemini Embedding 2 or Qwen3-VL.项目地址: https://gitcode.com/gh_mirrors/se/sentrysearch
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考