流式多模态模型(streaming MLLM)面对的输入是持续到达的视频片段,而不是一次性给完的完整视频。这带来一个直接的矛盾:思维链推理(Chain-of-Thought)需要”想完再说”,而流式场景要求”边看边说”。
一个朴素的基线
最直接的做法是让模型在每个时间步都完整重复一次推理:
写成伪代码大概是这样:
for frame in video_stream:
chunks = model.infer(frame) # 每帧都重新推理
for chunk in chunks:
emit(chunk)
问题很明显:第 步重复了前 步已经做过的推理,计算量随时间线性甚至超线性增长,而且重复的内容会让输出抖动。
三个观察
1. 推理可以增量缓存
KV cache 的复用不只是工程优化,它让”同一段推理只做一次”成为可能。一旦缓存住,第 步只需要计算增量部分:
这里 表示时刻 的推理状态。实践中我们发现,状态的更新量远小于状态本身,这给了我们近似丢弃旧状态的空间。
2. 冗余推理比迟到推理更糟
一个反直觉的现象:如果一段推理在 时刻已经算出来,但模型选择等到 才说出口,用户的体感比”晚一点想到”更差。因为在流式交互里,输出节奏本身携带信息。
| 策略 | 首字延迟 | 重复率 | 体感 |
|---|---|---|---|
| 全量重算 | 高 | 100% | 抖动 |
| 增量缓存 | 低 | 低 | 平滑 |
| 缓存 + 延迟输出 | 低 | 低 | 迟钝 |
3. 什么时候该”重新想”
不是所有时候都值得增量更新。当输入发生语义跳变时(例如镜头切换),缓存里的推理状态已经不再成立,此时反而应该丢掉缓存重算。
我们的实验里,一个简单但有效的判据是推理状态之间的距离超过阈值就重算。
还没解决的问题
- 阈值 怎么选?它和任务、视频长度、帧率都有关联,目前只能靠验证集调。
- 缓存状态的漂移。长时间运行后,累积误差会让状态偏离真实推理,越到后面越难纠正。
- 评测指标。流式场景下 BLEU / CIDEr 这类静态指标几乎失效,我们需要能同时衡量”及时性”和”内容一致性”的指标。
小结
流式 CoT 的核心矛盾不是”怎么算得更快”,而是怎么让推理过程本身变得可增量、可丢弃、可复用。这比单纯优化吞吐要难,但也更有意思。