ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

不换权重也能将TTFT降低77%:LLM推理优化全拆解

不换权重也能将TTFT降低77%:LLM推理优化全拆解 今年开年我们内部群里贴了一条评测记录同一份权重一行代码没改首字延迟TTFT从 2.3 秒干到 0.53 秒降幅 77%。群里第一反应是“又拿假数据骗我”但顺着配置和日志翻完大家都沉默了——项项都是调度、缓存、显存和算子层面的调整权重确实一片叶子都没动。做 AI Infra 的同学这两年应该都有同感模型权重带来的惊喜越来越平而同一份权重放在不同的推理引擎、缓存策略、调度策略下表现可以差出一个数量级。2026 年聊推理提速真正的增量基本都在权重之外。这篇文章就把“权重之外”到底能动哪些部分、每个动作的收益从哪来、容易踩哪些坑一次性说透。适合正在做 LLM 服务化、RAG/Agent 上线或者准备给视觉模型做部署优化的人参考。1. 别把“权重换慢”当玄学先看清延迟的账本1.1 TTFT 的首因是“执行路径”不是“知识含量”很多人一提推理慢第一反应就是“模型太大、权重太重”。这个直觉有道理但放错了层级。首字延迟的完整构成大体是排队时间、输入 token 化、Prefill 阶段计算、采样第一个 token、响应传回。权重只参与其中一部分计算而且权重的大小会同时影响显存占用、访存带宽和浮点运算量——但这不是全部。Prefill 阶段要干的核心事是把输入的 prompt 逐个 token 过一遍算出一个“语义快照”存进 KV Cache。这个过程里真正耗时的往往不是权重矩阵本身而是注意力计算怎么实现、KV Cache 要不要从头建、计算图有没有被优化、显存里的数据搬运是否高效。换句话说权重决定了模型“懂多少”但延迟由“懂的方式”在运行时怎么执行来定。打个比方权重像一本菜谱。同一本菜谱厨房里切配是不是提前备好了、灶台火力是不是稳定、传菜动线合不合理直接决定出菜速度。菜谱没换后厨改了动线、换了炒锅、加了预配流程翻台率就能大变样。0 行权重改动的推理提速走的全是“后厨改造”这条路线。1.2 范式转向权重红利退潮执行优化上场前几年的推理提速主线确实是改权重把 7B 蒸馏到 3B、把 FP16 换成 INT8/INT4、做低秩适配本质都是“让模型本身变小或更好算”。这类优化收益直接但代价也高重新训练、重新评测、重新走对齐流程还要担心量化后的精度回落。到了 2026 年基础模型能力普遍够用改权重的边际收益越来越低风险却一点没降。于是增量空间自然转向了执行侧。同一个开源权重装上 vLLM 或 SGLang 这类推理引擎配合连续批处理、前缀缓存、CUDA Graph延迟和吞吐可以肉眼可见地变化。更关键的是权重外的优化不改模型行为A/B 测试成本极低出了问题回滚配置就行不需要重新发一版模型。这个范式转变还有个隐性逻辑权重是长期资产不能为了临时性能问题随便动执行侧是运营资产可以每周甚至每天调。所以 2026 年的推理提速话题越来越多人问的是“同样的权重怎么把它跑得更快”而不是“要不要再换一版权重”。2. 权重之外的优化工具箱从输入到调度再到算子2.1 输入侧Prompt 瘦身和预填充拆分先说一个经常被忽略的点TTFT 在纯在线服务里很大一部分开销在 Prefill而 Prefill 的时间和输入长度直接相关。输入越长KV Cache 要算的越多第一个 token 出来的越慢。这跟权重一点关系没有纯粹是“喂进去的东西太多”。常见的输入侧优化有几个方向。一是精简系统提示词把不必要的描述删掉把 few-shot 示例压到最短很多团队靠这一条就能省下几十毫秒。二是做对话历史压缩多轮对话直接用摘要替代完整历史或者只保留最近几轮。三是把检索增强里的长文档切片成更小的块避免一个超大 prompt 拖慢整条链路。工程侧还有两个配套手段Chunked Prefill 和并行 Prefill。Chunked Prefill 是把一个超长输入的 Prefill 拆成若干小段穿插到别的请求解码间隙里执行避免某个长 prompt 独占 GPU 太久。并行 Prefill 则是把一个请求的前缀计算分到多张卡上同时做。这两招都不用动权重但对“长输入、高并发”场景的 TTFT 尾延迟帮助很大。2.2 复用侧前缀缓存和 KV Cache 命中如果说输入侧优化是“少算”那复用侧优化就是“不重算”。在线业务里大量请求拥有相同前缀同一个 system prompt、同一套 few-shot 模板、同一个 Agent 的长期 context。这些前缀算好的 KV Cache理论上是可以直接复用的。vLLM 的 Prefix Caching、SGLang 的 RadixAttention、llama.cpp 的 prompt cache核心思路都是把算过的 KV Cache 按前缀存起来下次遇到相同前缀直接拼接后续部分不用从头算一遍 Prefill。前缀越长节省越多命中率越高TTFT 掉得越明显。我实测过一个典型场景线上 Agent 带着一段 1200 token 的系统提示词之前每个请求都要完整 PrefillTTFT 稳在 1.8 秒左右。把这段系统提示词统一成固定模板、开启前缀缓存之后命中请求的 TTFT 直接掉到 0.6 秒以下。权重没换知识没有多一分纯粹是“这道菜上次备好的料直接端出来了”。2.3 调度侧连续批处理与投机采样调度是把 GPU 这个“后厨”的产能摊匀的关键。早期推理框架按“批次”跑一个 batch 没跑完新请求只能在队列里等TTFT 在并发升高时会迅速恶化。连续批处理Continuous Batching改变了这个逻辑一个请求生成完一个 token如果还没结束就继续排新请求可以在任意 token 间隙插入计算。新请求不用等整个批次清空排队时间大幅压缩。投机采样Speculative Decoding则是另一条路让一个小草稿模型先快速猜一串 token然后由大模型一次性验证。它主要降低的是单 token 生成间隔TPOT和解码总耗时。需要注意的是投机采样通常不会直接缩短首个 token 的产出时间因为第一个 token 还是要先正常走一遍前置计算。所以拿投机采样来压 TTFT方向就错了它解决的是“每个 token 之间的等待”这类问题。调度的另一层是优先级。有些引擎支持按请求优先级调整排队顺序把在线交互请求排在离线批处理前面。对在线业务来说牺牲一部分离线吞吐换 P95 TTFT 达标往往是值得的。2.4 底层执行PagedAttention、CUDA Graph 与算子融合再往底层看权重之外能抠出来的性能往往最“硬核”。PagedAttention 解决的是 KV Cache 显存碎片和浪费问题把显存按小块分页管理类似操作系统里的内存分页。它最大的收益是让更多并发请求塞进同一张卡批处理规模变大硬件利用率上去排队时间自然降下来。CUDA Graph 则针对内核启动开销。GPU 执行每个小算子都有固定的启动成本请求一多这些成本会堆得很高。CUDA Graph 把一整条计算链路的启动方式提前固化执行时一次性触发一串内核能省掉大量 CPU 下发指令的时间。对短请求、小 batch 的场景这一项往往能给 TTFT 带来肉眼可见的收益。算子融合就更直接了。把 FlashAttention、RMSNorm、量化、激活函数这类相邻操作合并成一个大内核减少显存读写次数。数据不用一趟趟搬来搬去Prefill 自然更快。这些全部发生在权重下面的执行层换哪个开源权重来都一样只要计算图能吃到这些优化。优化方向典型手段主要作用是否改权重输入侧Prompt 瘦身、Chunked Prefill降低 Prefill 开销否复用侧Prefix Caching、RadixAttention减少重复计算 KV否调度侧连续批处理、优先级队列缩短排队时间否底层执行PagedAttention、CUDA Graph、算子融合提升算子和显存效率否模型侧蒸馏、量化、换小模型减少计算量与参数量是3. 实操复盘一次把 TTFT 拉下来 77% 的完整过程3.1 基线怎么测得准固定输入、固定并发、看分位数先说明测试设置因为“77%”这种数字最怕口径不清楚。场景是一个内部 RAG Agent 服务模型用开源的 Qwen2.5-7B-Instruct单卡 A10G 部署。业务特征是系统提示词固定 1200 token用户请求平均 300 token在线并发 20 路左右。基线环境没有做任何优化朴素的 HuggingFace Transformers 循环生成FFN 默认配置显存不用池化没有缓存复用。测法非常死板固定 prompt 内容、固定输出长度上限 128 token用流式请求打 200 次记录每个请求从“发出”到“收到第一个 token”的时间取 P50 和 P95。基线跑出来的 P50 是 2.35 秒P95 是 3.86 秒。这里建议所有团队都按这个口径来第一预热模型再开始记录不然权重首次加载和 CUDA 初始化会污染数据第二不要只报均值P95 才是线上用户的真实体感第三输入和输出长度必须固定否则每次测的都不是同一道题。3.2 优化动作列表和收益拆解下面是这次优化的完整动作清单每一步都单独测过不搞一把梭。第一步从 Transformers 的朴素生成迁到 vLLM开连续批处理。这一步的效果来自引擎级的调度和显存管理PagedAttention 让 20 路并发不再互相挤压显存连续批处理让新请求不用排队等整批跑完。TTFT P50 从 2.35 秒降到 1.16 秒。第二步开启 Prefix Caching同时把系统提示词整理成完全统一的模板。这一步的效果来自 KV Cache 复用每个请求的 1200 token 前缀不再重复计算只需要算后面 300 token 的新内容。TTFT P50 从 1.16 秒降到 0.82 秒。第三步调整 Chunked Prefill 的 chunk 大小和 max_num_seqs。之前 A10G 上默认配置更偏向吞吐个别长 prefill 会把整卡的计算节奏拖住。把 chunk 调到 256 token 左右同时限制单批最大序列数避免显存被打满后触发 swap。TTFT P50 从 0.82 秒降到 0.64 秒P95 降得更多。第四步重新捕获 CUDA Graph并把 gpu-memory-utilization 从默认值调到 0.9让可用显存尽量给 KV Cache。这个动作对短请求特别明显内核启动开销被压掉不少。最终 P50 落在 0.53 秒相比基线 2.35 秒正好下降 77%。阶段动作TTFT P50TTFT P95基线Transformers 朴素生成2.35s3.86s第一步vLLM 连续批处理1.16s1.92s第二步开启 Prefix Caching 统一前缀0.82s1.31s第三步调整 Chunked Prefill0.64s0.97s第四步CUDA Graph 重捕获 显存调整0.53s0.78s3.3 为什么有些优化“调了却没反应”不是每个动作放到任何场景都有效。这次复盘里有几个现象值得展开。Prefix Caching 的前提是“请求之间有重复前缀”。如果业务里每个请求都是完全随机的用户输入没有固定 system prompt也没有多轮上下文那这步的收益基本为零。这次之所以有效是因为我们把系统提示词做成了统一模板相当于人为造出了可复用的前缀。Chunked Prefill 也不是越小越好。chunk 太小调度开销会变大chunk 太大长请求还是会卡住整卡节奏。这里面有个取舍必须结合请求长度分布来调。还有一个常见误操作有的人为了压 TTFT 把 max_num_seqs 调得很小结果 GPU 空闲并发一上来反而排队排得更狠P95 不降反升。CUDA Graph 在短请求上收益大在长请求上收益会被 Prefill 本身的耗时盖过。所以实测时要把请求长度分档看别拿一个超长输入去验证 CUDA Graph 的价值那是它帮不上的战场。4. 常见误区速查权重热词如何带偏你的优化方向4.1 llama.cpp offload 到内存省的是容量不是延迟网上有一个高频问题llama.cpp 把模型 offload 到内存是不是一种“权重层面的提速”这里要先澄清概念offload 出去的对象确实是权重张量但它解决的是显存放不下的容量问题不是性能问题。GGUF 模型的分层加载机制中--n-gpu-layers 决定了多少层放在 GPU多少层放在 CPU 内存。权重被放在 CPU 内存之后每次前向计算都要经过 PCIe 或内存总线搬运数据跨设备访问的延迟非常高。所以 offload 的层数越多单次推理通常越慢TTFT 反而可能变长。它存在的意义是让显存小的机器能跑大一点的模型属于“能不能跑”的兜底方案而不是“跑得快不快”的优化手段。真要提速优先让权重完整落在显存里其次再谈计算路径的优化。如果显存真的不够选择更小的量化等级或者更小的模型通常比 offload 更实际。4.2 视觉权重下载火爆但延迟瓶颈在前处理最近 DINOv3 权重、YOLOv8 预训练权重、SAM3 权重下载这类热度很高很多做视觉的朋友也在问“换了权重是不是推理就快了”。这类问题其实和 LLM 场景一样权重决定模型能力但视觉推理的单张延迟大头经常不在模型本身。一张图从输入到拿到结果要经过图像解码、缩放、归一化、通道变换、转 GPU 张量然后才是模型推理最后还有 NMS 或 mask 解码等后处理。我在实际项目里见过不少例子同样的 YOLOv8 权重PyTorch 原生跑要 80ms换成 TensorRT FP16 推理、固定输入尺寸、把前处理做成 GPU 算子整体掉到 25ms 以下。权重一个字没改延迟变了两倍多。所以看到“某某权重下载”热度飙升时先别急着跟进。假设部署流程已经成熟你该排查的是输入尺寸是否统一、推理是否用对了后端、前处理和模型推理能不能合并成一条 GPU 流水线。这些才是视觉推理提速的主战场。4.3 首字延迟、TPOT、吞吐三个指标别混在一起算账推理性能测试里最常见的问题是口径混乱。TTFT 是首字延迟指从请求发出到收到第一个 token 的时间TPOT 是单 token 生成间隔指每输出一个 token 之间的平均等待吞吐则是单位时间能处理的 token 数或请求数。这三者经常互相矛盾提高吞吐的批处理策略可能会拉长单个请求的 TTFT追求极致 TTFT又可能牺牲硬件利用率。我的建议是先把业务目标说清楚。在线助手类场景优先看 TTFT 的 P95离线评测、批量生成场景优先看 TPOT 和吞吐。追求 TTFT 时重点关注 Prefill 路径和排队时间追求 TPOT 时重点关注解码阶段和投机采样。别拿一个换权重的对比结果同时宣称首字延迟和吞吐都变好了这种话大概率哪个都不严谨。4.4 高频问题速查表常见疑问误区正解换新权重是不是推理必然更快权重能力与执行效率混为一谈新权重可能更强但延迟取决于执行侧优化offload 到内存能省显存还能提速把容量优化当成性能优化offload 会引入跨设备拷贝通常变慢TTFT 降了就是整体推理快了只盯着一个指标需要同时关注 TPOT、P95、吞吐前缀缓存开启后所有请求都受益没检查前缀重复率请求前缀随机时缓存命中率很低视觉模型推理慢就怪权重忽略前后处理链路输入尺寸、后端算子、管线融合同样关键5. 工程化验证与避坑经验5.1 TTFT 的测量脚本与统计口径网上很多 TTFT 的数字来自单次 curl 计时误差大得离谱。我自己常用的测量方式是写一个脚本用流式接口连续发请求记录首个 chunk 到达的时间收集足够样本后取分位数。import json import time import statistics import requests def measure_ttft(url: str, api_key: str, prompt: str, repeats: int 50): headers { Authorization: fBearer {api_key}, Content-Type: application/json, } samples [] for _ in range(repeats): payload { model: qwen2.5-7b-instruct, messages: [{role: user, content: prompt}], max_tokens: 32, stream: True, } t0 time.perf_counter() with requests.post(url, jsonpayload, headersheaders, streamTrue) as resp: for line in resp.iter_lines(): if line: samples.append((time.perf_counter() - t0) * 1000) break samples.sort() p50 samples[int(len(samples) * 0.50)] p95 samples[int(len(samples) * 0.95)] return p50, p95 p50, p95 measure_ttft(http://127.0.0.1:8000/v1/chat/completions, EMPTY, 你好) print(fTTFT P50: {p50:.1f} ms, P95: {p95:.1f} ms)有几个细节必须注意请求要先预热一轮再正式记录输出长度要尽可能小避免首个 token 之后的生成干扰流式读取逻辑要确保是流式请求非流式接口根本测不出 TTFT。另外不要只测一次至少跑 50 次数据才有点统计意义。5.2 回归测试和灰度发布的基本套路权重外的优化有一个好处不改变模型行为回滚容易。但正因为改动轻更容易被随手一调就带上线最后性能是涨是跌都不知道。所以我建议把性能测试固化到发布流程里。固定 GPU 型号、CUDA 版本、驱动版本和推理引擎版本把一组代表性 prompt 打进回归用例。每次调整配置或引擎版本自动跑一遍 TTFT P50/P95 和吞吐超过阈值就拦截发布。测试集要覆盖两种前缀类型一部分固定共享前缀用来验证缓存优化一部分随机前缀用来验证真实流量下缓存兜底时的表现。否则测试结果容易被缓存命中率美化上线就穿帮。灰度时也要分阶段放量。先切 5% 流量观察 TTFT P95 和显存水位确认没有长尾请求被打爆之后再逐步放大。整个过程中权重保持不动可以最大程度隔离性能变量。5.3 三个踩过的坑以及一点个人体会第一个坑为了压 TTFT 把并发上限调低结果 GPU 利用率掉到 30% 以下请求排队时间反而变长P95 全面恶化。TTFT 优化是排队时间和计算时间的平衡不是简单调低并发就能解决的。第二个坑前缀缓存的测试被“缓存污染”骗了。用同一组测试 prompt 反复跑命中率接近 100%上线后真实用户的前缀太随机收益缩水一大半。后来我把测试集分成共享前缀和随机前缀两组才拿到接近线上的真实收益曲线。第三个坑一开始只看 P50忽略 P95。个别超长请求在 Prefill 阶段会独占 GPU 很长时间导致同一时刻其他请求的 TTFT 出现尖刺。平均值看着还好但用户体感已经变差了。现在凡是看延迟我都强制同时看 P95必要时还会看 P99。最后聊一点个人体会。做推理优化这几年我最大的感受是权重决定模型“聪明不聪明”执行优化决定服务“快不快”。很多人一听到推理提速就想到换权重、下载新权重其实在业务系统里不碰权重能优化的空间远比想象中多。前缀命中率、批处理调度、算子实现、显存布局每一项都能单独撬动几十个百分点的延迟变化。我的建议是先把性能账本拆开TTFT、TPOT、吞吐各算各的然后从复用率最高、改动最小的地方动手。如果能把线上请求的 KV Cache 复用率报到 60% 以上再配上一个调度策略合理的推理引擎首字延迟大概率已经比换个同系列大模型还香。至少我这边实测下来比“0 行权重改动”这个数字还要好看一截。
返回列表