最近在搞一个本地知识库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的显存预分配策略在作怪,试试调低--gpu-memory-utilization到0.85,顺便把--max-num-seqs压到2看下。
Agent多轮工具调用本来就会让KV cache碎片化,你总token才4k但显存涨这么多,八成是prefill阶段临时tensor没及时释放。
这情况我倒是遇到过类似的,不过我是用TGI跑的,也出现过tool call多轮后显存异常增长。你总token才4000多确实不该涨这么狠,我怀疑是vLLM的continuous batching在tool call时把历史对话当成独立序列缓存了,导致KV cache没有正确复用。你可以试试把--enable-prefix-caching打开,或者手动把每轮tool call的system prompt固定下来,看看显存曲线会不会平缓些。
另外你提到max_tokens,我觉得关系不大,prefill计算量跟实际token数挂钩,除非你每次都生成一大段再截断。倒是可以检查下是不是Agent代码里把每轮完整历史都重新塞进请求了,vLLM对重复前缀的cache命中率其实挺敏感的。我之前是把每轮对话的tool result单独存起来,下一轮只传增量,显存直接降了30%。你要不也试试这个思路?
这情况我也踩过坑,Agent场景下显存暴涨真不一定是上下文长度的问题。你试试把--enable-prefix-caching打开,我这边开了之后重复的tool call前缀能复用KV cache,显存曲线平缓很多。另外你把max_tokens调小点,比如1024,有时候vLLM会按最大可能输出预留显存,实际生成没那么多但空间已经占住了。还有个小技巧,多轮工具调用时把历史消息里的system prompt和工具描述精简一下,别让它们重复进prefill,能省不少buffer。你那边如果还爆,可以看看是不是--max-num-seqs设太高,并发序列多了也会挤占显存。
显存涨这么多确实不太正常,我怀疑不光是max_tokens的问题。你试试把vLLM的--enable-prefix-caching开起来,Agent场景里工具调用的system prompt和工具定义是重复的,这个缓存能省不少显存。另外检查下是不是流式输出时response对象没释放干净,我之前遇到过类似情况,后来发现是前端没及时close连接导致的。还有个小建议,把工具调用的历史单独存下来,别全塞进对话上下文中,这样既省显存又能控制token数。
这情况我遇到过,vLLM在tool call场景下会把历史对话连同工具返回结果一起重新prefill,即便token总数不高,但每次工具调用后的KV cache碎片化挺严重的,显存增长曲线不是线性的。你可以试试把--enable-prefix-caching打开,再配合--max-num-seqs调小一点,我这边从16G涨到22G的问题就这么缓解的。另外max_tokens确实别设太大,Agent每轮输出如果都预留1024以上,很容易把显存撑满,建议按实际工具返回长度动态设置。
这问题我上周刚踩过,先说结论:大概率不是隐藏状态累积,vLLM的KV cache是按block动态分配的,不会因为tool call多轮就额外吃显存。我觉得你那个总token数4000多可能统计的不准,Agent场景下系统提示词、工具定义、历史observation反复拼接,实际进入模型的序列长度往往比你感知的长得多,尤其是工具返回的JSON或者数据库结果如果有几百行,那prefill的显存峰值会瞬间拉高。另外max_tokens设太大确实有影响,vLLM会为每个请求预分配完整的max_tokens长度的KV cache空间,如果你设成1024甚至2048,那多轮对话时每个请求都得预留这么大,累积起来相当可观。建议你把max_tokens调到256或512,然后开--enable-prefix-caching,这样工具定义和系统提示词部分能复用缓存。还有个土办法,用/metrics接口监控下每步的gpu_cache_usage_perc,如果单轮请求结束后cache usage没降下来,那就是释放策略的问题,可以试试--swap-space调大点。最后检查下是不是FastAPI那边没做并发控制,多个请求同时打进来,vLLM会为了保吞吐把显存撑满。
这个现象我这边也踩过,Agent多轮tool call时vLLM会把每轮对话的history和tool结果都塞进KV cache,即使token总数不高,但多轮调用之间的中间状态和长尾attention也会让缓存膨胀,14G到24G的涨幅其实挺典型的。你试试把--max-num-seqs调小一点,比如改成4或者8,能显著降低并发序列带来的显存峰值,另外确认下--enable-prefix-caching是不是开着,它对重复的tool call前缀有优化效果。还有个小建议,如果工具返回结果很长,可以在传给模型前做个截断,减少每轮的实际输入长度,这比调max_tokens直接得多。
我之前用vLLM跑Qwen2.5-7B做function calling也碰到过类似情况,观察下来显存上涨主要不是prefill,而是多轮对话里每次tool call返回结果后,vLLM会保留所有历史KV cache,而且Agent场景下系统提示词和工具描述往往被重复拼接,实际有效上下文可能比你想的大。可以试试把--max-model-len调小到5120,同时把--gpu-memory-utilization设到0.9,另外检查一下是不是--enable-prefix-caching没开,这个对重复前缀的缓存很关键。还有个小技巧,把工具描述从system prompt里拆出来,每次调用时单独作为user message传入,能明显减少缓存膨胀。我这么改之后,连续跑20轮工具调用,显存基本稳定在18G以内,你可以对比下自己的参数配置。
这问题我也踩过坑,Agent场景显存涨得快不一定是上下文长度的事。你提到总token才4000多,但每次tool call的tool result都会重新进KV cache,而且vLLM的continuous batching在流式输出时可能把prefill和decode混在一起,显存峰值会虚高。我之前跑类似流程,把max_tokens调小到512,同时开enable_prefix_caching,涨势明显缓和了,你可以试试看是不是这个原因。另外4090 24G跑7B本来就很极限,如果还开多个并发请求,建议直接上多卡或量化。
这问题我遇到过,vLLM在Agent场景下的显存增长其实很多时候是KV cache的碎片化加上prefill阶段的长尾效应,不是单纯看总token数。你试试把--max-num-seqs调小到4或者8,同时限制一下单次tool call的max_tokens到512,应该能明显缓解。另外如果工具返回结果很长,考虑先截断再塞回上下文,不然prefill的显存峰值会很夸张。
显存翻倍这个现象我也踩过,关键不在context长度,而是vLLM的显存预留机制——它默认会按max-model-len把KV cache全部分配好,你4K token实际用的少,但预留空间没释放。agent多轮tool call会让每次请求的序列变长,prefill阶段的计算图也会膨胀,建议试试把--max-model-len调低到8K,同时显存利用率拉到0.9,另外max_tokens别给太大,50-100就够工具返回用了。我这边之前也是4090,这么调完基本稳定在16G左右。
工具调用会缓存历史推理过程,把max_tokens调小点试试,我之前也遇到过这情况。
这问题我前几天刚踩过,vLLM在多轮tool call时显存增长确实有点反直觉。你总token才4000多,但中间那些工具返回的JSON结构往往很长,而且每轮agent的system prompt都会重新拼一遍,导致prefill的KV cache实际占用比你想的高不少。另一个坑是vLLM默认会为每个请求预留max_tokens的显存,你要是设了1024甚至2048,叠加多轮并发请求,那显存就是按最坏情况涨的。建议你把max_tokens调小到512试试,同时用--enable-prefix-caching,让重复的system prompt和工具描述走缓存,能省不少。还有,如果工具返回结果本身很长,考虑在后端截断或摘要一下再喂给模型,别让原始数据全进上下文。最后,24G快爆的时候注意看下nvidia-smi里是不是有碎片化,vLLM的显存池有时候不会自动回收,可以定期重启服务或者用--swap-space把部分KV挪到CPU。
vLLM的显存增长其实和hidden state累积关系不大,它不像transformers那样每轮都保存梯度,主要还是KV cache在作祟。你总token 4000多看着不多,但Agent场景下每个tool call的输入输出会反复重算prefill,而且vLLM默认会为未来可能的生成预留显存,这个预留量是按max-model-len算的,不是按当前实际长度。你可以试着把--max-model-len调低到4096或5120,同时--gpu-memory-utilization设成0.85以下,给KV cache留点余量。另外max_tokens如果设太大,比如1024或2048,每次生成都会按这个上限分配block,多轮下来碎片化也会吃显存,建议设成512左右。还有个小坑,如果用了--enable-prefix-caching,工具调用的system prompt和工具定义每次都会参与attention计算,这部分也会占显存。你可以在vLLM的日志里看下“KV cache size”那几行,对比不同轮次的实际数值,能更准确定位是预分配还是真实增长。我之前用Qwen2.5-14B跑类似场景,把max-model-len砍到6000后,多轮tool call稳定在20G以内,你可以试试。
这情况我也踩过坑,把max_tokens调小点,另外看看是不是工具调用时历史消息重复塞进prompt了。
显存涨这么快不正常,建议查下vLLM的block管理,开prefix caching能缓解不少。
Agent场景下工具调用会反复prefill历史消息,试试把max_tokens调小点,或者用--enable-prefix-caching。
说实话我遇到过一模一样的情况,vLLM在工具调用场景下显存涨得比普通对话快很多,不只是KV cache的问题。你试试把--max-model-len调小到4096或者更小,同时把--gpu-memory-utilization设成0.85以下,给CUDA留点余量,我这么改之后稳定多了。另外检查下FastAPI那边是不是把历史消息全塞进prompt了,tool call的返回结果有时候会重复拼接,这个也吃显存。还有个小技巧,关掉--enable-prefix-caching试试,有时候它反而让碎片化更严重。
遇到过类似的情况,不过我是用8B模型跑的Agent,显存涨得没你这么猛但趋势一样。我觉得不一定是隐藏状态累积,vLLM的KV cache是按块分配的,多轮tool call会不断产生新的历史记录,即使token总数不高,如果每轮工具返回的文本比较长,prefill阶段也会临时占用额外的显存,峰值会高不少。你可以试试把--max-num-seqs调小一点,或者限制工具返回内容的长度,另外把--gpu-memory-utilization设到0.9以上,给KV cache留更多空间,应该能缓解。还有你提到的max_tokens,如果设太大确实会影响显存分配,建议按实际需求调低。