SH

Soloharness

概念 · 辨析 · Agent

← 返回概念辨析

Concept Contrast Fable

预填充和解码阶段,一个整批输入一口吞,一个字一个字往外吐

预填充是推理的第一个阶段,把全部输入 token 一次性并行处理。解码阶段紧随其后,逐个自回归生成输出 token。有人讨论时把 prefill 简称为推理的那个「输入处理」,但 decode 才是真正产出了用户看到的结果——两个阶段的工程特征完全不一样。

寓言

一个灶台两口锅,一口猛火爆炒整锅料,一口文火慢炖逐勺盛

镇上有一家专做官宴的酒楼,后厨主灶由两兄弟掌管。哥哥管炒锅:食材一起下锅,旺火快翻,三两分钟出锅入盘——备菜要齐,少一味不开火。弟弟管汤锅:汤底早上熬好,客人点单时拿长勺一勺一勺盛进碗里,每勺都要看汤面油花和碗底料,不能急。

酒楼的效率全在后厨的衔接上。炒锅炒得快的时候,一锅接一锅推,十张桌子的菜同时出锅。但汤锅慢——每碗都要单独盛、单独看、单独加料。炒锅和汤锅中间有个传菜台,炒好的菜堆在那里等,每次卡住的都是汤锅那一边。

有一阵子酒楼接了很多大型寿宴——单张桌子菜量极大。炒锅的料量从一人份飙到整桌份,锅还是那个锅,火力没变,但翻一锅的时间长了近三倍。汤锅单碗速度没变,整体等更久。后厨主管把等菜投诉一条条翻出来,发现七成投诉不是因为上菜慢,是因为「菜和汤的间隔太大」——炒菜到了,汤还要等很久。

主管做了两件事。第一件是强化炒锅的备菜标准——菜量再大,备菜必须在两分钟内上齐,不要出现锅在火上烧着但缺一味料的空等。第二件是给汤锅加了一个保温分装台——汤锅主汤先在保温台里预盛到十只碗中,每次客人下单只需最后调味和点缀,把最慢的那端提速。

修正以后,寿宴的差评消失了。后厨的主管跟新来的学徒讲:炒锅是整个输入一次性并行处理——它吃的是计算密度,菜量越大对所有料在锅里的时间差要求就越苛刻。汤锅是逐个输出——它吃的是单步流畅度,提速的办法是减少单步之间的准备时间。一个厨房两个锅,但你往炒锅里放新鲜菜的时候汤锅照样在动,它们互相不暂停。

主管把这套经验写进后厨手册:炒锅吃的是备菜一次到位和旺火翻炒,汤锅吃的是每一勺之间不断档。炒锅慢,多半要查备菜和火力;汤锅慢,多半要查分装台和盛汤节奏。两口锅卡住的地方不同,修法也不同。

后来有人问主管,能不能把炒锅和汤锅合并成一口锅?主管想了想说炒锅大火短时,汤锅文火长时——放在同一个介质上只会让两样都做不好。你能做的,是让炒锅炒完以后的热菜直接滑进汤锅旁的传菜槽,中间不用凉盘重装。边界不动,流转要通。

预填充

推理的第一个阶段。整个输入序列的 token 一次性并行处理,计算所有 token 的注意力,输出第一个 token 的生成状态。吞吐导向,算力密集型。

解码阶段

推理的第二个阶段。逐个自回归生成输出 token,每一步计算新 token 对历史的注意力。时延敏感,内存访问密集型。

故事对应

  • 炒锅(猛火爆炒):prefill——全量输入 token 并行计算注意力
  • 汤锅(文火慢炖、逐勺盛):decode——逐个 token 自回归生成
  • 传菜台堵塞:prefill 快但 decode 慢导致用户感知延迟
  • 大型寿宴炒锅翻三倍时间:长输入的 prefill 延迟增长
  • 炒锅备菜标准强化:prefill 优化的关键是减少准备时间差
  • 汤锅保温分装台:decode 优化靠减少单步之间的等待间隔
  • 合并两口锅的讨论:prefill 和 decode 的计算特性不能混为一个核
  • KV 缓存复用:prefill 输出的中间状态直接传给 decode 不过冷重启

落到推理服务的延迟分析

用户觉得「模型反应慢」时,先分两个指标看:首 token 延迟和后续 token 间隔。首 token 延迟高说明 prefill 是瓶颈——输入太长或 batch 太大,需要优化 prefill 的并行策略。后续 token 间隔大说明 decode 是瓶颈——单步内存访问慢,需要优化 KV 缓存读写或尝试投机解码。服务监控面板上把 TTFT(首 token 时间)和 TPS(每秒生成 token 数)分开设面板,它们对应的是两段不同的优化路径。如果只优化了 prefill 就对延迟满意了,上线后长输出的场景会暴露 decode 的隐藏短板。