本教程系统讲解自动语音识别(ASR)技术,详细介绍开源多语言语音识别模型 SenseVoiceSmall 及其推理框架 FunASR。通过完整示例项目 voice2text,你将学会在本地部署 SenseVoiceSmall 模型,用 FastAPI 构建语音识别后端服务,实现"用户上传音频或用麦克风录音,输出识别文字",并对外暴露 OpenAI 兼容的语音识别接口。
前置教程
如想快速开始学习本教程,你可能需要先完成以下前置教程:
- Python+FastAPI在Windows环境下创建一个基础后端服务教程,本教程使用 FastAPI 构建语音识别后端服务,需要你掌握基础后端服务写法。
- OpenAI兼容API的概念与用法详解,本教程的示例服务对外暴露 OpenAI 兼容的语音识别接口,需要你了解其请求格式与设计规范。
资源下载
1. ASR 技术概览
1.1 什么是 ASR
ASR(Automatic Speech Recognition,自动语音识别) 是指将人类的语音音频自动转换为对应文字文本的技术,是人工智能语音领域的核心基础能力之一,与 TTS(文本转语音)恰好互为反向任务。
ASR 的应用场景非常广泛:
- 语音输入:手机输入法、语音笔记、会议纪要的自动转写
- 智能交互:语音助手、智能音箱、客服系统的语音理解前端
- 字幕生成:视频、直播、网课的自动字幕
- 语音翻译:先识别再翻译,构成语音翻译链路
- 无障碍服务:为听障人群提供实时字幕
现代 ASR 系统的核心处理流程如下:
采样率统一、降噪] B --> C[声学特征提取
如梅尔频谱] C --> D[声学模型与解码
音频映射为文字] D --> E[输出文本] classDef input fill:#d6eaf8,stroke:#1a6b8a,stroke-width:2px classDef process fill:#d5f5e3,stroke:#1e8449,stroke-width:2px classDef model fill:#ffecd6,stroke:#ca6f1e,stroke-width:2px classDef output fill:#ebdef0,stroke:#6c3483,stroke-width:2px class A input class B process class C,D model class E output
| 阶段 | 作用 | 说明 |
|---|---|---|
| 音频预处理 | 统一采样率、静音切除 | 保证输入质量一致 |
| 声学特征提取 | 将音频波形转为特征向量 | 常用梅尔频谱、特征滤波器组 |
| 声学模型与解码 | 将声学特征映射为文字序列 | 决定识别准确率与语种支持 |
ASR 的本质是"音频到文字"的映射,工程上的重点是选择合适的识别模型,并把它封装成易于调用的服务。
1.2 在线 ASR 与本地部署 ASR 的对比
调用 ASR 有两种主流方式:调用在线 ASR 服务 与 本地部署 ASR 模型。两者的对比如下:
| 对比项 | 在线 ASR 服务 | 本地部署 ASR(SenseVoiceSmall) |
|---|---|---|
| 联网要求 | 需要联网调用云端服务 | 无需联网,完全离线可用 |
| 调用成本 | 按量计费或订阅 | 模型开源免费,需自备硬件 |
| 数据隐私 | 音频上传至云端 | 数据不出本地,隐私可控 |
| 部署门槛 | 低,注册即可调用 | 较高,需要配置深度学习环境 |
| 语种支持 | 视服务商而定 | 支持中英粤日韩等 50+ 语言 |
| 识别速度 | 受网络影响 | 极低延迟,10 秒音频约 70ms 推理 |
1.3 本教程的选型
- SenseVoiceSmall:开源多语言音频理解模型,由阿里通义实验室(FunAudioLLM)开源,支持多语言语音识别、情感识别与音频事件检测,推理延迟极低。
- FunASR:阿里巴巴开源的语音识别工具包,负责加载与推理 SenseVoice 等模型,提供统一、简洁的调用接口。
选择建议:需要离线、隐私可控、低延迟的场景选择本地部署 SenseVoiceSmall;快速原型或语音量小的场景可选用在线服务。本教程的示例项目将本地模型封装为 OpenAI 兼容接口,便于与既有系统集成。
2. SenseVoiceSmall 模型详解
2.1 模型简介
SenseVoiceSmall 是由阿里通义实验室开源的多语言音频理解基础模型,采用非自回归端到端框架,参数量与 Whisper-Small 相当,但推理速度比 Whisper-Small 快 5 倍、比 Whisper-Large 快 15 倍,10 秒音频推理仅需约 70ms。
模型采用超过 40 万小时数据训练,支持中、粤、英、日、韩五语种的高精度语音识别。
SenseVoiceEncoderSmall] B --> C[非自回归解码
并行输出文字序列] C --> D[富文本结果
含情感/事件标签] classDef input fill:#d6eaf8,stroke:#1a6b8a,stroke-width:2px classDef model fill:#ffecd6,stroke:#ca6f1e,stroke-width:2px classDef process fill:#d5f5e3,stroke:#1e8449,stroke-width:2px classDef output fill:#ebdef0,stroke:#6c3483,stroke-width:2px class A input class B,C model class D output
2.2 核心能力
- 多语言识别:支持中文、粤语、英语、日语、韩语,识别效果优于 Whisper 模型
- 富文本识别:输出不仅包含文字,还包含情感标签(如
<|HAPPY|>)与音频事件标签(如<|BGM|>、<|Applause|>) - 情感识别:可辨识高兴、悲伤、生气、害怕等多种情绪
- 事件检测:可检测音乐、掌声、笑声、哭声、咳嗽、喷嚏等常见人机交互事件
- 逆文本正则化:可将口语化的"20度C"自动恢复为"20°C"等规范写法
- 低延迟推理:非自回归架构,推理耗时不随音频时长明显增加
2.3 本地模型目录
本教程假设 SenseVoiceSmall 模型已放置在 C:\models\SenseVoiceSmall,目录中应包含以下文件:
| 文件 | 作用 |
|---|---|
config.yaml |
模型配置(编码器结构、特征参数等) |
model.pt |
模型权重文件 |
am.mvn |
声学特征均值方差归一化参数 |
chn_jpn_yue_eng_ko_spectok.bpe.model |
多语言文本词表 |
demo.py |
官方推理示例脚本 |
example/ |
官方示例音频(含中英粤日韩五语) |

2.4 使用 FunASR 调用
SenseVoiceSmall 使用 FunASR 框架推理。核心代码如下:
from funasr import AutoModel
from funasr.utils.postprocess_utils import rich_transcription_postprocess
# 加载本地模型,可选用 VAD 切分长音频
model = AutoModel(
model="C:/models/SenseVoiceSmall",
device="cuda", # 无 GPU 时改为 "cpu"
vad_model="fsmn-vad", # VAD 用于长音频切分
vad_kwargs={"max_single_segment_time": 30000},
)
res = model.generate(
input="audio.mp3", # 任意格式音频
cache={},
language="auto", # auto / zh / en / yue / ja / ko
use_itn=True, # 是否包含标点与逆文本正则化
batch_size_s=60, # 动态 batch 总音频时长(秒)
merge_vad=True, # 合并 VAD 切分的短音频
merge_length_s=15,
)
text = rich_transcription_postprocess(res[0]["text"])
print(text)
AutoModel 可以直接传入本地模型目录;generate() 返回的原始结果包含语言、情感、事件等富文本标签,使用 rich_transcription_postprocess() 处理后即可得到纯文本。首次启用 VAD 会联网下载 fsmn-vad 模型,仅需一次。
3. 环境准备
3.1 创建环境
ASR 使用独立的 conda 环境 voice2text,依赖统一使用 uv 安装:
# 创建并激活 conda 环境
conda create -n voice2text python=3.10 -y
conda activate voice2text
# 安装 lzma 运行库(conda 的 Python 可能缺少 _lzma 模块,避免后续报错)
conda install -c conda-forge liblzma -y
# 安装 uv(Python 包管理工具)
pip install uv
3.2 安装依赖
先安装 CUDA 版 PyTorch,国内推荐从阿里云镜像直链下载 cu128 的 wheel(速度快);网络好的读者也可改用官方源。注意先装 torch 再装 funasr,避免 funasr 把 torch 解析成 CPU 版:
# 方法一:阿里云镜像直链(国内推荐)
uv pip install \
"https://mirrors.aliyun.com/pytorch-wheels/cu128/torch-2.8.0%2Bcu128-cp310-cp310-win_amd64.whl" \
"https://mirrors.aliyun.com/pytorch-wheels/cu128/torchvision-0.23.0%2Bcu128-cp310-cp310-win_amd64.whl" \
"https://mirrors.aliyun.com/pytorch-wheels/cu128/torchaudio-2.8.0%2Bcu128-cp310-cp310-win_amd64.whl"
# 方法二:PyTorch 官方源
uv pip install torch==2.8.0 torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
# 安装 funasr 与服务依赖(含 fastapi、uvicorn、soundfile 等)
cd voice2text
uv pip install -r requirements.txt --index-url https://pypi.tuna.tsinghua.edu.cn/simple
提示:无 GPU 时跳过 CUDA torch 安装即可,funasr 会使用 CPU 版 torch 推理,识别速度较慢但可运行。mp3/m4a 等格式由 torchaudio 内置的 FFmpeg 解码,无需单独安装 ffmpeg。
3.3 下载模型权重
SenseVoiceSmall 模型可通过 ModelScope 或网盘下载。国内用户推荐使用 ModelScope:
# 使用 ModelScope 下载(推荐国内用户)
modelscope download --model iic/SenseVoiceSmall --local_dir C:/models/SenseVoiceSmall
也可以从本教程资源下载区块的网盘地址直接下载模型压缩包,解压后将文件放到 C:\models\SenseVoiceSmall 目录即可。
4. 综合示例:voice2text 语音识别服务
4.1 项目目标与架构
示例项目 voice2text 将 SenseVoiceSmall 封装为一个完整的语音识别服务,实现以下目标:
- 用户上传一段音频,或用麦克风录音,服务识别并输出文字
- 对外暴露 OpenAI 兼容的
POST /v1/audio/transcriptions接口 - 构建前端页面,支持文件上传与浏览器内麦克风录音
整体架构如下:
static/index.html] -->|上传音频 / 录音 WAV| A[FastAPI 后端
main.py] A --> S[asr_service.py
FunASR 封装] S --> M[SenseVoiceSmall 模型
C:/models/SenseVoiceSmall] S -->|识别文字| U classDef frontend fill:#d6eaf8,stroke:#1a6b8a,stroke-width:2px classDef backend fill:#d5f5e3,stroke:#1e8449,stroke-width:2px classDef engine fill:#ebdef0,stroke:#6c3483,stroke-width:2px classDef model fill:#ffecd6,stroke:#ca6f1e,stroke-width:2px class U frontend class A backend class S engine class M model
4.2 项目结构
voice2text/
├── config.py # 服务配置(端口、模型路径、设备)
├── main.py # FastAPI 后端,识别接口
├── asr_service.py # ASR 识别服务(FunASR 封装)
├── requirements.txt # 依赖管理
├── static/
│ └── index.html # 前端页面(上传 + 录音)
└── README.md # 项目说明
4.3 配置文件 config.py
所有配置统一在 config.py 中修改,包括监听端口、模型路径、推理设备、识别语言等:
# config.py(核心片段,完整代码请查看 voice2text/config.py)
PORT = 8000
# SenseVoiceSmall 模型目录(需包含 config.yaml 与 model.pt 等文件)
ASR_MODEL_DIR = "C:/models/SenseVoiceSmall"
# 推理设备:cuda / cpu
ASR_DEVICE = "cuda"
# 识别语言:auto / zh / en / yue / ja / ko
ASR_LANGUAGE = "auto"
# 是否启用 VAD 长音频切分(首次使用会联网下载 fsmn-vad 模型)
ASR_USE_VAD = True
# 输出是否包含标点与逆文本正则化
ASR_USE_ITN = True
4.4 ASR 识别服务
asr_service.py 封装了 FunASR 的调用逻辑。考虑到模型加载耗时,采用懒加载方式在首次请求时才加载模型;同时 FunASR 模型非线程安全,使用全局锁串行化识别请求:
# asr_service.py(核心片段,完整代码请查看 voice2text/asr_service.py)
def _get_model():
"""懒加载 FunASR 模型(首次调用时加载)"""
global _model
if _model is None:
from funasr import AutoModel
kwargs = {"model": ASR_MODEL_DIR, "device": ASR_DEVICE}
if ASR_USE_VAD:
kwargs["vad_model"] = "fsmn-vad"
kwargs["vad_kwargs"] = {"max_single_segment_time": 30000}
_model = AutoModel(**kwargs)
return _model
def transcribe(audio_path, language=None):
"""将音频文件识别为文字,返回去除富文本标签的转写结果"""
model = _get_model()
with _recog_lock: # 串行化识别请求
res = model.generate(
input=audio_path, cache={},
language=language or ASR_LANGUAGE,
use_itn=ASR_USE_ITN,
batch_size_s=60, merge_vad=True, merge_length_s=15,
)
return rich_transcription_postprocess(res[0]["text"])
4.5 后端接口
main.py 是服务的核心入口,提供两个识别接口:自定义的 /api/transcribe 与 OpenAI 兼容的 /v1/audio/transcriptions:
# main.py(核心片段,完整代码请查看 voice2text/main.py)
@app.post("/api/transcribe")
async def transcribe(file: UploadFile = File(...)):
"""自定义识别接口:上传音频文件,返回识别文字"""
audio_path = _save_audio(file) # 保存为临时文件
try:
text = asr_service.transcribe(audio_path)
finally:
os.unlink(audio_path) # 识别后清理临时文件
return {"text": text}
@app.post("/v1/audio/transcriptions")
async def transcriptions(
file: UploadFile = File(...),
model: str = Form("SenseVoiceSmall"),
language: str = Form("auto"),
):
"""OpenAI 兼容的语音识别接口"""
audio_path = _save_audio(file)
try:
text = asr_service.transcribe(audio_path, language=language or None)
finally:
os.unlink(audio_path)
return {"text": text} # OpenAI 兼容返回格式
代码要点说明:
| 功能模块 | 实现方式 | 说明 |
|---|---|---|
| 音频接收 | UploadFile(multipart) |
前端通过表单上传音频文件 |
| 临时文件 | tempfile.NamedTemporaryFile |
识别结束后清理,不落盘 |
| 自定义接口 | POST /api/transcribe |
前端使用的简单接口 |
| 兼容接口 | POST /v1/audio/transcriptions |
与 OpenAI 规范一致,返回 {"text": ...} |
4.6 前端页面
前端为单页 HTML 应用,位于 static/index.html。你可以前往 voice2text/static/index.html 查看完整的示例代码。页面主要功能:
- 上传音频:选择本地音频文件(wav/mp3/m4a/flac 等)作为识别输入
- 麦克风录音:调用浏览器麦克风录音,通过 Web Audio API 实时采集并编码为 16kHz WAV
- 音频预览:识别前可播放已选音频或录音
- 识别展示:点击"开始识别",通过
fetch以 multipart 表单上传音频,展示返回的文字
麦克风录音采用 Web Audio API 采集原始 PCM 并编码为 WAV,不依赖 WebM/Opus,因此无需 ffmpeg 即可在服务端解码。
4.7 运行与测试
第一步:创建环境并安装依赖
若已按第 3 章完成环境准备(voice2text 环境已创建),直接激活即可;否则先按第 3 章创建环境并安装依赖。
conda activate voice2text
cd voice2text
# 安装服务依赖(若第 3 章已安装可跳过)
uv pip install -r requirements.txt --index-url https://pypi.tuna.tsinghua.edu.cn/simple
第二步:确认模型位置
确保模型位于 C:\models\SenseVoiceSmall(第 3.3 节),如需自定义路径,修改 config.py 中的 ASR_MODEL_DIR。
第三步:启动服务
python main.py
启动后访问 http://localhost:8000,即可看到语音识别界面。
第四步:验证功能
- 在页面中上传一段音频或点击录音,点击"开始识别",确认能正确输出文字
- 也可使用 curl 直接验证接口:
curl.exe -X POST http://localhost:8000/api/transcribe -F "file=@C:/path/to/audio.wav"

4.8 使用 OpenAI SDK 验证接口兼容性
由于服务暴露了 OpenAI 兼容接口,可以直接使用 openai 官方 Python SDK 调用:
# 使用 openai SDK 调用本地 voice2text 服务
from openai import OpenAI
client = OpenAI(
base_url="http://127.0.0.1:8000/v1", # 本地服务地址
api_key="not-needed", # 本地服务不校验 Key
)
with open("audio.wav", "rb") as f:
result = client.audio.transcriptions.create(
model="SenseVoiceSmall",
file=f,
language="auto",
)
print(result.text)
5. 总结
5.1 核心内容回顾
- ASR 技术:语音转文字,核心流程为音频预处理、声学特征提取、声学模型与解码
- SenseVoiceSmall:开源多语言音频理解模型,支持中英粤日韩识别、情感识别、事件检测,低延迟高精度
- FunASR 推理:
AutoModel加载本地模型,generate()识别,rich_transcription_postprocess清理富文本 - 服务封装:FastAPI 实现
/api/transcribe与 OpenAI 兼容的/v1/audio/transcriptions接口 - 前端应用:支持上传音频与麦克风录音,录音通过 Web Audio 编码为 WAV
5.2 常见问题与解答
问:首次识别时为什么会联网?
答:启用 VAD 时,首次运行会联网下载 fsmn-vad 模型(仅需一次,之后使用本地缓存)。关闭 VAD(ASR_USE_VAD = False)可完全离线,但长音频的切分效果会变差。
问:识别结果包含奇怪符号(如 <|HAPPY|>)?
答:这是 SenseVoice 的富文本标签(情感、事件、语种)。示例代码已使用 rich_transcription_postprocess() 清理,只保留纯文本。
问:麦克风录音后识别为空或失败?
答:确认浏览器允许麦克风权限;录音时长过短可能识别为空,建议录制 1 秒以上。也可改用上传音频方式测试。
问:无 GPU 如何运行?
答:跳过 CUDA torch 安装,并将 config.py 的 ASR_DEVICE 改为 "cpu"。SenseVoiceSmall 参数量小,CPU 推理也可接受。
问:上传 mp3/m4a 无法识别?
答:torchaudio 内置 FFmpeg 支持常见音频格式。若仍失败,可先转码为 wav 再上传,或确认 torchaudio 版本与后端正常。
举手提问