浅析大模型推理十二篇之Prefill-and-Decode

LLM 推理是系统设计与 AI 工程交汇之地:随着模型的不断升级,开源模型和商业模型的效率在不断逼近,2026 年开始,LLM 推理将进入新的阶段,开始从模型训练转向模型推理,为什么?数据统计模型的训练算力只占全球的 30%,而推理占 70%,这个比例将会继续增加,说明现在的开源模型已经大部分场景够用,最大的问题是如何将模型普及并让成本更低。

为此从去年的模型训练的一些总结,逐步转向模型推理的工程实践,最近一段时间也看了一些文章和书籍,于是我决定写一本手册,来介绍 LLM 推理的工程实践,预计分为 12 篇整体介绍推理,包括Prefill-and-Decode、KV cache、quantization、PagedAttention、FlashAttention、speculative decoding、parallelism strategies、vLLM、TensorRT-LLM 和 SGLang等。

前言

每次你向 ChatGPT、Claude 或 Gemini 发送消息时,几毫秒之内就会发生一件了不起的事。在某个数据中心里,一个拥有数十亿参数的模型被唤醒,读取你的文字,然后开始生成响应------一次一个 token,其成本在五年前看来简直不可思议。

构建 LLM 需要研究者的智慧来搭建正确的架构:在哪里使用 Attention,在哪里使用 Mamba 层,如果构建混合模型还需考虑其他层的选择。应该创建 MoE(Mixture of Experts)模型,还是让所有权重都处于激活状态?这些都属于研究层面的决策。

而模型构建完成后的 GPU 集群部署与运维------让它能够服务真实用户请求------则属于工程范畴,因此,LLM 推理与其说是研究,不如说是一门工程艺术。

在"推理"这个词的背后,存在着一个完整的工程学科------它决定了你的 AI 产品是快还是慢,是便宜还是昂贵,是可扩展还是脆弱,推理做得好不好,决定了你的产品只是一个令人惊艳的 demo,还是一个真正能存活的产品。

训练模型只发生一次,推理每天发生数十亿次,每一次低效都会累积叠加,每一个浪费的 GPU 周期都在烧钱,每多一毫秒延迟都在流失用户,这就是为什么世界上最顶尖的 AI 团队------Google、Meta、Anthropic、Mistral------都设有完整的工程组织,专门致力于让推理更快、更便宜、更可扩展。

什么是 prefill 和 decode?

当前最先进的模型是基于 decoder 的自回归模型(autoregressive model),这意味着它们基于之前的 token 来预测下一个 token,在预训练阶段,模型学习的就是基于前文 token 预测下一个 token。

Token 是大语言模型(LLM)处理和理解的基本文本或数据单元,模型并不逐个读取字母,而是将文本切分为更小的块,称为 token,一个 token 可以是一个完整的单词、单词的一部分(subword),或者单个标点符号。

当我们向 LLM 发送 prompt 时,模型首先在一次前向传播(forward pass)中处理整个 prompt,这个阶段称为 prefill ,读取完整 prompt 后,模型预测第一个输出 token,从发送请求到接收到第一个生成 token 的时间称为 TTFT (Time to First Token)。

此后,模型进入 decode 阶段,它一次生成一个 token,第一个生成的 token 成为 context 的一部分,然后模型预测第二个 token,第一个和第二个 token 成为 context 的一部分,然后模型预测第三个 token,以此类推,这个过程持续进行,直到模型达到 max_tokens 限制或生成 EOS(End of Sequence,序列结束符)。

只有经过 Prefill 和 Decode 这两个过程之后,我们才能从 LLM 得到最终的响应。

示例

Prompt:

复制代码
The capital of France

模型首先读取完整 prompt 并预测:

csharp 复制代码
is

此时 context 变为:

csharp 复制代码
The capital of France is

模型再次读取完整 context 并预测下一个 token:

复制代码
Paris

context 变为:

csharp 复制代码
The capital of France is Paris

然后模型预测下一个 token:

erlang 复制代码
.

接着预测:

xml 复制代码
<EOS>

最终输出为:

csharp 复制代码
The capital of France is Paris.

现在,对于每一个 token,模型中的 attention 层都会计算 K 和 V 向量。

Attention 简明示例:Query、Key 和 Value

在深入之前,让我们快速看一个 attention 如何工作的例子,以及 Query(Q)、Key(K)和 Value(V)向量分别是什么。

在模型预测下一个 token 之前,每个 attention 层为每个 token 创建三个向量:

  • Query(Q) :这个 token 在寻找什么?
  • Key(K) :这个 token 包含什么信息?
  • Value(V) :这个 token 应该向前传递什么信息?

让我们用一个很小的 prompt:

css 复制代码
I love AI

假设模型为每个 token 创建如下简单的 Key 和 Value 向量:

Token Key Vector K Value Vector V
I 1, 0 1, 0
love 0, 1 0, 2
AI 1, 1 3, 1

现在,假设当前 token 是 AI,其 Query 向量为:

ini 复制代码
Q_AI = [1, 1]

Attention 层使用点积将该 Query 向量与每个 token 的 Key 向量进行比较。

css 复制代码
Q × K^T,其中 K^T 表示 K 向量的转置

Q_AI · K_I    = [1, 1] · [1, 0] = 1
Q_AI · K_love = [1, 1] · [0, 1] = 1
Q_AI · K_AI   = [1, 1] · [1, 1] = 2

原始 attention 分数为:

css 复制代码
I     → 1
love  → 1
AI    → 2

这些分数经过 softmax 函数转换为概率:

css 复制代码
I     → 0.21
love  → 0.21
AI    → 0.58

这意味着 token AI 在分配 attention:

shell 复制代码
21% 的 attention 给 "I"
21% 的 attention 给 "love"
58% 的 attention 给 "AI"

现在模型使用这些 attention 权重来混合 Value 向量:

ini 复制代码
Attention Output =
0.21 × [1, 0] +
0.21 × [0, 2] +
0.58 × [3, 1]

最终输出约为:

css 复制代码
Attention Output ≈ [1.95, 1.00]

这个最终向量就是 token AI 的 attention 输出。

简单来说,attention 允许模型查看所有相关 token,决定每个 token 的重要性,然后组合它们的信息。

因此 attention 可以理解为:

vbnet 复制代码
将 Query 与 Key 进行比较 → 获得 attention 权重 → 混合 Value

这些混合后的信息随后在模型的下一层中继续传递,最终帮助预测下一个 token。

Decode 阶段的重复计算问题

Attention 会为 context 中的每个 token 计算 K 和 V 向量。

现在想象在 decode 阶段,如你所知,我们不断将输出 token 添加到 context 中,因此对于每个新的输出 token,我们需要重新计算 context 中所有先前 token 的 K 和 V 向量。

继续用上面的例子,假设我们给模型这个 prompt:

csharp 复制代码
The capital of France is

假设这个 prompt 有 5 个 token:

css 复制代码
[The] [capital] [of] [France] [is]

在第一次前向传播(prefill 阶段)中,模型为所有 5 个输入 token 计算 K 和 V 向量:

yaml 复制代码
Token 1: The      → K, V
Token 2: capital  → K, V
Token 3: of       → K, V
Token 4: France   → K, V
Token 5: is       → K, V

此后,模型预测第一个输出 token:

复制代码
Paris

Prefill 在此结束,Decode 现在开始。

context 变为:

csharp 复制代码
The capital of France is Paris

模型会再次处理完整 context,重新计算所有 token 的 K 和 V 向量:

yaml 复制代码
Token 1: The      → K, V  再次计算
Token 2: capital  → K, V  再次计算
Token 3: of       → K, V  再次计算
Token 4: France   → K, V  再次计算
Token 5: is       → K, V  再次计算
Token 6: Paris    → K, V  首次计算

然后模型预测下一个 token:

erlang 复制代码
.

context 变为:

csharp 复制代码
The capital of France is Paris.

模型会再次为完整 context 重新计算 K 和 V:

yaml 复制代码
Token 1: The      → K, V  再次计算
Token 2: capital  → K, V  再次计算
Token 3: of       → K, V  再次计算
Token 4: France   → K, V  再次计算
Token 5: is       → K, V  再次计算
Token 6: Paris    → K, V  再次计算
Token 7: .        → K, V  首次计算

并预测:

xml 复制代码
<EOS>

先前 token 的 K 和 V 向量保持不变,因此在每次 decode 步骤后重复计算它们是浪费的工作。

从第一性原理的工程角度思考:这个问题应该怎么解决?

如果某个计算很昂贵,而且结果会被反复使用,我们应该怎么做?

存起来。 下一篇讲 KV cache,如何有效解决重复计算的问题。

参考

(1)pub.towardsai.net/llm-inferen...

(2)handbook.modular.com/inference-o...

相关推荐
1名持续学习的码农13 小时前
GPT Plus、GPT Pro用户第一次用Codex,项目权限和Git分支怎么设置?
人工智能·git·gpt·elasticsearch·ai编程·codex
yuanyxh13 小时前
AI Agent 的使用进化史
agent·ai编程·claude
kyriewen14 小时前
Claude自己跑出去hack了3家公司——我为什么还在用它写代码
前端·ai编程·claude
西安小哥15 小时前
AI时代全栈面试通关指南:从背八股到聊架构
面试·ai编程
妙码生花15 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(四十八):菜单规则管理实现
前端·后端·ai编程
FantasticPerson15 小时前
46 · 综合实战:从零到上线,把所学串成一条线
ai编程·claude
windliang16 小时前
Claude Code 源码分析(四):Tool 工具系统-从 Schema 到真实执行
前端·ai编程·claude
Lx35216 小时前
用 TRAE Work 排查 Smartbi 报表数据不一致:从 3 小时缩短到 20 分钟
ai编程·trae
西安小哥16 小时前
用 TRAE 5 分钟生成一份客户能看的功能清单 Excel——l_prd_skills 实战复盘
产品经理·ai编程·产品