ブログ · · 約 6 分で読めます

音声 AI の応答の遅れ:どこで時間がかかり、どう縮めるか

音声 AI の返事が遅いと感じる原因は、話し終わりの判定・音声認識・生成 AI・音声合成・回線のどこかにあります。遅れが出る区間ごとの理由と測り方、流しながらつなぐ・最初の一文を短くする・道具の待ちをことばで埋めるなどの縮め方を説明します。

要点

  • 音声 AI の遅れは「相手が話し終えてから、AI の声の最初の音が相手に届くまで」の時間で考え、話し終わりの判定・音声認識・生成 AI・音声合成・回線の区間に分けて測ります。
  • 縮める基本は、各段を待たずに流しながらつなぐことです。生成 AI の返事を文ごとに音声合成へ渡し、最初の一文を短くすると、最初の音が早く出ます。
  • 外部の API を呼ぶ待ち時間は消せないので、「お調べします」のようなつなぎのことばで無言を作らないようにします。

音声 AI の返事が遅く感じるのは、相手が話し終えてから AI の声が届くまでに、話し終わりの判定・音声認識・生成 AI・音声合成・回線の 5 つの区間が順につながっているからです。縮めるには、まず区間ごとに時間を測り、いちばん長い区間から手を付けます。多くの場合、効くのは「各段を待たずに流しながらつなぐ」ことと「最初の一文を短くする」ことです。

人の会話の「間」

人どうしの会話では、返事はとても早く返ってきます。10 の言語の会話を調べた研究では、質問への返事が始まるまでの時間の平均は全体で約 208 ミリ秒、日本語では平均 7 ミリ秒でした(Stivers ほか, PNAS, 2009)。人は相手が話し終わる前から返事を準備しているためです。

音声 AI は、相手が話し終えたことを確かめてから処理を始めるので、人と同じ速さにはなりません。目標は「人と同じ」ではなく、相手が「聞こえていないのかな」と不安になる前に、何かしらの声を返すことです。

遅れが出る 5 つの区間

遅れは次の区間の合計です。電話でも Web でも同じ形です。

区間 何をしているか 長くなる主な理由
1. 話し終わりの判定 無音が続いたら「話し終えた」と決める 無音を長く待つ設定。言いよどみで切らないための余裕
2. 音声認識の確定 最後の音まで文字にして確定する 発話の最後を待ってから認識を始める作り
3. 生成 AI の最初の文字 指示文と会話の履歴を読んで返事を書き始める 長い指示文・長い履歴・大きなモデル・道具の呼び出し
4. 音声合成の最初の音 返事を声にする 返事の全文を待ってから合成する作り
5. 回線・ネットワーク 音声を相手の端末まで運ぶ 処理の場所と相手の距離、電話の網、音のバッファ

このうち 1 は、短くしすぎると相手が言いよどんだだけで AI が話し始めてしまいます。速さと割り込まない丁寧さの釣り合いの話なので、割り込みと話す順番で別に扱います。

区間ごとの測り方

「遅い」と感じたら、まず区間に分けて測ります。1 本の通話の中で、次の時刻を記録します。

  1. 相手の声が止まった時刻(VAD が無音を検出した時刻)
  2. 話し終わりと判定した時刻
  3. 音声認識の結果が確定した時刻
  4. 生成 AI の最初の文字(トークン)が届いた時刻
  5. 音声合成の最初の音のデータが届いた時刻
  6. その音を回線に送り出した時刻

この差を区間の長さとして並べると、どこが長いかが分かります。平均だけでなく、遅い方の値(上から 1 割の通話など)も見ます。会話の印象を悪くするのは、たまに来る長い待ちだからです。

python
# 1 回の受け答えの時刻(秒)から区間の長さを出す
STAGES = [
    ("turn_end", "speech_stopped", "turn_detected"),
    ("stt", "turn_detected", "transcript_final"),
    ("llm_first_token", "transcript_final", "llm_first_token"),
    ("tts_first_audio", "llm_first_token", "tts_first_audio"),
    ("send", "tts_first_audio", "audio_sent"),
]

def breakdown(ts: dict[str, float]) -> dict[str, int]:
    out = {name: round((ts[end] - ts[start]) * 1000) for name, start, end in STAGES}
    out["total"] = round((ts["audio_sent"] - ts["speech_stopped"]) * 1000)
    return out  # ミリ秒

縮め方

効きやすい順に並べます。

流しながらつなぐ

いちばん効くのは、前の段が終わるのを待たないことです。

  • 音声認識は、話している間から少しずつ認識する(ストリーミング)方式にする
  • 生成 AI の返事は、全文を待たずに文字が出てくるそばから受け取る
  • 句点(。)や疑問符で文を区切り、1 文ずつ音声合成に渡す

全文を待ってから合成する作りでは、返事が長いほど最初の音が遅れます。文ごとに渡せば、最初の音までの時間は返事の長さにほとんど左右されません。

最初の一文を短くする

文ごとに合成するなら、最初の文が短いほど最初の音が早く出ます。指示文で「最初に短い相づちや確認を言ってから本題に入る」ように書くと、自然さも上がります。

  • 悪い例: 「ご予約の変更でございますね。それでは、現在のご予約のお日にちと、ご希望の新しいお日にちを順番にお伺いしてもよろしいでしょうか。」
  • 良い例: 「承知しました。」「いまのご予約は、何日でしょうか。」

生成 AI に読ませる量を減らす

生成 AI の最初の文字までの時間は、読ませる文の量に左右されます。

  • 指示文から、その用途で使わない説明を消す
  • よくある質問の答えは、短く言い切る形で書く
  • 長い通話では、古いやりとりを要約して履歴を短く保つ

道具の待ちは、ことばで埋める

予約の空きの照会のように外部の API を呼ぶと、その応答を待つ時間は消せません。黙ったまま待つと、相手は電話が切れたと思います。呼ぶ前に「お調べしますので、少々お待ちください」と言い、待つ時間の上限を決めて、超えたらおわびして折り返しにします。道具の設計は 通話中に AI が API を呼ぶ で扱います。

割り込まれたら、すぐ止める

遅れとは逆向きの問題ですが、相手が話し始めたのに AI が話し続けると、待たされる感じが強くなります。電話の場合、送った音声は回線の手前でためられています。Twilio の Media Streams では、clear のメッセージでためた音声を捨てられます(WebSocket messages)。

処理の場所を相手に近づける

音声認識・生成 AI・音声合成の API と、音声を中継するサーバーの場所が離れていると、往復のたびに時間がかかります。音声を扱うサーバーは、使う API と電話の網のどちらにも近い地域に置きます。

voicast での応答の速さ

voicast では、話し終わりの判定・音声認識・生成 AI・音声合成をつなぐ部分を基盤が受け持ちます。相手が話し始めると話すのをやめて聞き(バージイン)、通話中の道具を呼ぶときは「お調べしますので、少々お待ちください」と言ってから、応答を 8 秒まで待ちます。時間切れや失敗のときは、AI がおわびして担当者からの折り返しにします。開発する側で気をつけるのは、会話の設定の指示文やよくある質問の答えを短く保つことと、道具の API を速く返すことです。

よくある質問

音声 AI の遅れは、どこから測ればよいですか。

相手の声が止まった時刻から、AI の声の最初の音を相手に送り出した時刻までを測ります。そのうえで、話し終わりの判定・音声認識・生成 AI・音声合成・送り出しの区間に分け、長い区間から直します。

話し終わりの判定を短くすれば速くなりますか。

速くはなりますが、相手が言いよどんだり、電話番号を区切って言ったりする途中で AI が話し始めやすくなります。用途に合わせて調整し、割り込まれたらすぐ止まる作りと組み合わせます。

速いモデルに替えるのがいちばん効きますか。

区間を測ってから決めます。生成 AI の区間が長いなら効きますが、全文を待ってから音声合成する作りのままだと、返事が長いときの遅れは残ります。まず流しながらつなぐ作りにするのが先です。

関連記事