多模态推理中的图片缓存:为什么视觉编码独立,KV Cache 仍受前缀顺序影响
区分 Base64 传输、视觉编码缓存与 LLM KV 前缀缓存,解释图片截断为何会影响后续文本命中,并给出上下文设计、监控与实验方法。
多模态模型通常使用独立的视觉编码器处理图片,因此很容易产生一个误解:既然图片有独立的编码模块,它是否也能脱离对话顺序,单独命中推理缓存?
答案是:图片编码结果可能被独立复用,但图片进入语言模型后,会成为统一序列中的视觉 token 或视觉 embedding。此时,它与文本共同参与 Transformer 推理,并受 LLM KV 前缀缓存的连续前缀匹配规则约束。
因此,删除历史图片、调整图片顺序,或者采用“只保留最近 N 轮图片”的滑动窗口,都可能让序列在较早位置发生变化。即使后面的文本和图片没有改变,其 KV cache 也可能无法继续命中。
先区分两类缓存
多模态推理中至少存在两类容易混淆的缓存:
- Vision Encoder Cache:复用图片的视觉编码结果。
- LLM KV Prefix Cache:复用统一输入序列已经计算出的 Transformer Key/Value 状态。
二者节省的计算阶段不同,命中规则也不同。
图片 URL / Base64
│
▼
下载或 Base64 解码
│
▼
图片预处理:缩放、裁剪、归一化、分块
│
▼
Vision Encoder ─────── Vision Encoder Cache
│ 复用图片视觉特征
▼
Visual Embeddings / Visual Tokens
│
文本 Token ────────────┤
▼
统一 Decoder 输入序列
│
▼
Transformer 推理
│
└──── LLM KV Prefix Cache
独立的视觉编码模块,并不意味着图片可以在语言模型内部脱离上下文位置单独复用。
Base64 是传输形式,不等同于模型 token
图片通过 API 传递时,常见形式包括可访问 URL、Base64/Data URL、上传后的资源标识或对象存储地址。在多数多模态推理链路中,Base64 只是图片字节的传输编码。服务端通常会先把它解码为图片字节,再完成格式解析、缩放、归一化、patch 切分和视觉编码。
所以,“从第一个不同的 Base64 字符开始,后面全部失去 KV 命中”并不是最严谨的描述。更准确的说法是:
图片内容、解码与预处理结果、视觉特征,或者图片在统一序列中的位置发生变化,会使 LLM 输入序列从对应位置开始不再相同,从而中断 KV 前缀匹配。
不过,Base64 或原始字节是否稳定,仍可能影响上游图片去重和视觉编码缓存。例如,同一张图片使用不同压缩参数重新编码、EXIF 信息变化、PNG 与 JPEG 互换、输入分辨率变化或裁剪区域不同,都可能让基于内容 hash 的缓存键变化。
为什么图片进入 Decoder 后仍受顺序影响
典型的多模态模型会先通过视觉编码器产生视觉特征,再通过投影层将其映射到语言模型可以处理的维度。统一序列可能类似:
[System 文本]
[User 文本]
[Image Start]
[Visual Token 1] ... [Visual Token M]
[Image End]
[Assistant 文本]
对 Decoder 而言,视觉 token 和文本 token 都处于同一条有顺序的位置序列中。在因果注意力模型里,第 i 个位置产生的 K/V 状态不仅与该位置的输入有关,也与它前面的完整上下文有关,可以简化理解为:
KV(i) = f(token[0], token[1], ..., token[i])
所以,相同图片在不同上下文位置出现时,可能具有相同的视觉编码结果,却不一定具有相同的 LLM KV 状态。
请求 A:[System][文本 A][图片 X][文本 B]
请求 B:[System][文本 C][图片 X][文本 B]
图片 X 的视觉编码可能相同,但它前面的文本已经变化,因此从首次变化的位置开始,Decoder 的 KV 前缀通常不能复用。
两层缓存的命中条件
Vision Encoder Cache 通常用于避免反复执行图片解码、预处理、patch 切分、视觉编码器推理和特征投影。缓存键可能由图片内容、预处理参数、输入分辨率、视觉编码器版本及投影层版本共同决定。
如果同一图片在多个请求中重复出现,即使位于不同对话轮次,仍可能复用视觉编码结果。但这只表示视觉模块少算了一次,不代表语言模型的 KV cache 已命中。
LLM KV Prefix Cache 复用的是 Transformer 已经计算出的 Key/Value 状态。它通常要求模型与推理配置兼容、prompt 模板与 system prompt 一致、工具定义及顺序一致、文本和视觉输入一致,并且各部分在序列中的位置与顺序一致。
最重要的规则是:KV cache 通常复用从序列开头开始的连续相同前缀,而不是在历史序列中任意寻找一个相同片段。
删除一张历史图片,为何影响其后的所有内容
假设第一次请求是:
[System]
[用户消息 1]
[图片 A]
[助手消息 1]
[用户消息 2]
[图片 B]
[助手消息 2]
[用户消息 3]
应用图片截断策略后,第二次请求变成:
[System]
[用户消息 1]
[图片 A 被删除]
[助手消息 1]
[用户消息 2]
[图片 B]
[助手消息 2]
[用户消息 3]
[图片 C]
两条序列在图片 A 原来的位置首次发生差异。因此,图片 A 之前的稳定前缀仍可能命中;从图片 A 的位置开始,后续 assistant 消息、user 消息和图片通常不能继续沿用原来的 KV 前缀。
即使图片 B 完全相同,也需要区分两件事:图片 B 的视觉编码结果可能命中 Vision Encoder Cache;但图片 B 所在位置的 Decoder KV 通常无法命中,因为此前的前缀已经改变。
这正是“图片编码可以复用”和“LLM 前缀无法复用”能够同时成立的原因。
滑动窗口为什么容易周期性打穿缓存
“只保留最近 N 轮中的图片”可以控制图片数量和上下文大小,却会持续改写历史:窗口向前滑动时,最早的一张图片被删除,较晚的图片和文本整体前移,再在末尾加入新图片。
它通常会呈现以下现象:
- 窗口未滑动时,cache ratio 较高;
- 窗口滑动的那一轮,cache ratio 明显下降;
- 对话越长,删除早期图片造成的后续失配越多;
- 图片越靠近序列开头,影响范围越广;
- 图片对应的视觉 token 越多,整体比例波动可能越明显。
所以,按最近轮次删除图片虽然直接,却不一定是最适合 KV cache 的上下文管理方式。
图片变化会不会影响 System Prompt 和文本命中
这取决于图片在序列中的位置。
如果输入顺序是 [System Prompt][User Message][Image][后续历史],只有图片变化时,图片之前的 System Prompt 和 User Message 仍可能命中;从图片所在位置开始,其后的文本与图片通常无法继续作为同一 KV 前缀命中。
如果输入顺序是 [System Prompt][Image][User Message],那么 System Prompt 仍可能命中,但图片之后的 User Message 通常也无法命中。
所以,不是“图片一变,所有文本都无法命中”,而是:图片之前的稳定前缀不受影响;从首次变化位置开始,其后的序列失去连续前缀复用条件。
同一图片被多轮引用时会发生什么
每轮都重新插入完整图片时,视觉编码可能被复用,但新追加位置仍需要生成 Decoder KV;同时 prompt 体积和重复视觉 token 会持续增加。
如果首次出现图片时为它分配稳定的 image_id,之后保持历史不变并使用稳定引用,那么后续请求主要在末尾追加文本,更有利于 KV cache。前提是应用层与模型能够可靠理解该引用关系。
最不利于前缀缓存的方式,是每轮重建图片列表并从历史中部清理旧图片。它虽然缩短上下文,却会从删除点开始使 KV 前缀失效,导致视觉编码缓存和 KV 缓存指标出现背离。
面向缓存的上下文设计
保持历史前缀不可变
已经发送给模型的历史内容,应尽量避免在后续请求中重写、删除或重新排序。把稳定内容放在前面,把变化集中在尾部:
稳定前缀:
System Prompt
+ 已确认的历史消息
+ 已出现图片的稳定表示
动态尾部:
本轮用户消息
+ 本轮新增图片
+ 本轮临时上下文
使用稳定图片标识并进行内容去重
可以基于规范化图片内容与预处理版本生成稳定标识。内容相同的图片应得到相同标识;但 URL 不适合作为唯一内容标识,因为 URL 和它指向的内容都可能变化。
感知哈希可以帮助识别“视觉上相同但字节不同”的图片,却不能据此直接断言模型编码结果可安全复用。视觉编码缓存仍应使用足以保证输入等价的键。
区分历史语义与视觉 payload
历史记录可以保存 image_id、图片描述、结构化元数据以及图片与任务对象的关系。真正需要模型重新查看时,再在动态尾部加入图片 payload。
自动描述可能丢失细节,因此不能把图片摘要视为原始视觉信息的完全替代。更稳妥的做法是把它作为检索与选择机制,而不是无条件替换图片。
按唯一图片而非出现次数管理配额
同一张图片被多轮引用时,应分别统计对话中的引用次数、唯一图片数量、本轮需要重新编码的图片数量,以及本轮进入 Decoder 的视觉 token 数量。仅按“出现次数”管理配额,容易产生不必要的重复输入。
避免从历史中部逐项删除
如果必须控制上下文大小,可以在稳定边界上进行整段摘要、开启新的缓存段、把旧历史压缩为版本固定的摘要块,或者在序列末尾追加新的状态快照。
摘要本身也会改变前缀,但在可控边界上偶尔重建一次,通常比每轮持续改写历史更容易监控和优化。
此外,动态日期、随机 ID、请求级追踪信息、顺序不稳定的工具定义、无序 Map 序列化和每轮变化的系统提醒,也都会打断前缀。不参与推理的动态元数据应移出 prompt;必须保留的动态内容尽量放在末尾。
如何正确监控 Cache Ratio
常见的 LLM KV 缓存读取率可以表示为:
KV Cache Read Ratio
= cache_read_input_tokens / total_prompt_input_tokens
不同服务商或网关对 prompt token 的定义可能不同。使用指标前,需要确认分母是否包含普通未缓存输入、cache read、cache creation、视觉 token、System Prompt、工具 schema 和服务端隐藏模板。
还可以同时观察:
KV Cache Write Ratio
= cache_creation_input_tokens / total_prompt_input_tokens
Uncached Input Ratio
= uncached_input_tokens / total_prompt_input_tokens
如果推理系统暴露视觉编码层指标,还应单独监控 encoder cache hit rate、视觉特征复用量、唯一图片数与图片去重率。不能用 Vision Encoder Cache 的命中率代替 LLM KV Cache Ratio,反之亦然。
缓存指标建议至少按模型版本、单轮/多轮、纯文本/多模态、图片数量、视觉 token 数量、对话轮次、是否发生图片淘汰、是否发生历史摘要、总输入长度和上下文构造策略版本拆分。只观察全局平均值,很容易掩盖“窗口滑动时突降、其他轮次正常”的周期性问题。
一个可复现的受控实验
为了确认图片截断对 KV cache 的影响,应固定模型版本、System Prompt、工具定义、文本内容、图片内容、预处理参数、请求间隔、推理参数和上下文构造代码版本,每次只改变一个变量。
| 实验组 | 第二次请求的变化 | 预期现象 |
|---|---|---|
| A | 完全相同 | KV 命中最高 |
| B | 只在末尾追加文本 | 历史前缀基本可复用 |
| C | 只在末尾追加图片 | 追加前的前缀可复用 |
| D | 删除最早图片 | 从删除位置起失配 |
| E | 删除最近图片 | 失配位置较晚,影响相对较小 |
| F | 图片不变但更换编码格式 | Encoder Cache 可能失配 |
| G | 图片相同但调整顺序 | 从首次换序位置起失配 |
| H | 历史保留 image_id,图片在尾部按需追加 | 检验稳定引用方案 |
每次调用应记录总 prompt token、cache read token、cache creation token、uncached token、视觉 token 数量、图片数量、唯一图片数量、首个上下文差异位置、Vision Encoder 是否命中、首 token 延迟、总耗时、输入成本与输出质量。
报告时应同时展示 token 加权总体命中率、请求命中率分布、按轮次变化曲线、发生图片淘汰与未发生淘汰的对比,以及延迟、成本和质量之间的权衡。不要只用“命中请求数/总请求数”表示缓存效果,因为命中少量 token 与命中大量 token 不应具有相同权重。
常见误区
相同图片一定能命中全部缓存。 相同图片只能说明视觉编码结果具有复用可能;它前面的上下文或位置不同,LLM KV cache 仍可能无法复用。
图片使用 Base64,因此 Base64 会被当成文本 token。 Base64 通常是传输编码,真正进入模型的往往是预处理后的视觉特征。具体行为仍应以所使用的模型 API 和推理服务实现为准。
删除图片只影响图片 token。 删除发生在历史中部时,它改变了后续 token 的上下文位置与注意力前缀,影响会延伸到后面的文本和图片。
有图片缓存就说明 KV cache 命中了。 视觉编码缓存和 LLM KV 缓存是两套不同机制,需要使用不同指标观察。
Cache Ratio 越高,方案一定越好。 缓存率还要与输出质量、上下文完整性、总输入量、首 token 延迟、总成本、显存占用和长会话稳定性共同评估。为了提高命中率而保留过多无关图片,同样可能增加资源消耗。
结论
多模态模型通常拥有独立的视觉编码器,图片也可能拥有独立的编码缓存。但当视觉特征被送入语言模型后,它们就成为统一 Decoder 序列的一部分,与文本共同参与因果注意力和 KV 状态计算。
因此,相同图片可能命中 Vision Encoder Cache,却不一定命中 LLM KV Prefix Cache;KV 前缀依赖从序列开头开始的连续一致性;删除历史图片会从删除位置起改变后续上下文;滑动窗口会周期性改写历史前缀;图片之前的稳定内容仍可命中,而图片之后的文本和图片通常无法继续沿用原有 KV 前缀。
真正有效的优化方向通常不是“为图片单独开缓存”这一句话,而是保持历史不可变、稳定图片引用、按内容去重,将动态视觉 payload 尽量放在序列尾部,并分别监控视觉编码复用与 Decoder KV 前缀复用。