3、推理流水线概述:从输入prompt到输出文本的完整流程

大模型推理(Inference)并非简单的"输入一句话、输出一句话"的黑盒操作,而是一条由多个阶段紧密衔接的工程流水线。从用户输入原始文本(Prompt)到最终流式呈现的文本(Output),中间涉及文本预处理、化、模型前向计算、采样策略、后处理与流式传输等多个环节。理解这条流水线的整体架构,是进行性能调优、故障排查和二次开发的基础。本章将完整拆解这一过程,并重点剖析各阶段的功能、瓶颈与工程实现要点。

TGI 推理流水线全景图 ① 输入与预处理 原始Prompt 文本清洗/截断 Tokenize → IDs (padding/attention mask) Batch 组装 ② 模型前向计算 Embedding 层 Layers × N (Self-Attention) Feed-Forward / MoE LayerNorm / KV-Cache → Logits 矩阵 (batch, seq_len, vocab) ③ 采样与解码 Greedy / Top-k / Top-p Temperature 缩放 重复惩罚 Beam Search (可选) → 下一个 ID 循环直至 EOS/最大长度 ④ 后处理与流式输出 Detokenize → 文本 特殊过滤 增量解码 (Incremental) SSE / WebSocket 推送 流式返回客户端 (首延迟优化) 自回归循环:新拼接至输入序列,重复②③直至终止 关键性能指标(贯穿流水线) • TTFT (Time To First ):从请求到首个返回,受预处理+首轮前向+采样影响 • TPOT (Time Per Output ):每生成一个的耗时,受模型前向+采样+通信影响 • Throughput (吞吐):每秒生成的总数,受Batch Size、KV-Cache命中率、显存带宽限制 • 显存占用:KV-Cache随序列长度线性增长,是长文本推理的主要瓶颈

上图展示了推理流水线的四个核心阶段及其循环关系。在实际工程中,TGI(Text Generation Inference)等框架会将上述流程封装为高并发的服务,并引入Continuous Batching、Paged Attention等优化技术。下面我们逐一深入每个阶段的原理与实现细节。

3.1 预处理阶段:从原始文本到 IDs

核心原理:预处理是将人类可读的文本转换为模型可计算的数值向量的第一步。大模型通常使用BPE(Byte Pair Encoding)或SentencePiece等子词分词算法,将文本切分为序列。每个对应词表中的唯一ID。预处理阶段还需处理特殊(如<bos>、<eos>、<pad>),并生成Attention Mask以区分真实与填充。

操作流程:

  1. 文本清洗:去除不可见字符、统一换行符、处理BOM头,确保输入编码为UTF-8。
  2. 截断与填充:若输入超过模型最大上下文长度(如4096),需进行头部保留或尾部截断策略;批量推理时,短序列需填充至Batch内最大长度。
  3. Tokenize:调用分词器将文本转为 IDs列表,同时记录与原始字符的偏移映射(用于后续高亮或溯源)。
  4. 构造模型输入:生成input_ids、attention_mask,部分模型还需position_ids。
案例拆解:以输入"请解释量子纠缠"为例,分词器可能输出 ['请','解释','量子','纠缠'],对应IDs为 [102, 356, 789, 2345]。若Batch内另一条输入更长,则短序列末尾填充<pad>(ID=0),Attention Mask对应位置置0,防止模型关注填充位。
预处理组件输入输出典型耗时占比
文本清洗原始字符串规范化字符串<1ms
分词器规范化字符串 IDs + 偏移量1-5ms
批处理组装多条序列Padding后的张量<1ms
常见误区:忽略attention_mask会导致模型对Padding位置计算注意力,产生无效计算并可能引入噪声。此外,不同分词器对空格、标点的处理规则不同,跨语言场景需验证分词一致性。

3.2 模型前向计算:从到Logits

核心原理:模型前向是推理流水线的计算核心。 IDs首先经过Embedding层映射为稠密向量,随后逐层通过Transformer Block(包含Self-Attention、Feed-Forward、LayerNorm等子层)。在自回归解码中,每一步仅生成一个,但需要将当前序列的所有重新输入模型计算。为加速推理,TGI等框架引入了KV-Cache技术,缓存历史的Key和Value矩阵,避免重复计算。

计算流程:

  • Embedding Lookup:从词表矩阵中取出对应的向量,维度通常为hidden_size(如4096)。
  • Transformer Layers:每个Layer包含多头自注意力(MHA)或分组查询注意力(GQA)、前馈网络(FFN)。计算量随序列长度平方增长(注意力部分),但KV-Cache将增量计算降为线性。
  • 输出投影:最后一层输出经LM Head(权重与Embedding共享或独立)映射为词表大小的Logits向量。
# 伪代码示意(TGI内部逻辑)
for step in range(max_new_tokens):
    if step == 0:
        kv_cache = None
    logits, kv_cache = model(input_ids, past_key_values=kv_cache)
    next_ = sample(logits[:, -1, :])  # 仅取最后一个位置的Logits
    input_ids = torch.cat([input_ids, next_], dim=-1)
    if next_ == eos__id:
        break
实战场景:当Batch Size=4、序列长度=2048时,无KV-Cache的注意力计算量为4×2048²×头数,而使用KV-Cache后,新增计算量仅为4×1×2048×头数,计算量降低约2048倍。这也是TGI能实现高吞吐的关键。
计算组件计算量复杂度显存占用优化手段
Self-AttentionO(n²·d)O(n²) 中间矩阵FlashAttention、PagedAttention
FFNO(n·d²)O(n·d)MoE稀疏激活
KV-CacheO(n·d·layers)O(n·d·layers·2)量化、GQA、窗口注意力
风险提示:KV-Cache随生成长度线性增长,长文本生成(如32K上下文)可能耗尽显存。TGI通过--max-batch-total-tokens参数限制总数,超出时触发调度等待。

3.3 采样与解码策略:从Logits到下一个

核心原理:模型输出的Logits是一个未归一化的分数向量,需通过采样策略决定最终选择的 ID。采样策略直接影响生成文本的多样性、连贯性和创造性。TGI支持多种策略,包括Greedy Search、Temperature采样、Top-k、Top-p(核采样)以及Beam Search。

判断与操作流程:

  1. Logits缩放:将Logits除以Temperature参数(T)。T>1使分布更平滑(增加随机性),T<1使分布更尖锐(趋于确定性)。
  2. Top-k过滤:仅保留概率最高的k个,其余置为负无穷。
  3. Top-p过滤:按概率从高到低累加,直到累计概率超过p,保留该集合内的。
  4. Softmax归一化:将过滤后的Logits转为概率分布。
  5. 随机采样:从分布中抽取一个 ID。
# TGI 请求参数示例
{
  "inputs": "请写一首关于春天的诗",
  "parameters": {
    "temperature": 0.8,
    "top_k": 50,
    "top_p": 0.95,
    "max_new_tokens": 128,
    "repetition_penalty": 1.1
  }
}
案例拆解:假设Logits为 [2.0, 1.0, 0.5, -1.0],T=0.5时缩放为 [4.0, 2.0, 1.0, -2.0],Softmax后概率约为 [0.84, 0.11, 0.04, 0.01]。若Top-p=0.9,则保留前两个(累计概率0.95),第三个被过滤。最终采样结果大概率是第一个,但仍有小概率选第二个,从而增加多样性。
策略特点适用场景风险
Greedy确定性最高代码生成、数学推理易重复、缺乏创意
Temperature全局调节随机性对话、故事生成过高导致胡言乱语
Top-k限制候选集大小通用场景k值固定,动态性差
Top-p动态候选集创意写作与Temperature叠加需调参
常见误区:Temperature与Top-p同时使用时应先缩放再过滤,否则过滤阈值失真。另外,重复惩罚(Repetition Penalty)会修改已出现的Logits,需注意惩罚强度过大可能导致语义不连贯。

3.4 后处理与流式输出:从 IDs到用户可见文本

核心原理:模型生成的 IDs需经过Detokenize还原为文本,并过滤特殊(如<eos>、<pad>)。流式输出则是在生成过程中逐或逐片段地将文本推送给客户端,显著降低首延迟(TTFT)的感知,提升交互体验。

实现流程:

  • 增量Detokenize:由于一个可能对应半个字符(如UTF-8多字节字符),需维护一个解码缓冲区,等待完整字符后再输出。
  • 特殊处理:移除<eos>、<bos>,将<unk>替换为占位符或保留原文。
  • 流式传输:基于SSE(Server-Sent Events)或WebSocket,将增量文本封装为事件推送。TGI支持stream=true参数,返回data: {"": {"text": "..."}}\n\n格式。
# 流式响应示例(SSE格式)
data: {"": {"text": "春天"}}
data: {"": {"text": "来了"}}
data: {"": {"text": ",万物"}}
data: {"": {"text": "复苏"}}
data: {"finished": true, "generated_tokens": 4}
实战场景:某聊天机器人要求TTFT<500ms。通过流式输出,首个在200ms内返回,用户立即看到"正"字出现,后续每50ms一个,整体感知延迟大幅降低。同时,TGI的--max-stop-sequences可配置停止词,如遇到"用户:"时提前终止生成。
后处理环节输入输出关键点
Detokenize IDs序列拼接文本处理字节级BPE的跨字符
特殊过滤含控制的序列纯净文本保留<|assistant|>等角色标记
流式封装增量文本SSE/WS帧心跳保活、错误重传机制
风险提示:流式输出时若客户端断开连接,服务端应停止生成以节省算力。TGI通过--max-batch-prefill-tokens控制预填充阶段数,防止大Prompt阻塞小请求的流式响应。

3.5 全流程串联与性能调优要点

核心原理:推理流水线的整体性能取决于最慢阶段。预处理阶段通常为CPU密集型,模型前向为GPU密集型,采样与后处理为CPU与GPU混合。TGI通过异步流水线、Continuous Batching和CUDA Graph等技术,将各阶段重叠执行,最大化硬件利用率。

调优操作流程:

  1. 分析瓶颈:使用nvidia-smi监控GPU利用率,若低于50%则可能受CPU预处理或采样拖累。
  2. 调整Batch策略:增大--max-batch-total-tokens可提升吞吐,但会增加TTFT;需平衡SLA要求。
  3. 启用优化内核:开启FlashAttention、PagedAttention,可降低显存占用并加速注意力计算。
  4. 量化与剪枝:使用FP16/BF16混合精度,或INT8/INT4量化(如、AWQ),减少显存带宽压力。
案例复盘:某在线文档AI助手在长文本摘要场景下,TTFT高达3秒。分析发现:预处理阶段分词耗时50ms,但模型前向因KV-Cache未命中导致重复计算。优化措施:①启用PagedAttention,KV-Cache利用率提升40%;②将max_new_tokens从512降至256;③使用Top-p=0.9替代Beam Search(Beam=4)。最终TTFT降至800ms,吞吐提升2.3倍,但生成质量略有下降(ROUGE-L从0.42降至0.39),通过增加repetition_penalty=1.15部分弥补。
优化手段影响指标代价适用场景
Continuous Batching吞吐↑,TTFT↓调度复杂度↑高并发在线服务
KV-Cache量化显存↓精度轻微损失长上下文场景
投机解码(Speculative Decoding)TPOT↓需草稿模型自回归生成瓶颈
CUDA Graph延迟↓显存占用↑固定Shape推理
经验总结:推理流水线的优化应遵循"先测量、再定位、后优化"的原则。建议在TGI中开启--metrics-format=prometheus,监控tgi_request_duration、tgi_queue_size等指标,建立基准后逐步调整参数。同时,流式输出并非所有场景必需,离线批处理任务可关闭以简化日志与错误处理。