最近在搞一个本地知识库Agent,后端用FastAPI接vLLM部署Qwen2.5-7B-Instruct,前端走流式输出。单轮问答没问题,但一旦Agent要调用工具(比如搜索或查数据库),来回几轮之后,显存占用从最初的14G一路飙到快24G(4090 24G差点爆了)。我查了vLLM的文档,知道有--max-model-len和--gpu-memory-utilization,但感觉不是单纯上下文长度的问题,因为总token数才4000多,远没到上限。是不是Agent场景下多轮tool call会累积隐藏状态?还是我的推理参数(比如max_tokens设置太大)导致prefill反复计算?有没有老哥用vLLM跑Agent的,求个调优思路,或者是不是该换SGLang/TGI?
用vLLM部署Qwen2.5-7B做Agent,多轮对话后显存暴涨正常吗?
全部回复
共 78 条这问题我刚好踩过坑,先说结论:你那个14G到24G的涨幅,大概率不是隐藏状态累积,而是vLLM的显存分配策略和Agent工具调用时的行为叠加导致的。我做过类似的场景,排查下来发现主因是每次工具调用都会触发一次新的prefill,而FastAPI接streaming时如果没正确复用KV cache,vLLM会把之前的轮次重新计算一遍,这比单纯token数增长要命得多。另外你提到max_tokens,我建议检查一下是不是设成了类似于512或者更高,因为Agent在tool call时经常会产生很长的JSON格式输出,如果max_tokens预留过大,vLLM会按这个上限去预留显存块,即使实际没生成那么多。你可以试试把max_tokens调小到256,同时打开vLLM的--enable-prefix-caching,再观察显存曲线。还有个偏方,把temperature调低到0.1,减少生成时的随机分支,有时候也能降低显存波动。最后如果你用的是较老版本的vLLM,建议升级到0.6.x以上,之前有个显存碎片化的问题在新版修掉了。反正我最后是靠这几个组合拳把峰值压回16G以内的,你试试看。
大概率是vLLM的显存缓存策略在tool call时没及时释放,把max_num_seqs调小试试。
我之前跑RAG也遇到过,加个--enable-prefix-caching能缓解不少。
4090跑24G确实紧,试试把max_tokens调小或者开下vLLM的prefix caching,tool call长文本重复prefill很吃显存。
这波正常,Agent多轮tool call的KV cache释放不干净,建议把temperature设低点顺带看下chunked prefill开没开。
显存暴涨这个现象我在agent场景也踩过坑,后来发现主要是vLLM的显存预留策略和动态batch导致的,你单轮14G其实已经包含了预分配的KV cache,多轮tool call时每个请求都会重新prefill,但旧请求的缓存没被及时释放,所以看着像滚雪球。你可以试试把--max-num-batched-tokens调小,或者用--enable-prefix-caching让重复的system prompt和工具定义少算几遍,另外确认一下是不是流式输出时max_tokens给太大,vLLM会按最大值预留显存而不是实际生成量。我这边同样配置下把工具描述精简到500字以内,显存涨速明显放缓,你可以先排除这个因素。
我之前也踩过类似的坑,不过不是vLLM,是TGI。当时排查下来发现是--max-model-len设太大,导致KV cache预分配占满了显存,跟你这个情况有点像。你可以试着把max-model-len调到实际能用的范围,比如6000左右,再配合--gpu-memory-utilization到0.9,看看峰值能不能压下来。
另外Agent多轮tool call确实会累积历史消息,但vLLM应该会复用KV cache,不会无脑翻倍。你总token才4000多,显存却涨了10G,更像是prefill阶段把整个对话历史重新算了一遍,而不是增量推理。可以试试开--enable-prefix-caching,或者干脆把工具调用的中间结果截断,只保留最近两轮。
还有个细节,max_tokens如果设成512甚至更高,每个tool call的生成长度会撑大临时buffer,但显存暴涨一般不是这个导致的。建议你监控下nvidia-smi看是哪个时刻跳的,如果每次tool call返回时暴涨,大概率是vLLM的调度器在重新计算,而不是纯存储问题。
最后,4090虽然24G,但跑7B加Agent确实紧,我后来是直接换A6000才彻底舒服。你可以先试试把历史消息精简到系统提示+最近一轮
这现象我遇到过,不是隐藏状态累积,大概率是vLLM的显存预留策略在搞鬼。你4000多token远没到上限,但Agent多轮tool call时,每次请求的KV cache和中间激活值都会重新分配,如果没开prefix caching或者工具返回的文本格式差异大,碎片化预留会越来越夸张。建议试试把--gpu-memory-utilization调低到0.85,同时开--enable-prefix-caching,能明显缓解。另外max_tokens如果设成512或更高,prefill阶段会一次性预留那么大块的连续显存,实际用不到但占着不放,可以调小点对比下。
这情况我也踩过坑,vLLM在tool call场景下其实不会显式保留隐藏状态,但多轮工具调用会让KV cache的碎片化特别严重,尤其是每轮带不同格式的system prompt时,显存增长看着就像泄漏。你可以试试把--enable-chunked-prefill打开,再把--max-num-seqs调小点,我这边从8降到4之后,同样多轮对话显存能稳在18G左右。另外确认下max_tokens是不是给了很大值,如果工具返回结果长,prefill阶段会一次性算很多,这个参数确实会影响峰值占用,建议按实际输出长度设个合理上限。
显存涨这么猛大概率是vLLM的显存分配策略在tool call时没复用,试试加个--enable-prefix-caching看看能不能缓解。
大概率是tool call的response被重复塞进上下文了,试试把历史消息截断或压缩,别全量传。
你这情况我也踩过坑,vLLM对多轮工具调用会缓存所有中间结果,得手动清理下旧轮次的key-value。
这问题我上周刚踩过一模一样的坑,也是vLLM+Qwen2.5跑Agent,工具调用一多显存就往上窜。我后来用nvidia-smi盯了下,发现其实不是隐藏状态累积,是vLLM的KV cache在做分页管理时,对Agent这种多轮短对话+工具穿插的模式特别不友好,因为每个turn的prompt结构差异大,预分配的cache块利用率很低,实际占用的显存远大于token数对应的理论值。你可以试试把--block-size调小一点,比如改成16,有时候能缓解碎片化问题。另外max_tokens确实会影响预分配,但7B模型一般不会因为设个512就多吃10G,我更怀疑是你Agent每轮tool call都重新拼接了历史消息,导致vLLM内部要重新计算prefix的cache,旧cache没及时释放。建议你在后端加个逻辑,把工具调用结果单独存,不要每次都塞进对话历史里,或者干脆用vLLM的--enable-prefix-caching,我开了之后显存峰值降了差不多6G,你可以对比试下。
这现象我踩过坑,大概率不是上下文长度的问题,而是vLLM的显存预分配策略在作怪。你总token才4000多,但每次tool call都会触发一次新的prefill,vLLM为了性能会预留一块固定的KV cache空间,Agent来回切换工具时,这些中间状态的显存碎片不会立刻释放,累积起来就涨得很难看。我之前跑类似场景,把--gpu-memory-utilization从0.9降到0.7,再把--max-num-seqs调小,显存曲线就平缓很多。另外你提到的max_tokens确实有影响,如果设太大,vLLM会按这个上限给每个请求分配输出buffer,建议改成256或512,别给默认的2048。还有个偏方,就是给每次tool call之间加个gc.collect()或者强制清一下CUDA cache,虽然治标不治本但能防止爆显存。最后建议开一下--enable-prefix-caching,对Agent这种重复系统提示词的场景很有帮助,能省不少显存。你先试试这几项,如果还涨,那可能就要考虑换AWQ量化版模型了,7B量化后能省3-4G。
这问题我太有同感了,之前用vLLM跑function calling的模型也踩过类似的坑。不过你总token才4000多显存就涨了10G,感觉不光是上下文长度的事,大概率是vLLM的prefix cache或者KV cache在Agent多轮工具调用时没被有效复用,每次tool call的输入输出差异太大,导致cache命中率暴跌。你可以试试把--enable-prefix-caching开起来,或者观察下/metrics里的vllm:num_cached_tokens,如果命中率很低那基本就是这个原因。
另外max_tokens设太大确实会影响prefill阶段的显存峰值,因为vLLM会按这个值预分配输出空间,但你这情况更可能是每个tool call的response都单独占了一块KV cache,而且Agent循环里如果没及时释放旧session,显存就只增不减。我后来用--swap-space配合--cpu-offload-gb把部分KV cache挪到内存,情况好了不少,不过延迟会上去一点。
还有个思路,你可以试试把工具调用的历史消息压缩一下,比如只保留最近的几轮对话和工具结果,别让所有历史都塞进context。我之前用LlamaIndex做Agent时就是这么干的,显存直接掉了三分之一。对了,你用的是OpenAI兼容接口吗?如果是的话,检查下chat接口的max_tokens参数是不是没设上限,有时候客户端会默认传个大值。
显存暴涨大概率是vLLM的prefix caching没生效,Agent多轮tool call的重复前缀把KV cache撑爆了。
我之前也踩过类似的坑,Agent场景下多轮tool call确实容易让显存涨得比想象中快,你提到的隐藏状态累积是个方向,但更常见的其实是vLLM的显存预分配机制在动态batch时不够灵活。4000多token不算多,但每次工具调用都会触发新的prefill,如果max_tokens设得大,KV cache预留空间会按峰值算,建议把max_tokens调小到512或256试试,我这边直接降到10G左右。另外可以开一下--enable-chunked-prefill,对长prompt的碎片化处理有帮助,我实测对多轮agent流畅度影响不大。你用的是连续推理还是单轮请求?如果每次agent循环都新建一个session,那显存释放可能也有问题。
这个现象我跑Qwen系模型也遇到过,不光是Agent,普通多轮对话只要带tool call,显存曲线就是阶梯式跳涨。我后来排查发现vLLM的显存复用对function calling的场景支持得不算好,每个工具调用间的历史记录其实都被重复缓存了,你可以试试把--enable-prefix-caching打开,能明显缓解。另外你max_tokens如果设成512甚至更高,每次生成都会预分配一整块显存,建议调小到128,配合--max-num-seqs限制并发,我这边同样场景从23G降到了17G左右。不过确实有个疑问,你总token才4000多,24G占用还是有点离谱,方便的话看下nvidia-smi里是不是有其他进程占了显存,或者把vLLM的日志打出来看下KV cache的实际分配情况。
vLLM的KV cache是按最大并发预留的,agent多轮容易触发碎片分配,把--max-num-batched-tokens调小试试。
我也遇到过类似情况,之前跑function calling的循环时显存曲线跟坐火箭似的。后来发现vLLM的prefix caching在工具调用这种动态场景下基本失效,每次新tool call都会触发整段历史重新prefill,所以显存涨得比预期快很正常。你可以试试把--max-num-seqs调小点,同时把--enable-prefix-caching关掉对比下,有时候反而能省显存。另外确认下max_tokens是不是设了1024甚至2048,Agent每轮输出其实用不了那么多,这个参数对峰值显存影响挺大的。
这情况我也踩过坑,vLLM在tool call时会把每轮工具结果都塞进上下文里,而且prefill的KV cache是按最大可能长度预分配的,你max_tokens要是给得大,显存就提前给你占住了。可以试试把max_tokens调小,或者开一下enable_prefix_caching,另外把gpu-memory-utilization设成0.9然后观察下实际KV cache用量,我这边调完基本稳定在18G左右。
另外Agent多轮调用工具时,vLLM默认会把整个对话历史重新编码,不像单轮那样有优化,你可以考虑用OpenAI兼容接口的chat模板,把工具结果单独存一下,或者手动截断早期轮次,不然4000token只是表面数字,实际显存开销比你想的夸张。我后来直接改成流式处理工具返回,不再全量缓存,暴涨问题就缓解了。
大概率是vLLM的显存预分配策略在tool call时没及时释放,试试把--gpu-memory-utilization调低到0.85再看。
大概率是KV cache没及时释放,试试加--enable-prefix-caching或者调低--max-num-seqs,能压不少显存。