コンテンツへ移動

ボイスエージェントの遅延最適化:ステップバイステップガイド

公開日
最終更新日

聴くこの記事を聴く

音声エージェントの応答性は、ユーザーが話し終えてからエージェントが応答を開始するまでの合計遅延で決まります。この遅延が単一の遅いコンポーネントによって生じることはほとんどありません。複数の独立したステージで蓄積され、それぞれが数十〜数百ミリ秒を要します。削減するには、各ステージにどれだけ時間がかかっているかを把握する必要があります。

音声エージェントのレイテンシー最適化とは、時間がどこで費やされているかを特定し、ステージごとに取り戻す作業です。

この記事は、レイテンシーの概念的な概要を補完するものです。そちらではレイテンシーとは何かを説明し、こちらではアーキテクチャと測定を扱います。測定基準となるレイテンシーバジェットと、実行すべき具体的な対策を得られます。

概要

  • 初回オーディオ到達時間は、単一モデルの推論時間ではなく、パイプライン全体を表します。
  • LLMの初回トークン到達時間とエンドポインティングが、最も大きな2つの要素です。
  • ステージを直列で実行するのではなく重複させることで、バジェットの大部分を取り戻せます。
  • ストリーミング、コーデックの選択、プレーヤーバッファの調整により、それぞれ測定可能なミリ秒単位の短縮が可能です。
  • 自社のデプロイ環境でリージョンごとに測定し、P50とP95を報告してください。

音声エージェントのレイテンシーバジェットを定義する

レイテンシーバジェットとは、パイプラインの各ステージに割り当てた時間の合計が目標値以下となるように設定する、初回オーディオ到達時間の目標です。定義は最初のステップであり、エンジニアが似ていても意味の異なる2つの数値を混同しがちなため、レイテンシー対策で最も間違いやすい部分でもあります。

1つ目はモデル推論レイテンシー、つまりモデルが出力を生成するのにかかる時間です。Flashモデルでは、ネットワークとアプリケーションのオーバーヘッドを除き、一般的な短い入力で約75msです。これは内部的な指標で、モデル同士の比較には役立ちます。ただし、ユーザーが体験する数値ではありません。

ユーザー視点では、初回オーディオ到達時間(TTFA)に注目します。これは、ユーザーが話し終えてからエージェントの応答の最初のサンプルを聞くまでの経過時間です。TTFAはパイプライン全体を合計するため、常に単一モデルの推論レイテンシーより大きくなります。

カスケード型音声エージェントは、次の5つのステージで構成されます。

  • キャプチャ(マイク)-> STT -> LLM -> TTS -> 再生

マイクからオーディオを取得し、テキストに文字起こしして言語モデルへ送信します。モデルのテキストを再び音声に合成し、その音声をバッファリングして再生します。各ステージでレイテンシーが加わり、いくつかのステージでは最大のコストが予想とは異なります。

これは、ユーザーに比較的近い場所にサーバーがある英語エージェントの例です。数値は目安の範囲であり、保証値ではありません。

What it covers
Capture + endpointing
Mic capture, VAD/turn-detection delay before the turn is considered finished
STT finalization
Last partial to committed transcript after end-of-speech
Network (client to your server to our API)
Round-trips across the pipeline
LLM time-to-first-token
Prompt processing until the first usable token
TTS time-to-first-audio
First TTS request until first audio chunk leaves the model
Player buffering
Client-side buffer before playback begins
End-to-end TTFA
The total latency of the end-to-end pipeline
P50
Capture + endpointing
120 ms
STT finalization
60 ms
Network (client to your server to our API)
60 ms
LLM time-to-first-token
250 ms
TTS time-to-first-audio
110 ms
Player buffering
80 ms
End-to-end TTFA
~680 ms
P95
Capture + endpointing
280 ms
STT finalization
150 ms
Network (client to your server to our API)
160 ms
LLM time-to-first-token
600 ms
TTS time-to-first-audio
220 ms
Player buffering
150 ms
End-to-end TTFA
~1560 ms

一般に、レイテンシーの要素として最も大きいのは、LLMの初回トークン到達時間と、チェーンの先頭にあるエンドポインティング遅延です。 

この表はパイプラインを可視化するのに便利ですが、各ステージが厳密に直列で動くように見えます。実際はそうではありません。音声エージェントのレイテンシー最適化で特に重要な対策の多くはステージを重複させることであり、以下のバジェットの大部分もこの重複によって取り戻せます。

スピーチtoテキスト:文字起こしとエンドポインティングのレイテンシー最適化

文字起こしはパイプラインの2番目のステージですが、実際のコストは文字起こしそのものではなく、ユーザーが話し終えたタイミングを判断することにあります。このセクションでは、音声エージェントのレイテンシー最適化に役立つ両方の側面を説明します。

文字起こしはLLMに到達する前に行われます。Scribe v2 Realtime(scribe_v2_realtime)は、約150msで部分文字起こしを返し、オーディオチャンクをストリーミングします。そのため、ユーザーがまだ話している間に文字起こしが作成されます。8kHz〜48kHzのPCMとmu-lawエンコーディングをサポートしており、これは後述するコーデックのセクションで重要です。150msの部分結果は低コストです。

より大きなレイテンシーコストはエンドポインティング、つまりシステムがユーザーの発話ターンが実際に終了したと判断する瞬間です。

音声アクティビティ検出(VAD)は無音を基準に発話を区切りますが、ここで時間が蓄積します。たとえば、ターン終了を宣言するまでに700msの無音を待つと、文字起こし自体に加えて毎ターン700msが追加されます。この遅延は文字起こし精度ベンチマークには現れませんが、実際の会話では非常に明確です。パイプライン全体で制御できる最大のレイテンシーとなることが多く、制御可能であるため最初に取り組むのに適しています。

エンドポインティングは、応答性と中断のトレードオフです。無音しきい値を短くするとエージェントはすぐに応答しますが、自然な間でユーザーの発話を途中で切ってしまうおそれがあります。しきい値を長くすると安全ですが、反応が鈍くなります。実務では、スピーチtoテキストのレイテンシーを最適化するには、次の3つを変更します。

  1. 無音しきい値を微調整する:ユーザーの自然な間を切り詰めない最小値まで無音しきい値を下げ、推測ではなく本番環境で中断率を測定してください。
  2. 物理的な制御イベントを組み込む: VADタイマーを待つ代わりに、アプリケーションが別のシグナル(プッシュ・ツー・トークの解除、UIイベントなど)でターン終了を認識できる場合は、手動コミット制御を使用します。
  3. LLMの処理と重複させる:部分結果を早期に下流へ流します。安定した部分結果をLLMへ入力し、最終文字起こしが異なる場合は修正します。これは、エンドポインティング遅延をLLMのプロンプト処理の背後に隠す投機的実行の一種です。

詳細については、Scribe v2 Realtimeをスピーチtoテキストの機能ページとリアルタイムスピーチtoテキストのプロダクトページで詳しく説明しています。

LLMがレイテンシーに与える影響

言語モデルは通常TTFAへの最大の単一要因であり、音声エージェントのレイテンシー最適化において重複処理の効果が最も大きい箇所でもあります。重要なのは、エージェントは回答全体を用意してから話し始める必要はないという点です。

レイテンシーバジェットを最も多く取り戻せるパターンは、LLMからトークンをストリーミングし、到着次第、文または節の境界でチャンク化してTTSへ渡すことです。文の境界までトークンをバッファリングし、次の文がまだ生成されている間にその文を合成します。

const SENTENCE_END = /(?<=[.!?])\s+/;

async function* speakLlmStream(tokens: AsyncIterable<string>) {
  let buffer = "";
  for await (const token of tokens) {
    buffer += token;
    const parts = buffer.split(SENTENCE_END);
    buffer = parts.pop() ?? ""; // keep the incomplete fragment
    for (const sentence of parts) {
      if (sentence.trim()) yield* synthesize(sentence.trim());
    }
  }
  if (buffer.trim()) yield* synthesize(buffer.trim());
}

async function* synthesize(text: string) {
  const stream = await elevenlabs.textToSpeech.stream("JBFqnCBsd6RMkjVDRZzb", {
    text,
    modelId: "eleven_flash_v2_5",
    outputFormat: "mp3_44100_128",
  });
  yield* stream;
}

長時間の会話では、TTS WebSocketを推奨します。接続を開いたままにすることで、文ごとに接続を再確立することなく、テキストを段階的に受信できます。同時実行数の上限にカウントされるのは、モデルが実際にオーディオを生成している時間だけなので、アイドル状態で開いているWebSocketのコストはほぼゼロです。

テキスト読み上げ:ストリーミングと音声の選択

テキスト読み上げは、レイテンシーを最も正確に把握できるステージです。主なレバーは2つあります。オーディオのストリーミング方法と、選択する音声です。

Flash v2.5(eleven_flash_v2_5)は、エージェントで使用すべきモデルです。短い入力では約75msのモデル推論を実現し、32言語をサポートし、リクエストあたり最大40,000文字を受け付けます。

75msという数値は推論のみを指します。上記のバジェットにあるTTSのTTFAは、推論にネットワーク往復時間とサーバースケジューリングが加わるため、より大きくなります。

ここで最も大きなレバーとなるのはストリーミングです。オーディオ全体をリクエストして待機すると、ユーザーはクリップ全体の合成が完了するまで何も聞けません。ストリーミングでは、最初のチャンクが生成されるとすぐにユーザーに届き、残りはすでに聞いている間に到着します。ストリーミングによってモデル自体が速くなるわけではなく、モデルがまだ生成中の段階でユーザーへの出力を開始するだけです。

ストリーミングのハウツーガイドではHTTPストリーミングを扱い、リアルタイムWebSocketガイドでは、LLMからのトークンを入力する際に必要となるWebSocketの方法を説明しています。

クライアントは一度だけ初期化し、以下のすべての呼び出しで再利用します。

import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

const elevenlabs = new ElevenLabsClient({ apiKey: process.env.ELEVENLABS_API_KEY });

次にストリームを設定し、到着した順に転送します。

const stream = await elevenlabs.textToSpeech.stream("JBFqnCBsd6RMkjVDRZzb", {
  text: "Your call is connected. How can I help today?",
  modelId: "eleven_flash_v2_5",
  outputFormat: "mp3_44100_128",
});

for await (const chunk of stream) {
  // forward each chunk to your audio sink as it arrives
}

もう1つのレバーは音声の選択で、これにもレイテンシーコストがあります。デフォルト音声、合成音声、Instant Voice Clone(IVC)は、Professional Voice Clone(PVC)より高速に合成されます。PVCには生成ごとのオーバーヘッドを増やす追加のモデル複雑性があるためです。レイテンシー要件が厳しいエージェントでは、FlashとIVCまたはデフォルト音声の組み合わせが最も低レイテンシーな選択肢です。

ストリーミングチャンクサイズの選択

TTSへトークンが流れ、オーディオが戻ってくる環境では、次にチャンクのサイズと、再生開始前にプレーヤーがどれだけバッファリングするかを決めます。

小さいチャンクはより早くプレーヤーに到達し、初回バイトのレイテンシーを下げますが、メッセージ数とチャンクごとのオーバーヘッドがわずかに増えます。大きいチャンクは転送効率が高い一方、最初のチャンクを待つ時間が長くなります。対話型エージェントでは、発話の序盤は小さいチャンクを優先してください。ユーザーが待っているのは最初のチャンクであり、後続のチャンクはオーディオがすでに再生されている間に到着するため、サイズの影響は小さくなります。

プレーヤーは残りのレイテンシーのかなりの部分を占めます。多くのオーディオプレーヤーは、最初のバイトで再生を開始しません。ストリームが一時的に遅くなっても音切れしないよう、少量をバッファリングします。デフォルトで500msのバッファは一般的で、知覚されるレイテンシーに直接追加されます。これを減らすと、音切れリスクがわずかに高まる代わりにTTFAが低下します。適切な値は、サーバーとクライアント間のネットワークジッターによって決まります。

  • 安定した接続(サーバー側再生、同一拠点にあるクライアント)では、50〜150msのバッファで通常は安全であり、TTFAを目に見えて短縮できます。
  • ジッターの大きいモバイル接続やリージョン間接続では、より大きいバッファにより、レイテンシー以上に悪影響を及ぼす音声の途切れを防止できます。

ここで選ぶ正確な設定は、現在のユースケースと優先事項によって決まります。

コーデックの選択

オーディオの送信先に応じて、リクエストするコーデックを決めるべきです。mp3_44100_128、mp3_22050_32、pcm_16000、pcm_24000、ulaw_8000などの形式を返します。転送経路のネイティブ形式に合わせることでトランスコードのステップが不要となり、音声エージェントのレイテンシー最適化に役立ちます。

Twilioなどの電話サービスでは、ulaw_8000を使用してください。電話ネットワークはエンドツーエンドで8kHzのmu-lawを使用するため、直接リクエストすればパイプライン内のトランスコードを回避でき、通信事業者の期待する形式にも一致します。電話ネットワークがすぐにダウンサンプリングする高音質オーディオを合成しても利点はありません。レイテンシーが増えるだけで、聞こえる品質は何も向上しません。

WebRTCとブラウザ再生には、PCM(pcm_24000またはpcm_16000)またはMP3形式を使用します。PCMは非圧縮のため、クライアント側のデコード工程が不要になり、チャンクごとのレイテンシーをわずかに削減できます。また、Web Audioパイプラインに直接入力する場合にも便利です。MP3はネットワーク上でよりコンパクトなので、軽量なクライアント側デコードを必要とする代わりに、帯域が限られた接続で役立ちます。

地理的位置とネットワーク距離

上記の最適化はいずれも、バイトの移動距離が短いことを前提としています。地理的位置はレイテンシーバジェットの下限を決めるため、ほかを調整する前に確認する価値があります。

北米、欧州、東南アジアのクラスターからリクエストを処理し、各リクエストを最寄りのクラスターへ自動的にルーティングします。パブリックインターネット上のネットワーク往復時間は地理的な近さに応じて通常20〜200msであり、インフラの配置を変えない限り削減できません。

北米クラスターからすぐ近くのサンフランシスコでは瞬時に感じられるエージェントも、トラフィックがターンごとに海を2回横断する南アジアのユーザーには遅く感じられることがあります。

解決策は、アプリケーションサーバーをElevenLabsだけでなくユーザーの近くにも配置することです。ユーザーが欧州にいる場合は、ユーザーからサーバーまでの経路を短くするため、エージェントバックエンドを欧州で実行してください。その後、近隣クラスターからサーバーからモデルまでの経路はルーティングで処理されます。

音声エージェントのレイテンシーを自分で測定する

上記のレイテンシーバジェット表の数値は、計画のための例示的な範囲です。実際のリリース判断に使う数値は、自社のデプロイ環境に対してこのようなスクリプトを実行して得るべきです。

以下の計測コードでは、多数回の試行を通じて、TTSステージ単体のTTFA、すなわちリクエストから最初のオーディオチャンクまでの時間を測定し、パーセンタイルを報告します。開発マシンではなく、サーバーが稼働するのと同じリージョンから実行してください。先ほどのelevenlabsクライアントを使用する前提です。

const VOICE_ID = "JBFqnCBsd6RMkjVDRZzb";
const TEXT = "Thanks for waiting. I have pulled up your account and I can help with that now.";
const TRIALS = 50;

async function measureTtfa(): Promise<number | null> {
  const start = performance.now();
  const stream = await elevenlabs.textToSpeech.stream(VOICE_ID, {
    text: TEXT,
    modelId: "eleven_flash_v2_5",
    outputFormat: "mp3_44100_128",
  });
  for await (const _chunk of stream) {
    return performance.now() - start; // first chunk -> stop the clock
  }
  return null;
}

function percentile(values: number[], p: number): number {
  const v = [...values].sort((a, b) => a - b);
  const k = (v.length - 1) * (p / 100);
  const lo = Math.floor(k);
  const hi = Math.min(lo + 1, v.length - 1);
  return v[lo] + (v[hi] - v[lo]) * (k - lo);
}

const samples: number[] = [];
for (let i = 0; i < TRIALS; i++) {
  const ttfa = await measureTtfa();
  if (ttfa !== null) samples.push(ttfa);
  await new Promise((r) => setTimeout(r, 300)); // space requests, don't measure your own queueing
}

console.log(`trials: ${samples.length}`);
console.log(`P50:    ${percentile(samples, 50).toFixed(0)} ms`);
console.log(`P95:    ${percentile(samples, 95).toFixed(0)} ms`);

覚えておくべきポイント:

  • P50とP95を報告する:平均値ではなく、これらに注目してください。平均値はテールを隠しますが、エージェントを信頼できないと感じさせるのはテールです。P95は20ターンに1回の体験を表します。 
  • 地域別の検証: 提供先の各リージョンから同じスクリプトを実行し、結果を分けて保持してください。
  • 精度のために間隔を空ける: リクエストの間隔を空けてください(上記のsetTimeout)。一度にすべて送信すると、サービスではなく自分のキューイングを測定することになります。同時実行数の上限を超えると、リクエストは優先度に応じてキューに入り、通常は約50ms追加されます。容量を超えるとHTTP 429が返されます。
  • レイテンシーチェーン全体を測定する: 同じ計測パターンをほかのステージにも拡張します。STTの完了、LLMの初回トークン、プレーヤーの起動を同じperformance.now()の計測範囲で囲めば、自身の数値で完全なバジェット表を埋め、最初に対策すべきステージを確認できます。

これらのヒントに従えば、音声エージェントのレイテンシーを自分で測定できます。そこから、最初に取り組むべき優先事項が明確になります。

音声エージェントのレイテンシーを最も削減する方法は?

すぐに取り組める項目に絞るなら、次の変更が最も効果的です。

おおよその影響度順に、次の方法でエージェントのレイテンシーを削減できます。

  • 安定したSTTの部分結果でLLMの処理を開始し、エンドポインティング遅延を隠します。
  • 文の境界でLLMトークンをTTSへストリーミングし、1文目の合成と2文目の生成を重複させます。
  • TTSオーディオをプレーヤーへストリーミングし、ネットワークジッターが許容する最小値までプレーヤーバッファを削減します。
  • 最も低レイテンシーなTTSにはFlashとデフォルト音声またはIVCを使用し、コーデックを転送先に合わせます(電話はulaw_8000、ブラウザ/WebRTCはPCMまたはMP3)。
  • ネットワーク経路は現実に存在し均一ではないため、サーバーをユーザーの近くに配置し、リージョンごとに測定します。

より具体的で高度な手法については、レイテンシー最適化のデベロッパー向けハウツーガイドをご覧ください。すぐに実行できる完全な出発点としては、APIクイックスタートとストリーミングのハウツーに完全な例があります。 

微調整済みのエージェントカスケードをよりすばやく利用したいですか? ElevenAgentsには、重複処理の最適化を実装したこのパイプラインが用意されています。

ElevenAgentsで低レイテンシーの音声エージェントを構築

音声エージェントのレイテンシー最適化では、各ステージを測定したうえで、最も遅いステージがすでに進行中の処理の裏で動くように重複させる必要があります。上記のパターンを使って数回の反復でカスケードを手作業で構築・調整することも、すでにレイテンシー最適化が組み込まれたパイプラインから始めることもできます。

ElevenAgentsは、ストリーミングSTTからトークン単位のLLM引き渡し、Flash TTSまで、この完全なカスケードを実装しています。重複処理の手法もすでに組み込まれています。ゼロから始める代わりに、最も重要なパフォーマンスに合わせてしきい値を調整できます。

ElevenAgentsを使用して今すぐエージェントを作成するか、詳細については営業にお問い合わせください。

音声エージェントのレイテンシー最適化に関するよくある質問 

関連記事

最高品質のAIオーディオで創造する