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 预处理
- 用户文字 → token ids(CPU 内存)
- 查表取出 embedding 向量、叠加位置编码(CPU 或 GPU)
- 组装输入张量:
[batch_size, seq_len, d_model]- 比如单条提问长度 2048 token,d_model=4096 → 张量 shape
[1, 2048, 4096]
- 比如单条提问长度 2048 token,d_model=4096 → 张量 shape
阶段 2:数据搬运进 GPU 计算区
- CPU 内存张量通过 PCIe 拷贝到 GPU 显存(Global Memory)
- 推理框架(vLLM / TensorRT / Transformers)做内存优化:
- 连续内存排布、padding 合并、KV 缓存预分配
- 计算调度:
- 显存向量分批送入 SM 流多处理器(计算核心)
- 向量数据先缓存到 L2 Cache → 片上共享内存/寄存器(高速计算区)
核心:真正矩阵乘法(Attention、FFN)全部在 GPU 寄存器/片上缓存完成,显存只做存储交换。
阶段 3:Transformer 多层循环计算(核心区域)
输入向量逐层穿过 N 层 Decoder:
- 多头 Self-Attention:输入向量 × Q/K/V 权重矩阵 → 注意力分数 → 加权融合特征向量
- FFN 前馈网络:特征升维映射、激活、降维回原维度
- 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
- logits 做 Softmax,转为每个 token 的概率分布
- 根据采样策略(greedy / top-p / top-k)选出概率最高的 token id
- 把这个 token id 追加到输入序列,重新走一轮前向计算(自回归生成)
步骤 4:循环直到终止
不断生成新 token,直到产出终止符 </s>,停止迭代。
步骤 5:解码输出文本
收集所有生成的 token id,送入 Tokenizer 反向解码,转回自然语言,返回给用户。
四、完整九步链路(含工程与硬件细节)
1. 用户提问文本输入
用户原始自然语言(中文/英文混合),包含空格、标点、特殊符号。额外前置操作:
- 预处理清洗:剔除不可见控制字符、统一换行/空格格式、截断超长文本(不超过模型上下文窗口上限,如 8k / 32k tokens)
- 拼接完整 Prompt:系统提示词 + 历史对话上下文 + 当前用户 Query
2. Tokenizer 分词编码 → 得到 Token IDs
使用模型配套 BPE / SentencePiece 分词器处理完整 Prompt:
- 按训练时的词表规则切分为最小子词单元(token),中文会单字/词语混合拆分
- 映射每个 token 为唯一整数 Token ID
- 补充特殊标记:句首
<bos>、句尾<eos>、填充<pad>,生成一维 ID 数组 - 输出 CPU 内存上的
[batch, seq_len]整型张量(batch=1 单轮对话)
3. 查表获取 Token Embedding + 叠加位置编码
两者均为模型内置权重矩阵,常驻 CPU,推理时拷贝至 GPU 显存:
- Embedding 查表:权重矩阵 shape
[词表总量, 隐藏层维度](例如 152k × 4096);根据所有 Token ID 索引矩阵对应行,取出每个 token 的 FP16/BF16 高维向量,得到张量[1, seq_len, hidden_dim] - 位置编码融合:LLM 无法感知文字顺序,预计算正弦余弦/可学习位置向量,shape 与 Embedding 完全一致;向量逐元素相加融合,携带时序位置信息
- 此时得到完整输入特征张量,仍存在 CPU 内存
4. CPU 张量拷贝至 GPU 全局显存
- 执行 CUDA 内存拷贝(cudaMemcpy),将融合后的 Embedding 张量从主机内存搬运至显卡全局显存
- 配套分配显存空间:提前预分配 KV Cache 缓存区(Decoder 推理核心,存储每一层历史注意力 key/value 向量,大幅减少重复计算)
- 同步 CPU/GPU 指令流,等待拷贝完成后才启动计算
5. 调度张量送入 GPU SM,循环执行多层 Decoder
一张 NVIDIA GPU 由数十个 SM 并行组成,调度器分片分发张量至所有 SM 协同计算:
- 单块 SM 内部硬件:CUDA Core(通用浮点运算)、Tensor Core(AI 矩阵乘法专用加速单元,LLM 核心算力)、片上高速 Shared Memory
- 逐层循环执行 N 层 Decoder(如 32 层、40 层),每层固定流程:
- 多头自注意力:读取 KV Cache,计算 Query-Key 相似度,Softmax 归一化权重,加权融合 Value 向量
- FFN 前馈网络:高维向量升维、激活函数、降维
- 残差连接 + 层归一化 LN
- 中间计算数据优先存放 SM 片上 Shared Memory(读写速度远高于全局显存),仅中间结果写回显存更新 KV Cache
- 全部层计算完成,输出序列末尾的隐藏特征向量(自回归仅取最后一个 token 特征用于预测下一词)
6. LM Head 线性层映射,输出词表概率 Logits
LM Head 是一个线性权重矩阵,存储在 GPU 显存:
- 输入:单层 Decoder 输出的末尾隐藏向量
[1, hidden_dim] - 矩阵乘法映射至词表维度,输出
[1, vocab_size]的原始得分 Logits - 可选预处理:对 Logits 做温度缩放、Top-P / Top-K 截断,屏蔽
<pad>等无效 token 得分
7. 采样算法选出单个新 Token ID(自回归核心循环)
对 Logits 概率分布采样,两种主流方案:
- 贪心采样:直接取分数最高的 token
- 随机采样(TopP / TopK):筛选高分 token 后随机选取,回答更有创造性
输出单个整数 Token ID。
8. 循环推理(关键:迭代生成整段回复)
- 将刚生成的 Token ID 追加到原始输入序列尾部
- 仅对新增的 1 个 token 重复步骤 3~7(复用历史 KV Cache,不用重新计算整段上下文,大幅提速)
- 循环迭代,直到采样出
<eos>终止标记,停止生成
9. Token ID 序列解码 → 可读自然文字
- 收集全部生成的 Token ID 序列,送入 Tokenizer 反向解码逻辑
- 根据词表映射 ID 还原子词,拼接合并为完整句子
- 自动清理分词产生的特殊分隔符、空白冗余字符,输出人类可读回答
五、容易被混淆的区分
- LLM 内部 Token Embedding:维度极高(4096+)、FP16/BF16,只给 Transformer 计算,不存向量库
- RAG 检索 Embedding:低维(384/768),专门相似度计算,不进大模型主干
- 内存占用举例(2048 上下文,d_model=4096,FP16):单条输入向量
1 × 2048 × 4096 × 2B = 16,777,216 B = 16MB,换成 FP32 直接翻倍 32MB
关键工程点
- KV Cache:Decoder 自回归推理性能的核心——没有它每一轮都要重算全部上下文,速度暴跌几十倍
- 硬件分层差异:全局显存(低速,存全部权重/KV 缓存)→ SM 共享内存(高速,临时计算),向量读写存在明显的层级速度差距
- 精度细节:BF16 多用于模型权重存储,FP16 多用于中间计算,两者算力、数值范围有区分
- Batch 逻辑:多用户并发时会批量拼接多个 Prompt 送入 GPU,单轮对话 batch=1
- 计算与 IO 阻塞:CPU-GPU 数据拷贝会占用耗时,大维度向量(如 4096 维)传输开销不可忽略