LLM 推理全链路:从提问文本到输出 Token

一次 LLM 提问从文本到输出的完整旅程:Token 化、Embedding、GPU 计算、KV Cache、LM Head 与自回归采样。

LLM 用户提问的完整流程:文本 → Embedding → 模型计算 → 输出。这篇文章拆开每一步,并补充工程与硬件层面的细节。

极简流程

1用户提问文本
2→ Tokenizer → token ids
3→ 查表得到 FP16/BF16 高维 Token Embedding 向量 + 位置编码
4→ CPU → GPU 显存 → 送入 SM 计算单元循环多层 Decoder
5→ 输出隐藏特征向量 → LM Head 映射为词表概率 logits
6→ 采样选出 token,循环自回归生成
7→ token 序列解码 → 可读文字输出

一、你的提问会被转换成什么向量(Embedding)

这里有两套完全不同的向量,不要混淆:输入 Token Embedding(LLM 原生)检索 Embedding(RAG 配套)

1. LLM 原生输入向量(推理必走,每轮对话都有)

1)先分词(Tokenizer)

你的句子切为 token id(数字,如 你=123,好=456)。

2)Token Embedding 层(模型第一层权重矩阵)

  • 矩阵尺寸:[词表大小 V, 隐藏维度 d_model]
  • 举例常见模型:
    • LLaMA2 / Qwen:d_model=4096 / 8192,向量是 FP16/BF16(极少 FP32)
    • 小参数量开源模型:d_model=768 / 1024 / 2048
  • 每个 token id 查表取出一行,得到 d_model 维浮点数向量
  • 向量含义:语言语义;位置信息会叠加位置编码(RoPE/ALiBi)

重点:这不是检索向量,是 Transformer 底层特征向量,维度极高(4k+),不用于向量库检索。

2. RAG 检索用 Embedding(只有知识库场景才会生成)

如果带文档检索,你的提问会单独丢给专用 Embedding 模型(bge、e5、all-MiniLM):

  • 维度低:384 / 768 维
  • 存储格式:FP16 / INT8 / INT4 量化压缩
  • 用途:去向量库做相似度匹配召回文档,不进大 LLM 主 Transformer 计算

3. 存储精度

线上推理几乎全部:

  • Token Embedding:BF16 / FP16(显存减半,速度翻倍)
  • 只有训练、高精度微调才用 FP32

二、向量如何进入模型计算区域(GPU/显存流转全过程)

阶段 1:CPU 预处理

  1. 用户文字 → token ids(CPU 内存)
  2. 查表取出 embedding 向量、叠加位置编码(CPU 或 GPU)
  3. 组装输入张量:[batch_size, seq_len, d_model]
    • 比如单条提问长度 2048 token,d_model=4096 → 张量 shape [1, 2048, 4096]

阶段 2:数据搬运进 GPU 计算区

  1. CPU 内存张量通过 PCIe 拷贝到 GPU 显存(Global Memory)
  2. 推理框架(vLLM / TensorRT / Transformers)做内存优化:
    • 连续内存排布、padding 合并、KV 缓存预分配
  3. 计算调度:
    • 显存向量分批送入 SM 流多处理器(计算核心)
    • 向量数据先缓存到 L2 Cache → 片上共享内存/寄存器(高速计算区)

核心:真正矩阵乘法(Attention、FFN)全部在 GPU 寄存器/片上缓存完成,显存只做存储交换。

阶段 3:Transformer 多层循环计算(核心区域)

输入向量逐层穿过 N 层 Decoder:

  1. 多头 Self-Attention:输入向量 × Q/K/V 权重矩阵 → 注意力分数 → 加权融合特征向量
  2. FFN 前馈网络:特征升维映射、激活、降维回原维度
  3. LayerNorm、残差连接:每层输出依然是同维度 [seq_len, d_model] 向量,逐层更新语义特征

关键缓存:KV Cache(生成必备)

每轮提问的 key/value 向量会存入显存 KV 缓存,后续生成新 token 不用重复计算历史输入,大幅提速。

三、模型如何输出文字(向量 → 可读文本)

步骤 1:最后一层输出隐藏向量

Decoder 最后一层输出依旧是 [seq_len, d_model] 高维特征向量。

步骤 2:LM Head 线性投影(关键输出层)

权重矩阵 [d_model, V 词表大小],做矩阵乘法:高维语义向量 → 长度等于词表 V 的 logits 向量(几万维)。例:Qwen 词表 151936,logits 维度=151936。

步骤 3:采样生成单个 token

  1. logits 做 Softmax,转为每个 token 的概率分布
  2. 根据采样策略(greedy / top-p / top-k)选出概率最高的 token id
  3. 把这个 token id 追加到输入序列,重新走一轮前向计算(自回归生成)

步骤 4:循环直到终止

不断生成新 token,直到产出终止符 </s>,停止迭代。

步骤 5:解码输出文本

收集所有生成的 token id,送入 Tokenizer 反向解码,转回自然语言,返回给用户。

四、完整九步链路(含工程与硬件细节)

1. 用户提问文本输入

用户原始自然语言(中文/英文混合),包含空格、标点、特殊符号。额外前置操作:

  • 预处理清洗:剔除不可见控制字符、统一换行/空格格式、截断超长文本(不超过模型上下文窗口上限,如 8k / 32k tokens)
  • 拼接完整 Prompt:系统提示词 + 历史对话上下文 + 当前用户 Query

2. Tokenizer 分词编码 → 得到 Token IDs

使用模型配套 BPE / SentencePiece 分词器处理完整 Prompt:

  1. 按训练时的词表规则切分为最小子词单元(token),中文会单字/词语混合拆分
  2. 映射每个 token 为唯一整数 Token ID
  3. 补充特殊标记:句首 <bos>、句尾 <eos>、填充 <pad>,生成一维 ID 数组
  4. 输出 CPU 内存上的 [batch, seq_len] 整型张量(batch=1 单轮对话)

3. 查表获取 Token Embedding + 叠加位置编码

两者均为模型内置权重矩阵,常驻 CPU,推理时拷贝至 GPU 显存:

  1. Embedding 查表:权重矩阵 shape [词表总量, 隐藏层维度](例如 152k × 4096);根据所有 Token ID 索引矩阵对应行,取出每个 token 的 FP16/BF16 高维向量,得到张量 [1, seq_len, hidden_dim]
  2. 位置编码融合:LLM 无法感知文字顺序,预计算正弦余弦/可学习位置向量,shape 与 Embedding 完全一致;向量逐元素相加融合,携带时序位置信息
  3. 此时得到完整输入特征张量,仍存在 CPU 内存

4. CPU 张量拷贝至 GPU 全局显存

  1. 执行 CUDA 内存拷贝(cudaMemcpy),将融合后的 Embedding 张量从主机内存搬运至显卡全局显存
  2. 配套分配显存空间:提前预分配 KV Cache 缓存区(Decoder 推理核心,存储每一层历史注意力 key/value 向量,大幅减少重复计算)
  3. 同步 CPU/GPU 指令流,等待拷贝完成后才启动计算

5. 调度张量送入 GPU SM,循环执行多层 Decoder

一张 NVIDIA GPU 由数十个 SM 并行组成,调度器分片分发张量至所有 SM 协同计算:

  1. 单块 SM 内部硬件:CUDA Core(通用浮点运算)、Tensor Core(AI 矩阵乘法专用加速单元,LLM 核心算力)、片上高速 Shared Memory
  2. 逐层循环执行 N 层 Decoder(如 32 层、40 层),每层固定流程:
    • 多头自注意力:读取 KV Cache,计算 Query-Key 相似度,Softmax 归一化权重,加权融合 Value 向量
    • FFN 前馈网络:高维向量升维、激活函数、降维
    • 残差连接 + 层归一化 LN
  3. 中间计算数据优先存放 SM 片上 Shared Memory(读写速度远高于全局显存),仅中间结果写回显存更新 KV Cache
  4. 全部层计算完成,输出序列末尾的隐藏特征向量(自回归仅取最后一个 token 特征用于预测下一词)

6. LM Head 线性层映射,输出词表概率 Logits

LM Head 是一个线性权重矩阵,存储在 GPU 显存:

  1. 输入:单层 Decoder 输出的末尾隐藏向量 [1, hidden_dim]
  2. 矩阵乘法映射至词表维度,输出 [1, vocab_size] 的原始得分 Logits
  3. 可选预处理:对 Logits 做温度缩放、Top-P / Top-K 截断,屏蔽 <pad> 等无效 token 得分

7. 采样算法选出单个新 Token ID(自回归核心循环)

对 Logits 概率分布采样,两种主流方案:

  1. 贪心采样:直接取分数最高的 token
  2. 随机采样(TopP / TopK):筛选高分 token 后随机选取,回答更有创造性

输出单个整数 Token ID。

8. 循环推理(关键:迭代生成整段回复)

  1. 将刚生成的 Token ID 追加到原始输入序列尾部
  2. 仅对新增的 1 个 token 重复步骤 3~7(复用历史 KV Cache,不用重新计算整段上下文,大幅提速)
  3. 循环迭代,直到采样出 <eos> 终止标记,停止生成

9. Token ID 序列解码 → 可读自然文字

  1. 收集全部生成的 Token ID 序列,送入 Tokenizer 反向解码逻辑
  2. 根据词表映射 ID 还原子词,拼接合并为完整句子
  3. 自动清理分词产生的特殊分隔符、空白冗余字符,输出人类可读回答

五、容易被混淆的区分

  1. LLM 内部 Token Embedding:维度极高(4096+)、FP16/BF16,只给 Transformer 计算,不存向量库
  2. RAG 检索 Embedding:低维(384/768),专门相似度计算,不进大模型主干
  3. 内存占用举例(2048 上下文,d_model=4096,FP16):单条输入向量 1 × 2048 × 4096 × 2B = 16,777,216 B = 16MB,换成 FP32 直接翻倍 32MB

关键工程点

  1. KV Cache:Decoder 自回归推理性能的核心——没有它每一轮都要重算全部上下文,速度暴跌几十倍
  2. 硬件分层差异:全局显存(低速,存全部权重/KV 缓存)→ SM 共享内存(高速,临时计算),向量读写存在明显的层级速度差距
  3. 精度细节:BF16 多用于模型权重存储,FP16 多用于中间计算,两者算力、数值范围有区分
  4. Batch 逻辑:多用户并发时会批量拼接多个 Prompt 送入 GPU,单轮对话 batch=1
  5. 计算与 IO 阻塞:CPU-GPU 数据拷贝会占用耗时,大维度向量(如 4096 维)传输开销不可忽略
由 Hugo 构建,Cloudflare Pages 自动部署。