外观
FunASR ASR Server 架构设计与 2-Pass 流水线
本文档详细介绍 onnx-platform/funasr-asr-server 的系统整体架构、单进程双端口设计与核心 2-Pass 语音识别流水线。
1. 系统设计背景与演进
在旧版语音平台中,语音识别通常依赖封装好的 C++ 动态库(如 fanasr-runtime.dll / .so),存在以下维护痛点:
- 跨平台构建脆弱:不同操作系统与 GCC/MSVC 编译链对 C++ 动态库 ABI 极度敏感,容易产生符号冲突或崩溃;
- 多进程内存膨胀:流式服务与离线服务拆分为两个独立二进制进程,每个进程都要单独加载一遍数百 MB 至数 GB 的声学模型,内存占用翻倍;
- 黑盒排障困难:底层 C++ 崩溃难以生成可追踪的 Rust/Go 级堆栈日志。
纯 Rust 统一重构方案
onnx-platform/funasr-asr-server 采用 纯 Rust 自研算法前端与调度器,将所有外部 C++ 库彻底剥离,仅保留官方标准的 onnxruntime 动态库。 在单一进程中,通过 Axum 与 Tokio 同时绑定双端口网络监听,统一管理共享声学模型实例。
2. 单进程双端口并发架构
系统在单一可执行程序中同时启动两个独立的异步 TCP 监听服务,架构图如下:
text
+-------------------------------+ +-------------------------------+
| FreeSWITCH / WS 流式推流客户端 | | HTTP 客户端 / Whisper API 调用 |
+---------------+---------------+ +---------------+---------------+
| |
| WS ws://host:10099/audio | HTTP POST http://host:10094/asr
v v
+-----------------------------------------------------------------------------------------------+
| funasr-asr-server (单一操作系统进程) |
| |
| [Listener 1: 10099 端口] [Listener 2: 10094 端口] |
| server::ws_streaming server::http_offline |
| - GET /health - GET /health |
| - GET /audio (WebSocket 升级) - POST /asr, POST /recognize |
| - 子协议: audio.drachtio.org - POST /v1/audio/transcriptions |
| - 每连接分配独立 TwoPassSession 会话上下文 - Multipart 解析 + FFmpeg 转码辅助 |
| \ / |
| \ / |
| v v |
| +-----------------------------------------------------+ |
| | FunAsrEngine (全局单例, Arc<FunAsrEngine> 共享) | |
| | - Tokenizer: BPE 词表编解码 | |
| | - FSMN-VAD: 语音活动检测 | |
| | - Paraformer-Online: 流式实时编码与预测 | |
| | - Paraformer-Large: 离线全局双向 Attention 大模型 | |
| | - CT-Transformer: 智能标点符号预测 | |
| +-----------------------------------------------------+ |
+-----------------------------------------------------------------------------------------------+核心收益
- 模型内存零浪费:大模型权重只在堆内存驻留一份,
Arc<FunAsrEngine>提供跨线程、跨协议的并发只读共享; - 连接隔离与并发控制:流式连接数受
concurrency.maxSessions严格保护,离线请求受独立的请求计数器追踪; - 优雅停机(Graceful Shutdown):通过 Tokio
watch::channel广播停机信号,捕获SIGINT/Ctrl+C后,Axum 平滑等待进行中的识别完成再安全退出。
3. 2-Pass 双流实时识别流水线
2-Pass(双遍流式流水线)是当前工业级语音识别兼顾超低延迟与极高准确率的核心算法范式:
- Pass 1(流式实时流):每收到一小包音频(约 20ms~600ms),立即通过轻量流式模型计算,在用户说话过程中以毫秒级延迟吐出字(Partial 增量文字),用户能即时看到字幕跳出;
- Pass 2(整句离线精算流):当用户说完一整句话、停顿(静音)触发 VAD 切句时,系统将这一整句话的完整音频输入到参数量更大的全局双向 Attention 离线模型,重新做全局解码,并结合标点模型加上逗号、句号(Final 终态文字),纠正 Pass 1 产生的同音字或语法偏差。
详细处理时序图 (ASCII)
text
[音频输入: PCM16 16kHz]
|
v
[TwoPassSession::push_pcm16] (src/engine/session.rs)
|
|-- 1. 音频格式转换: [u8] -> i16 -> f32 浮点采样 [-32768.0, 32768.0]
|
+---------------------------------------------------------------------+
| [步骤 1: FSMN-VAD 语音活动检测] |
| - 提取 80 维 Fbank 特征 |
| - 结合 4 层历史 Memory Cache 评估静音/人声概率 |
| - 状态机输出边沿: |
| * speech_started: 标记进入语音段,冲刷 1s Pre-roll 缓冲 |
| * speech_completed: 标记本句结束,进入 Pass 2 结算 |
+---------------------------------------------------------------------+
|
|-- 处于说话中 (speech_active == true)
|
+---------------------------------------------------------------------+
| [步骤 2: Pass 1 流式推理 - Paraformer-Online + CIF] |
| - 将音频推入滑动窗口 (约 600ms 一步) |
| - 提取 LFR (560维) 特征并做 CMVN 均值归一化 |
| - Encoder 提取声学向量 -> Predictor 预测声学权重 alpha |
| - CIF (连续积分点火器): |
| 累加 sum(alpha) >= 1.0 时 -> 触发点火 (Fire!) |
| 发射声学 Embedding 向量到 Decoder |
| - Decoder 实时出字 -> 下发 partial 文本帧 (isFinal: false) |
+---------------------------------------------------------------------+
|
|-- 检测到断句 (speech_completed == true 或收到客户端结束信号)
|
+---------------------------------------------------------------------+
| [步骤 3: Pass 2 整句离线精算 - Paraformer-Large + CT-Transformer] |
| - 取出整句缓存的原始音频 PCM (包含字头与字尾) |
| - 送入 Paraformer-Large 离线大模型: |
| 全局双向自注意力机制 (Global Self-Attention) 全局精算 |
| 贪心解码 (Greedy Search) 产出高质量无标点文本 |
| - 送入 CT-Transformer 标点模型: |
| 结合 jieba 分词与拼音嵌入,自动回填逗号、句号、问号 |
| - 下发 final 文本帧 (isFinal: true) 替换此前的 partial 结果 |
| - 重置单句缓存与 CIF 积分器,准备接收下一句话 |
+---------------------------------------------------------------------+4. 模块职责与目录结构
text
onnx-platform/funasr-asr-server/
├── src/
│ ├── main.rs # 主入口:初始化配置、绑定双 Listener、优雅停机
│ ├── config.rs # 强类型配置反序列化与多 Profile 管理
│ ├── logging.rs # tracing 结构化日志子系统
│ ├── engine/ # 纯 Rust 推理引擎核心
│ │ ├── mod.rs # ONNX Runtime 动态库自动定位与 Engine 单例组装
│ │ ├── session.rs # TwoPassSession 会话协调器与推流调度
│ │ ├── frontend.rs # Kaldi 兼容 Fbank (FFT/Mel/LFR/CMVN)
│ │ ├── tokenizer.rs # BPE 词表编解码
│ │ ├── vad.rs # FSMN-VAD 状态机与 Memory Cache
│ │ ├── online.rs # Paraformer-Online 双模型与 CIF 积分点火器
│ │ ├── paraformer.rs # Paraformer-Large 离线全局模型
│ │ ├── punc.rs # CT-Transformer 标点恢复与 jieba 切词
│ │ └── sensevoice.rs # SenseVoice 多语种标签解析
│ └── server/ # 双端口网络协议层
│ ├── mod.rs
│ ├── ws_streaming.rs # 10099 端口 WebSocket 流式推流实现
│ ├── http_offline.rs # 10094 端口 HTTP 离线与 Whisper 接口实现
│ ├── protocol.rs # 协议帧序列化与 DTO 契约
│ └── ffmpeg.rs # 外部 FFmpeg 子进程音频转码防线