vLLM 下 Qwen3.5 加载 safetensors 卡住?TaoToken 这样把 Base URL 指向 API 通道

vLLM 下 Qwen3.5 加载 safetensors 卡住?TaoToken 这样把 Base URL 指向 API 通道 用 vLLM 起 Qwen3.5-2B 时卡在 safetensors 加载和 Encoder cache 初始化是最近问得比较多的一个场景。这篇不继续调 vLLM 参数而是用 TaoTokenhttps://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentvllm-qwen35-safetensors创建一个 Key把客户端 base_url 指向 https://taotoken.net/api用 OpenAI 兼容接口直接请求 Qwen3.5 视觉模型。TaoToken 在这里只做一件事把模型通道从本机 GPU 换到 API 通道vLLM 的部署卡顿问题随之绕开不动你任何本地文件。下面按排障视角拆开讲先复现卡住的位置再给可直接复制的配置和验证步骤。一、vLLM 加载 Qwen3.5 卡在 safetensors 与 Encoder cache 的真实现场先看一个典型的启动命令这也是很多人第一次跑 Qwen3.5 多模态模型时用的版本vllm serve /root/model/Qwen3.5-2B \ --host 0.0.0.0 \ --port 8004 \ --max_model_len 10000 \ --served-model-name Qwen3.5-2B \ --gpu-memory-utilization 0.4 \ --mm-encoder-tp-mode data \ --mm-processor-cache-type shm命令敲下去之后终端输出的日志顺序大致是这样的(EngineCore_DP0 pid2340912) FutureWarning: The cuda.nvrtc module is deprecated ... Loading safetensors checkpoint shards: 100% Completed | 1/1 [00:0200:00, 2.23s/it] Loading weights took 2.43 seconds Model loading took 4.25 GiB memory and 3.395487 seconds Encoder cache will be initialized with a budget of 16384 tokens, and profiled with 1 image items of the maximum feature size.注意几个数字权重加载只花了 2.43 秒显存占用 4.25 GiBsafetensors 分片进度条已经 100%。也就是说磁盘读取和权重映射这两步其实已经结束了卡住的位置不在 safetensors 本身。真正停在原地的是下一行也就是 Encoder cache 的初始化和性能预分析。这一行的含义是vLLM 给视觉编码器缓存分配了 16384 个 token 的预算并且要用「一张最大特征尺寸的图片」去做一次 profiling。问题就出在这个「最大特征尺寸」上。当--mm-processor-kwargs里没有限制max_pixels时vLLM 会按模型上限去构造这张用于 profiling 的图。按 Qwen3.5 系列的视觉处理规则每个视觉 token 对应 32×32 像素token 上限 16384那么像素上限就是 16384 × 32 × 32 16,777,216 像素。换算成常见比例接近 4096×4096 的正方形图或者 5461×3072 级别的宽屏图。为了跑一次 profiling 就临时造出这种量级的张量在单卡或者显存本来就紧张的机器上很容易出现进程明显僵住、日志长时间不推进的情况。再叠加--mm-encoder-tp-mode data这一类需要跨卡搬运编码器数据的参数或者--mm-processor-cache-type shm这种依赖共享内存的策略卡顿就会被进一步放大。后面把命令改成限制单图像素上限例如加上--mm-processor-kwargs {max_pixels: 524288}再换掉编码器张量并行模式和缓存类型确实能往前走一段。但在实际排障里这条路往往要走好几轮先猜是显存不够再怀疑是共享内存没配然后回头调--max-model-len和--gpu-memory-utilization一圈下来模型还没真正跑起来。如果你的目标只是「让 Qwen3.5 看一眼图片把里面的字段抽出来」而不是「把多模态推理服务长期部署在本地机房」那么继续在 vLLM 参数里打转的性价比并不高。更直接的做法是把模型通道从本机 GPU 挪走改走 OpenAI 兼容 API。二、TaoToken 前置把模型通道从本机 GPU 挪到 API这一步的目标很明确不再由本地 vLLM 承担 Qwen3.5 的推理只保留你的业务代码把请求发到一个 OpenAI 兼容的端点上。操作顺序如下。第一步打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentvllm-qwen35-safetensors 完成注册并登录。第二步进入控制台打开 API Keys 页面创建一个新的 Key。这个 Key 就是后面代码里的YOUR_API_KEY只显示一次记得先落到本地的.env或者密钥管理里不要直接写死在业务代码中。第三步记住两个地址这两个地址在后面的排查里会反复用到接口地址base_urlhttps://taotoken.net/api注意后面不要自己补/v1API Key创建后得到的那串字符第四步确认要调用的模型 ID。Qwen3.5 视觉模型在模型列表里的 ID 以控制台展示为准下面的示例代码里写成MODEL_ID你把它替换成实际值即可。如果你同时用到纯文本和视觉两类任务建议在配置文件里分开写两个常量别用同一个变量名换来换去。这里需要说清楚边界TaoToken 只替换模型通道不替代你的编辑器也不接管本地文件读写。你本地的 vLLM 目录、模型权重、conda 环境都原封不动只是客户端不再往http://127.0.0.1:8004发请求而是往https://taotoken.net/api发。三、可复制配置OpenAI 兼容 base_url 指向 https://taotoken.net/api先放环境变量把 Key 和地址从代码里抽出来# .env TAOTOKEN_API_KEYYOUR_API_KEY TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_MODELMODEL_IDPython 侧用官方openaiSDK 即可不需要额外装任何 vLLM 相关的依赖import os from openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ[TAOTOKEN_BASE_URL], # https://taotoken.net/api ) resp client.chat.completions.create( modelos.environ[TAOTOKEN_MODEL], messages[ {role: user, content: 用一句话说明你是谁。} ], temperature0.1, ) print(resp.choices[0].message.content)如果你想先用 curl 确认通道是否通可以直接发一个最小请求curl https://taotoken.net/api/chat/completions \ -H Authorization: Bearer YOUR_API_KEY \ -H Content-Type: application/json \ -d { model: MODEL_ID, messages: [{role: user, content: ping}], temperature: 0 }多模态请求的结构和 OpenAI 一致图片既可以用公网 URL也可以本地读成 base64import base64 from openai import OpenAI client OpenAI( api_keyYOUR_API_KEY, base_urlhttps://taotoken.net/api, ) with open(./sample_card.png, rb) as f: b64 base64.b64encode(f.read()).decode() resp client.chat.completions.create( modelMODEL_ID, messages[ { role: user, content: [ { type: text, text: 把这张图里的姓名、证件号、有效期抽成 JSON字段缺失就写 null。, }, { type: image_url, image_url: {url: fdata:image/png;base64,{b64}}, }, ], } ], temperature0.1, ) print(resp.choices[0].message.content)这里有几个要点值得记住图片走image_url字段base64 形式必须带data:image/png;base64,前缀base_url保持为https://taotoken.net/api不要拼成https://taotoken.net/api/v1model字段填控制台里显示的那个 ID不要填本地路径也不要填Qwen3.5-2B这种 vLLM 的--served-model-name。四、验证请求图片 文字输入跑通 Qwen3.5配置写完做一次完整的验证确认「图片 文字」这条链路是通的。建议按下面三步走不要一上来就丢生产图。第一步纯文本探活。用上面那段最小 chat 请求或者 curl 版本确认返回里有正常的choices[0].message.content并且 usage 字段里能看到 token 计数。这一步只验证鉴权和地址。第二步小图验证。找一张分辨率不高的截图比如 800×600 左右的表单截图跑一次多模态请求。请求体里同时包含一段文字指令和一个image_url。这一步验证的是模型是否真的接收到了视觉输入而不是只把指令当文本处理。第三步换成本篇的真实场景一张横置的扫描件或者证件照指令写成字段抽取任务要求输出固定结构的 JSON。比如请识别这张图片中的全部可见文字并回答三个问题 1. 图片是横向还是纵向 2. 姓名和证件号码分别是多少 3. 有效期截止日期是多少。 输出 JSON不要输出 JSON 以外的内容。成功的结果通常有三个特征返回内容是合法 JSON可以直接被json.loads解析关键字段能对上图片里的实际内容usage 里的prompt_tokens明显高于纯文本请求说明图片 token 确实被计入。到这一步你本地不再需要跑着 vLLM 进程也不需要再盯着 Encoder cache 那行日志。原来卡住的服务可以直接停掉端口释放出来给别的用途。五、本篇常见错排查这一类接入问题报错大多集中在几个固定位置。按下面顺序查基本能覆盖绝大多数情况。现象一请求返回 404 或路径相关错误。九成是 base_url 写错了。正确写法是https://taotoken.net/apiSDK 会自己补上/chat/completions。如果你的代码里写成了https://taotoken.net/api/v1或者写成了https://taotoken.net/api/v1/chat/completions再让 SDK 补一次路径就会重复。先把 base_url 改干净再试。现象二返回 401 或鉴权失败。检查三件事Key 是不是复制时带了首尾空格环境变量有没有真正加载可以用echo $TAOTOKEN_API_KEY确认请求头里是不是写成了Authorization: Bearer YOUR_API_KEY但忘了替换成真实 Key。现象三提示模型不存在或 model not found。常见原因是把本地 vLLM 的--served-model-name当成了模型 ID。Qwen3.5-2B是你在本机起的服务名不是 API 通道上的模型标识。以控制台模型列表里的 ID 为准示例代码中统一用MODEL_ID占位就是这个意思。现象四图片请求返回参数错误。优先看 base64 前缀。纯 base64 字符串不带data:image/png;base64,前缀服务端无法判断媒体类型。另外注意扩展名和实际格式要一致把 jpg 内容标成 png 有时也能过但不要依赖这个行为。现象五图片太大导致请求失败或超时。图片 token 数量由像素决定单图过大时输入 token 会快速上涨。业务侧如果只是做字段抽取先把长边压到 1600 像素以内再上传识别效果通常不受影响请求也更稳。这和你在 vLLM 里设max_pixels是同一个思路只是挪到了发送端。现象六本地 vLLM 进程还在占着显存和端口。既然改走 API 通道就把本地那个卡住的进程清掉。用nvidia-smi确认显存已经释放用lsof -i:8004或者ss -lntp确认端口没有残留监听否则你可能会以为是新配置没生效其实请求还被路由到了旧进程。现象七环境变量改了但代码没生效。Python 进程启动后再改.env是不会自动重载的需要重启进程。用 Jupyter 的话重启 kernel 再试。六、把 Key 和文档收好下一次排障不用重来回到最初的问题vLLM 在 Qwen3.5 上卡在 safetensors 加载之后的那一行 Encoder cache 初始化本质上是本地多模态推理服务在显存、编码器并行策略、图片像素预算三件事上的取舍。这条路能调通但每次换机器、换卡型、换图片规格你都要重新走一遍参数组合。把这部分交给 API 通道之后你的关注点就只剩业务代码怎么组织图片和指令怎么解析返回的 JSON怎么把结果写回你的审查流程。模型 ID 变了就改一个常量Key 过期就换一个 Key不需要再碰 GPU 相关配置。现在要做的两件事打开 API Keys 页面创建或管理你的 Keyhttps://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentvllm-qwen35-safetensors对照接入文档确认 base_url、模型 ID 和多模态消息结构https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentvllm-qwen35-safetensors如果你打算把这条通道用在长期的编码或 Agent 场景里可以顺带看一下 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentvllm-qwen35-safetensors把上面第三节的配置贴进你的项目跑一次第四节的验证请求这条链路就算通了。下一次再遇到类似的服务端卡顿你至少可以先问一句这块推理真的需要跑在我自己这台机器上吗。