多模态 LLM 与本地多模态检索 PoC:从原理到工程落地(图片 / 视频关键帧 / LaTeX 公式)
本文目标:用 4 种难度梯度递增 的方式解释什么是多模态 LLM(Multimodal LLM),并系统说明 数学公式、图片、视频 在真实工程中如何被 存储、查询(检索)、创造(生成) 。随后给出一套 本地可跑的多模态检索 PoC (FAISS + SQLite + OpenCLIP),包含 数据结构、向量库选型、索引参数、评估指标(Recall@K、nDCG、latency),以及可直接运行的最小 Repo 结构与用法。
1. 多模态 LLM:4 种难度梯度递增的解释
1.1 最简单版:把多模态 LLM 当成"能看、能听、能读、能写"的大脑
- 传统 LLM 主要处理文本:读/写文字。
- 多模态 LLM 进一步支持多种输入/输出模态:
- 数学公式(通常以 LaTeX/MathML 等形式表达)
- 图片(像素)
- 视频(一串图片帧 + 时间维度;常伴随音轨/字幕)
内容怎么存储(最直观)
- 数学公式:以文本形式存储(例如 LaTeX),也可能以结构化形式(MathML、AST)存储。
- 图片:以文件(PNG/JPG/WebP)或对象存储 blob 形式保存。
- 视频:以文件(MP4 等)保存,本质是编码后的帧序列与音轨。
内容怎么查询
- 你用文本/图片/视频片段发起查询;
- 系统找到相关材料后再组织上下文交给模型回答。
内容怎么创造
- 公式:生成 LaTeX(或可渲染数学文本)。
- 图片:生成新图像。
- 视频:生成新视频片段(逐帧生成或在潜空间生成)。
1.2 工程落地版:统一套路是"内容 → 向量表示 → 索引检索 → 生成/回答"
真实系统往往把多模态内容统一成"可检索的向量表示(embedding)",再用向量索引做近邻搜索。
原始内容: 文本/公式/图片/视频
编码器: Embedding
向量索引: Vector DB / ANN
检索TopK: 相关内容
多模态LLM: 融合上下文
输出: 答案/公式/图片/视频
数学公式(LaTeX)在工程中的常见做法
- 存储:LaTeX 文本(最常见),或 MathML/AST(更结构化)。
- 查询 :
- 关键词/全文检索(比如
\int、Fourier)。 - 向量检索(把 LaTeX/描述编码为向量,做相似度)。
- 结构检索(基于 AST 的匹配,偏进阶)。
- 关键词/全文检索(比如
图片检索(Text → Image、Image → Image)
- 存储:原图 + 元数据(标签、作者、时间、权限);
- 索引:为图片生成 embedding 写入向量库;
- 查询:文本向量或图片向量与库中向量做相似度搜索。
视频检索(Text → Video Segment)
视频体量大,工程上通常"把视频拆小":
- 存储:原视频;
- 预处理 :抽 关键帧 、生成 字幕/ASR、按时间切分 segment;
- 索引:关键帧 embedding + 字幕 embedding;
- 返回:视频 ID + 时间段 + 证据帧/字幕片段。
1.3 机器学习机制版:关键是"表征对齐 + 融合机制 + 解码生成"
多模态检索的核心是让不同模态映射到同一个语义空间,并用相似度度量检索。
设:
- 文本编码器 f t ( ⋅ ) f_t(\cdot) ft(⋅)
- 图像编码器 f i ( ⋅ ) f_i(\cdot) fi(⋅)
- 视频编码器 f v ( ⋅ ) f_v(\cdot) fv(⋅)
得到向量:
e t = f t ( t ) , e i = f i ( I ) , e v = f v ( V ) \mathbf{e}_t=f_t(t),\quad \mathbf{e}_i=f_i(I),\quad \mathbf{e}_v=f_v(V) et=ft(t),ei=fi(I),ev=fv(V)
常用相似度为余弦相似度:
s i m ( a , b ) = a ⊤ b ∥ a ∥ ∥ b ∥ \mathrm{sim}(\mathbf{a},\mathbf{b})=\frac{\mathbf{a}^\top\mathbf{b}}{\|\mathbf{a}\|\;\|\mathbf{b}\|} sim(a,b)=∥a∥∥b∥a⊤b
工程实现中,通常先做 L2 归一化,再用点积(Inner Product)近似余弦相似度。
**融合机制(LLM 如何"用视觉信息推理")**常见两类:
- 把图像/视频编码成 token,让 LLM 通过注意力机制读取;
- 先用视觉模型抽取结构化信息(OCR、检测框、caption),再交给 LLM 推理(稳定但上限受视觉总结质量影响)。
1.4 最严谨版:检索目标函数、ANN 近邻搜索、生成分布与可验证约束
1) 检索作为近邻搜索问题
给定查询 q q q,编码为向量 e q \mathbf{e}q eq;库中向量为 { e k } k = 1 N \{\mathbf{e}k\}{k=1}^{N} {ek}k=1N,要找 Top-K:
arg topK k ∈ { 1.. N } s i m ( e q , e k ) \operatorname*{arg\,topK}{k\in\{1..N\}} \mathrm{sim}(\mathbf{e}_q,\mathbf{e}_k) k∈{1..N}argtopKsim(eq,ek)
当 N N N 很大时使用 ANN(Approximate Nearest Neighbor) 算法(如 HNSW、IVF-PQ)在精度与延迟之间折中。
2) 表征对齐的典型训练目标:对比学习(InfoNCE)
以文本-图片配对为例,设相似度矩阵 s i j s_{ij} sij,InfoNCE 的常见形式:
L = − 1 B ∑ i = 1 B log exp ( s i i / τ ) ∑ j = 1 B exp ( s i j / τ ) \mathcal{L}=-\frac{1}{B}\sum_{i=1}^{B}\log \frac{\exp(s_{ii}/\tau)}{\sum_{j=1}^{B}\exp(s_{ij}/\tau)} L=−B1i=1∑Blog∑j=1Bexp(sij/τ)exp(sii/τ)
其中 τ \tau τ 为温度系数。该目标使匹配对更近、不匹配更远,从而支持跨模态检索。
3) 生成(创造)可视为条件生成分布
- 图像生成: p ( I ∣ c ) p(I\mid c) p(I∣c)
- 视频生成: p ( V ∣ c ) p(V\mid c) p(V∣c)
扩散模型的去噪训练目标(常见形式):
E t , x 0 , ϵ [ ∥ ϵ − ϵ θ ( x t , t , c ) ∥ 2 ] \mathbb{E}_{t,\mathbf{x}0,\epsilon}\left[ \|\epsilon-\epsilon\theta(\mathbf{x}_t,t,c)\|^2 \right] Et,x0,ϵ[∥ϵ−ϵθ(xt,t,c)∥2]
4) 数学公式生成的严谨工程:生成-校验-修复闭环
仅生成 LaTeX 不够,工程上经常加入:
- 编译/渲染校验: c o m p i l e ( L a T e X ) = t r u e \mathrm{compile}(\mathrm{LaTeX})=\mathrm{true} compile(LaTeX)=true
- 数学一致性校验:用符号计算/单元测试验证等式成立
2. 本地可跑的多模态检索 PoC:目标、架构与流程
2.1 PoC 目标能力
- Text → Image/Video:输入文本,检索相关图片与视频关键帧(并返回时间戳)。
- Text/LaTeX → Formula:输入 LaTeX 或描述,检索相似公式(LaTeX 文档条目)。
- (可选增强)Image → Image/Video:用图片作为查询做相似检索。
2.2 最小可行架构(本地、可离线运行)
- 原始媒体:本地文件系统(images/videos)
- 元数据:SQLite(轻量、便于回表与调试)
- 向量索引:FAISS(本地快速、工程最简)
- Embedding:
- 图片/视频关键帧:CLIP(图文同空间,支持 text→image)
- 公式 LaTeX:PoC 使用"文本向量"基线(直接用 CLIP text embedding 对 LaTeX+desc 编码)
2.3 离线入库 + 在线查询:端到端流程图
离线入库与建索引
Images
CLIP image embedding
Videos
Extract keyframes
CLIP image embedding
LaTeX formulas
CLIP text embedding
FAISS clip index
FAISS formula index
SQLite metadata
在线查询
Query text
CLIP text embedding
Search clip index
Search formula index
TopK images/frames
TopK formulas
Results with uri and timestamps
3. 数据结构设计(文件系统 + SQLite)
3.1 文件系统约定
data/
images/ # 图片
videos/ # 视频(可选)
frames/ # 抽取的关键帧(自动生成)
formulas/ # 公式数据(jsonl)
qrels/ # 查询与标注(示例)
meta/
items.sqlite # SQLite 元数据(自动生成)
indexes/
clip.faiss
formula.faiss
idmap_clip.npy
idmap_formula.npy
3.2 SQLite items 表(统一主表)
item_id:主键(UUID)modality:image | video_frame | formulauri:文件路径或 pseudo-urivideo_id:视频标识(帧所属视频)timestamp_ms:关键帧时间戳(毫秒)title:标题(公式可用)text:LaTeX 原文(公式可用)created_at:创建时间(ISO)
4. 向量库与索引:选型、参数、相似度
4.1 选型:FAISS(PoC 首选)
优点 :纯本地、依赖轻、速度快、实现最简单
补足:元数据过滤弱,因此与 SQLite 组合("向量检索 → item_id → SQLite 回表")
4.2 相似度:余弦相似度(实现为 IP + 归一化)
对向量做 L2 归一化后使用点积:
- 余弦相似度等价于归一化向量点积
- FAISS 使用
METRIC_INNER_PRODUCT
4.3 索引结构与默认参数(HNSW)
PoC 默认采用 HNSW:
M = 32efConstruction = 200- 查询时
efSearch = 128(可调)
适用规模:小到中等(10k--数十万向量)性能与精度兼顾。
5. 评估指标与口径:Recall@K、nDCG@K、Latency
5.1 Recall@K
R e c a l l @ K = ∣ T o p K ∩ R e l e v a n t ∣ ∣ R e l e v a n t ∣ \mathrm{Recall@K}=\frac{| \mathrm{TopK} \cap \mathrm{Relevant} |}{|\mathrm{Relevant}|} Recall@K=∣Relevant∣∣TopK∩Relevant∣
5.2 nDCG@K
DCG:
D C G @ K = ∑ i = 1 K 2 r e l i − 1 log 2 ( i + 1 ) \mathrm{DCG@K}=\sum_{i=1}^{K}\frac{2^{rel_i}-1}{\log_2(i+1)} DCG@K=i=1∑Klog2(i+1)2reli−1
nDCG:
n D C G @ K = D C G @ K I D C G @ K \mathrm{nDCG@K}=\frac{\mathrm{DCG@K}}{\mathrm{IDCG@K}} nDCG@K=IDCG@KDCG@K
5.3 Latency(建议拆分统计)
- t e m b e d t_\mathrm{embed} tembed:embedding 时间
- t s e a r c h t_\mathrm{search} tsearch:FAISS search 时间
- t p o s t t_\mathrm{post} tpost:回表/融合/去重时间
- t t o t a l = t e m b e d + t s e a r c h + t p o s t t_\mathrm{total}=t_\mathrm{embed}+t_\mathrm{search}+t_\mathrm{post} ttotal=tembed+tsearch+tpost
建议报告:P50 / P95 / P99。
6. 最小 Repo:可运行入口、示例数据与命令
本文已提供一个最小 repo(zip 包)用于本地直接运行,包含:
scripts/build_poc.py:建库 + 入库 + 建索引scripts/extract_frames.py:抽视频帧(可选,依赖 ffmpeg)scripts/query.py:查询并打印返回(含 latency breakdown)scripts/make_qrels_from_db.py:从模板生成可用 qrels(为示例评估服务)scripts/eval.py:Recall@K、nDCG@K、latency 报告- 示例数据:
data/images/:简单形状图片(便于快速验证 text→image)data/formulas/formulas.jsonl:示例 LaTeX + descdata/qrels/:示例 queries 与 qrels 模板
6.1 运行步骤(最短路径)
- 安装依赖:
bash
python -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install -r requirements.txt
- (可选)安装 ffmpeg(用于视频抽帧):
bash
brew install ffmpeg
- 建库 + 建索引:
bash
python scripts/build_poc.py
- 查询:
bash
python scripts/query.py --index clip --text "a blue circle" --topk 5
python scripts/query.py --index formula --text "gaussian integral" --topk 5
python scripts/query.py --index formula --text "\\int_{-\\infty}^{\\infty} e^{-x^2} \\, dx" --topk 5
- 生成 qrels 并评估:
bash
python scripts/make_qrels_from_db.py
python scripts/eval.py --queries data/qrels/queries.tsv --qrels data/qrels/qrels.tsv --k 10
6.2 默认索引参数(PoC 版)
- HNSW:
M=32,efConstruction=200 - 查询:
efSearch=128 - 相似度:IP(配合归一化近似 cosine)
7. 工程化扩展建议(从 PoC 到可用系统)
当 PoC 链路跑通后,常见增强方向:
- 视频关键帧更合理:从 1fps 升级到镜头切分关键帧(SceneDetect)+ 相邻帧去重。
- 返回片段聚合:帧级命中聚合到 segment(时间窗合并),输出"可播放片段"而不是单帧列表。
- 公式检索更结构化:LaTeX AST/MathML 特征 + 结构相似度重排,提高"等价变形"命中。
- 两阶段检索:ANN 粗召回 + rerank(交叉编码器/多模态重排)提升 nDCG。
- 权限与多租户:SQLite 可换 Postgres;向量库可换支持 payload 过滤的 Qdrant/Weaviate 等。
附:本地 PoC Repo(zip 包)下载
你已获得一个最小可跑 repo 的 zip 包(用于本地解压运行)。同一目录下也可直接作为博客配套项目发布。
- Repo zip:
mm-multimodal-retrieval-poc.zip
结语
多模态 LLM 的工程核心可以概括为三句话:
- 存储:原始内容(文件/对象存储) + 元数据(DB) + 向量表示(embedding)。
- 查询:查询也编码成向量 → ANN 检索 Top-K → 回表组装证据 → 输出结果或喂给 LLM 推理。
- 创造:文本/公式多为序列生成;图片/视频多为扩散/时空生成模型;严谨场景需要校验闭环。
如果你希望在现有 PoC 上继续升级到"可对外发布的工程项目"(带 API、UI、可复现 benchmark、Docker、CI、数据集脚本),建议优先从 视频片段聚合 + 评估体系完善 两块切入。
