用 vLLM 跑 VibeVoice-ASR:官方文档给的完整路径
如果你已经用仓库 demo/ 里的脚本跑通过单文件转写,接下来大概率会碰到同一个问题:脚本是一次一个文件的形态,进程起来就为了转一段音频,转完退出。要把它变成一个能被别的服务调用、能并发接单的接口,靠 demo 脚本改是绕不开重复造轮子的。
VibeVoice 仓库为这件事单独准备了一条路径,文档在 docs/vibevoice-vllm-asr.md,代码在 vllm_plugin/ 目录下。这篇就沿着这两处,把安装、加载、请求形态和文档写明的限制过一遍。文中所有事实都来自 github.com/microsoft/VibeVoice 仓库内的文档与源码,我们没有下载权重也没有起过服务。
一、这条路径解决的是什么
docs/vibevoice-vllm-asr.md 开头写明的定位是:把 VibeVoice ASR 模型部署成 API 服务,对外暴露 OpenAI 兼容的 /v1/chat/completions 端点,支持流式返回。
它对使用者最实际的一点写在特性列表里:Plugin Architecture — No vLLM source code modification required,也就是不需要改 vLLM 源码。这句话在 pyproject.toml 里能找到对应的实现:
[project.entry-points."vllm.general_plugins"]
vibevoice = "vllm_plugin:register_vibevoice"
vLLM 通过 vllm.general_plugins 这个 entry point 组来发现插件,只要 vibevoice 这个包被 pip 装进环境,vLLM 启动时就会调用 vllm_plugin 包里的 register_vibevoice()。vllm_plugin/__init__.py 的模块注释也是这么写的:这个函数由 vLLM 通过 entry point 机制自动调用,确保它在所有 vLLM 进程里都跑一遍。
理解这一点,后面很多现象才有落点——比如为什么排查清单里会有一条「验证 entry point」。
二、前置条件
这一段最容易被跳过,但它决定了你要不要换一台机器。
运行形态是容器。 文档给的安装方式只有一种,标注为 Recommended:用官方 vLLM Docker 镜像。命令里带 --gpus all,也就是需要一块(或多块)能被 Docker 直通的 NVIDIA GPU,宿主机要装好 NVIDIA Container Toolkit。仓库里我们没有找到不用容器、直接在宿主机装 vLLM 跑这个插件的官方步骤。
Python 版本。 pyproject.toml 写明 requires-python = ">=3.10"。不过既然走官方镜像,这一条更多是给想自己搭环境的人看的。
FFmpeg 是硬依赖,不是可选项。 音频解码整条链路都压在 FFmpeg 上:vllm_plugin/model.py 里定义了 _PatchedAudioMediaIO,直接继承并替换掉 vLLM 自己的 AudioMediaIO,load_bytes / load_base64 / load_file 三个方法全部改走 vibevoice.processor.audio_utils 里的 load_audio_bytes_use_ffmpeg 与 load_audio_use_ffmpeg。所以文档 Troubleshooting 里「Audio decoding failed」那条的第一步是让你确认 ffmpeg -version。启动脚本会自己 apt-get install -y ffmpeg libsndfile1,前提是容器能连到 apt 源。
Windows 侧要注意的地方。 文档给的命令是 Linux/macOS shell 写法,里面有一处 -v $(pwd):/app。$(pwd) 是 POSIX shell 语法,在 PowerShell 里不会被展开成当前目录,这一处你需要换成 PowerShell 自己的写法或写绝对路径;在 Git Bash 里则要注意路径会被转换成 Windows 形式。Windows 上要有 --gpus 支持,通常意味着走 Docker Desktop 的 WSL2 后端并配好 GPU 直通。仓库文档里没有针对 Windows 的专门说明,上面这段属于通用做法,不是该项目的官方内容。
三、启动脚本每一步在改什么
文档给的启动命令是把一个脚本塞进官方镜像跑:
docker run -d --gpus all --name vibevoice-vllm \
--ipc=host \
-p 8000:8000 \
-e VIBEVOICE_FFMPEG_MAX_CONCURRENCY=64 \
-e PYTORCH_ALLOC_CONF=expandable_segments:True \
-v $(pwd):/app \
-w /app \
--entrypoint bash \
vllm/vllm-openai:v0.14.1 \
-c "python3 /app/vllm_plugin/scripts/start_server.py"
这是文档里原样给出的命令,其中的镜像 tag 与两个环境变量取值是仓库当前文档写的值,随版本可能变动。
真正干活的是 vllm_plugin/scripts/start_server.py。它的 main() 按顺序做五件事,每一件都在改环境里的某个具体东西:
install_system_deps()——apt-get install -y ffmpeg libsndfile1,补上镜像里没有的音频依赖。--skip-deps可以跳过。install_vibevoice()——把挂载进来的仓库目录以可编辑模式装进 Python 环境。这一步同时也是插件生效的那一步:完成安装后 entry point 才会注册到环境里。download_model(args.model)——调huggingface_hub.snapshot_download,默认 model id 是microsoft/VibeVoice-ASR。文档提醒模型会落到容器内的 Hugging Face 缓存目录,容器删了就得重下。generate_tokenizer(model_path)——调vllm_plugin.tools.generate_tokenizer_files,把生成的文件写进模型目录。--skip-tokenizer可以跳过。- 起服务:
data_parallel_size > 1时走start_dp_server(),否则走start_vllm_server(),后者用os.execvp直接把当前进程替换成 vLLM。
第 4 步值得单独说。generate_tokenizer_files.py 的模块注释写明它从 Qwen2 base tokenizer 下载后打补丁(脚本里 DEFAULT_QWEN_MODEL 取的是 Qwen/Qwen2.5-7B,注释说明是因为扩展 token 在这一版里齐全;这是仓库当前代码里的默认值,随版本可能变动),加上 VibeVoice 用的音频 token(<|AUDIO|>、<|audio_bos|>、<|audio_eos|>)并改写 chat template。改写的关键在模板里那句判断:part['type'] == 'audio' or part['type'] == 'audio_url' 时输出 <|AUDIO|>。这就是「请求里塞一段音频」最终变成模型输入的那一步。
而 register_vibevoice() 注册的四样东西是:VibeVoiceConfig 注册进 AutoConfig(键名 vibevoice)、VibeVoiceASRTextTokenizerFast 注册进 AutoTokenizer、Qwen2AudioProcessor 注册进 AutoProcessor、以及把 VibeVoiceForCausalLM 以 VibeVoice 和 VibeVoiceForASRTraining 两个架构名注册进 vLLM 的 ModelRegistry。代码注释特意强调架构名必须与 config.json 里 architectures 列表对得上,并且 tokenizer 那一段带了一条大写的 IMPORTANT:它把 speech_start_id、speech_pad_id、speech_end_id 映射到三个 Qwen 扩展 token,注释自述这会显著影响 ASR 质量——即使请求本身返回成功。
四、请求长什么样
vllm_plugin/tests/test_api.py 是文档指定的测试脚本,也是请求形态最直接的出处。它拼出来的 payload 结构是这样:
payload = {
"model": "vibevoice",
"messages": [
{"role": "system", "content": "..."},
{"role": "user", "content": [
{"type": "audio_url", "audio_url": {"url": data_url}},
{"type": "text", "text": prompt_text}
]}
],
"stream": True,
}
以上为按仓库代码中的接口语义组合的示例,未经实测,以仓库最新代码为准。
几处要专门指出来:model 字段的值是 vibevoice,对应启动命令里的 --served-model-name vibevoice,改了一边另一边也要改。data_url 是 data:{mime};base64,{audio_b64},也就是音频整个 base64 塞进请求体。脚本里的 max_tokens、temperature、top_p 是仓库示例脚本中的取值,属于示例值,不是推荐配置。
hotwords 的实现方式尤其反直觉:它不是一个独立的 API 字段。脚本的文档字符串写得很清楚——hotwords 以 with extra info: {hotwords} 的形式拼进 prompt 文本里。同时 prompt 里还会带上音频时长(脚本用 ffprobe 读出来)和要求返回的字段名 Start time、End time、Speaker ID、Content。所以你如果自己写客户端,得照着这个 prompt 模板拼,而不是去找参数。
五、边界:文档与代码写明的限制
音频时长有上限,而且可以被环境变量改。 vllm_plugin/inputs.py 里定义了 _MAX_AUDIO_DURATION,取自环境变量 VIBEVOICE_MAX_AUDIO_DURATION,仓库当前代码里的默认值是 3660(秒),随版本可能变动。代码注释自述这个默认值对应模型的设计容量,并写明可以通过那个环境变量下调;校验发生在音频转成 tensor 之前,超过就直接抛 ValueError,代码里对这一步的注释是「提前拦住」而不是等到运行中才失败。
文件必须在挂载目录里。 _build_vllm_cmd() 拼给 vLLM 的参数里带了 --allowed-local-media-path /app,文档也单独提醒:音频或视频文件必须放在容器内挂载的 /app 目录下。
长音频可能进重复循环。 仓库为此专门提供了第二个测试脚本 test_api_auto_recover.py,其文档字符串把恢复策略写在明处:先贪心解码,检测到循环则用更高的 temperature 重试,有重试上限,并截断到最后一个完整片段边界。也就是说,这个问题在仓库层面是被承认存在的,处理方式是客户端侧的重试与截断,不是服务端自动兜住。
多卡的两个方向不要混。 文档的表格写明 --tp N 是把一个模型切到 N 张卡上,--dp N 是跑 N 份独立副本。start_dp_server() 的实现是:装 nginx,给每个副本分配 frontend_port + 100 + i 的内部端口,写一份 least_conn 的 upstream 配置,nginx worker 数默认取副本数的两倍。文档明确写了总卡数 = dp × tp,代码里也有对应的 assert。
两处源与源之间对不上的地方,说完就停,不做解释:一是 install_vibevoice() 执行的是 pip install -e /app[vllm],而 pyproject.toml 的 [project.optional-dependencies] 里我们只找到 streamingtts 这一个 extra,没有 vllm;二是 vllm_plugin/model.py 的注释引用了 docs/max_num_batched_tokens_issue.md,但仓库 docs/ 目录下我们没有找到这个文件。
六、怎么验证配对了
按仓库文档给的顺序,有几个互相独立的检查点:
- 服务起没起来:
docker logs -f vibevoice-vllm。DP 模式下脚本会逐个探测各后端的/v1/models,就绪时打印对应端口,失败也会打印,日志里能直接看出是哪个副本没起来。 - 插件加载没加载:文档 Troubleshooting 的「Plugin not loaded」给了两条命令,
pip show vibevoice确认包在,pip show -f vibevoice | grep entry确认 entry point 在。这两条对应的正是第一节讲的注册机制。 - 模型目录完整没完整:「Model not found」那条要求确认模型路径下有
config.json与权重文件,并且 tokenizer 文件已生成——也就是第三节的第 4 步没被跳过。 - 端到端:
docker exec -it vibevoice-vllm python3 vllm_plugin/tests/test_api.py /app/audio.wav,文档同时给了带--hotwords的形式。
最后一句提醒:这条链路在启动时会向容器内 apt-get install 与 pip install,并会从 Hugging Face 拉取权重,属于在你的机器上执行外部程序与下载外部内容。上线前请自己确认网络出口与镜像来源符合你所在组织的要求。
本文依据 github.com/microsoft/VibeVoice 仓库与 Hugging Face 模型卡于 2026-08-18 的公开内容整理,
事实来自仓库内的文档与源码。我们没有下载权重、没有跑过推理、也没有做过训练,
因此不涉及显存占用、推理速度、识别准确率与音质的任何描述,也不与其它模型做比较或排名。
该项目持续更新,文中涉及的模块路径、配置字段与接口写法随版本变动,请以仓库最新内容为准。
仓库 README 的风险与限制一节写明:该模型仅供研究与开发用途, 未经进一步测试与开发不建议用于商业或真实场景,并特别提示了合成语音被用于伪造与虚假信息的风险。 使用合成语音时应遵守所在司法辖区的法律法规,并在分享 AI 生成内容时主动披露。
安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。