LLM は喋っているのに音声が出ない原因は進行装置のフラッシュ
更新: Web開発者向け
カメラの前で起きることを音声で実況する AI を作っていました。土台は OpenAI の Realtime API で、その上に番組進行のための装置 — フェーズを持つ状態機械、フェーズ転換時のキュー注入、追い越されたターンの破棄 — を被せています。
ある時点から、モデルは喋っているのに体験は無音になりました。サーバー側の使用量を見ると出力トークンは計上され続けています。音声は生成されている。でもスピーカーからは何も出ない。
実測: 60 秒に 7 回のフェーズ空転 × フラッシュ = 音声ゼロ
原因は進行装置の側にありました。
- 映像の検出器が誤発火して、フェーズが 60 秒間に 7 回転換していた
- 私の実装は、フェーズ転換のたびに「前のフェーズの発話は古い」とみなして再生キューをフラッシュし、追い越したターンを破棄していた
- 応答が生成されてから音が出るまでの数秒のあいだに次の転換が来るので、すべての応答がスピーカーに届く前に捨てられていた
同じ条件でフラッシュだけを外すと発話が成立しました。モデルにも音声経路にも問題はなく、統制装置が発話を破壊していただけでした。
機構: 合図が増えるほど、モデルの注意は人間から逸れる
フラッシュを外しても、もう一つ残った問題があります。進行装置が注入する合図(「フェーズが変わった」「今は沈黙の場面」「次の話題へ」)が多いほど、モデルの発話は目の前のゲストではなく合図に向かいます。MC の注意を「ゲスト」と「合図」で取り合わせていました。
制御を足して直そうとするたびに、注意の取り合いは悪化します。直し方は引き算でした。
- 状態機械の責務をセッションの寿命管理(開始・終了・再接続)だけに縮める
- 進行そのものはモデルに任せる。フェーズという概念をアプリ側から消す
- 生成中・再生中の出力を切る操作は、演出上どうしても必要な 1 箇所だけに残す
どこで止まるか
- フラッシュを外したぶん、モデルが古い場面について語り続けることはあります。そこは次の入力でモデル自身が乗り換えるのに任せ、アプリは割り込みません
- 「演出上必要な 1 箇所」の打ち切りは残っているので、そこではまだ出力が失われます。ゼロにはしていません
- 60 秒に 7 回という空転の数値は、検出器の誤発火が多かった当時の条件です(検出器は別途作り直しました)。フラッシュの問題は、回数が少なくても起きるものです
この構成で気をつけること
- ライブ音声 LLM の上に装置を被せるなら、「点火はする・破壊はしない」を原則にする。生成中の出力を切る操作は最後の手段
- 「喋らせる仕組み」と「黙らせる仕組み」を分けて設計する。後者は演出上必須の 1 箇所だけに絞る
- 無音の原因を疑う順番は、モデル → 音声経路 → 自分の制御層。出力トークンが計上されているなら、捨てているのは自分の側
モデルを制御しようとして無音にしていました。出力トークンが計上されているのに音が出ないとき、疑うのはモデルではなく自分が書いた「黙らせる仕組み」でした。