上一篇:第 10 篇《长上下文:平方级代价与"挑着看"》 |下一篇:第 12 篇《重启不丢记忆》
一句话导读:大模型推理里,如果新问题的开头和上一轮一模一样,上一轮算过的部分就能直接拿回来用——判断"一样"靠给开头算一个前缀指纹(prefix fingerprint),存这些结果的地方叫前缀缓存(prefix KV cache)。
关键词:推理引擎入门、大模型推理、多轮对话、前缀(prefix)、前缀指纹、前缀缓存、逐位相同
前两篇把"逐词生成"和"长上下文"的坑都踩过了。现在放进真实场景:聊天。聊到第二轮、第三轮,有时开头明显短、有时又没快多少。规律不取决于运气,取决于两轮的开头是否逐位相同。
① 一句话概念
开头一样,上一轮算过的就能直接复用。
② 起点:老师批改同一份作业的修订版
想象你是一位老师,学生交来一篇作文。你从头到尾读了一遍,在每段旁边做了批注。第二天,同一个学生又交了同一篇作文的修订版:第一段原封不动,只有第三段改了两句。你会怎么批?
你不会把第一段从头再读一遍——昨天读过,批注还在,直接从改动的地方往下看就行。省下的力气很实在:作文越长、改动越靠后,省得越多。但这有个硬前提:修订版的前面部分确实和昨天一模一样。如果交来的是一篇全新的作文,哪怕标题、主题相同,只要第一段换了写法,旧批注就一点用不上。
还有两条现实约束。第一,桌上摊不开太多份作业,昨天批过的得收起来——哪些留、哪些收,需要一套规则。第二,你只能从开头对齐:修订版如果是在中间插了一句,插入点往后的旧批注全都对不上,只能从插入点重来。
③ 伪代码:指纹命中就只补尾巴
函数 处理请求(本轮词序列) -> KV: 前缀指纹 = 指纹(本轮词序列[0 : 上一轮长度]) 若 前缀缓存.含有(前缀指纹): KV = 前缀缓存.取(前缀指纹) # 命中,直接复用 新增 = 本轮词序列[上一轮长度 : 末尾] KV = 继续算(KV, 新增) # 只算新增的尾巴 否则: KV = 从头算(本轮词序列) # 全部重算 前缀缓存.存(指纹(本轮词序列), KV) -> KV逐行要点:
指纹那行比的是数字序列,不是文字。词(token)是文字切块查表后的编号,指纹(fingerprint)是这段编号的"短代号",内容一样代号就一样。文字看着相同不算数——切块方式不同,编号就可能不同(第 18 篇会讲切块)。若 前缀缓存.含有(...)这行的意思是:这把钥匙能不能开门。命中就用上一轮的 KV 接着算,没命中只能从头。所以"第二轮更快"不是必然的——得看两轮开头是否逐位相同。新增与继续算:只算尾巴。省下的是首字时间(从提问到看见第一个字要等多久),不是吐字速度。- 最后一行把这一轮的结果也存起来。存得越多,命中机会越多,占的地方也越多——所以必须有一套淘汰(eviction)规则,把"最久没用过"的收走。
两轮的词序列怎么对齐、接头在哪,如图 1 所示。
图 1两轮对话的词序列:复用区 + 新增区:上面一条是第一轮的词序列,橙色,标"从零开始算一遍";下面一条是第二轮,前段灰色标"复用"(与第一轮逐格对齐),尾段绿色标"新增"。左边那道竖向虚线表示"整段搬过来",两条的接头位置就是"只补尾巴"的起点。
缓存槽位怎么从命中一路走到淘汰,如图 2 所示。
图 2缓存的一生:命中 → 复用 → 变老 → 淘汰:一排缓存槽位,被当前请求命中的那个高亮显示;随着新请求进来,久没被用到的先变暗(变老),最后被打叉收走(淘汰),腾出地方给新段落。箭头自左向右,表示"新来的挤掉最旧的"。
④ 纸笔实验(必做)
两轮对话:第一轮 100 个词,第二轮 120 个词,前 100 个完全相同。数一数两种做法各要处理多少个词:
- 不复用:第一轮 100 + 第二轮 120 =220个词。
- 复用:第一轮 100 + 第二轮只算新增的 20 =120个词。
预期结果:220 与 120。
单看第二轮,处理量从 120 降到 20,快 6 倍;两轮合计少处理 100 个词,约省下 45%。
必须记住的提醒:这里假设"前缀逐位相同"。哪怕只改一个标点,切块后编号就可能变,指纹对不上,复用立刻落空——第二轮又变回 120 个词。
可选 REPL 版(Python 伪代码):
第一轮 = 100 第二轮 = 120 不复用 = 第一轮 + 第二轮 复用 = 第一轮 + (第二轮 - 第一轮) print(不复用, 复用, 第二轮 / (第二轮 - 第一轮)) # 预期 220 120 6.0⑤ 进阶锚点
进阶锚点:本篇概念在《30 天手搓推理引擎》Day 11里被真正实现——
11-1 多轮对话的浪费:上一轮 prefill 算完就被扔了/11-2 前缀缓存键:怎么知道"两轮一样"?/11-3 缓存的一生:内存、容量与淘汰。入门版到这里就够了;进阶版会多出:真实的首字时间前后对比读数、"缓存键"具体怎么定,以及内存涨跌与淘汰策略的实测。
想动手 → 仓库
https://gitee.com/pei-xiaoguang/kestrel-llm,从 Day 1 开始。
下篇预告:第 12 篇更狠一点——如果连进程都重启了呢?内存里的记忆会全部消失。我们要给它做个"存档"。