首页
/ VibeVoice ASR 部署实战:从 Docker + vLLM 推理服务到 Gradio 网络 Demo 的完整搭建

VibeVoice ASR 部署实战:从 Docker + vLLM 推理服务到 Gradio 网络 Demo 的完整搭建

2026-09-05 21:58:56作者:宗隆裙

本篇基于仓库内的部署指南 setup_gradio_demo.md,讲清楚 VibeVoice ASR(语音识别)模型在 GPU 环境下的端到端部署流程:如何用一条 docker run 命令拉起基于 vLLM 的高性能推理服务(支持单卡与多卡数据并行),验证 OpenAI 兼容 API,再叠加 Gradio Web Demo 生成可公开访问的试听/转录页面。读完本文,你可以独立完成 ASR 服务的容器化部署、多 GPU 扩容与故障排查,并深入理解启动脚本 start_server.py 与服务端插件的实现细节。

一、整体架构:两个组件,一条链路

整个 Demo 由两个独立进程组成,均运行在同一个 Docker 容器内:

  1. ASR 服务vllm/vllm-openai:v0.14.1 官方镜像中运行 start_server.py,它负责装依赖、拉模型、生成 tokenizer 文件,最终启动 vllm serve,对外提供 OpenAI 兼容的 /v1/chat/completions 接口(模型名注册为 vibevoice);
  2. Gradio 前端gradio_asr_demo_api_video.py 通过 HTTP 调用上面的 API,提供音频/视频上传、流式转写、分段试听与字幕生成界面,可用 --share 生成 gradio.live 公网链接。

pyproject.toml 可以看到,vibevoice 包通过 vllm.general_plugins 入口点注册 vllm_plugin:register_vibevoice,这意味着 vLLM 无需修改源码即可识别并加载 VibeVoice 模型——安装即插即用。

二、前置条件

  • 具备 CUDA 的 GPU(多卡部署需更多显存设备);
  • 支持 GPU 的 Docker(nvidia-docker);
  • 本地已克隆 VibeVoice 仓库(容器会把当前目录挂载为 /app):
git clone https://github.com/microsoft/VibeVoice.git
cd VibeVoice

三、Step 1 — 启动 ASR 服务

启动脚本 start_server.py 会自动完成五件事:安装系统依赖(FFmpeg、libsndfile1)、以 vLLM 插件方式安装 VibeVoice、从 Hugging Face 下载模型(默认 microsoft/VibeVoice-ASR)、通过 generate_tokenizer_files.py 生成 tokenizer 文件、最后 exec 启动 vllm serve

3.1 单 GPU(默认)

docker run -d --gpus '"device=0"' --name vibevoice-asr-demo \
  --ipc=host \
  -p 6001:6001 \
  -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 --port 6001"

两个环境变量的作用:

  • VIBEVOICE_FFMPEG_MAX_CONCURRENCY=64:控制音频解码(FFmpeg)的并发上限,DP 模式下启动脚本还会自动为每个 worker 单独注入该值;
  • PYTORCH_ALLOC_CONF=expandable_segments:True:开启 PyTorch 可扩展显存分段分配,缓解显存碎片导致的 OOM。

3.2 多 GPU 数据并行(负载均衡)

docker run -d --gpus '"device=0,1,2,3"' --name vibevoice-asr-demo \
  --ipc=host \
  -p 6001:6001 \
  -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 --port 6001 --dp 4"

--dp 4 表示在 4 张 GPU 上各跑 1 个独立副本。从源码 start_dp_server 可以看到其实现细节:

  • 为每个副本分配独立 GPU(通过 CUDA_VISIBLE_DEVICES)与内部端口(前端端口 + 100、+101……);
  • 自动安装并启动 nginx 反向代理,采用 least_conn(最少连接)调度,worker 数默认为 2 × 副本数,对外只暴露一个端口;
  • 设计注释说明:这样做是为了规避 vLLM 内置 DP 协调器在大音频载荷下的单进程 HTTP 瓶颈;
  • 每个后端最多等待 10 分钟就绪,任何一个 worker 退出都会触发整体优雅关闭。

Tip--dp N 用于 N 路数据并行(吞吐扩容,推荐);--tp N 用于张量并行(单卡放不下大模型时切分)。两者默认均为 1,详细原理见 vibevoice-vllm-asr.md

3.3 检查日志

docker logs -f vibevoice-asr-demo

等待出现 Application startup complete. 即表示服务就绪(含模型下载,首次约 2 分钟以上)。

3.4 启动脚本暴露的全部参数

对照 start_server.py 的 argparse 定义,除 --port--dp/--tp 外还可调节:

参数 说明 默认值
--model, -m Hugging Face 模型 ID microsoft/VibeVoice-ASR
--port, -p 服务端口 8000
--max-num-seqs 单批次最大并发序列数 64
--max-model-len 最大模型上下文长度(支撑长音频) 65536
--gpu-memory-utilization 显存占用比例 0.8
--skip-deps 跳过系统依赖安装 off
--skip-tokenizer 跳过 tokenizer 文件生成 off

这些值最终会传入由 _build_vllm_cmd 拼出的 vllm serve 命令,其中固定携带 --dtype bfloat16--no-enable-prefix-caching--enable-chunked-prefill--allowed-local-media-path /app 等 ASR 场景针对性配置。

四、Step 2 — 验证服务

# Check the model is loaded
curl http://localhost:6001/v1/models

预期输出:

{
  "data": [{ "id": "vibevoice", ... }]
}

4.1 用真实音频快速测试

仓库自带的 test_api.py 是最小验证客户端:

docker exec -it vibevoice-asr-demo \
  python3 /app/vllm_plugin/tests/test_api.py /app/en-Alice_woman.wav \
  --url http://localhost:6001

从源码看,该脚本会把音频 base64 编码后以 audio_url 形式放入 /v1/chat/completions 请求,prompt 中要求模型按 Start time / End time / Speaker ID / Content 四个键输出 JSON,并以流式方式接收增量结果;结束后打印总耗时与 RTF(实时因子)= 处理时长 / 音频时长,可用于直观评估服务吞吐。它还支持 --hotwords 参数,把热词以 "with extra info" 形式嵌入 prompt,提升专有名词、人名识别准确率:

python3 /app/vllm_plugin/tests/test_api.py /app/en-Alice_woman.wav --hotwords "Microsoft,Azure,VibeVoice"

(测试音频路径可按需替换为挂载目录中的任意 wav/mp3 文件。)

五、Step 3 — 启动 Gradio Demo

Gradio 进程与 ASR 服务分离,便于单独重启前端而不动推理服务。这里用 tmux 让进程在容器内后台常驻。

5.1 安装 tmux

docker exec vibevoice-asr-demo apt-get install -y tmux

5.2 在 tmux 中启动 Gradio

docker exec vibevoice-asr-demo bash -c \
  "PYTHONUNBUFFERED=1 tmux new-session -d -s gradio \
  'PYTHONUNBUFFERED=1 python3 /app/vllm_plugin/scripts/gradio_asr_demo_api_video.py \
  --api_url http://localhost:6001 --share \
  2>&1 | tee /tmp/gradio.log'"

PYTHONUNBUFFERED=1 保证 Python 输出不缓冲,日志能实时写入 /tmp/gradio.log(这也是排查"日志为空"的关键)。

5.3 获取 Share 链接

等待约 20 秒后:

docker exec vibevoice-asr-demo cat /tmp/gradio.log

预期看到:

✅ Connected to API: http://localhost:6001 | Model: vibevoice
🚀 Starting VibeVoice ASR Demo
* Running on local URL:  http://0.0.0.0:7860
* Running on public URL: https://xxxxxx.gradio.live

gradio.live 链接为公网可访问的临时分享(有效期约 1 周)。

5.4 Gradio 启动参数

Flag 说明 默认值
--api_url URL vLLM 服务地址 http://localhost:8000
--share 创建 Gradio 公网链接 off
--port PORT 本地 Gradio 端口 7860
--cloudflared 用 Cloudflare 隧道代替 Gradio share off
--max_video_size MB 允许上传的视频大小上限 50

补充源码中同样存在但文档未强调的两个参数(见 gradio_asr_demo_api_video.py):--model_name(不指定时自动从 /v1/models 探测)与 --max_new_tokens(默认 4096)。启动时 demo 会调用 demo.queue(default_concurrency_limit=10),即队列模式下最多 10 个请求并发处理,天然支持多人同时使用。

5.5 Demo 前端的实现要点

gradio_asr_demo_api_video.py 的源码结构看,它不只是简单的转写页面:

  • 多格式兼容:识别 .wav/.mp3/.flac/.ogg/.opus/.m4a 等音频与 .mp4/.webm/.mov/.mkv 等视频扩展名;视频会先用 ffmpeg 抽取 16kHz 单声道 MP3 音轨再提交识别;
  • 流式输出VibeVoiceAPIClient.transcribe_streamingstream: True 请求 API,边收边向页面推送增量文本,并解析 usage 字段展示 token 统计;
  • 截断容错_parse_segments_parse_truncated_segments 会在响应被截断时尽力抢救出完整的分段(Start/End/Speaker/Content),避免长音频"全军覆没";
  • 分段试听与字幕:转写完成后可按说话人分段并行切片(ThreadPoolExecutor),并生成 SRT / WebVTT 字幕文件;
  • 热词上下文:界面支持填入 context info,拼入 prompt 后同样走热词增强识别路径。

六、服务管理

6.1 只停 Gradio(保留 ASR 服务)

docker exec vibevoice-asr-demo tmux kill-session -t gradio

重启 Gradio:重跑 Step 3 中的 tmux 命令即可。

6.2 全部停止

docker stop vibevoice-asr-demo
docker rm vibevoice-asr-demo

七、一键完整示例(GPU 0 + 端口 6001)

# 1. Start server
docker run -d --gpus '"device=0"' --name vibevoice-asr-demo \
  --ipc=host -p 6001:6001 \
  -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 --port 6001"

# 2. Wait for startup (~2 min), then verify
docker logs -f vibevoice-asr-demo  # wait for "Application startup complete."
curl http://localhost:6001/v1/models

# 3. Install tmux and launch Gradio
docker exec vibevoice-asr-demo apt-get install -y tmux
docker exec vibevoice-asr-demo bash -c \
  "PYTHONUNBUFFERED=1 tmux new-session -d -s gradio \
  'PYTHONUNBUFFERED=1 python3 /app/vllm_plugin/scripts/gradio_asr_demo_api_video.py \
  --api_url http://localhost:6001 --share \
  2>&1 | tee /tmp/gradio.log'"

# 4. Get the public link
sleep 20 && docker exec vibevoice-asr-demo cat /tmp/gradio.log

八、故障排查

问题 处理办法
CUDA out of memory 换用其他 GPU(device=X),或在 start_server.py 中把 --gpu-memory-utilization 调低(如 0.7
Gradio 日志为空 多等一会(约 30s);Gradio 会缓冲输出,务必加 PYTHONUNBUFFERED=1
Port already in use 换端口,或停掉占用容器:docker stop <name> && docker rm <name>
Share 链接显示 "No interface" Gradio 仍在加载,等待日志出现 Application startup complete
tmux: command not found 先执行 docker exec <container> apt-get install -y tmux

补充两条从源码可确认的排查线索:DP 模式下每个后端就绪判定依赖其内部端口的 /v1/models(最长等待 10 分钟),若日志停在 "Waiting for all backends to be ready" 应检查 --gpus 提供的卡数是否 ≥ --dp × --tp--dp N 启动前脚本会显式断言 GPU 数量充足,数量不足会直接给出 Need X GPUs ... but only Y available 的明确报错。

九、延伸阅读

登录后查看全文
热门项目推荐
相关项目推荐