ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

大语言模型推理性能优化:深入理解Prefill与Decode阶段

2026/8/17 4:58:16 拓冰建站 浏览量
大语言模型推理性能优化:深入理解Prefill与Decode阶段 在大语言模型推理的实际工程中理解 Prefill 和 Decode 两个阶段的差异是进行性能优化、成本控制和问题排查的基础。很多开发者在使用 LLM API 或部署开源模型时只关注输入和输出却忽略了内部这两个关键步骤如何影响延迟、吞吐量和资源消耗。当遇到推理速度慢、显存占用高或长文本生成不稳定时如果不清楚 Prefill 和 Decode 各自在做什么排查将无从下手。本文将从工程实践角度深入解析 Prefill 和 Decode 阶段的核心机制、性能特征以及 KV Cache 在其中扮演的角色。我们会先理清概念然后通过一个模拟的推理流程来直观展示两个阶段的工作接着分析它们对计算和内存资源的不同需求最后给出针对性的性能调优思路和常见问题排查清单。无论你是正在集成 LLM 服务的应用开发者还是负责模型部署的算法工程师理解这些细节都将帮助你更有效地设计系统、定位瓶颈。1. 理解 LLM 推理流水线从输入到输出的两个关键阶段大语言模型的推理并非一次性计算整个输出序列。为了提高效率它被设计成一个迭代式的自回归过程这个过程清晰地划分为 Prefill 和 Decode 两个阶段。理解这个划分是后续一切优化和问题分析的前提。1.1 Prefill 阶段一次性计算与上下文准备Prefill或称“预填充”阶段发生在处理用户输入的 prompt提示词时。这个阶段的核心任务是基于完整的输入 prompt一次性计算出模型中所有 Transformer 层对于这些输入 tokens 的 Key 和 Value 向量并将它们缓存起来形成 KV Cache。假设用户输入是“请用 Python 写一个快速排序函数。” 这个句子被分词成 N 个 tokens。在 Prefill 阶段模型会并行处理这 N 个 tokens通过前向传播为每个 token 在每一层都生成对应的 Key (K) 和 Value (V) 向量。这些K和V向量被存储在内存中这就是 KV Cache 的初始内容。同时模型会生成 prompt 中最后一个 token对应“函数。”的隐状态这个隐状态将作为 Decode 阶段生成第一个输出 token 的“种子”。为什么需要 Prefill因为 Transformer 的核心注意力机制如自注意力在计算某个 token 的输出时需要看到序列中所有其他 token 的信息。对于固定的 prompt一次性计算出所有 token 的 KV 并缓存避免了在后续 Decode 阶段为生成每一个新 token 而反复计算整个 prompt 的注意力这是 Transformer 推理得以高效的关键优化。Prefill 阶段的计算特征是计算量巨大但高度可并行。其耗时与 prompt 长度N的平方在原始注意力下或线性在某些优化注意力下相关并且会消耗大量显存来存储 KV Cache。1.2 Decode 阶段迭代式生成与缓存复用Decode或称“解码”或“生成”阶段发生在模型逐个生成输出 tokens 时。这个阶段的核心任务是利用 Prefill 阶段准备好的 KV Cache以自回归的方式每次只计算并生成一个新的 token。接上例模型开始生成回答。假设第一个输出 token 是 “def”。模型将 “def” 作为输入对于第一步输入是来自 Prefill 的最后一个 token 的隐状态所预测的 token。在每一层模型计算当前输入 token“def”的 Query (Q) 向量。这个Q向量会与 Prefill 阶段缓存的、属于 prompt 的所有K向量进行计算注意力得分也会与之前 Decode 步骤中缓存的、已生成 tokens 的K向量进行计算。根据注意力得分加权求和对应的V向量得到当前层的输出。模型最终预测出下一个 token例如 “quicksort”。关键一步将当前步骤生成的 token“def”的K和V向量也追加到 KV Cache 中供下一步使用。Decode 阶段的计算特征是单步计算量小但串行不可并行。每一步都只处理一个 token计算其Q向量并与不断增长的 KV Cache 进行注意力计算。其耗时与当前总序列长度Prompt长度 已生成长度相关并且随着生成进行KV Cache 会不断增长内存压力和每一步的注意力计算开销也会缓慢增加。1.3 两阶段对比与 KV Cache 的角色我们可以通过一个表格来清晰对比两个阶段特性维度Prefill 阶段Decode 阶段触发时机每个请求开始时处理用户输入的 prompt。Prefill 结束后循环执行直至生成结束。输入长度一次性处理整个 prompt长度N。每次只处理当前 token长度为1。计算模式计算密集型并行计算整个 prompt 的所有 token。内存带宽密集型串行计算每一步都需读取整个 KV Cache。主要计算为 prompt 的 N 个 token 计算并缓存 K, V 向量。为当前 token 计算 Q 向量并与历史 K 进行注意力计算。KV Cache创建并初始化KV Cache。读取并扩展KV Cache追加新 token 的 K, V。耗时关系与 prompt 长度N强相关通常为 O(N²) 或 O(N)。与当前总序列长度(N 已生成数)相关单步耗时较短但步数多。优化重点降低长 prompt 的计算延迟如使用 FlashAttention, PagedAttention。提高单步解码速度管理不断增长的 KV Cache 内存。KV Cache 的本质它是一个用于存储历史序列包括 prompt 和已生成部分中每个 token 在每一层 Transformer 的 Key 和 Value 向量的内存空间。它避免了重复计算是连接 Prefill 和 Decode 的桥梁也是内存占用的主要部分。其大小公式约为2 * 层数 * 隐藏维度 * 序列长度 * 数据类型字节数。2. 环境准备与模拟推理流程为了更直观地理解我们不需要部署完整的百亿参数模型。我们可以通过一个高度简化的 Python 模拟程序来演示 Prefill 和 Decode 的逻辑流程以及 KV Cache 的变化。这有助于建立清晰的思维模型。2.1 模拟环境设置我们使用 Python 进行概念模拟。重点在于逻辑而非真实计算。# simulate_prefill_decode.py import numpy as np from typing import List, Dict, Tuple class SimpleKVCache: 一个极简的 KV Cache 模拟类 def __init__(self): self.keys [] # 模拟每一层的 K 向量列表 self.values [] # 模拟每一层的 V 向量列表 def append(self, k_vector, v_vector): 向缓存中追加一个 token 的 K, V self.keys.append(k_vector) self.values.append(v_vector) def get_all(self): 获取当前所有缓存的 K, V模拟注意力计算时的读取 return np.array(self.keys), np.array(self.values) def __len__(self): return len(self.keys) def dummy_attention(q: np.ndarray, k_cache: np.ndarray, v_cache: np.ndarray) - np.ndarray: 模拟注意力计算q 与所有 k 计算相似度加权平均 v # 简化计算假设相似度为点积 scores np.dot(q, k_cache.T) # (1, cache_len) # 简化 softmax attn_weights np.exp(scores) / np.sum(np.exp(scores)) # 加权求和 context np.dot(attn_weights, v_cache) # (1, hidden_dim) return context def dummy_transformer_layer(input_vec: np.ndarray, kv_cache: SimpleKVCache, is_prefill: bool) - Tuple[np.ndarray, np.ndarray]: 模拟单层 Transformer 的前向传播。 - input_vec: 输入 token 的向量 - kv_cache: 该层的 KV Cache - is_prefill: 是否为 Prefill 阶段 # 模拟生成当前 token 的 K, Q, V 向量实际模型通过线性层产生 hidden_dim input_vec.shape[-1] W_k np.random.randn(hidden_dim, hidden_dim) * 0.01 W_q np.random.randn(hidden_dim, hidden_dim) * 0.01 W_v np.random.randn(hidden_dim, hidden_dim) * 0.01 k_vec np.dot(input_vec, W_k) # (1, hidden_dim) q_vec np.dot(input_vec, W_q) v_vec np.dot(input_vec, W_v) if is_prefill: # Prefill: 计算并缓存 K, V 用 Q 和当前步的 K 计算自注意力此处简化 # 注意实际 Prefill 是并行计算所有 prompt tokens这里用循环模拟 kv_cache.append(k_vec, v_vec) # 对于 Prefill我们简化输出实际会输出处理后的向量序列 output_vec input_vec # 简化 else: # Decode: 缓存当前 token 的 K, V kv_cache.append(k_vec, v_vec) # 使用当前 Q 与缓存中的所有 K 进行注意力计算 all_k, all_v kv_cache.get_all() context dummy_attention(q_vec, all_k, all_v) # 简化后续处理如FFN直接返回 context output_vec context return output_vec, k_vec, v_vec2.2 模拟完整的 Prefill-Decode 流程下面我们模拟一个包含 2 层 Transformer 的微型“模型”处理 prompt 并生成 3 个 token 的过程。def simulate_inference(prompt_tokens: List[str], generate_len: int 3): 模拟推理流程 prompt_tokens: 模拟的 prompt token 列表 generate_len: 要生成的 token 数量 hidden_dim 8 # 极小的隐藏维度用于演示 num_layers 2 print(*50) print(f开始推理模拟) print(fPrompt Tokens: {prompt_tokens}) print(f目标生成长度: {generate_len}) print(*50) # 初始化每层的 KV Cache kv_caches [SimpleKVCache() for _ in range(num_layers)] # ---------- Prefill 阶段 ---------- print(\n[Prefill 阶段开始]) prompt_vectors [np.random.randn(1, hidden_dim) for _ in prompt_tokens] # 模拟 prompt 向量化 # 逐层处理整个 prompt for layer_id in range(num_layers): print(f\n 处理第 {layer_id1} 层:) layer_kv_cache kv_caches[layer_id] # 在实际 Prefill 中所有 token 是并行计算的。这里用循环模拟每个 token 的处理逻辑。 for idx, token_vec in enumerate(prompt_vectors): # 注意为了简化这里每层的输入都是上层的输出。我们直接传递 token_vec。 output_vec, k, v dummy_transformer_layer(token_vec, layer_kv_cache, is_prefillTrue) prompt_vectors[idx] output_vec # 更新作为下一层的输入简化 print(f Token {prompt_tokens[idx]}: 缓存了 K/V (形状 {k.shape}/{v.shape})) print(f 本层 Prefill 结束。当前 KV Cache 长度: {len(layer_kv_cache)}) # Prefill 后最后一个 token 的输出向量作为 Decode 的起始状态 decoder_input_vec prompt_vectors[-1] print(f\n[Prefill 阶段结束] 最后一层输出向量形状: {decoder_input_vec.shape}) print(f各层 KV Cache 长度: {[len(c) for c in kv_caches]}) # ---------- Decode 阶段 ---------- print(\n[Decode 阶段开始]) generated_tokens [] for step in range(generate_len): print(f\n --- 生成第 {step1} 步 ---) current_vec decoder_input_vec # 逐层解码 for layer_id in range(num_layers): layer_kv_cache kv_caches[layer_id] output_vec, k, v dummy_transformer_layer(current_vec, layer_kv_cache, is_prefillFalse) current_vec output_vec print(f 第 {layer_id1} 层: 追加了新的 K/V 到缓存。当前缓存总长度: {len(layer_kv_cache)}) # 模拟从输出向量预测下一个 token (这里随机选择一个) predicted_token f[Token_{step1}] generated_tokens.append(predicted_token) print(f 预测 Token: {predicted_token}) # 将预测的 token 向量化作为下一步的输入简化这里用随机向量模拟 decoder_input_vec np.random.randn(1, hidden_dim) print(f\n[Decode 阶段结束]) print(f最终生成的 Tokens: {generated_tokens}) print(f最终各层 KV Cache 长度: {[len(c) for c in kv_caches]} (Prompt:{len(prompt_tokens)} Generated:{generate_len})) if __name__ __main__: # 模拟一个包含 3 个 token 的 prompt simulate_inference(prompt_tokens[[CLS], 请, 写], generate_len3)运行上述模拟代码你会看到类似以下的输出它清晰地展示了两个阶段的分界和 KV Cache 的动态增长 开始推理模拟 Prompt Tokens: [[CLS], 请, 写] 目标生成长度: 3 [Prefill 阶段开始] 处理第 1 层: Token [CLS]: 缓存了 K/V (形状 (1, 8)/(1, 8)) Token 请: 缓存了 K/V (形状 (1, 8)/(1, 8)) Token 写: 缓存了 K/V (形状 (1, 8)/(1, 8)) 本层 Prefill 结束。当前 KV Cache 长度: 3 处理第 2 层: Token [CLS]: 缓存了 K/V (形状 (1, 8)/(1, 8)) Token 请: 缓存了 K/V (形状 (1, 8)/(1, 8)) Token 写: 缓存了 K/V (形状 (1, 8)/(1, 8)) 本层 Prefill 结束。当前 KV Cache 长度: 3 [Prefill 阶段结束] 最后一层输出向量形状: (1, 8) 各层 KV Cache 长度: [3, 3] [Decode 阶段开始] --- 生成第 1 步 --- 第 1 层: 追加了新的 K/V 到缓存。当前缓存总长度: 4 第 2 层: 追加了新的 K/V 到缓存。当前缓存总长度: 4 预测 Token: [Token_1] --- 生成第 2 步 --- 第 1 层: 追加了新的 K/V 到缓存。当前缓存总长度: 5 第 2 层: 追加了新的 K/V 到缓存。当前缓存总长度: 5 预测 Token: [Token_2] --- 生成第 3 步 --- 第 1 层: 追加了新的 K/V 到缓存。当前缓存总长度: 6 第 2 层: 追加了新的 K/V 到缓存。当前缓存总长度: 6 预测 Token: [Token_3] [Decode 阶段结束] 最终生成的 Tokens: [[Token_1], [Token_2], [Token_3]] 最终各层 KV Cache 长度: [6, 6] (Prompt:3 Generated:3)这个模拟清晰地展示了Prefill一次性处理了 3 个 prompt tokens为每层创建了长度为 3 的 KV Cache。Decode每生成一个 token都会向每层的 KV Cache 追加一对 K/V导致缓存长度从 3 增长到 6。在真实模型中Decode 每一步的注意力计算都需要读取这个不断增长的完整 KV Cache。3. 性能特征分析与工程影响理解了基本流程后我们需要从工程角度分析这两个阶段对系统性能延迟、吞吐量、内存的不同影响。这是进行容量规划、资源分配和问题排查的核心。3.1 计算复杂度与延迟构成Prefill 阶段延迟 (T_prefill)主要来源对长度为N的 prompt 进行前向传播。计算量主要在于注意力机制。复杂度原始自注意力O(N² * d)其中d是隐藏维度。这是平方级增长长 prompt 延迟显著。使用 FlashAttention、PagedAttention 等优化后可降低到接近O(N * d)并更好地利用 GPU 显存带宽。工程表现用户点击“发送”后到看到第一个字开始输出之前的等待时间主要就是T_prefill。对于长文档总结、长上下文问答这个延迟可能达到数秒甚至数十秒。Decode 阶段延迟 (T_decode_per_token)主要来源生成单个 token 的前向传播。计算量相对固定且较小。复杂度O((NM) * d)其中M是已生成 token 数。随着生成进行(NM)线性增长每一步需要读取的 KV Cache 也线性增长导致单步解码时间 (T_decode_per_token) 会缓慢增加。工程表现决定输出文字的“打字速度”。T_decode_per_token乘以需要生成的 token 数量M就是整个生成过程的流式输出时间。通常T_decode_per_token在几毫秒到几十毫秒之间。注意在流式输出场景中用户感知的“首字延迟”是T_prefill而后续输出速度则受T_decode_per_token影响。优化T_prefill能更快得到响应优化T_decode_per_token能让输出更流畅。3.2 内存占用KV Cache 是主要挑战内存占用主要来自两部分模型参数和 KV Cache。模型参数固定大小与序列长度无关。例如一个 7B 的模型参数大约占用 14 GBFP16。KV Cache动态大小是内存管理的核心。其占用公式可估算为KV Cache 大小 ≈ 2 * batch_size * num_layers * hidden_size * seq_len * bytes_per_param2: 代表 K 和 V 两个缓存。batch_size: 同时处理的请求数批处理大小。num_layers: Transformer 层数。hidden_size: 每层的隐藏维度。seq_len:当前总序列长度(Prompt Generated)。bytes_per_param: 数据类型字节数如 FP16 是 2INT8 是 1。对 Prefill 的影响Prefill 需要为整个 prompt 一次性分配 KV Cache 内存。如果 prompt 很长例如 32K tokens即使 batch_size1KV Cache 也可能占用数十 GB 显存导致 OOM内存不足。对 Decode 的影响Decode 过程中KV Cache 随生成不断增长。如果生成很长例如聊天历史很长或生成长文档最终序列长度可能超过预设的最大上下文长度导致缓存溢出模型无法继续生成或性能骤降。3.3 吞吐量Throughput的权衡吞吐量指单位时间如每秒内处理的 token 总数。它受批处理Batching策略影响极大。Prefill 阶段计算密集GPU 利用率高非常适合大批次Large Batch处理。可以将多个用户的 prompt 打包成一个批次一次性进行 Prefill 计算显著提高 GPU 利用率和整体吞吐量。Decode 阶段内存带宽受限且每个请求的生成步调不一致有的生成长有的短。进行批处理Continuous Batching 或 Iteration-Level Batching更复杂但能有效提高吞吐量。其原理是动态地将正在解码的多个请求组合成批次当一个请求生成结束后用新请求替换它保持 GPU 持续工作。工程上的矛盾点提高 Prefill 吞吐量需要增大批次但这会瞬间申请巨大的 KV Cache 内存batch_size * seq_len。提高 Decode 吞吐量需要高效的动态批处理调度以避免 GPU 空闲。4. 常见问题、排查路径与优化策略基于以上分析我们可以系统地应对 LLM 推理中遇到的各种性能问题。4.1 问题一首字延迟Time To First Token, TTFT过高现象用户发送请求后等待很长时间才看到第一个输出 token。根因分析这几乎总是 Prefill 阶段耗时过长导致的。排查与解决思路检查 Prompt 长度确认是否传入了过长的 prompt。通过日志或监控查看输入 token 数。分析 Prefill 计算是否使用了优化的注意力算子确认推理引擎如 vLLM, TensorRT-LLM, TGI是否启用了 FlashAttention 或类似优化。对于长 prompt2K启用这些优化至关重要。硬件是否匹配Prefill 是计算密集型需要强大的 GPU 算力如 H100, A100。在低端 GPU 上处理长 prompt 必然慢。考虑 Chunked Prefill如果模型和框架支持如 vLLM可以将超长 prompt 分块chunk进行 Prefill虽然可能略微增加总计算量但能平滑延迟避免单次巨大计算造成的卡顿。优化 Prompt考虑是否可以通过提示词工程缩短必要 prompt。移除冗余信息。4.2 问题二生成速度慢输出卡顿现象第一个字出来之后后续输出断断续续速度很慢。根因分析这通常是 Decode 阶段单步耗时 (T_decode_per_token) 过长或吞吐量不足。排查与解决思路检查当前序列长度随着生成进行KV Cache 变长每一步的注意力计算开销增大。监控生成过程中的单步延迟是否随生成长度增加而明显上升。检查批处理配置是否启用了动态批处理Continuous Batching这是提高 Decode 吞吐量的关键。确保使用的推理服务器支持此功能如 vLLM, TGI。批处理大小是否合理过小的 batch_size 无法充分利用 GPU过大的 batch_size 可能导致内存不足触发显存交换反而更慢。需要根据 GPU 显存和模型大小调整。检查解码参数是否使用了低效的采样策略贪婪解码Greedy最快采样Sampling稍慢束搜索Beam Search会成倍增加计算量beam width 倍。评估是否必须使用束搜索。max_new_tokens是否设置过大无限制的生成长度会持续增加 KV Cache 和延迟。使用量化将模型权重和 KV Cache 从 FP16 量化到 INT8 甚至 FP4可以大幅减少内存占用和带宽压力从而提升 Decode 速度。但需注意可能带来的精度损失。4.3 问题三显存不足OOM现象推理服务崩溃日志报错 “CUDA out of memory”。根因分析总内存占用模型参数 KV Cache超过 GPU 显存。排查与解决思路计算 KV Cache 预算根据前面的公式估算在目标batch_size和max_seq_len下 KV Cache 的占用。例如模型Llama2-7B (hidden_size4096, num_layers32)批次batch_size4序列max_seq_len4096精度FP16 (2 bytes)KV Cache 大小 ≈2 * 4 * 32 * 4096 * 4096 * 2 bytes ≈ 8.6 GB加上模型参数 ~14 GB总需求 22 GB显然在 24G 显存的卡上就很紧张。调整关键参数降低batch_size最直接有效但会降低吞吐量。降低max_seq_len限制单个请求的最大长度防止超长请求耗尽内存。使用 PagedAttentionvLLM这是解决内存碎片化和 OOM 的利器。它允许 KV Cache 以非连续块Page的形式存储在显存中极大提高了显存利用率通常可以支持更大的 batch_size。启用 KV Cache 量化如前所述将 KV Cache 量化为 INT8。监控与限流在生产环境部署监控跟踪每个请求的 prompt 长度和生成长度。实现请求限流防止突发的大量长上下文请求同时打满显存。4.4 优化策略速查表优化目标可采取的措施说明与注意事项降低首字延迟 (TTFT)1. 启用 FlashAttention 等优化算子。2. 对超长 prompt 使用 Chunked Prefill。3. 升级 GPU 算力。4. 优化/缩短 prompt。FlashAttention 对长文本效果显著。Chunked Prefill 是 trade-off可能增加总计算量但改善延迟体验。提高生成速度1. 启用 Continuous Batching。2. 使用更快的采样方式如贪婪解码。3. 对模型和 KV Cache 进行量化。4. 使用如 vLLM 的高效推理引擎。Continuous Batching 是提高 Decode 吞吐量的核心技术。量化需测试精度是否可接受。节省显存1. 使用 PagedAttention (vLLM)。2. 量化 KV Cache 和模型权重。3. 合理设置max_seq_len和batch_size。4. 使用模型并行将大模型拆分到多卡。PagedAttention 能显著提升显存利用率支持更大批次。量化是牺牲精度换容量。提高吞吐量1. 增大 Prefill 批次大小。2. 使用 Continuous Batching。3. 优化调度策略如优先调度短请求。4. 使用多 GPU 并行服务多个模型副本。Prefill 和 Decode 的批处理策略不同需要推理引擎良好支持。吞吐量和延迟通常需要权衡。5. 生产环境最佳实践与扩展方向在理解了基本原理和常见问题后要将 LLM 推理稳定、高效地应用于生产还需要考虑更多工程细节。5.1 推理服务选型与配置不要从零开始搭建推理服务。优先选择成熟的开源推理引擎它们已经集成了上述大多数优化。vLLM目前高性能 LLM 推理的事实标准之一。核心优势是 PagedAttention 和高效的 Continuous Batching。配置简单吞吐量高非常适合自建 API 服务。Text Generation Inference (TGI)Hugging Face 推出的推理服务。同样支持 Continuous Batching、FlashAttention 等与 Hugging Face 模型库集成好。TensorRT-LLMNVIDIA 官方优化方案能将模型编译成高度优化的 TensorRT 引擎在 NVIDIA GPU 上达到极致性能。但使用复杂度较高。配置示例 (vLLM)# 启动一个 vLLM 服务加载 Llama2-7B 模型启用量化 python -m vllm.entrypoints.api_server \ --model meta-llama/Llama-2-7b-chat-hf \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.9 \ --max-model-len 8192 \ # 最大序列长度 --quantization awq # 使用 AWQ 量化节省显存关键参数--max-model-len: 定义了 KV Cache 的最大长度直接影响内存预分配。--gpu-memory-utilization: 目标 GPU 显存利用率vLLM 会根据此值动态管理批处理大小。--quantization: 指定量化方法如awq,squeezellm。5.2 监控与可观测性在生产环境中必须监控以下核心指标延迟指标prefill_latency_ms: Prefill 阶段延迟。decode_latency_per_token_ms: 单 token 解码延迟可统计 P50, P99。time_to_first_token_ms: 首字延迟。total_request_latency_ms: 请求总延迟。吞吐量指标tokens_per_second: 每秒处理的 token 数区分 Prefill 和 Decode。requests_per_second: 每秒处理的请求数。资源与容量指标gpu_memory_used: GPU 显存使用量。kv_cache_memory_used: KV Cache 内存使用量如果引擎暴露。batch_size_current: 当前动态批次大小。queue_size: 请求排队数量。业务指标input_tokens_per_request: 每个请求的输入 token 数分布。output_tokens_per_request: 每个请求的输出 token 数分布。当prefill_latency异常高时检查输入长度当decode_latency随生成增长而飙升时检查序列长度是否接近max_model_len当gpu_memory_used持续高位可能需调整批次大小或启用量化。5.3 面向未来的扩展Chunked Prefill 与 Streaming LLM对于超长上下文如 128K场景传统的 Prefill 和 Decode 机制面临挑战Chunked Prefill将超长 prompt 分成多个块chunk逐块进行 Prefill 计算并更新 KV Cache。这可以将一次性的巨大计算和内存压力分散开改善 TTFT但需要推理引擎和模型架构的支持。Streaming LLM / 无限上下文这是更前沿的方向旨在解决 Decode 阶段 KV Cache 无限增长的问题。通过类似滑动窗口、重点保留H2O, StreamingLLM或递归压缩Mamba, RWKV的机制在保持主要性能的同时将 KV Cache 的大小限制在一个固定值从而实现真正的“无限”生成能力。在选择模型和推理方案时可以关注是否支持此类特性。理解 Prefill 和 Decode 的二分法是驾驭 LLM 推理性能的起点。在实际项目中你需要根据具体的模型规模、请求负载模式长/短文本高/低并发和硬件条件在这两个阶段之间找到平衡点。从配置一个高效的推理服务器开始细致地监控其核心指标并依据本文提供的排查清单应对性能瓶颈是构建稳定、可扩展 LLM 应用服务的关键一步。