一、缓存怎么实现:存下运算结果,下次直接当入参

本质:大模型推理是一串矩阵运算。缓存 = 把之前算好的中间结果(KV 矩阵向量)存下来;下次算新内容时,把这些向量直接当入参丢进下游公式,历史原文不再重算。

根本原因:运算是确定性的——同样的文字 + 同样的模型权重,算出的中间结果必然相同;且历史文字的中间结果只取决于它自己,与后面问什么无关,所以可以存下来反复复用。

flowchart LR
A["历史原文 (仅首次过一遍)"] --> B["矩阵运算<br/>得中间结果: KV 向量"]
B --> C["存入显存"]
C -- "直接当入参" --> E["下游公式"]
D["新内容"] --> E
E --> F["出新结果 不重算历史"]

例子(草稿纸):连环数学题,第一步算出中间结果 X=5 写在草稿纸上;第二步直接拿 5 当入参继续算,不会重新推导 X 怎么来的。缓存就是”草稿纸上的数字”,大模型读的是数字,不是原文。

二、缓存的两种用法:隐式 vs 显式

隐式(系统自动复用前缀)

sequenceDiagram
participant C as 客户端
participant E as 推理引擎
participant V as 显存 KV
C->>E: 请求1: 系统提示词 + Q1
E->>V: 从头算 KV 并存储
E-->>C: 返回答案1
C->>E: 请求2: 系统提示词 + Q2
E->>V: 前缀匹配! 直接读 KV
E-->>C: 返回答案2 (只算新增)

例子:System Prompt”你是专业客服”每轮自动复用,不用改代码。

显式(主动寄存,凭 ID 取用)

sequenceDiagram
participant C as 客户端
participant P as 厂商存储池
participant E as 推理引擎
C->>P: 上传 500 页手册, 请求缓存
P-->>C: 返回 Cache ID: abc123
C->>E: 问题 + ID (不传全文)
E->>E: 凭 ID 调出 KV 当入参
E-->>C: 返回答案 (读取费率极低)

例子:全公司员工提问都带同一个 ID,与会话 ID 无关。

三、一台机器装不下时:多机怎么协作

痛点:对话越长,”握手”次数越多(生成变慢),KV 向量越积越多(撑爆显存)。

前提:矩阵乘法天然支持”分块算、再合并”——分开算与一台机器串行算数学上完全等价,所以”大公式”才能拆给多台机器。

1. 张量并行(切参数矩阵)

flowchart TD
M["某层权重矩阵 (单卡装不下)"] --> S1["切片1"] & S2["切片2"] & S3["切片3"] & S4["切片4"]
S1 --> G0["GPU0 算自己那份"]
S2 --> G1["GPU1 算自己那份"]
S3 --> G2["GPU2 算自己那份"]
S4 --> G3["GPU3 算自己那份"]
G0 & G1 & G2 & G3 --> R["合并 = 完整结果"]

例子:4 人分算一张巨型乘法表,每人算 1/4,拼起来等于一人算完。

为什么拼起来不会出问题?

数字例子:输入 x = [1, 2],权重 W = [[3, 5], [4, 6]],单卡串行结果 = [11, 17]。

flowchart TD
X["完整输入 x=[1,2] (广播给所有卡)"] --> G0["GPU0 拿第1列 [3,4]<br/>算出第1格 = 14"]
X --> G1["GPU1 拿第2列 [5,6]<br/>算出第2格 = 15"]
G0 --> R["按位置拼好"]
G1 --> R
R --> O["[11, 17] = 单卡串行结果"]

补充:也可以横着切——每卡拿部分输入和部分权重,算”部分贡献值”,最后相加(乘法分配律,同样精确)。业界实际两种切法组合使用。

2. 流水线并行(切网络层)

flowchart LR
D["输入"] --> G0["GPU0<br/>层1-25"] --> G1["GPU1<br/>层26-50"] --> G2["GPU2<br/>层51-75"] --> G3["GPU3<br/>层76-100"] --> O["输出"]

例子:汉堡工厂 A 做面包、B 煎肉饼、C 组装、D 打包;微批处理让多个”汉堡”同时在线上流动,所有卡不闲着。

为什么等价:模型的层本来就是逐层串行执行的,切层只是让不同机器接力执行同一条计算链,每步计算内容不变,天然等价。唯一问题是效率(有卡空等),用微批处理解决。

3. 上下文并行(切长文本,环形传阅 KV)

flowchart LR
C1["GPU0<br/>存1-25万字 KV"] --> C2["GPU1<br/>存25-50万字 KV"] --> C3["GPU2<br/>存50-75万字 KV"] --> C4["GPU3<br/>存75-100万字 KV"] --> C1

例子:4 人各持 1/4 会议纪要,围成一圈传阅;传完一圈每人都”读”过全部纪要,手里只存 1/4。

为什么等价:注意力是”新词与历史词逐个握手”,而握手可以分段算、再累加(像累加求和)。每卡先算新词与自己那段的局部握手,KV 沿环传阅时逐段累加局部结果,传完一圈 = 单卡看完全文的结果。

4. 调度约束

四、推测解码提速

flowchart TD
A["小弟 (小模型/浅层)<br/>高速盲猜 5 词"] --> B["大哥 (完整模型)<br/>一次性并行验证"]
B --> C{"全部正确?"}
C -- 是 --> D["5 词瞬间输出"]
C -- 否 --> E["丢弃重算 保证无幻觉"]

例子:猜”今天天气真不错”全对 → 瞬间输出;猜”烤地瓜”错 → 丢弃重算。

接受率:代码/数学等规律性场景命中率高 → 提速显著;闲聊命中率低 → 校验开销可能拖慢。

演进(Early Exit):大哥前 20 层当小弟,与深层共享同一份完整 KV 向量,解决独立小模型”缺上下文”的痛点。