一、先说一个实际遇到的问题:明明没人说话,ASR 却“说了一大段”

做熙瑾会悟的 ASR 能力时,有一个问题一开始其实挺容易被忽略:

录音没有人说话,模型却识别出了文字。

例如会议开始前,设备已经开始录音,但现场还没有人讲话。

原始音频可能是:

00:00 - 00:08 静音

00:08 - 00:15 空调声

00:15 - 00:20 轻微键盘声

00:20 - 00:25 静音

正常情况下,这几秒应该直接被过滤掉。

但实际测试的时候,ASR 可能返回类似:

“今天我们主要讨论一下项目的整体情况……” 甚至有时候还能连续生成好几句话。

第一次遇到这个现象,很多人的第一反应可能是:

“是不是 ASR 模型识别能力不行?”

实际上不完全是。

这个问题通常不是简单的“模型准确率低”,而是一个由音频输入、VAD、模型解码机制、上下文信息以及后处理策略共同造成的问题

尤其是基于 Attention/Encoder-Decoder 架构的语音识别模型,在面对低质量、低能量甚至接近纯静音的音频时,有可能根据训练过程中学到的语言模式“猜”出一段看起来合理的文本。

所以这里出现了一个很有意思的现象:

模型不是听到了这句话,而是在没有足够语音信息的时候,生成了一句“它认为可能存在的话”。

这也是我们在会议 ASR 场景里重点处理的问题之一。

二、所谓“幻觉识别”到底是什么?

这里先把概念说清楚。

ASR 中所谓的“幻觉识别”,并不是模型真的产生了类似大语言模型那种完整意义上的幻觉,而是工程上经常用来描述:

输入音频缺少有效语音信息,但 ASR 模型仍然输出了具有语言结构的文本。

例如:

真实音频:

——————————————

静音

——————————————

ASR输出: “感谢大家今天参加本次会议。” 或者:

真实音频: 空调声 + 鼠标声 + 轻微背景噪声 ASR输出: “下面我们开始讨论第二个问题……” 对于普通语音 Demo 来说,这个问题可能不明显。

但对于会议产品影响非常大。

因为会议系统后面还有一层:

一旦 ASR 在静音阶段生成了一段“假文字”,后面的 LLM 可能还会一本正经地把它总结进去。

最终就会变成:

录音里没人说话,但是会议纪要里出现了不存在的内容。

这就不是一个简单的识别误差了。

三、问题排查:到底是谁把“静音”变成了文字?

我们把整个 ASR 链路拆开以后,可以发现问题一般出现在几个地方。

真正需要重点关注的是:

如果只盯着 ASR 模型本身,很容易陷入一个误区:

“换个更大的模型是不是就好了?”

实际上不一定。

很多时候,让模型少吃一点无效音频,比单纯换一个更大的模型更有效。

四、第一个问题:VAD 没有把静音过滤干净

VAD,也就是:

Voice Activity Detection,语音活动检测。

它主要负责判断:

这一段音频到底有没有人在讲话?

这是解决静音幻觉最直接的一道防线。

假设原始音频是:

0s ───────────────────────── 60s

讲话 静音 讲话

████ ---- ████

VAD 之后:

[05s - 18s] [39s - 55s] ASR 实际收到的就不是完整的 60 秒,而是两段有效语音。

这样可以直接减少:

静音输入

背景噪声输入

空白音频

无效推理

幻觉文本

五、VAD 为什么还会误判?

问题又来了。

VAD 也不是万能的。

会议环境里经常出现:

键盘声 鼠标声 敲桌子 翻纸 空调 椅子移动 远处说话 手机震动 有些声音的能量并不低。

如果只使用简单的音量阈值:

if RMS > threshold: 有人说话 很容易把噪声当成人声。

所以在实际工程里,VAD 最好不要只依赖一个指标。

可以组合:

最终形成一个更加稳定的语音活动判断。

六、第二个问题:不能只依赖 VAD,ASR 前面还需要一道“静音门”

这是实际工程中比较值得做的一层。

即使 VAD 判断“可能存在语音”,也可以在真正送进 ASR 前再做一次检查。

例如计算:

RMS(Root Mean Square)能量。

简单来说,就是判断当前音频整体能量水平。

伪代码可以理解成:

energy = calculate_rms(audio)

if energy < silence_threshold:
    return empty_result

当然,生产环境不能简单写死一个阈值。

因为不同设备:

会议室麦克风 笔记本麦克风 USB麦克风 录音笔 手机 底噪完全不一样。

所以更合理的做法是:

动态估计噪声底,再判断当前音频是否明显高于噪声水平。

例如:

两者之间需要建立一个合理的判定区间。

七、第三个问题:ASR 模型本身为什么会“编”出文字?

这个问题就涉及 ASR 模型内部机制了。

以 Encoder-Decoder 类模型为例:

当输入语音足够清晰时:

能够共同帮助模型生成正确文本。

但如果输入的是:

静音 或者:

极低能量噪声 那么有效声学信息非常少。

这时候 Decoder 仍然可能根据已经生成的 token 和训练过程中学到的语言概率继续往下生成。

简单理解就是:

所以会出现:

这种看起来非常离谱,但模型概率上又可能说得通的结果。

八、Whisper 类模型为什么尤其需要关注这个问题?

在实际工程中,Whisper 是一个很常见的选择。

它的优点非常明显:

多语言能力较强

模型生态成熟

工程资料丰富

对复杂音频有一定鲁棒性

社区使用广泛

但在实际应用中,静音、噪声、重复音频、异常片段等场景仍然需要额外处理。

因此不能简单地:

result = whisper.transcribe(audio)

然后把所有输出直接当成最终结果。

更合理的思路是建立:

Whisper + VAD + no_speech判断 + log probability + compression ratio + 后处理 多层过滤机制。

九、Whisper 场景下可以关注哪些指标?

如果使用 Whisper 或类似模型,可以重点观察模型提供的相关评分信息。

例如:

1. no_speech probability

可以理解为:

模型认为这一段没有说话的概率。

如果:

no_speech_prob 很高 那么可以考虑直接丢弃该 Segment。

当然,不能简单理解为:

no_speech_prob > 0.5 就一定删除。

具体阈值还是应该根据自己的会议数据进行测试。

2. Average Log Probability

如果生成文本时平均 log probability 很低,说明模型对当前结果其实没有那么有把握。

可以把它作为一个过滤指标。

例如:

共同判断。

3. Compression Ratio

这个指标在检测异常重复文本时也有一定参考价值。

比如输入异常音频后出现:

“大家好大家好大家好大家好大家好……” 或者:

“谢谢谢谢谢谢谢谢……” 这种明显异常的重复结果,就可以进一步过滤。

十、第四个问题:音频切得太长,也容易放大幻觉

假设一个会议录音:

00:00 ───────────────── 10:00

中间可能只有:

讲话 → 静音 → 讲话 → 静音 → 噪声 → 讲话

如果直接把 10 分钟音频交给模型:

10分钟音频 ↓ ASR

模型需要在大量无效音频中寻找语音。

这时候风险自然会上升。

所以更合理的处理方式是:

例如:

Segment 01:00:02 - 00:18

Segment 02:00:24 - 00:43

Segment 03:01:05 - 01:31

十一、Segment 不能切得太碎

但是这里又存在另一个坑。

如果切得过碎:

“今天我们主要讨论项目进度” 可能变成:

“今天我们” “主要讨论” “项目进度” 上下文被切断后,识别准确率反而会下降。

所以实际项目里需要做一个折中:

最小语音长度 + 最大Segment长度 + 静音间隔 + 前后上下文 共同决定切分策略。

这也是为什么 VAD 参数不能照着网上的一组数字直接抄。

会议、访谈、电话、直播、课堂,参数都可能不一样。

十二、第五个问题:会议环境的“静音”其实不一定是真静音

这一点非常重要。

实际录音里面很少存在真正意义上的:

绝对 0 声音 更多的是:

低频空调声 + 麦克风底噪 + 电流声 + 远处人声 + 桌面振动 所以:

静音检测实际上是在做“语音与非语音”的分类。

这也是为什么音频预处理很重要。

十三、音频预处理可以做什么?

比较常见的处理包括:

1. 重采样

统一采样率。

例如:

48kHz ↓ 16kHz 具体采样率根据模型要求决定。

2. 单声道转换

如果业务模型主要使用 Mono:

Stereo ↓ Mono

3. 音量归一化

避免不同设备录音音量差异太大。

4. 降噪

可以使用:

  • RNNoise
  • WebRTC Audio Processing
  • DeepFilterNet
  • 企业自己的降噪模块

但降噪也不能过度。

如果把人声高频部分一起削掉,ASR 反而可能更差。

十四、第六个问题:不要把“静音过滤”全部交给模型

这是整个问题排查过程中比较重要的一点。

如果架构变成:

其实已经晚了一步。

更好的方式是:

也就是说:

前面过滤一次,模型结果出来以后再过滤一次。

形成双保险。

十五、第七个问题:ASR 输出之后还需要做“幻觉文本过滤”

这是我们实际工程里比较值得增加的一层。

假设 ASR 输出:

“谢谢大家的观看。” 但原始音频:

静音 6 秒 这时候即使 ASR 自己认为这句话概率不错,我们仍然可以通过上下文判断:

音频能量 ≈ 0 VAD = 无语音 文本 = 非空 最终:

文本 → 丢弃

十六、可以设计一个简单的多指标判定策略

例如:

VoiceScore =

α × VADScore

+ β × EnergyScore

+ γ × ASRConfidence

+ δ × NoSpeechScore

不一定非要真的采用这个公式,但这个思路比较重要。

不要:

只看一个指标。

而是把多个信号综合起来。

例如:

条件

判断

VAD 无语音

高概率丢弃

音频能量极低

倾向丢弃

no_speech_prob 高

倾向丢弃

ASR 置信度低

倾向丢弃

出现大量重复文本

丢弃

Segment 极短

根据业务判断

多项指标同时异常

直接丢弃

十七、Paraformer 场景应该怎么处理?

如果使用 Paraformer 等非自回归 ASR 模型,处理思路有所不同。

Paraformer 的特点之一就是推理效率较好,在中文语音识别、实时场景中比较适合。

但模型快并不意味着:

静音就一定不会识别出文本。

因此同样建议:

如果部署的是 FunASR 相关模型组合,也可以结合:

形成完整处理链。

十八、SenseVoice 场景也建议采用前后双层过滤

SenseVoice 这类模型除了语音识别,还可以用于语音相关任务。

但在企业会议场景里,不管使用什么模型,都不建议把:

模型输出 直接等同于:

最终文本 统一增加:

会更加稳妥。

十九、一个比较实用的 ASR 防幻觉架构

最终我们可以把这套方案整理成下面这样:

这个架构的关键就在于:

ASR 不是唯一的判断者。

二十、异常结果可以考虑“重新识别”

还有一个比较实用的方法。

如果第一轮识别结果异常:

VAD正常 但是 ASR置信度很低 不要马上把结果返回给用户。

可以尝试:

比如第一次:

0s - 15s

第二次改成:

2s - 13s

或者:

增加上下文 再识别一次。

这种方式虽然增加一点计算量,但对于离线会议转写非常实用。

二十一、对于实时 ASR,还要处理“尾部静音”

实时会议里经常有这种情况:

用户: “我们先讨论一下这个问题……” 然后停了两秒。

ASR 需要判断:

是不是一句话结束了?

如果 Endpointing 做得不好,就可能把:

讲话 + 2秒静音 + 后面的噪声 一起送进模型。

所以实时 ASR 中通常需要处理:

这里的静音时长是非常重要的参数。

太短:

用户一句话还没说完就被截断。

太长:

用户说完了,文字迟迟不出来。

因此实时会议需要在:

准确率和延迟之间做平衡。

二十二、为什么“规则过滤”不能做得太狠?

看到这里,有人可能会想:

“既然静音容易产生幻觉,那我把所有短文本都过滤掉。”

这个方法看起来简单,但很容易误伤。

比如:

“好。” “可以。” “对。” “嗯。” 这些都是非常短的语句。

如果简单按照:

文本长度 < 3 直接删除,那么正常会议内容也会丢失。

所以过滤规则最好结合:

综合判断。

二十三、还可以建立一个“幻觉文本黑名单”

在真实业务中,如果长期积累数据,会发现一些固定模式。

例如某些模型在无语音情况下容易生成:

“谢谢大家。” “感谢观看。” “请大家关注。” “字幕由……” 这些文本在特定会议场景下本身就比较可疑。

可以建立:

hallucination_patterns:
  - "感谢大家"
  - "谢谢观看"
  - "欢迎订阅"
  - "请关注"

但这里必须强调:

黑名单只能作为辅助规则,不能作为主要解决方案。

否则换一个业务场景,很容易误删真实内容。

二十四、如何验证优化到底有没有效果?

不能凭感觉。

建议建立一套专门的“静音测试集”。

例如:

然后比较优化前后:

指标

优化前

优化后

静音误识别率

较高

明显下降

正常语音召回率

基准

保持稳定

幻觉文本数量

较多

减少

平均推理量

较高

降低

无效 ASR 请求

较多

减少

真正需要关注的是:

不能为了降低幻觉,把正常语音一起过滤掉。

所以测试的时候至少要同时看:

误报率 + 漏报率。

二十五、最终落地的一套解决方案

结合熙瑾会悟会议场景,这个问题最后可以归纳成五层。

第一层:音频层

重采样 降噪 音量归一化 声道处理

第二层:VAD 层

VAD模型 + 动态能量阈值 + 最小语音时长 + 静音持续时间

第三层:ASR 层

Paraformer SenseVoice Whisper 根据场景选择。

第四层:模型结果层

no_speech probability 平均log probability 文本重复度 置信度 Segment长度 进行二次判断。

第五层:业务层

术语纠错 文本规范化 上下文判断 异常文本过滤 会议纪要校验 这样才能真正形成完整的防幻觉体系。

二十六、实际项目中我比较推荐的处理链路

如果让我重新设计这部分,我会采用:

这里有一个核心原则:

不要试图让 ASR 模型一个人解决所有问题。

让:

VAD 负责判断有没有声音,ASR 负责判断说了什么,声纹负责判断是谁说的,后处理负责把文字整理干净,大模型负责理解会议内容。

每一层负责自己的事情,整个系统反而更加稳定。

二十七、这次问题给 ASR 部署带来的一个经验

以前做 ASR,很容易把注意力放在:

模型准确率 但是实际进入生产以后,会发现:

异常输入处理能力,同样重要。

真实世界不是一个干净的数据集。

用户会:

  • 录到空白
  • 录到噪声
  • 录到远处说话
  • 录到设备碰撞
  • 录到会议暂停
  • 录到突然关麦
  • 录到很长的静音

这些都属于正常情况。

如果系统没有设计异常输入处理机制,那么再好的模型也可能出现奇怪结果。

所以一个真正稳定的企业级 ASR 系统,应该具备:

正常语音 → 正常识别

静音 → 不输出

噪声 → 尽量过滤

弱语音 → 谨慎判断

异常结果 → 二次校验

低置信度 → 重识别

长时间静音 → 自动结束Segment

这次熙瑾会悟 ASR 的“静音幻觉识别”问题,看起来只是一个小 Bug,但实际往下追,会发现它涉及整个语音识别链路。

真正解决它,并不是简单地换一个模型。

更有效的方式是把问题拆开:

前面负责减少无效输入,中间负责提高识别质量,后面负责拦截异常结果。

对于熙瑾会悟这种企业级会议系统来说,这套思路尤其重要。

因为会议录音不像实验室数据,环境永远是变化的。有人说话的时候要准确识别,没人说话的时候也要**“保持安静”**。

从这个角度看,ASR 的准确率不应该只理解成:

“说话的时候识别得有多准。”

还应该包括:

“没说话的时候,系统能不能忍住不乱说。”

这其实也是企业级语音识别系统和简单 Demo 之间非常明显的区别。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐