千问大模型宣布升级实时语音识别大模型 Fun-ASR-Realtime。关键信息很直接:首字延迟控制在百毫秒级别,流式识别准确率接近离线模型,并支持 16 种方言和 30 种语言。它已经在影视飓风「重返荒岛」100 小时直播中承担实时字幕能力,累计识别 6 万余条字幕、约 132 万字。
对开发者来说,这不是“又一个 ASR 模型发布”的新闻。它指向的是直播、会议、客服、内容生产这类实时场景里最难平衡的三件事:低延迟、稳定识别、多语言/方言覆盖。
实时字幕真正卡在哪里
离线语音识别可以等一句话说完再整体推理,模型有完整上下文,准确率天然更容易做高。直播字幕不一样,观众等不了几秒,字幕系统必须边听边吐字。
这里的“首字延迟百毫秒级”很关键。它影响的是用户第一次看到字幕的时间,而不是整段话全部完成的时间。首字出来得快,字幕就有“跟嘴”的感觉;首字慢,即使最终文本准确,也会显得滞后。
但实时 ASR 的工程难点不止模型:
- 音频采集端要稳定输出 PCM、Opus 或其他约定格式。
- 传输层要避免网络抖动把音频块挤成一团。
- 服务端要处理分片、增量结果、最终结果、断线重连。
- 前端字幕要处理覆盖、回滚、标点补全和说话人切换。
Fun-ASR-Realtime 这次强调“识别准确率接近离线模型”,说明它瞄准的是实时系统里长期存在的妥协:以前低延迟往往意味着更高错字率,现在模型能力正在压低这个代价。
100 小时直播是很硬的工程验证
影视飓风「重返荒岛」100 小时直播提供了一个有代表性的测试场景:长时间、连续、多说话人、环境复杂,并且观众会直接看到字幕质量。
摘要里提到累计识别字幕 6 万余条、约 132 万字。这个量级说明系统不只是跑了一个演示,而是在长链路里经受了真实流量:
- 直播持续时间长,连接管理和资源回收不能出问题。
- 户外或复杂环境下,背景声会干扰识别。
- 主播表达里可能混杂口语、停顿、重说和专有名词。
- 字幕生成不能只追求准确,还要控制输出节奏。
如果你在做直播字幕或会议转写,应该重点关注“端到端字幕体验”,而不是只看 ASR 单点指标。模型给出增量文本之后,字幕系统还要决定什么时候上屏、什么时候替换上一段、什么时候冻结为最终文本。
可以这样实践:搭一个实时 ASR 字幕客户端骨架
下面示例是一个可改造的 WebSocket 流式识别客户端骨架。由于摘要没有给出 Fun-ASR-Realtime 的具体调用协议,这里明确标注为“假设接口”:假设服务端接收 16kHz、单声道、16-bit PCM 音频块,并通过 WebSocket 返回 JSON 格式的增量识别结果。
运行前需要替换:
ASR_WS_URL:你的实时 ASR WebSocket 地址。ASR_TOKEN:你的鉴权令牌。input.wav:16kHz 单声道 WAV 文件,或先用下面的ffmpeg命令转换。
ffmpeg -y -i input.mp4 -ac 1 -ar 16000 -f wav input.wav
python3 -m venv .venv
. .venv/bin/activate
pip install websockets
python realtime_asr_client.py input.wav
realtime_asr_client.py:
import asyncio
import json
import os
import sys
import wave
import websockets
ASR_WS_URL = os.environ.get("ASR_WS_URL", "wss://example.com/asr/realtime")
ASR_TOKEN = os.environ.get("ASR_TOKEN", "replace-me")
CHUNK_MS = 100
def read_pcm_chunks(wav_path: str, chunk_ms: int = CHUNK_MS):
with wave.open(wav_path, "rb") as wf:
channels = wf.getnchannels()
sample_rate = wf.getframerate()
sample_width = wf.getsampwidth()
if channels != 1 or sample_rate != 16000 or sample_width != 2:
raise ValueError("WAV must be 16kHz, mono, 16-bit PCM")
frames_per_chunk = sample_rate * chunk_ms // 1000
while True:
data = wf.readframes(frames_per_chunk)
if not data:
break
yield data
async def receive_results(ws):
async for message in ws:
event = json.loads(message)
text = event.get("text", "")
is_final = event.get("final", False)
if text:
prefix = "FINAL" if is_final else "PARTIAL"
print(f"[{prefix}] {text}")
async def stream_audio(wav_path: str):
headers = {"Authorization": f"Bearer {ASR_TOKEN}"}
async with websockets.connect(ASR_WS_URL, additional_headers=headers) as ws:
await ws.send(json.dumps({
"type": "start",
"format": "pcm_s16le",
"sample_rate": 16000,
"channels": 1,
"language": "auto"
}))
receiver = asyncio.create_task(receive_results(ws))
for chunk in read_pcm_chunks(wav_path):
await ws.send(chunk)
await asyncio.sleep(CHUNK_MS / 1000)
await ws.send(json.dumps({"type": "end"}))
await receiver
if __name__ == "__main__":
if len(sys.argv) != 2:
raise SystemExit("Usage: python realtime_asr_client.py input.wav")
asyncio.run(stream_audio(sys.argv[1]))
这个骨架的重点不是某个 SDK 名称,而是实时 ASR 的基本形态:固定音频格式、按时间片发送、并发接收增量结果。接入真实服务时,你需要按服务商文档调整鉴权方式、消息字段、音频编码和结束信号。
落地时别只盯模型名
如果准备把类似 Fun-ASR-Realtime 的能力接到生产系统,可以按下面的清单推进:
- 延迟拆开测:采集延迟、网络延迟、模型首字延迟、字幕渲染延迟分别打点。
- 音频格式统一:直播推流、ASR 输入和归档音频最好有明确转换链路。
- 增量结果要可回滚:实时模型可能先输出临时文本,再用更完整上下文修正。
- 方言和多语言要做灰度:16 种方言、30 种语言覆盖很有价值,但你的业务语料仍要单独验收。
- 长时间运行要压测:100 小时直播说明方向可行,自己的系统还要验证断线、重连、限流和内存增长。
实时字幕系统的价值来自整条链路。模型把首字延迟和准确率往前推了一步,开发者要做的是把这一步接成稳定的产品体验:听得清、出得快、错了能改、断了能续。