powered by TechFeed
表示モード
Deep Dive

音声エージェントの応答を3秒→1秒に改善した方法 — LLMは一切変えず、CPUとターンテイキングの設計を直した

11月5日、Seemanth Rajuが「Your Voice Agent Isn't Slow Because of the LLM」と題した記事を公開した。本番の架電エージェントが抱えていた約3秒の応答遅延を、LLM・STT・TTSのプロバイダーを一切変えずに約1秒へ短縮したという実装知見だ。犯人はモデルではなく、CPU飽和とターンテイキング設計の2点だったという。

11月5日、Seemanth Rajuが「Your Voice Agent Isn't Slow Because of the LLM」と題した記事を公開した。本番の架電エージェントが抱えていた約3秒の応答遅延を、LLM・STT・TTSのプロバイダーを一切変えずに約1秒へ短縮したという実装知見だ。犯人はモデルではなく、CPU飽和とターンテイキング設計の2点だったという。


3秒→1秒の改善、モデルは一切変えていない

本番の架電エージェントが応答に約3秒かかっていた。最終的に約1秒まで短縮できた。LLM、STTプロバイダー、TTSの音声はいずれも変更していない。

遅さの原因として最初に疑うのはモデルだ。より速いLLM、ストリーミング対応TTS(テキスト音声変換)、低レイテンシのASR(自動音声認識)——そういった選択肢を検討してプロバイダーを比較し始める。だが、それで改善するのはごく一部に過ぎなかったという。2秒分の遅延は「誰もリストに載せない場所」に隠れていた。

音声エージェント領域ではレイテンシへの注目が急速に高まっており、LiveKit・Vocode・Daily.coといったリアルタイム音声インフラを提供するプロジェクトが相次いでエンドツーエンドの遅延削減を主要課題として挙げている。その文脈でも、本記事が「モデル以外のボトルネック」を実測値で示している点は実践的な価値が高い。


原因はCPU飽和だった

各ステージのタイムスタンプを取得してみると、特定のボトルネックが見つかると思いきや、全ステージが均等に少しずつ遅いという異常なパターンが現れた。

これが「告白」だと記事は述べる。互いに無関係なステージが一斉に劣化する場合、問題はそれらの下層にある。

調べると、ホストマシンのCPU使用率が**通常運用中に96%**に達していた。高負荷テスト時ではない。日常的なコール量をさばいている最中に、だ。

インスタンスは「早期に、安価に選んで、以降見直していなかった」共有コアのバーストインスタンス(GCP上のburstableタイプ。平常時は低コストだが、CPUクレジットが枯渇すると性能が大きく落ち込む)だった。これをn2-standard-8(専有コアVM)に移行したところ、CPU使用率は約23%に落ち着き、エンドツーエンドのターンレイテンシは3秒から1秒になった。

なぜ音声はCPU飽和に特に弱いのか

記事では3つの理由が挙げられている。

  • 音声は連続したデッドラインである。フレームは10〜20msごとに届き、次のフレームが来る前に処理しなければならない。処理が遅れればジッター(音のぶれ)となり、耳に聞こえる。
  • 全ステージが同じ枯渇したコアを奪い合う。VAD(Voice Activity Detection:音声区間検出)、リサンプリング、コーデック処理、WebSocket読み取り、TTS再生ループ——これらが同時にCPUを要求するため、遅延が特定ステージではなく全体に分散して現れる。
  • バーストインスタンスはクレジットが切れると静かにスロットリングされる。エラーログには何も出ない。ダッシュボードも赤くならない。パイプライン全体がじわじわ遅くなるだけで、その形状がまさに「モデルが遅い」と誤認させる。

1秒にしても、まだ電話が切られていた

レイテンシとターンテイキングの感覚は別問題だ。レイテンシは沈黙の長さ、ターンテイキング(会話の発話権の受け渡し制御)はその沈黙が何を意味するかの問題だ。

記事が特に重点を置く3つの失敗がある。

1. 発話の途中で切ってしまう
VADの終話判定が早すぎて、息継ぎ中に割り込んでしまう。記事では0.3秒の無音閾値を採用したと書かれているが、「これはベストプラクティスではなくトレードオフだ」と明記している。自分の通話録音を聴いて調整すべきで、このブログの値をそのままコピーするなと言っている。

2. 無音になったときのリカバリーがない
部分的な転写の欠落、プロバイダーの一時的な不具合、ステートマシンの袋小路——いずれもエージェントが黙り込んだまま復帰しない。電話の相手は「回線が切れた」と判断して切ってしまう。8秒間エージェントが発話しなかった場合に何かを話すリカバリープロンプトを追加したところ、数百ミリ秒のレイテンシ改善より効果があったという。

3. 割り込み後にシステムプロンプトが消える
ユーザーが応答途中に割り込んだとき(バージイン:エージェントの発話中に人間が話し始める操作)、コンテキストの再構築でコアのシステムプロンプトが脱落していた。エージェントは流暢に話し続けるが、自分のルールに従わなくなる。メトリクスには現れず、顧客には明白というワーストケースだ。バージインをサポートするなら、割り込み後にシステムプロンプトが残っているかをアサートするテストを書くべきだと記事は述べる。

これらの改善を合わせた結果、エージェントとの会話に実際に参加した発信者の割合が、応答した通話の約40%から約60%に上昇した。


プロバイダーを変える前に確認すべきチェックリスト

記事がまとめる確認順序は以下の通りだ。安価に切り捨てられるものから順番に当たれというアドバイスだ。

  1. 実トラフィック時のホストCPU(アイドル時や負荷テスト時ではなく、最繁忙時間中の実通話時)。70%超ならまずそこを直す。
  2. インスタンスタイプ。バーストインスタンスならリアルタイム音声には向かない。
  3. ストリーミングができているか。LLMの全レスポンスを待ってからTTSを開始していないか。最初のトークン・最初のバイトが重要な数字だ。
  4. VAD閾値を自分の録音で確認する。
  5. 無音時のリカバリーパスがあるか。
  6. バージイン後のシステムプロンプト保全をテストしているか。
  7. その後にはじめてモデルの乗り換えを検討する。

記事の末尾では「この結果はPython + GCP + 電話網のパイプラインに基づくもので、WebRTCブラウザ製品とは異なる」と正直に限界を示している。また、コールの一部は最後まで遅いままで原因を完全には特定できなかったとも書かれており、キャリア側の変動やプロバイダーのコールドスタートが原因ではないかと推測されている。

詳細はYour Voice Agent Isn't Slow Because of the LLMを参照していただきたい。