大模型推理Prefill与Decode分离:KV Cache优化与参数调优实战
1. 从一次线上推理抖动说起为什么Prefill和Decode必须拆开看前段时间帮一个团队排查他们自研推理服务的延迟毛刺问题现象很典型P99延迟时不时飙到两三秒但平均延迟看着还行GPU利用率却始终上不去卡在40%上下晃悠。他们一开始怀疑是显存不够、模型太大甚至动了换卡换机器的念头。我让他们把请求按阶段拆开打点结果一目了然——问题根本不在算力而在于Prefill和Decode这两个阶段的资源争抢。这个场景其实在推理系统里非常普遍。大模型推理从计算特征上天然分成两个阶段**Prefill预填充**负责把用户输入的整段prompt一次性喂进模型算出所有输入token的KV并生成第一个输出token**Decode解码**则是自回归地一个token一个token往外吐。前者是计算密集型矩阵乘法规模大、并行度高能把GPU的算力吃满后者是访存密集型每生成一个token都要把整个KV Cache读一遍算力利用率极低但显存带宽压力巨大。把这两个阶段混在一个批次里跑就像让短跑运动员和马拉松选手同场竞技——Prefill的长序列会拖慢Decode的响应Decode的频繁小批次又会让Prefill的算力利用率下降。所以现在主流的推理引擎无论是哪家的方案核心优化方向都是PD分离Prefill-Decode Disaggregation加上KV Cache精细化管理。这篇笔记就把我这两年在几个项目里踩过的坑、调过的参数、验证过的方案系统地梳理一遍。适合读这篇的人正在做推理服务部署、被延迟和吞吐折磨的工程师想搞明白KV Cache到底怎么占显存、怎么优化的同学以及准备做PD分离架构选型的技术负责人。我会尽量把原理讲透同时给出可以直接抄的参数和排查思路。2. Prefill与Decode的本质差异先搞清楚在优化什么2.1 两个阶段的计算特征对比要调优先得把这两个阶段的脾气摸清楚。我用一个具体的例子来说明假设模型是70B参数、FP16精度输入prompt长度2048输出长度512batch size为1。Prefill阶段要处理2048个token每个token都要和所有历史token做注意力计算。这个阶段的矩阵乘法维度大GPU的Tensor Core能跑满计算时间大致和序列长度的平方成正比注意力部分加上和序列长度成正比的部分FFN等。实测下来70B模型处理2048长度prompt在单张高端卡上大概几百毫秒。Decode阶段每次只处理1个新token但它需要读取之前所有token的KV Cache。这时候计算量很小瓶颈在显存带宽——要把几十GB的KV Cache从显存里读出来参与注意力计算。每生成一个token的时间基本恒定主要取决于KV Cache的大小和显存带宽。维度PrefillDecode计算特征计算密集型访存密集型并行度高整段并行低逐token串行算力利用率高可达70%低常低于10%显存带宽压力中等极高延迟敏感度影响首token时间TTFT影响每token时间TPOT批次策略大batch提升吞吐小batch降低延迟这张表是我自己实测总结的不同模型和硬件会有差异但趋势是一致的。理解了这个差异后面所有的优化手段就都有了解释的根基。2.2 为什么混跑会导致互相拖累很多人会问既然Prefill算力利用率高、Decode算力利用率低那把它们放一起不正好让Decode填空、Prefill吃满吗理论上很美实际很骨感。问题出在调度粒度上。当一个批次里同时有Prefill请求和Decode请求时调度器必须等整个批次的所有请求都完成才能进入下一步。Prefill请求处理时间长Decode请求就得干等而Decode请求每步都要执行Prefill请求又被迫频繁插入。结果就是两边的延迟都被拉高而且GPU的流水线频繁被打断利用率反而下降。更麻烦的是显存碎片。Prefill阶段需要为长prompt分配大块连续的KV CacheDecode阶段则是持续的小块增长。混在一起时显存分配器很难高效管理容易出现明明有空间却分配不出来的碎片问题。我见过一个案例显存利用率显示还有15GB空闲但就是无法接收新请求最后发现是碎片导致的。提示如果你的服务同时有长prompt和长输出需求混跑几乎必然导致延迟抖动。这时候优先考虑PD分离而不是去调batch size。2.3 PD分离的核心思路PD分离的本质是让专业的资源干专业的事。把Prefill和Decode放到不同的实例组上各自用最适合的批次策略和并行配置。Prefill实例组可以配大batch、高并行度追求吞吐Decode实例组配小batch、优化显存带宽追求低延迟。两者之间通过KV Cache的传输来衔接——Prefill算完KV后把KV传给Decode实例Decode接着往下生成。这个架构的代价是KV传输开销。KV Cache动辄几十GB跨实例传输需要高速网络。所以PD分离是否划算取决于你的网络带宽和请求特征。如果prompt很短、输出也很短传输开销可能超过收益如果是长prompt长输出的场景收益非常明显。3. KV Cache的显存账本算清楚才能调得动3.1 KV Cache到底占多少显存这是最基础也最容易被忽略的问题。很多人部署时发现显存不够第一反应是模型太大其实KV Cache可能才是大头。KV Cache的大小计算公式KV Cache大小 2 × 层数 × 注意力头数 × 头维度 × 序列长度 × batch_size × 精度字节数以70B模型为例假设80层、64个注意力头、头维度128、FP16精度2字节单个token的KV Cache 2 × 80 × 64 × 128 × 2 2.6 MB如果序列长度2048、batch size 16那么KV Cache总量 2.6MB × 2048 × 16 ≈ 85 GB这个数字相当惊人。模型权重本身FP16也就140GB左右KV Cache在长序列大batch下能占到显存的很大比例。所以KV Cache优化不是锦上添花而是决定服务能不能跑起来的关键。3.2 PagedAttention为什么有效传统KV Cache分配是连续的每个请求预留最大序列长度的空间。这导致两个问题一是内部碎片实际用了500长度却占了2048的空间二是外部碎片请求来来去去后显存被切得七零八落。PagedAttention的思路借鉴了操作系统的虚拟内存分页。把KV Cache切成固定大小的block比如16个token一块用页表来管理逻辑块到物理块的映射。这样请求的KV Cache不需要连续按需分配block碎片问题基本消除。实测下来PagedAttention能把显存利用率从60%左右提升到90%以上意味着同样的显存能支撑更大的batch或更长的序列。这是目前几乎所有主流推理引擎的标配。3.3 量化KV Cache的收益与代价KV Cache量化是另一个大杀器。把FP16的KV降到INT8甚至INT4显存直接减半或减到四分之一。但这里有个坑KV Cache量化对精度的影响比权重量化更敏感。因为KV会参与注意力计算量化误差会被放大。我实测过INT8量化在大多数场景下精度损失可接受困惑度上升不到1%但INT4就需要谨慎某些任务上会出现明显的质量下降。量化方案显存节省精度影响适用场景FP16基准无精度要求极高INT850%轻微大多数生产场景INT475%明显显存极度受限、可接受质量下降FP850%轻微支持FP8的硬件注意KV Cache量化要和权重量化分开评估。有些团队权重用了INT4KV还用FP16结果显存还是不够。两个都要看。4. PD分离架构的落地细节从设计到部署4.1 实例配比怎么定PD分离后Prefill实例和Decode实例的数量配比是个关键决策。配比失衡会导致一方成为瓶颈。我的经验算法是这样的先测出单个Prefill实例的吞吐每秒能处理多少prompt token和单个Decode实例的吞吐每秒能生成多少output token。然后根据业务的输入输出比例来算。假设业务平均输入2048 token、输出512 token比例4:1。如果单Prefill实例每秒处理10000 prompt token单Decode实例每秒生成2000 output token那么处理一个请求Prefill需要0.2秒Decode需要0.256秒。为了平衡Prefill和Decode实例数比大约是1:1.3。实际部署时还要留余量因为流量是波动的。我一般会按峰值流量的1.5倍来配置然后通过自动扩缩容来应对日常波动。4.2 KV Cache传输的优化PD分离后Prefill算完的KV要传给Decode。这个传输如果没优化好会成为新的瓶颈。传输优化的几个方向压缩传输KV在传输前做量化压缩到Decode端再解压。INT8压缩能把传输量减半网络压力大幅降低。分层传输不是等所有层的KV都算完才传而是算完一层传一层流水线化。这样Decode能更早开始工作降低首token延迟。就近调度调度器尽量把同一个请求的Prefill和Decode分配到网络距离近的实例上减少传输延迟。我实测过不做任何优化的情况下70B模型2048长度prompt的KV传输要几百毫秒比Prefill本身还慢。加上压缩和分层传输后能压到几十毫秒基本可接受。4.3 调度器的设计要点PD分离的调度器比单体架构复杂得多要同时考虑Prefill队列、Decode队列、KV传输队列的状态。核心逻辑是请求进来先进Prefill队列Prefill完成后KV进入传输队列传输完成后进入Decode队列。调度器要保证各队列不积压同时尽量让同一个请求的Prefill和Decode在时间上衔接紧密。一个容易忽略的点是超时处理。如果KV传输失败或Decode实例挂了请求要有重试或降级机制。我在一个项目里就遇到过Decode实例OOM导致请求卡死的情况后来加了超时重试才稳定。5. 参数调优实战那些文档不会告诉你的细节5.1 batch size不是越大越好很多人以为batch size越大吞吐越高在Decode阶段这不一定成立。Decode阶段每个token都要读一遍KV Cachebatch size增大意味着KV Cache读取量线性增长。当batch size超过某个阈值后显存带宽成为瓶颈吞吐不再提升反而因为单批次处理时间变长导致延迟上升。我实测的经验值是Decode阶段的batch size控制在8到32之间比较合适具体取决于模型大小和显存带宽。可以通过压测找到拐点——吞吐不再随batch size增长的那个点。Prefill阶段则相反batch size可以开得比较大因为计算密集大batch能充分利用算力。但也要注意显存限制Prefill的KV Cache是瞬时分配的batch太大会OOM。5.2 块大小block size的选择PagedAttention的block size是个需要调的参数。block太小页表开销大管理复杂block太大内部碎片增加。常见的选择是16或32。我一般先用16如果发现页表管理开销明显比如block数量过多导致调度变慢再调到32。这个参数对性能的影响不是特别大但值得花十分钟测一下。5.3 抢占与重计算的权衡当显存不够时推理引擎需要决定是抢占把某些请求的KV换出到CPU内存还是重计算丢弃KV需要时重新算。抢占的代价是PCIe传输重计算的代价是算力。一般来说如果CPU内存充足且PCIe带宽高抢占更划算如果算力有富余重计算更简单。我的建议是优先用抢占但要设置好换出阈值。不要等到显存完全满了才换出留10%到20%的余量避免频繁换入换出导致的抖动。6. 常见问题排查速查表调优过程中遇到的问题五花八门我把高频问题整理成表方便快速定位。现象可能原因排查方向解决思路TTFT高但TPOT正常Prefill排队或算力不足看Prefill队列长度和GPU利用率增加Prefill实例或优化batchTPOT高但TTFT正常Decode显存带宽瓶颈看显存带宽利用率和batch size减小batch或量化KV Cache延迟周期性抖动显存碎片或换入换出看显存分配日志调block size或预留余量吞吐上不去批次策略不合理看各阶段利用率PD分离或调batchOOM但显存显示有空闲碎片或预留不足看最大连续空闲块重启服务或调分配策略KV传输慢网络带宽或未压缩看传输耗时占比开启压缩和分层传输这张表是我从多次排查中总结的基本覆盖了80%的常见问题。遇到新问题时先对照这张表缩小范围再深入分析。实操心得排查延迟问题一定要分阶段打点。TTFT首token时间和TPOT每token时间要分开监控否则根本定位不到是Prefill还是Decode的问题。我见过太多团队只监控端到端延迟结果排查时两眼一抹黑。7. 几个容易踩的坑和我的应对经验第一个坑是盲目追求PD分离。PD分离不是银弹它引入了KV传输开销和架构复杂度。如果业务是短prompt短输出或者流量很小单体架构反而更简单高效。我一般建议先压测单体架构确认瓶颈确实在PD争抢上再考虑分离。第二个坑是KV Cache量化一刀切。不同层对量化的敏感度不一样有些层量化后精度掉得厉害。可以做分层量化敏感层保持FP16其他层量化。这个需要一些实验但收益明显。第三个坑是忽略CPU内存。KV Cache换出到CPU内存时如果CPU内存不够会触发swap性能直接崩掉。部署时要确保CPU内存至少能容纳峰值时换出的KV量。第四个坑是调度器没有背压机制。请求大量涌入时如果调度器无限制接收会导致队列爆炸、延迟飙升。要有背压队列满了就拒绝或降级保护系统稳定。最后分享一个我常用的压测方法用不同长度的prompt和输出组合画一张二维的性能热力图。横轴prompt长度纵轴输出长度颜色表示延迟或吞吐。这张图能直观看出系统在什么区间表现好、什么区间会崩对容量规划和参数调优非常有帮助。这套东西我在几个项目里反复验证过从单体到PD分离从FP16到INT8 KV每一步都有明确的收益和代价。核心还是那句话先搞清楚在优化什么再动手调参数。盲目调参不如先把账算清楚。

相关新闻

JCache缓存过期策略:TTL与TTI的关键差异与实战解析

JCache缓存过期策略:TTL与TTI的关键差异与实战解析

1. 题面解析:先把标准答案钉死最近又有人在群里贴出这道JCache基础篇的面试题:JCache(JSR-107)标准要求实现必须支持哪两种缓存过期策略?题目很短,答错率却很高。有人脱口而出“TTL和TTI”,有人…

2026/10/12 22:50:41 阅读更多 →
C++策略模式:给行为装上可插拔引擎的工业实践

C++策略模式:给行为装上可插拔引擎的工业实践

1. 策略模式不是“换算法”,而是给行为装上可插拔的引擎刚接触策略模式时,我跟很多初学者一样,把它简单理解成“用if-else换成了多态调用”。直到在某高校实验室参与一个跨平台图像处理Demo开发时,才真正踩进坑里——当时我们为同…

2026/10/12 22:50:41 阅读更多 →
maki和tree题解:树形DP与DFS统计恰好一个黑点的路径

maki和tree题解:树形DP与DFS统计恰好一个黑点的路径

2020牛客寒假算法基础集训营1的F题,名字叫maki和tree,题目标签写得很直白:树形DP、树上DFS。但这道题当年卡住不少人的地方不在代码,而在“到底该数什么”。它给出一棵节点染成黑白两色的树,要求统计满足特定条件的简单…

2026/10/12 22:50:41 阅读更多 →

最新新闻

文华财经波段指标源码拆解:从设计逻辑到实盘避坑指南

文华财经波段指标源码拆解:从设计逻辑到实盘避坑指南

"文华财经软件指标价值上亿波段指标源码"——我第一次看到这个标题的时候,第一反应是:又来个收割韭菜的。但说实话,这几年在期货圈子里摸爬滚打,类似"价值上亿""源码泄露""稳赚不赔"的标…

2026/10/13 4:40:10 阅读更多 →
JVM调优:STW无法消除的真相与现代GC的优化策略

JVM调优:STW无法消除的真相与现代GC的优化策略

老Java人都知道,JVM调优和线上故障排查打交道时,最让人血压上升的词就是STW(Stop-The-World)。哪怕你已经用上了G1、ZGC,还是会发现日志里时不时出现一段“user0.xx sys0.xx real0.xx”的停顿,业务线程在某…

2026/10/13 4:40:10 阅读更多 →
零代码搭建AI自动化工作流:不懂代码也能轻松上手

零代码搭建AI自动化工作流:不懂代码也能轻松上手

1. 为什么不懂代码的人反而更适合搭建AI自动化工作流很多人一听到“自动化工作流”这五个字,脑子里立刻浮现出一堆代码、脚本、API接口,然后下意识地觉得自己这辈子跟它无缘了。我刚开始接触这块的时候也是这个反应,觉得这是程序员才玩得转的…

2026/10/13 4:40:10 阅读更多 →
AI漫剧智能量产全流程:从剧本到成片的标准化实操指南

AI漫剧智能量产全流程:从剧本到成片的标准化实操指南

1. 从零起步做AI漫剧,先搞清楚这条流水线到底长什么样很多人第一次听到“AI漫剧”这个词,脑子里浮现的画面要么是那种粗糙的PPT式翻页动画,要么是满屏AI味儿的塑料感画面配机械配音。我刚开始接触这个方向的时候也是这么想的,直到…

2026/10/13 4:40:10 阅读更多 →
Robomaster智能无人机Ego-planner局部轨迹规划实战指南

Robomaster智能无人机Ego-planner局部轨迹规划实战指南

简介:本资源是面向Robomaster智能无人机赛的自主控制框架,基于Ego-planner实现路径规划与决策,适合具备ROS与C基础、希望深入无人机算法与自主飞行开发的参赛者与研究者。压缩包共994个文件,约96.35MB,以cpp、hpp、h等…

2026/10/13 4:40:10 阅读更多 →
吉林大学编译原理实战:Lex/Yacc/C手写编译器全流程

吉林大学编译原理实战:Lex/Yacc/C手写编译器全流程

简介:本资源是吉林大学编译原理课程的完整实践配套包,面向计算机专业本科生、考研备考学生及编译器技术初学者,聚焦词法分析、语法解析、中间代码生成与目标代码实现等核心能力训练。压缩包共27个文件,涵盖4个Java源码&#xff08…

2026/10/13 4:39:10 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →