统一三模型任务:vLLM 0.6.3+解决多客户端切换问题
当你的 PDF 处理需要同时兼顾三种模型时,手动切换客户端、调整请求格式的繁琐让人无法忍受。而这周末,通过将这三个模型(GLM-OCR、DeepSeek-OCR-2、Dots.mocr)集成到同一个统一网关上,用 OpenAI SDK 统一调用,就可以完全摆脱这种烦恼。核心在于利用 vLLM 0.6.3+ 的特性来统一对话模板和图片 token 处理,避免每次都要修改各自代码中的 modeling_xxx.py。
统一对话模板与图片处理
vLLM 的 --chat-template 参数能够将三个模型的对话模板统一到同一个后端,而 --limit-mm-per-prompt 则通过限制图片 token 的占用来调整各个模型的性能需求。例如,GLM-OCR 的 image=4 限制与 DeepSeek-OCR-2 的 image=4 相同,但切换到 Dots.mocr 时,如果不调整,可能会因为模板差异导致图片处理超时。此时,需要确保 Dots.mocr 的模板文件(如 ~/.config/vllm/templates/dots-mocr.jinja)中正确替换 <|image|> 为 <image>,否则会出现模型识别错误。
显存与并发规划
三个模型的全量加权浮点格式(bf16)总需求为 52G VRAM,而一张 24G 的 RTX 3090/4090 无法同时运行。因此,我选择使用 AWQ 4bit 量化版(来自 qtip-ai 或 ModelTC 的转换),将三个模型压缩到一张 48G 的 A6000 显卡上,并设置并发数量为 2,以满足日常批量单据的处理需求。如果显存不足,可以尝试减少 --max-model-len 参数,但这样会影响模型的上下文长度,可能导致部分任务无法完成。
三个终端独立启动
为了避免端口冲突,我将每个模型分别启动在不同的端口:
# GLM-OCR 运行在 8001 端口,使用 GLM-OCR 的内置模板 glm-ocr,并限制图片 token 为 4 个
vllm serve qtip-ai/GLM-OCR-9B-AWQ --port 8001 --chat-template glm-ocr --limit-mm-per-prompt image=4 --max-model-len 8192 --quantization awq_marlin
# DeepSeek-OCR-2 在 8002 端口,使用 DeepSeek-VL2 的模板 deepseek-vl2,同样限制图片 token 为 4
vllm serve qtip-ai/DeepSeek-OCR-2-7B-AWQ --port 8002 --chat-template deepseek-vl2 --limit-mm-per-prompt image=4 --max-model-len 4096 --quantization awq_marlin
# Dots.mocr 在 8003 端口,需要自定义模板文件,确保 token 处理一致
vllm serve qtip-ai/Dots.mocr-7B-AWQ --port 8003 --chat-template dots-mocr --limit-mm-per-prompt image=4 --max-model-len 8192 --quantization awq_marlin
如果某个模型在 --limit-mm-per-prompt 设置下无法满足任务需求,比如图片超出限制,那么请求将被自动拒绝,此时需要调整 image 参数或增加 --max-model-len,但这会影响其他模型的性能稳定性。
可选的统一网关层
为了进一步简化调用流程,可以使用 LiteLLM Proxy 作为聚合路由器,配置如下:
model_list:
- model_name: glm-ocr
litellm_params:
model: openai/glm-ocr
api_base: http://localhost:8001/v1
api_key: ""
- model_name: deepseek-ocr
litellm_params:
model: openai/deepseek-ocr
api_base: http://localhost:8002/v1
api_key: ""
- model_name: dots-ocr
litellm_params:
model: openai/dots-ocr
api_base: http://localhost:8003/v1
api_key: ""
LiteLLM 会根据 model_name 来转发请求,但如果某个模型的端口或配置发生变化,需要重新部署 LiteLLM 才能保持路由正常工作。此外,如果某个模型在并发情况下出现卡顿,可能需要调整 LiteLLM 的并发设置或检查显存分配是否合理。
全部回复 (3)
想当场把话说完?进全球 AI 聊天室,登录就能开口。
vLLM多模态并发卡死的问题,我之前也是被折磨得够呛,特别是切换任务时还要手动改客户端和请求格式,太麻烦了。不过最近我尝试了一个解决方案,直接将三个模型(GLM-OCR、DeepSeek-OCR-2和Dots.mocr)都挂在同一个 /v1/chat/completions 后面,通过 OpenAI SDK 的统一调用,把每个模型的端口分别设为 8001、8002、8003,这样只需要修改一次请求头中的 api_base 参数即可切换模型,省去了重复配置的麻烦。具体操作时,记得在启动 vLLM 时加上 --chat-template 和 --limit-mm-per-prompt 来统一模板和图片 token 占位符,比如 --chat-template glm-ocr --limit-mm-per-prompt image=4,这样就能避免手动修改各自 repo 里的代码。显存方面,我用了 AWQ 4bit 量化版,三个模型共享一张 48G A6000,并发设置为 2,日常批量处理单据时也很稳定。
把三个模型都挂到同一个 /v1/chat/completions 接口后,代码量直接砍掉一半,再把自定义的 dots-mocr jinja 模板丢进 ~/.config/vllm/templates/ 并且把 <|image|> 换成 <image>,这样调用就统一了,效率提升简直是救命!
既然直接在Colab开跑已经足够方便,但手头的PDF解析任务涉及多个模型(如GLM-OCR、DeepSeek-OCR-2和Dots.mocr),每次切换客户端或调整请求格式都会让流程变得复杂。于是,我决定将这三个模型统一部署到同一个
/v1/chat/completions端点上,使用vLLM 0.6.3+作为统一的推理网关,通过--chat-template和--limit-mm-per-prompt参数,直接对接OpenAI SDK,避免了每次切换模型时需要手动修改代码或请求格式。这样既保证了任务的高效执行,又让整个流程变得干净利落,显存规划上则通过AWQ 4bit量化版(如HuggingFace上的qtip-ai或ModelTC)共享一张48G的A6000或双3090 NVLink设备,并发设置为2,足以应对日常批量单据的需求。