Skip to main content

02 - 多模态大模型怎么工作

用户对着点单机器人说了句话,同时拍了张菜单照片,问「这个有什么推荐」。他期待听到语音回答。

这一个请求里,要处理的东西有三样:一段音频、一张图片、最后还要吐出一段音频

问题来了:一个大模型本来只会读写文字。这三样东西是怎么进去、又怎么出来的?

这一篇按三个问题往下走:为什么非要这样做(第一节)、模型怎么学会的(第二节)、内部长什么样(第三节起)。

一、为什么非要多模态

先说个反问:这事不用多模态也能做

语音转文字有现成的,大模型有现成的,文字转语音也有现成的。三个串起来就行 —— 这套叫拼接式,至今仍是绝大多数产品的实现方式,因为每一段都能单独换、单独调、单独买。

那为什么还要有多模态模型?两个理由。

理由一:每转换一次,管子就窄一次。

用户第三遍重复「少冰」,语气已经不耐烦了。语音转文字之后,输出是一行纯文字「我要少冰」—— 「不耐烦」这三个字不在里面。后面的大模型看到的只有那行字,它不知道用户在生气;再后面的语音合成拿到的也只有一行字,更没有依据挑语气。

丢掉的不只是情绪。口音、语速、背景里有没有别人在讲话 —— 只要过了「转成文字」这一步就全没了。文字是个很窄的管子。

图片那边同理:先让一个模型把图描述成一句话,再把这句话给大模型 —— 描述里没提到的细节,后面永远拿不回来。

理由二:串行的三段,延迟是加起来的。

拼接式必须等前一段完全结束才能开始下一段:听完 → 想完 → 才开始说。而多模态模型可以边想边说 —— 文字刚吐出几个字,语音合成就能开工。这个差别在语音对话里是决定性的。

什么时候不该上多模态模型

如果你的场景只是「把用户说的话转成文字,然后走已有的文本流程」,拼接式更好 —— 便宜、灵活、每段都能单独优化,而且不会幻觉出用户没说过的话

只有当「听出情绪并据此调整回答」这类能力成为核心体验时,多模态模型的代价才划算。

二、一个只会读文字的模型,怎么学会看图

这是最反直觉的一步,也是最该先想明白的。

你可能以为要把 LLM 重训一遍,让它「学会看图」。不是的 —— 训练时 LLM 基本是冻住不动的。

真正的做法是:在旁边训一个翻译层

为什么这样行得通?关键在于 LLM 已经会的东西比你想的多。它读过海量文本,早就理解「一只猫趴在沙发上」这句话意味着什么 —— 它的内部空间里,这句话对应着一个位置。

所以要让它「看懂」一张猫的照片,不需要教它什么是猫。只需要一个翻译层,把这张照片算出来的向量,搬到跟那句话相近的位置上去。搬对了,LLM 就当它是那句话来处理。

训练分两步:

阶段用什么数据训哪部分目的
① 对齐预训练海量「图—文字描述」配对只训翻译层让图像向量落到正确的位置上
② 指令微调「图 + 问题 → 答案」翻译层,有时也轻调 LLM让它会按指令回答,而不只是描述

这就解释了一个常被问的问题:为什么接一个新模态那么快? 因为不用重训 LLM,也不用重训编码器 —— 图像编码器(比如 CLIP ViT)和 LLM 都是现成的、冻住的,你只训中间那个翻译层。这也是为什么开源社区能在一个基座上迅速衍生出几十个多模态变体。

三、内部拆成五个部件

有了上面的直觉,再看结构就清楚了。业界把这套东西拆成五个部件,几乎所有多模态模型都能往上套:

左边两个是(理解侧),右边两个是(生成侧),中间那个是原来就有的语言模型。LLM 还额外有一条出口:直接吐文字回答,不走 ④ ⑤。

部件干什么
① 模态编码器把原始信号(波形、像素)算成一串向量
② 输入投影器把这串向量对齐到 LLM 认识的空间
③ LLM 骨干真正做理解和推理,也是唯一「懂语义」的一层
④ 输出投影器把 LLM 的输出翻译给生成器
⑤ 模态生成器变回音频、图片、视频

把这五个格子填上真实模型名,就是下面这张业界通用的示意图:

多模态大模型的五部件结构:左侧图像视频音频经模态编码器(ViT、CLIP ViT、HuBERT 等)编码,过输入投影器(线性层、MLP、Q-Former 等)进入 LLM 骨干;右侧经输出投影器再由模态生成器(Stable Diffusion、Zeroscope、AudioLDM)还原成图像视频音频
出处:LLMForEverybody。图里有个容易忽略的细节 —— 雪花标记表示这部分是冻结的,火焰标记表示要训。编码器和生成器大多直接拿现成的、冻住不动,真正训练的只有中间那两个投影器。这也解释了为什么「接一个新模态」比想象中便宜:你不用重训 LLM,只要训一个把新模态对齐过来的投影器。

左半边叫多模态理解(进),右半边叫多模态生成(出)。很多模型只做左半边 —— 那类叫 VLM(能看图但不能画图)。

LLM 骨干还在正中间 —— 这是最该先记住的一点。多模态不是另起炉灶,是在语言模型外面接翻译官。所以你对文本推理的全部认知(01 篇那六个概念)都还成立,只是外面多了几层。

这一章后面几篇,就是把这五个部件逐个拆开

部件哪一篇
音频进来(① ②)03 听
语音出去(④ ⑤)04 说
图像视频进来(① ②)05 看
图像视频出去(④ ⑤)06 画
五个部件长在一个模型里08 Omni

四、进来这一侧:编码器和投影器

先说清楚 LLM 那一端要什么:一串长度相同的向量

文字天然对得上 —— 「珍珠」在词表里是第 28374 号,去嵌入表取第 28374 行就完事,查表而已。

音频、图片、视频对不上,因为它们是连续的,没有天然的「一颗一颗」。

三条路的终点相同,起点和代价完全不同文本已经是离散 id查嵌入表图像 / 视频像素矩阵切 patch音频一维波形分帧视觉编码器ViT / SigLIPmel 或 codec两条路,见第二节一串等长向量文本走嵌入表拿到图像走编码器直接给出音频两条路都能到这序列里的位置由占位符预留向量在 forward 里覆盖上去Transformer它并不知道哪一段是图哪一段是音频代价也因此对它透明:一秒视频铺开可能比一千字文本还长关键的不对称:文本那条路几乎不花时间,另外两条要跑一个真正的神经网络。所以多模态请求的 prefill 里,「编码器耗时」是一项独立开销,它不在语言模型的 KV cache 里,也不受 KV 复用的保护 —— 第 07 篇讲的 encoder cache 就是为它单独建的。
「Transformer 不知道哪一段是图」这句话有个直接后果:所有多模态的调度、缓存、复用逻辑都得在进入模型之前做完。框架层能拿到的抓手只有「占位符区间」和「这块内容的哈希」两样东西。

① 模态编码器干的就是「切开并算成向量」这件事。不同模态用不同的编码器:

模态常用编码器输出
图像ViT、CLIP ViT、SigLIP每个小方块一个向量
音频Whisper 编码器、CLAP每 20~40 毫秒一个向量
视频图像编码器逐帧 + 时间维处理每帧若干向量

② 输入投影器解决的是另一个问题:编码器吐出来的向量维度、分布,跟 LLM 嵌入表里那些向量对不上。投影器把它们「翻译」到同一个空间里,通常就是一个 MLP,有时是交叉注意力。

翻译完之后,这些向量被塞进 LLM 输入序列里 —— 塞在哪?塞在占位符的位置上。提示词里先留好 N 个坑(形如 image_pad 的特殊标记),forward 时把真实向量覆盖上去。

占位符是后面一连串坑的根源

坑的数量必须和向量数量严格对上。留了 256 个坑、编码器给了 257 个向量,多的那个要么被丢、要么把后面顶掉 —— 而且不报错。

更麻烦的是:两张完全不同的图,占位符的编号是一模一样的。拿它当缓存键会让一个用户看到另一个用户的图。09 篇专门讲怎么堵。

五、出去这一侧:投影器和生成器

生成侧是反着走的。

LLM 只会吐文字 token。要让它「说话」或者「画图」,得在后面接一个⑤ 模态生成器 —— 语音这边是声码器,图像这边是扩散模型。

中间的④ 输出投影器负责把 LLM 的输出翻成生成器认识的形式。

这里有个关键取舍:生成器要的到底是文字,还是 LLM 的中间状态?

接什么好处代价
文字简单,每段都能单独换语气、情绪、口音全丢了 —— 文字是个很窄的管子
中间状态(隐状态)副语言信息能传下去两段绑死,而且要边生成边传

Omni 模型选后者,代价是整个服务架构都得跟着变。这条线索会贯穿 08 篇

六、从服务的角度看,这五个部件各自要多少钱

上面是模型视角。换成服务视角,你真正要关心的是每个部件吃什么资源、会怎么坏:

部件计算特点显存主要风险
① 模态编码器一次算完,算力密集尖峰后立刻释放它一跑,正在解码的所有人都要停下等
② 输入投影器一个小 MLP,可忽略可忽略坑位数和向量数对不上
③ LLM 骨干一步一个字,步数不定随生成不断增长显存不够时要抢占
④ 输出投影器同 ②可忽略——
⑤ 模态生成器声码器一次算完;扩散要算几十轮恒定扩散那类不能抢占,踢出去等于白算

这张表里藏着整章后半段的全部动机:① ③ ⑤ 三类计算的脾气完全不同,而你只有一套调度器。07 篇专讲这个冲突。

七、一笔 token 账

最后给一个换算,后面估容量时反复要用。

同一条时间轴上,各类输入折算成的序列长度(对数感受,非等比)500 字中文约 350 token · 用户以为这是「一次普通请求」的基准一张 448×448 图256~1024 token · 取决于 patch 大小与是否做 2×2 合并10 秒语音(理解侧)500 token · 50 向量/秒,Whisper 系编码器的固定换算10 秒语音(生成侧)1500~2000 整数 · 帧率 × 码本数,25 fps × 8 = 200/秒5 秒视频 @ 2 fps约 2500 token · 10 帧 × 每帧 256读法:一句「帮我看下这段视频」的请求,序列长度相当于七篇 500 字短文。它的 KV cache 占用、prefill 时间、被抢占重算的代价,都按这个长度算。生成侧那一行还有个额外性质:这 1500 个整数不是一次算完的,是 250 个自回归步一步步吐出来的 —— 长度决定显存,步数决定延迟,两者要分开看。
这张表最实用的地方是估容量:给定 KV cache 显存,能同时跑多少路语音对话,答案基本由这里的换算和上下文长度决定,跟模型参数量关系不大。

三条经验

  • 理解侧看「向量/秒」,生成侧看「步/秒」。前者决定显存和预填充长度,后者决定用户等多久才听到第一个音。混用是最常见的估算错误。
  • 一张普通清晰度的图,进序列就是几百到一千多个 token,跟一篇短文档同量级。视频再乘帧数。
  • 多模态请求「看起来短,跑起来长」。一句「帮我看下这段视频」,序列长度可能相当于七篇 500 字短文。

八、新手最容易混的三件事

「多模态」不等于「什么都能出」。 很多模型只有左半边 —— 能看图听声,但只会吐文字,这类叫 VLM。要它画图或说话,得配上右边的输出投影器和生成器,那是另一套训练。看一个模型支持什么,要分开看进和出。

「能看图」不等于「看懂图」。 编码器把图变成了向量,不代表 LLM 真的理解了空间关系、文字细节、数量。这是模型能力问题,不是工程问题。

编码器不是免费的。 很多人把注意力全放在 LLM 上,但在多模态服务里,编码器经常是那个把所有人卡住的家伙 —— 它跑的时候,正在等字的用户全都得停。

下一篇03 - 听,从音频这一路开始,看编码器具体怎么工作。