上一篇:第 12 篇《重启不丢记忆》 | 下一篇:第 14 篇《一次服务很多人》
一句话导读:一次只生成一个词太慢,那就先猜几个、再让大模型一次性核对——猜对的直接白赚,猜错的无损丢弃。本篇讲清它的直觉与算术。
关键词:推理引擎入门、大模型推理、草稿(draft)、验证(verify)、接受长度、回退
第 12 篇把"记忆"存到硬盘上,解的是"重启"这一种等待。回到最日常的等待:逐词生成一次只吐一个词。能不能一次多吐几个?这一篇的"草稿 + 验证"就是这个思路——对结果无损,但对速度不打包票。
① 一句话概念
先猜几个词,再一次核验;猜对就白赚。
② 起点:抢答游戏里的一次性交卷
想象一个抢答游戏。主持人问完题,你心里没底,于是先把四个答案一口气写在答题板上。主持人不是一个一个判,而是拿过去一次看完:"第一个对、第二个对、第三个错了。"你答对几个就前进几格,还能额外白拿一格——对了两个就站到第三格,后面作废。
所以值不值全看"押得准不准":押得准,一次核验换好几格;押不准,那四个白写。还有个前提——主持人得能一次性看完这四个,否则还不如一个一个答。
③ 伪代码:先猜 4 个,再一次性核验
函数 生成(提示词, 大模型, 草稿器) -> 词序列: 输出 = [提示词] 当 没有遇到结束符: 草稿 = 草稿器.猜(输出, 4) # 便宜,先猜 4 个 判定 = 大模型.一次并行检查(输出, 草稿) # 一次前向,不是四次 m = 判定.接受前几个(草稿) # 遇到第一个不同就停 输出.追加(草稿[0 : m]) # 猜对的,照单全收 输出.追加(判定.真实下一个词) # 断点处用大模型自己的结果 # 下一轮从第 m+1 个之后继续 返回 输出 # 代价: 每轮 1 次大模型前向 ↔ 前进 1 ~ 5 个词逐行要点:
草稿器.猜(输出, 4):草稿器不必另配小模型——本引擎的办法是翻历史:把上下文末尾几个词当窗口,在更早的历史里找一模一样的片段,跟在它后面的词就是候选。它便宜、不占参数,猜错不花钱。大模型.一次并行检查(输出, 草稿):把这 4 个词当成"一段 4 个词的输入"一起送进去,权重只读一遍,同时得到每个位置"模型会选的下一个词"。这是省钱的根源——一次前向覆盖四个位置。m = 判定.接受前几个(草稿):逐位比对:草稿里第 i 个词是否正好等于模型在该位置会选的词?一旦不同就停。这样结果与"老老实实逐词生成"逐位相同。输出.追加(...)那两行:接受的前 m 个照单全收;断点处(第 m+1 个)换成模型自己的真实结果。所以即使猜错,也绝不会输出错误内容——只损失速度,不损失正确性。- 最后那行注释:每轮固定花掉一次前向,能前进 1+m 个词;m 平均偏小时,比"逐词生成"更亏。注意:这里省下的是前向次数,它未必等于省下的时间——每次前向多贵,还得另算。
草稿、验证、接受与回退的关系如图 1 所示。
图 1猜 4 个 → 一次验 4 个 → 接受前 m 个:草稿器先产出 4 个词,大模型一次并行判定;前 m 个(m = 2)打勾接受、第 m+1 个打叉丢弃,再沿回退箭头继续下一轮。
④ 纸笔实验(必做)
任务:草稿器每轮猜 4 个词,"一次并行检查 4 个词"记作 1 次前向。按"本轮接受 0 个 / 2 个 / 4 个"三种情况,算这一轮花了几次前向、前进几个词,再和"逐词生成"比一比省了几次。
- 接受 0 个:断点处那 1 个词要前进,花 1 次前向,和逐词生成 1 个词打平。
- 接受 2 个:前进 3(2 个接受 + 1 个断点),花 1 次前向;逐词生成 3 个词要 3 次 → 省 2 次。
- 接受 4 个:4 个全接受、再白赚断点处 1 个,前进5个词,花 1 次前向;逐词生成 5 个词要 5 次 → 省4次。
预期结果:接受 0 个是"1 次对 1 次",接受 2 个是"1 次对 3 次",接受 4 个是"1 次对 5 次"。收益随平均接受长度上升,接受 0 纯亏——真问题是"什么场景下接受长度才够高"。
三种接受情况的对比如图 2 所示。
图 2接受 0/2/4 个时,省了几次大模型调用:横轴是"大模型前向次数";上方是实心灰条"逐个生成(基准)",占满 4 格;下面三条对应接受 0/2/4 个,各占 1 格。
可选 REPL 版:
# 每轮猜 4 个,"一次并行检查"固定算 1 次大模型前向def总前向(每轮接受,轮数):前向=0前进=0formin每轮接受[:轮数]:前向+=1# 一次并行检查 = 1 次前向前进+=m+1# 接受的 m 个 + 断点处 1 个return前向,前进# 例:每轮接受 = [0, 2, 4] → (3, 9)# 追问:同样的 9 个词若逐词生成,需要 9 次前向(省下 6 次)⑤ 进阶锚点
进阶锚点:本篇概念在《30 天手搓推理引擎》Day 13里被真正实现——
13-1 decode 为什么慢:逐词、带宽、不可并行/13-2 草稿 + 验证:spec decode 的实现/13-3 回退与收益边界:哪些场景 spec 才划算。
入门版到这里就够了;进阶版会多出:草稿构造(翻历史找重复片段)、批量验证与"无损回放"的 KV 回滚逻辑,以及板端开/关投机解码的逐字节一致性实测与收益边界(引自进阶系列源码与文档口径)。
想动手 → 仓库https://gitee.com/pei-xiaoguang/kestrel-llm,从 Day 1 开始。
下篇预告:这一篇我们优化的是"一个请求"。下一篇换个角度:一次服务很多人——不是把一个人服务到底,而是每一轮给每个在等的请求都各发一个词。