最近在搞一个内部用的智能客服,选了个7B的模型,用vLLM部署在单张A100上。离线测试时感觉还好,一上线并发一上来,响应时间直接奔着10秒去了,用户狂吐槽。我试了调低max_num_batched_tokens和换量化,效果不明显。想问下大家,有没有比较成熟的方案或者参数调优经验?比如是否一定要上多卡推理?或者有没有轻量级的替代框架?另外,是不是我的batch设置有问题?求指点,谢谢!
部署7B模型到生产环境,推理速度慢得离谱,请问怎么优化?
全部回复
共 164 条先排查下是不是并发打满时显存和算力分配的问题,A100跑7B理论上不该这么慢,10秒大概率是prefill阶段被长prompt堵住了。建议把max_num_batched_tokens调大而不是调小,配合vLLM的continuous batching看看,另外开一下--enable-chunked-prefill对长文本并发提升很明显。如果还不行,试试把模型切成FP8或者AWQ量化,单卡吞吐能翻一倍。多卡不一定必要,除非你的并发QPS真的一直在50以上。顺带问下你用的什么量化方式,GPTQ和AWQ在vLLM上性能差距挺大的。
试试把并发请求压成连续批处理,vLLM的continuous batching参数调过没?我这边调完直接快了三倍。
之前也踩过类似的坑,单卡A100跑7B并发一上来确实容易崩,你先看看是不是prefill和decode阶段混在一起导致显存碎片化严重,试试用vLLM的continuous batching配合paged attention把max_num_seqs调小一点,比如从256降到64。另外量化别光看AWQ,试试FP8或者GPTQ的4bit,有时候对吞吐的影响比延迟更明显。如果业务允许的话,部署两个实例做负载均衡,比直接上多卡更灵活,毕竟多卡通信开销也不小。还有个小细节,确认下你的prompt长度是不是被padding得很长,有时候这个才是隐性杀手。
我之前也踩过类似的坑,单张A100跑7B其实算力是够的,但并发一上来瓶颈多半在显存带宽和调度上。建议先看看你的vLLM是不是默认用了连续batching,试着把max_num_seqs调小一点(比如32或64),同时把gpu_memory_utilization拉到0.9以上,给KV cache留足空间。另外量化的话,AWQ比GPTQ在低并发下延迟更稳,但别用INT8,实际提升很小。如果还不行,可以试试把模型切成2卡tensor parallel,单卡延迟能降一半,但注意通信开销,小batch下可能不如单卡调优。最后,确认下你的输入prompt是不是特别长,长文本会直接拖垮首token延迟,考虑加个长度截断或做上下文压缩。
我之前也踩过类似的坑,单看离线吞吐量挺好看,一上真实并发就露馅。你试过把vLLM的--max-num-seqs调小一点吗?比如默认256改成64或32,有时候并发高反而是排队等decode,不是算力不够。另外不一定非要上多卡,先确认一下是不是卡在显存带宽上,7B模型其实可以试试AWQ量化配合FP8,显存占用降下来后batch能开更大。还有个小建议,把客户端的请求做一下流式返回,首token延迟能压到1秒内,用户体感会好很多。
我之前也踩过类似的坑,单看离线吞吐根本反映不了线上情况。你试试把vLLM的continuous batching开启,然后把max_num_seqs调大点,同时把gpu_memory_utilization设到0.9,有时候是显存没吃满导致调度碎片化。另外确认下你的输入输出长度是不是有极端长尾,客服场景经常有超长上下文,这玩意对首token延迟影响巨大,可以加个prompt缓存或者截断策略。多卡不一定必须,但如果你并发超过20,单卡确实有点吃力,可以先用2卡做tensor parallel看看,成本比换框架低。
我之前也踩过类似的坑,单卡A100跑7B其实算力是够的,问题往往出在vLLM的批处理和显存管理上。你调max_num_batched_tokens没用,很可能是这个值设得太小,导致并发请求被拆成太多小batch,反而增加了调度开销,建议直接把它提到几千甚至上万,让vLLM自己动态拼batch。还有,检查下是否开了continuous batching,这个对在线推理的延迟影响特别大,默认没开的话一定要打开。另外,量化别只盯着AWQ或者GPTQ,试试FP8或者KV cache量化,显存带宽瓶颈往往比算力更致命。如果并发实在高,先别急着上多卡,单卡调优空间还有不少,比如用--enable-prefix-caching缓存客服常见问题的前缀,能省掉大量重复计算。多卡的话,张量并行在7B规模上收益有限,除非你同时跑好几个模型,否则通信开销可能抵消掉计算增益。最后问下,你的A100是40G还是80G版本?如果显存还有余量,把max_model_len调大点、预分配更多KV cache,响应时间有时候能直接砍半。
单张A100跑7B按理说不该这么拉胯,你这大概率是并发请求把prefill和decode混在一起挤爆了,试试用vLLM的continuous batching把max_num_seqs调小点,比如压到16-32之间,同时把--enable-chunked-prefill打开,能明显改善首token延迟。如果还不行,可以考虑把模型切成4-bit量化配AWQ,精度损失不大但吞吐能翻倍。多卡不是必须的,但如果你并发超过20,单卡确实到头了,上张4090做张量并行分两卡跑也就几分钟的事。另外检查下是不是prompt太长,把历史对话截断到512 token以内,很多时候响应慢是输入序列在拖后腿。
之前跑7B也踩过这坑,后来发现瓶颈多半在prefill阶段而不是decode,试试把max_num_batched_tokens调高而不是调低,同时给vLLM开上continuous batching,并发上去后吞吐能好不少。另外A100单卡跑7B其实够用,但得看看是不是你的输入输出长度太长把显存吃满了,可以限制下最大生成长度。如果还不行,可以试试把模型切到FP8或者用AWQ量化,配合vLLM的量化内核,通常能有一倍提升。多卡的话除非你并发特别高,不然暂时没必要,先把单卡的调度参数摸透再说。
我之前也踩过这坑,问题多半在并发和max_num_seqs没调好,试试把max_num_seqs设成8到16再配个continuous batching。
看到这个情况我第一反应是并发上来了但显存没吃满,你先看一眼gpu利用率是不是一直在低位徘徊。单张A100跑7B理论上不该这么慢,vLLM的continuous batching对短对话场景挺吃香的,但你这响应10秒大概率是排队卡在prefill阶段了,试试把max_num_seqs调大点,同时把max_paddings设成1,让batch尽量填满。
另外我怀疑你离线测试的时候是不是用了固定prompt长度,上线后用户问题长短不一,长prompt的prefill会直接卡住整个batch,这种情况可以考虑把模型切成4bit或者8bit,虽然量化后单token速度提升有限,但能腾出显存塞更大的batch,整体吞吐会好看很多。
多卡的话其实不一定要上,除非你模型切分后能把单卡负载降下来,但7B在A100上单卡理论能扛住几十并发,问题多半在参数没调透。你可以试试开vLLM的--enable-prefix-caching,如果客服问题有大量重复开头,这个能省掉不少重复计算。
还有个比较野的路子,如果业务能接受,把模型蒸馏到一个3B甚至2B的小模型,配合rag把知识库外置,响应能压到1秒内,内部工具场景准确率损失可能没你想象的大。我上次调类似问题最后发现是tokenizer的padding策略没对齐,导致vLLM分配显存碎片化了,你要不也检查下这块?
我之前也踩过类似的坑,单卡A100跑7B其实瓶颈往往不在显存而在计算和调度上。你试试把max_num_seqs调小一点,比如压到32或16,同时确保vLLM的continuous batching真正生效,有时候并发高是因为请求排队而不是推理慢。另外别急着上多卡,先看看是不是prompt太长或者output长度限制设得太高,还有attention后端用flash-attention会快很多。如果还是慢,可以试下把模型量化到FP8或者AWQ,效果比GPTQ在vLLM里更稳。
我之前也踩过类似的坑,7B在A100上单卡并发一高确实容易崩,10秒响应多半是prefill和decode互相抢资源了。可以试试把vLLM的continuous batching调小,比如把max_num_seqs限制在16左右,同时给模型开paged attention的显存池,别让KV cache吃满。另外不一定急着上多卡,先把输入长度截断到512,输出限制到128,很多客服场景其实用不到那么长上下文。如果还不行,可以看看是不是prompt里塞了太多系统指令,精简一下往往效果立竿见影。
先查下实际并发数和输入长度,10秒大概率是prefill没控住,vLLM的continuous batching要配好max_num_seqs才行。
我碰到过类似的情况,其实问题可能不在vLLM本身,而是并发请求的调度策略和前缀缓存没调好。你试试把max_num_batched_tokens提上去,同时开一下continuous batching,有时候反而比调低更有效。另外,单张A100跑7B理论上不该这么慢,检查下是不是显存碎片化或者CPU offload被意外触发了。如果还不行,可以看看LightLLM或者SGLang,有些场景下它们对并发控制更细腻。你那边并发大概是多少?如果是几十路的话,可能得考虑多卡了。
试试把max_num_seqs调大点,vLLM默认批处理太小,并发一上来就卡死,另外开个prefix caching能省不少事。
先查下是不是max_num_seqs太小导致并发排队,调到32试试,vLLM这块比量化影响大。
试试把模型切成4bit加FP8 KV cache,A100上吞吐能翻倍,延迟比多卡划算多了。
vLLM官方文档里其实强调过max_num_batched_tokens不是单纯调低就行的,你试过把continuous batching的开关打开吗?之前我遇到过类似情况,最后发现是CPU offload和GPU显存分配互相打架,建议先nvidia-smi盯一下实际显存占用和GPU利用率。另外单卡A100跑7B并发高确实吃力,但先别急着上多卡,试试把模型切到4bit并配合paged attention,吞吐能翻一倍。还有个细节,你的prompt里要是带太多历史对话,prefill阶段会卡死,得控制上下文长度。
并发一上来就崩多半是显存带宽瓶颈,先查下vLLM的continuous batching有没有真正生效,再试试把max_num_seqs调低到16看看。
试试把并发请求压到4以内,配合Continuous Batching调优,单卡A100跑7B其实能到1秒内。