最近在搞一个本地知识库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 条这情况我遇到过类似的,别急,大概率不是显存泄漏。vLLM在Agent多轮tool call时会为每轮对话保留K/V cache,你虽然总token才4000,但每轮Function Call的输入输出都会重新走一遍prefill,加上max_tokens如果设得很大,它会按最大值预留显存,所以看着涨得凶。你可以试试把--max-model-len调小点,或者强制设--max-num-seqs,还有就是把Agent每轮的对话历史截断,只保留最近几轮,这能明显压住显存曲线。
这情况太典型了,我之前用vLLM跑函数调用也踩过坑。显存暴涨大概率不是上下文长度问题,而是vLLM的显存管理机制在Agent多轮tool call时,每个step的KV cache没被及时释放,加上你max_tokens如果设得高,prefill阶段会一次性预留大量显存。建议把--max-model-len调小到实际够用的值,再把--gpu-memory-utilization设到0.9以下,同时检查一下是不是每次工具调用都重新加载了系统prompt,那会让prefill重复计算。另外可以试试--enable-prefix-caching,对多轮相似前缀的请求能省不少显存。
显存暴涨大概率是vLLM的prefix caching没开,tool call历史会被重复计算,加个--enable-prefix-caching试试。
也可能是max_tokens设太大,把每次生成的预留空间都占了,调小点能省不少。
说实话这个现象我在生产环境也踩过,vLLM的显存增长在tool call场景下确实比纯对话诡异很多。你总token才4000多但显存快到24G,我觉得不完全是max-model-len的锅,更像是vLLM的KV cache预留策略和Agent多轮请求之间的交互问题。vLLM默认会按max-model-len一次性分配KV cache空间,哪怕你实际没用满,显存占用也会先撑起来,而且每次tool call返回结果后重新发起请求,之前的KV cache不一定被及时释放,尤其是用了连续多轮工具调用时,前缀复用逻辑可能没你想的那么高效。
另一个我怀疑的点是prefill阶段的计算峰值,Agent场景下每轮tool result都是新文本,会触发重复的prefill而不是增量decode,这时候显存峰值会比纯对话高不少,因为要同时缓存中间激活值。你可以试试把--max-model-len调小到实际需要的大小,比如8K,同时把--gpu-memory-utilization设到0.85左右,给KV cache留点余量但别让它无限膨胀。另外max_tokens别设太大,比如256或512就够了,不然每轮生成时vLLM会为最大可能长度预留显存,即使实际生成很短。
我之前跑过类似的RAG Agent,最后是改成每次请求前手动清一下vLLM的cache,或者用更细粒度的控制参数,比如--block-size调小一点,能缓解不少。你可以先看下vLLM的日志里每个请求的KV cache命中率,如果很低,基本就是前缀复用失效了,这时候把工具结果的prompt格式固定住,让前缀尽可能一致,比调显存参数更有效。建议在本地用nvidia-smi监控一下prefill和decode阶段的显存曲线,能更清楚看到暴涨发生在哪一步。
遇到过类似情况,tool call来回切换时KV cache的碎片化比普通对话严重不少,尤其vLLM的page管理在这种多轮分支场景下会有额外开销。你试试把--max-num-seqs调小,或者开一下--enable-chunked-prefill,有时候能缓解。另外确认下是不是每次tool调用都重新build了完整的prompt,有些Agent框架会把历史工具结果全拼进去,token数看着不多但实际长度分布很散。还有个小细节,max_tokens别设太大,decode阶段也会占显存,尤其是流式输出时prefill和decode叠加容易吃满。
这情况我遇到过,24G跑7B本来就紧巴巴的,你那个14G到24G的涨幅更像是vLLM的显存缓存策略在作祟,尤其是tool call来回切换时,之前对话的KV cache不释放,新请求又拼命占。建议你把--gpu-memory-utilization调到0.9以下,再配合--max-num-seqs限制并发,不然多轮之后必然爆。另外,总token数4000多但显存涨这么多,不排除是vLLM对工具调用这类特殊格式的padded batch处理不够优化,你可以试试把工具定义精简一下,或者每次tool call后手动截断历史对话,只保留最近两轮。
这问题我太有同感了,之前用vLLM跑类似的多步工具调用也踩过坑。你说的显存暴涨,我怀疑不是隐藏状态累积,而是vLLM的显存分配策略在作祟——它默认会预分配一部分KV cache,即使实际token数才4000多,但多轮tool call会导致每次请求的prompt长度变化剧烈,vLLM为了保持性能会尽量复用之前的KV cache,但Agent场景下每轮对话的输入结构都不同(比如工具返回结果插在中间),这会让它不得不重新计算前缀,反而触发显存碎片化。我试过把--gpu-memory-utilization调到0.85,同时把--max-num-seqs调小到1(强制串行处理),显存峰值能压下来不少,不过吞吐会降。另外检查下你的max_tokens,如果设成512甚至更高,每个输出步都会预分配那么多显存,即使实际只生成了几十个token,这部分膨胀在Agent多轮累加下也挺可观的。还有个思路是干脆对工具调用场景单独开一个vLLM实例,用不同的调度参数,别和普通对话混在一起,虽然麻烦但显存曲线会平滑很多。你试试把max_tokens降到128,然后看下nvidia-smi你峰值是不是出现在prefill阶段,如果是,那基本就是预分配的问题了。
这情况我也踩过坑,vLLM在tool call多轮时其实会为每个历史请求保留完整的KV cache,加上你如果max_tokens设得偏大,prefill阶段计算量会明显增加,显存自然就上去了。可以试试把max_tokens调小到256或512,同时开一下--enable-prefix-caching,对重复的工具调用前缀会有缓存效果。另外Agent场景建议单独起一个长对话专用的vLLM实例,和普通问答分开,不然互相挤显存很麻烦。你那边total token数4000多是按什么口径算的?如果包含工具返回的文本,实际占用可能比想象中高不少。
这现象我也踩过坑,vLLM的显存增长不光是KV cache,Agent模式里多次tool call切换时,历史对话被反复prefill,加上每个工具返回的文本都算进上下文,实际占用的临时buffer比你想的多得多。你可以试试把--max-model-len调小到8k以下,同时把--gpu-memory-utilization设到0.9,再配合--enable-prefix-caching,能明显缓解。另外确认下是不是每次工具结果都跟历史消息一起传给模型了,有些框架会重复拼接,这才是真凶。你观察下单次工具调用前后的显存增量,如果每次都是跳涨几G,那就是prefill的临时张量没释放干净。
同款配置踩过坑,4090跑7B多轮tool call确实会这样。你总token才4000多但显存涨这么多,大概率不是上下文长度的问题,vLLM的KV cache是按最大并发和max-model-len预分配的,但Agent场景下每轮工具调用都会重新走一遍prefill,中间状态释放不干净。可以试试把--max-num-seqs调小点,或者换个调度策略,另外检查下是不是流式输出时response对象没正确关闭,我之前就是这里泄漏。还有个偏方,把工具调用结果直接截断塞进上下文,别让模型自己生成太长的观察内容,能省不少显存。
这问题我熟,之前用vLLM跑类似Agent场景也踩过坑。你总token才4000多但显存飙到24G,大概率不是上下文长度的问题,而是tool call的时候每次都会把历史对话重新塞进prefill阶段,加上vLLM的KV cache是按最大并发和最大长度预分配的,哪怕实际没用满,显存也先占上了。我上次试过把--gpu-memory-utilization调到0.85,再配合--max-num-seqs限制并发,显存峰值能压下来不少,但偶尔还是会在多轮工具调用后出现碎片化增长。你查一下是不是每次工具返回结果后,系统prompt或工具定义被重复拼接了,有些版本对这类结构化输入的显存管理优化得不好。另一个思路是给Agent加个短期记忆裁剪,只保留最近两轮的工具结果,把更早的压缩成摘要再喂给模型,这样既省显存也不影响效果。我这边还发现把--enable-prefix-caching打开能显著减少重复prompt的prefill开销,你可以试试看是不是这个原因。
我遇到过类似情况,不是上下文长度的问题,vLLM在tool call场景下每次函数调用都会重新计算KV cache,而且Agent多轮对话的prompt结构变化大,prefill阶段的开销会明显增加。你试试把--enable-prefix-caching打开,能复用之前的计算,另外检查下是不是每次tool结果都拼进历史了,那会让KV cache碎片化。max_tokens设太大倒不是主因,但别超过2048,否则单次生成预留空间太多。我这边调完从峰值22G降到了16G左右,你可以参考下。
遇到过类似情况,不过我是用TGI跑的,多轮tool call后显存曲线也是阶梯式上涨。你说的隐藏状态累积我觉得方向对,vLLM的continuous batching在Agent场景下每个请求的KV cache生命周期会被拉长,即便token数不高,中间那些工具调用的输出token也会被算进显存分配里。可以试试把--enable-prefix-caching打开,然后调低--max-model-len到8K看看,有时候默认分配策略会预留太多空间。另外确认下max_tokens是不是设成512或更高了,工具调用那轮如果返回长文本,prefill的计算峰值会很夸张。
这问题我遇到过,vLLM对多轮tool call的显存管理确实有点坑。你总token才4000多,但每次工具调用返回的结果会被当成新请求的一部分重新走prefill,中间状态没释放干净,累积起来就涨得厉害。建议试试把--max-num-seqs调小,或者开一下--enable-chunked-prefill,应该能缓解。另外确认下max_tokens是不是设成了512或更高,工具返回长文本时很容易把单次生成长度拉满。
这问题我也踩过坑,vLLM在Agent场景下多轮tool call的显存暴涨,很大概率是每次工具调用都触发了完整的prefill,而vLLM对这类非连续对话的KV Cache管理并不高效,会保留大量中间状态的缓存。你可以试试把--max-model-len调大但把--gpu-memory-utilization设低一点,强制它更激进地释放缓存,或者直接开--enable-prefix-caching看看能不能复用工具调用的公共前缀。另外max_tokens确实会影响预分配空间,但4000多token不该涨这么多,建议在日志里开--verbose确认下每个请求的实际KV cache大小,我之前发现是vLLM默认的调度策略在长会话里会预留太多buffer。
这问题我也踩过坑,vLLM的显存增长跟Agent tool call关系真不大,主要是每个step的prefill都会重新计算历史KV cache,多轮工具调用等于把之前的对话反复过了一遍,所以就算token总数不高,显存也会涨得很快。你可以试试把--enable-prefix-caching开起来,能复用公共前缀的缓存,另外max_tokens别给太大,尤其tool call的response一般很短,设个512就够用了。还有个取巧的办法,就是定期把历史对话做个摘要压缩掉,不然就算这次不爆,多跑几个session迟早要撞墙。
显存涨这么快大概率是vLLM的KV cache没及时释放,Agent工具调用时历史轮次全被保留了,试试开prefix caching或者调低gpu-memory-utilization。
显存涨这么猛大概率是tool call的history没被正确截断,vLLM对多轮function calling的cache管理有坑,试试把对话轮次压缩下。
检查下是不是每次工具调用都传了完整历史,vLLM的prefix cache在动态工具结果下会失效,手动限制下max_tokens和轮次试试。
我之前跑类似场景也遇到过这问题,后来发现多半不是隐藏状态累积,而是vLLM的显存池没及时释放,加上Agent每轮tool call都会重新走一遍prefill,峰值就叠上去了。你可以试试把--max-num-seqs调小点,或者给每个请求显式设个max_tokens上限,别让默认值太大。另外我怀疑跟--enable-prefix-caching也有关系,开一下看看能不能缓解重复前缀的显存开销。
工具调用时vLLM会为每轮单独缓存历史KV,4000token看着不多但多轮累积也吓人,试试开--enable-prefix-caching或者把max_tokens调小点。
这情况正常,Agent场景下工具返回的内容会反复prefill,建议把--gpu-memory-utilization设到0.9再配个--swap-space,能缓解不少。