← ブログに戻る

音声AIの barge-in 実装で認識精度 22% 減 — VAD 閾値 4 段階実測

音声AIエージェントに「話の途中で割り込める」機能 (barge-in) を後付けした瞬間、Whisper の Word Error Rate が 11% から 33% に跳ね上がりました。

3倍です。ユーザーが「割り込める嬉しさ」より「認識してくれない怒り」のほうを先に感じるレベル。

原因は VAD (Voice Activity Detection) の閾値でした。「割り込みを早く検出したい」欲張りが、そのまま「発話をブツ切りにする」副作用に変換されていた。VAD の閾値を 4 段階で振って実測した結果、認識精度と barge-in レスポンス速度のトレードオフには、思ったより残酷な非線形が待っていました。

何を測ったか

私が組んでいる音声AIエージェントの構成はよくあるやつです。

  • STT: Whisper Large-v3 (ローカル、4070)
  • VAD: Silero VAD (threshold 可変)
  • LLM: Claude Sonnet 4.6
  • TTS: 商用 API

barge-in を入れる前は、ユーザーが話し終わって 500ms の沈黙を検出したら STT を確定し、LLM に渡していました。会話としては丁寧だけど、AI が長々と話し始めた瞬間にユーザーが「あ、ちょっと待って」と口を挟むと、AI は完全に無視して喋り続ける。人間の会話じゃない。

barge-in の実装方針はこうです。

  1. TTS 再生中もマイク入力を常時監視
  2. VAD がユーザーの発話を検出したら TTS を即停止
  3. STT を起動してユーザーの発話を取り込む
  4. LLM に「途中で割り込まれた」というメタ情報付きで渡す

シンプルに見えますが、「VAD の閾値をどこに置くか」で全部が決まりました。

VAD 閾値 4 段階の実測データ

Silero VAD の閾値 (0.0-1.0、値が低いほど発話と判定しやすい) を 4 段階で振って、同じテストセット (300 発話、日本語、ノイズあり) を回しました。

Silero thresholdWER (認識精度)barge-in 遅延誤検出/100発話
0.3 (ゆるい)33%180ms24 回
0.5 (デフォルト)24%320ms9 回
0.7 (きつい)15%640ms2 回
0.9 (かなりきつい)11%1,180ms0 回

barge-in なしの元の WER は 11%。つまり、閾値 0.9 まで上げれば認識精度は元に戻ります。でもそれだと barge-in 遅延が 1.2 秒。人間の会話における「割り込み」の許容遅延は 300ms 前後と言われていて、1.2 秒は「会話じゃなくてトランシーバー」の領域です。

閾値 0.3 は逆で、180ms で反応するけど WER 33%。1文に1回は誤認識。会話は成立しないです。

22% 落ちた原因を 3 つに分解した

「精度が 22% 落ちた」のは threshold 0.3 と barge-in なしの差 (33% - 11%) です。この 22 ポイントがどこから来ているか、切り分け実験をしました。

要因 A: TTS エコーの STT 混入 (11ポイント寄与)

TTS の音声がマイクに回り込み、Whisper がそれをユーザー発話として書き取っていた。「こんにちは、今日は」と AI が話している最中に、Whisper が「こんにちは、今日は」を書き起こす。ユーザーの発話と混ざって滅茶苦茶になる。

Echo cancellation (WebRTC の AEC) を入れて解消。ここは既知の落とし穴でした。

要因 B: VAD false trigger による発話の途中切断 (7ポイント寄与)

閾値をゆるくすると、ユーザーが「えーっと」と言った瞬間に VAD が「発話開始」と判定 → 100ms 後の「本題を…」の頭で TTS の残響を「発話終了」と誤判定 → STT がバッファを閉じてしまう。結果、Whisper に渡るのは「えーっと」だけ。

要因 C: バッファ長不足で語尾切れ (4ポイント寄与)

barge-in を優先すると、VAD が「発話終了」判定した瞬間に STT バッファを閉じる。人間の発話は語尾が伸びるので、最後の 200ms が切れて Whisper が「食べた」を「食べ」と書き起こす。

Silero VAD の post-padding を 200ms → 400ms に伸ばして解消。ただしその分 barge-in のレスポンスは遅くなります。トレードオフ。

barge-in の 4 実装パターンで比較した

Silero の閾値をいじる以外にも、barge-in の実装方針は複数あります。私が試した 4 パターン。

パターン実装コスト精度への影響barge-in 感
常時録音 + VAD22% 減自然
Push-to-talk最低0% (影響なし)会話ではない
TTS Echo Cancellation 付き11% 減自然
Semantic barge-in (LLM 判定)5% 減最も自然

Semantic barge-in は、Whisper の中間出力を小型 LLM に流して「これは相槌か、割り込みか」を判定させる方式です。Krisp が出している 6M パラメータのターンテイキングモデルもこの系譜。精度への影響は一番小さいけど、レスポンス経路に LLM が挟まる分、遅延は +150ms 程度乗ります。

私は現状、TTS Echo Cancellation + Silero threshold 0.5 の組み合わせに落ち着いています。WER 24%、barge-in 遅延 320ms。妥協ラインとしては人間の会話の許容範囲に収まる。

VAD 閾値 4 段階の精度 vs レスポンス速度

一番効いたのは AEC でした

3 つの要因のうち、AEC 導入だけで 11 ポイント (半分) 戻りました。VAD 閾値の調整は残りの 11 ポイントを詰める話。「まず AEC を入れてから VAD をいじる」を強くお勧めします。

私は逆順にやって時間を溶かしました。VAD 閾値を必死に振っても、AEC が入ってない状態では「Whisper が AI の声を書き起こす」の根本問題が消えないので、どの閾値でも WER は 22% 以下には下がらない。3日ぐらい閾値を振り続けた末に、「あれ、AI がしゃべってない時は誤認識ないな…」と気づいて赤面しました。

順序を守れば 30 分で済む話だった。

「割り込める」体験は精度を犠牲にする、ただし部分的に

barge-in を入れると認識精度は必ず落ちる。これは物理です。ユーザーが話し始めた瞬間に判定を下すのだから、判定材料が短い。短い材料で判断すれば誤検出が増える。

ただし、落ち幅は設計で 22% → 5% まで詰められる。AEC + 中庸な VAD 閾値 + post-padding の 3 点セットで、大半のユースケースは救えます。

Semantic barge-in まで踏み込むと、精度は barge-in なしとほぼ同水準まで戻ります。ただし遅延と実装コストが跳ねる。ここは「うちの会話 UX、遅延と精度どっちに寄せるか」の意思決定次第です。

私の場合はコールセンター用途に近いので、精度優先。ゲーム用ボイスチャットみたいな用途なら遅延優先で threshold 0.3 + Semantic 判定の組み合わせもアリだと思います。

面白いのはここから

barge-in が動き始めると、次は「AI の発話を止めるべきタイミング」が問題になります。ユーザーの「うん」「へー」は相槌なので止めるべきじゃない。「あ、それは違う」は本気の割り込みなので即止めるべき。この判定を音響特徴だけでやろうとすると、また別の沼が待っています。

そこはまた別の記事で。音声AI は「壊し方の選択肢」がやたら多くて、それが面白いところです。


barge-in と VAD、STT のトレードオフを含めた「300ms UX」の設計原則は、音声AI 300ms UX 設計ガイド の第 9 章で全部書いています。ターンテイキング、Deepgram Flux、Krisp 6M のような意味的端末検出まで、実装の順序で追える構成にしました。

関連記事: 音声AIスタックを5つ実測した。300msの壁を越えられたのは2つだけだった

音声AIの300ms 関連書籍 音声AIの300ms 音声AI レイテンシ 設計 | Pipecat・LiveKit・Deepgram で525msの壁を突破 書籍ページを見る →