vLLM 推理引擎

使用 vLLM 加速自回归 LLM-based ASR 模型。新版引擎支持离线批量转写、SDK 级 chunk 流式推理,以及集成 VAD、热词和说话人标签的生产级 WebSocket 服务。

概述

音频 frontend、encoder、adaptor 和可选 CTC 时间戳解码器仍在 PyTorch 中运行;LLM 解码部分通过 prompt embedding 交给 vLLM,获得 PagedAttention、连续批处理和 tensor parallel 多卡并行能力。

适用模型

模型系列vLLM 支持说明
FunASRNano支持Audio encoder + adaptor + Qwen3-0.6B LLM。
LLMASR / LLMASRNAR支持Whisper-style 音频编码器后接 Qwen、Vicuna 或 LLaMA 解码。
GLMASR支持GLM-ASR-Nano 使用自回归 LLM 解码。
QwenAudioWarp支持LLM-based audio generation path。
Paraformer、SenseVoice、Conformer、Transformer不支持这些模型不是 LLM 自回归解码路径,请使用标准 AutoModel

三种入口

模式入口适用场景
离线 SDK 推理AutoModelVLLMFunASRNanoVLLM大规模文件转写、吞吐优先的任务。
流式 SDK 推理FunASRNanoStreamingVLLMPython 应用中需要 chunk 级增量文本。
WebSocket 实时服务serve_realtime_ws.py生产实时客户端,支持 VAD 分句和说话人标签。

安装环境

pip install "funasr>=1.3.0"
pip install "vllm>=0.12.0"
pip install safetensors tiktoken websockets regex

# 如果使用源码树中的 AutoModelVLLM
cd /path/to/FunASR
pip install -e .
资源最低要求推荐
GPU 显存8 GB16 GB 以上,给 KV cache 留出更充足空间。
CUDA11.812.x
GPU 数量1使用 tensor parallel 时建议 2 张或更多。

首次运行时,FunASR 会从 model.pt 提取 LLM 权重到 vLLM 兼容目录,例如 Qwen3-0.6B-vllm;后续启动会复用已准备好的权重。

离线 SDK 推理

推荐通用接口

from funasr.auto.auto_model_vllm import AutoModelVLLM

model = AutoModelVLLM(
    model="FunAudioLLM/Fun-ASR-Nano-2512",
    hub="ms",                    # 也可以使用 "hf"
    tensor_parallel_size=2,
    gpu_memory_utilization=0.8,
)

results = model.generate(
    ["audio1.wav", "audio2.wav"],
    language="中文",
    hotwords=["张三", "北京"],
)
for item in results:
    print(f"[{item['key']}] {item['text']}")

Fun-ASR-Nano 直接接口

from funasr.models.fun_asr_nano.inference_vllm import FunASRNanoVLLM

engine = FunASRNanoVLLM.from_pretrained(
    model="FunAudioLLM/Fun-ASR-Nano-2512",
    tensor_parallel_size=4,
)

results = engine.generate(
    inputs="wav.scp",
    language="中文",
    hotwords=["开放时间"],
    max_new_tokens=512,
)

命令行

cd examples/industrial_data_pretraining/fun_asr_nano

# 单文件
python demo_vllm.py --input audio.wav --language 中文

# 批量 + 多卡 tensor parallel
python demo_vllm.py --input wav.scp --tensor-parallel-size 4 --batch-size 32

# 热词 + JSONL 输出
python demo_vllm.py --input audio.wav --hotwords 张三 北京 --output results.jsonl

流式 SDK 推理

FunASRNanoStreamingVLLM 将音频切成 720 ms chunk,对累积音频重编码,把各 chunk prompt 批量送入 vLLM,并返回 fixed/unfixed 文本区域。适合 Python 应用做实时字幕或增量展示。

from funasr.models.fun_asr_nano.inference_vllm_streaming import FunASRNanoStreamingVLLM

engine = FunASRNanoStreamingVLLM.from_pretrained(
    model="FunAudioLLM/Fun-ASR-Nano-2512",
    chunk_ms=720,
    rollback_chars=8,
)

for result in engine.streaming_generate("audio.wav", language="中文"):
    if result["is_final"]:
        print(f"最终: {result['text']}")
    else:
        print(f"[{result['audio_duration_ms']:.0f} ms] 确认: {result['fixed_text']}")
行为说明
Stage 1前 10 个 chunk 不使用 prev_text,用于找到稳定前缀。
Stage 2后续 chunk 使用稳定前缀作为 assistant context。
Rollback最后 rollback_chars 个字符保持未确认,等待后续 chunk 修正。
短音频前 1.5 到 3 秒可能为空或不稳定,这是模型特性。

WebSocket 实时服务

实时服务集成 streaming VAD、vLLM 分段解码、partial 预览、幻觉重复清理、热词、语种提示和说话人分离。

启动服务

cd examples/industrial_data_pretraining/fun_asr_nano

# 单卡
CUDA_VISIBLE_DEVICES=0 python serve_realtime_ws.py --port 10095 --language 中文

# 多卡 tensor parallel
CUDA_VISIBLE_DEVICES=0,1 python serve_realtime_ws.py \
    --port 10095 \
    --tensor-parallel-size 2 \
    --language 中文

# 完整参数示例
python serve_realtime_ws.py \
    --port 10095 \
    --model FunAudioLLM/Fun-ASR-Nano-2512 \
    --hub ms \
    --device cuda:0 \
    --decode-interval 0.48 \
    --hotword-file 热词列表 \
    --language 中文 \
    --dtype bf16 \
    --tensor-parallel-size 1 \
    --gpu-memory-utilization 0.8 \
    --max-model-len 2048

客户端

客户端用法
浏览器打开 client_mic.html,支持麦克风、文件上传、热词和说话人标签。
Python CLIpython client_python.py --server ws://localhost:10095 --mic
测试脚本python client_test.py --server ws://localhost:10095 --file audio.wav

远程 GPU 服务器访问前先做端口转发:ssh -L 10095:localhost:10095 <server>

协议

客户端 -> 服务端:
  "START"                 初始化会话
  "HOTWORDS:词1,词2"      设置热词,可选
  "LANGUAGE:中文"          设置语种,可选
  [binary bytes]          PCM16 16 kHz 单声道音频
  "STOP"                  结束并触发最终解码

服务端 -> 客户端:
  {"event": "started"}
  {"event": "hotwords_set", "hotwords": ["词1", "词2"]}
  {"event": "language_set", "language": "中文"}
  {"sentences": [...], "partial": "...", "is_final": false}
  {"sentences": [...], "partial": "", "is_final": true}
  {"event": "stopped"}

推理逻辑

路径触发条件输出
确认段解码动态 VAD 检测到端点。整段音频送入 vLLM 解码,结果锁定到 sentences
Partial 预览达到 --decode-interval,默认 0.48 秒,且有足够新音频。临时 partial 文本,后续可能覆盖。
最终处理收到 STOPflush 剩余 VAD 音频,强制结束当前语音段,执行最终说话人重聚类,返回 is_final: true

动态 VAD

动态 VAD 会根据当前语音段累计时长调整静音阈值:短句等待更长静音,避免切碎;长句更快切分,避免 ASR 输入过长。

流式封装默认阈值

累计语音时长静音阈值效果
≤ 5 秒2.0 秒短句不被过早切断。
5-10 秒1.5 秒正常对话分句。
10-15 秒1.0 秒长句开始收紧。
15-30 秒0.8 秒更快切分。
30-45 秒0.4 秒防止 ASR 段过长。
> 45 秒0.1 秒强制切分。

fsmn-vad 原生默认阈值

累计语音时长静音阈值
≤ 5 秒800 ms
5-10 秒600 ms
10-20 秒500 ms
20-30 秒400 ms
> 30 秒300 ms
# 默认 dynamic_silence=True
model.generate(input="audio.wav")

# 关闭动态静音阈值
model.generate(input="audio.wav", dynamic_silence=False)

# 自定义 schedule: (累计时长上限ms, 静音阈值ms)
model.generate(input="audio.wav", silence_schedule=[
    (5000, 1000),
    (15000, 500),
    (float("inf"), 200),
])
from funasr import AutoModel
from funasr.models.fsmn_vad_streaming.dynamic_vad import DynamicStreamingVAD

vad_model = AutoModel(model="fsmn-vad", device="cuda:0")
vad = DynamicStreamingVAD(vad_model)

for chunk in audio_stream:
    segments = vad.feed(chunk)
    for start_ms, end_ms in segments:
        print(f"Speech: {start_ms}-{end_ms} ms")

final_segments = vad.finalize()

性能

场景PyTorch baselinevLLM加速
离线,5.6 秒音频0.89 秒0.30 秒3x
离线,2-GPU tensor parallel0.89 秒~0.20 秒4.5x
批量 16 条约 16x 串行成本约 4x4x
批量 32 条约 32x 串行成本约 5x6x
WebSocket RTF0.1560.0782x

API 参考

AutoModelVLLM

参数默认值说明
model-ModelScope/Hugging Face 模型 id 或本地模型目录。
hub"ms""ms""modelscope""hf""huggingface"
device"cuda:0"PyTorch 音频 encoder 和 adaptor 运行设备。
dtype"bf16""bf16""fp16""fp32"
tensor_parallel_size1vLLM tensor parallel 使用的 GPU 数量。
gpu_memory_utilization0.8vLLM KV cache 使用的 GPU 显存比例。
max_model_len4096vLLM 最大序列长度。

generate()

参数默认值说明
inputs-音频路径、路径列表、numpy array、tensor、wav.scp 或 JSONL。
languageNone语种提示,例如 "中文""English""日本語"
hotwordsNone热词列表,会写入 ASR prompt。
itnTrue是否进行逆文本正则化。
max_new_tokens512每条音频最大生成 token 数。
temperature0.0默认贪心解码。
repetition_penalty1.0vLLM generation 的重复惩罚参数。

返回格式:[{"key": str, "text": str, "timestamps": [...]}]。当模型包含可选 CTC decoder 和 tokenizer 时,会返回时间戳。

FAQ

Q: 首次启动为什么慢?
vLLM 需要初始化 KV cache 和 CUDA graph,FunASR 也可能需要从 model.pt 提取 LLM 权重,首次启动通常约 60-90 秒。
Q: CUDA OOM 怎么办?
降低 gpu_memory_utilization,降低 max_model_len,或增加 tensor_parallel_size
Q: Paraformer 能用 vLLM 吗?
不能。Paraformer 是非自回归模型,不使用 vLLM KV-cache 解码。
Q: WebSocket 服务和 streaming_generate() 如何选择?
生产实时 ASR 推荐 WebSocket 服务,它基于 VAD 自然端点切分;SDK 集成或 chunk 级演示可使用 streaming_generate()
Q: 浏览器无法访问远程服务器麦克风?
Chrome 要求 HTTPS 或 localhost。可先执行 ssh -L 10095:localhost:10095 <server>,再从本机 localhost 打开客户端。