音声で操作するAIエージェントの構築
音声エージェントの本質は、STT・LLM・TTSの単純な接続ではなく、ストリーミング処理・ターン検出・割り込み処理・ツール呼び出しのオーケストレーションにある。各コンポーネントの役割と落とし穴を、実行可能なコード例とともに解説する。
音声エージェントを構築する際、多くの人は「音声認識(STT)」「大規模言語モデル(LLM)」「音声合成(TTS)」の3つをつなげばよいと考える。その最も単純な形は逐次処理で、ユーザーが話し終えてからSTTが全文を書き起こし、LLMが回答全体を生成し、TTSが音声を再生する。しかしこれは2026年時点の本番標準ではない。各段階が前の段階の完了を待つため遅延が積み重なり、自然な会話にはほど遠い。
実際の難しさはプロンプトやモデルではなく、オーケストレーションにある。音声は「書き起こし」の問題というより「ターンテイキング(話者交替)」の問題だ。ストリーミング音声認識、意味的な発話終了検出、ストリーミング生成、割り込み処理、音声制約下でのツール呼び出し。これらの設計が、自然に感じられるエージェントと、チャットボットを載せた電話案内のようなシステムを分ける。
本番では、各段階が出力を次の段階へ段階的に渡すストリーミング方式が標準となる。STTは暫定の書き起こしをLLMへ送り、LLMはトークンをTTSへ流し、TTSはLLMが残りを生成している間に最初の文から音声を再生する。この方式は割り込みやバッファリング、部分状態の処理が複雑になるが、実用的な遅延予算を満たせるのはこの方式だけだ。人間同士の会話では、発話と発話の間隔は自然に200〜300ms程度。応答が500msを超えると遅く感じられ、3秒を超えると大半のユーザーは離脱したり故障を疑ったりする。現在の主要プロバイダーの音声対音声システムでは、初回トークンまでの時間は0.8秒から3秒の範囲に集中している。つまり、応答内容を1語も考える前に、アーキテクチャの選択だけで「自然」か「電話を切られる」かが決まる。
ストリーミングSTTの役割は「音声ファイルを書き起こす」ことではない。入力ストリームを継続的に処理し、ユーザーが話している最中に書き起こしを出力し、話し終えたと確信できたら確定イベントを送る。本番のSTTは通常、常時接続のWebSocketを使う。音声は約50ms単位の小さなチャンクで送られ、ストリーミングの転写イベントが返ってくる。途中のPARTIALイベントは新しい音声が来るたびに更新され、最後に確定したFINALイベントが1つ届く。下流の処理はFINALイベントだけを信頼し、PARTIALはリアルタイム表示専用にする。注文番号や電話番号、固有名詞などのエンティティ精度は特に重要で、1桁聞き間違えると後続の関数呼び出し全体が失敗する。人間のオペレーターなら「確認させてください」と聞き返せるが、システムではその余裕がない。
ターン検出は独立したコンポーネントだ。書き起こしテキストではなく、音声ストリームの無音パターンを消費して「話し終えたか」を判断する。判定が早すぎると、考え中の沈黙を遮ってしまう。遅すぎると、会話のたびに間延びした空白が生まれる。本番システムは通常、2つの数値で制御する。最小無音時間(標準は約600ms)は、書き起こし側も文が完成したと判断した場合にだけターンを終了する。最大無音時間(約1500ms)は、たとえ曖昧な間でも応答を強制する上限だ。高齢者向けや医療などゆっくり話す場面では上限を2500ms程度に引き上げ、テンポの速い会話では最小値を300ms程度まで下げる。これは用途に応じて調整するポリシーであり、アーキテクチャに固定された定数ではない。
さらに、ストリーミング生成ではLLMのトークンがTTSへ逐次渡される必要があり、バージイン(割り込み)処理ではユーザーが話し始めたら再生中の音声を速やかにキャンセルしてリスニングへ戻す。音声制約下のツール呼び出しは、関数呼び出しの判断を遅延予算の中に組み込み、不足パラメータを自然な対話で補完する設計が求められる。これらのオーケストレーションを一通り整えて初めて、音声エージェントは「会話できる」と呼べるものになる。