話すAIアバターはひとつのモデルではない — STT・LLM・TTSの後ろに顔を付けたパイプラインで、敵は遅延の合計
顔の品質より先に見るもの — 4段階の遅延と、重ねて縮めるストリーミング
話すAIアバターを初めて見ると、巨大なモデルひとつが聞いて考えて顔まで動かしているように見える。分解すると違う。普通の音声エージェントの後ろに顔の生成器をひとつ付けたパイプラインだ。
だから体感品質を決めるのは、顔がどれだけリアルかより4段階の遅延の合計になる。この記事を読めば、アバターがなぜ遅いのか、どこから詰めればいいのかの順番がつかめる。
4つの段階
① STT(音声を文字に) ② LLM(返答を作る) ③ TTS(返答を音声に) ④ 顔(音声を口の形・表情のフレームに)。ユーザーが話し終えたかはVAD(音声区間検出)が判断し、映像はWebRTCで双方向にストリーミングする。
最初の3つは音声アシスタントと同じで、新しいのは④だけだ。音声エージェントを作ったことがあるなら、そこに④を載せるだけと考えればいい。テキストのチャットボットしか作ったことがないなら、遅延を気にする場所がLLMひとつから4つに増える。
順番に待つと遅い
4段階をひとつずつ終えてから次に渡すと、ユーザーは4段階の時間を全部足した分だけ待つ。だから実際のサービスは区間を重ねる。LLMが最初の一文を出したらすぐTTSを始め、音声が少しでも出たらすぐ顔の生成を始める。
下の段が重ねた形だ。人が感じるのは「最初の音が出るまで」で、そこがぐっと縮む。バーの長さは説明用で、測った値ではない。
割り込みもパイプラインの問題
会話の途中でユーザーが話をさえぎったら(barge-in)、②③④を全部止める必要がある。顔だけ止めてTTSが動き続けると、口は閉じているのに声が出る。
Anam SDKにはそのための TALK_STREAM_INTERRUPTED イベントと interruptPersona() が別に用意されている。Anam APIのドキュメントには、transcription→LLM→TTS→最初の音声までを段階ごとのp50 / p90 / p99で返すセッション分析エンドポイントもある。遅延は段階ごとに見ろ、とベンダー自身が言っているわけだ。このエンドポイントはまだ実際に呼んでいない。
自分で分解するために作ったもの
app10に、STT→LLM→TTS→顔を一段ずつ別々に動かして段階ごとのmsを出すページ(/avatar_pipeline)を作った。Anamは段階を切り離せるので、こういう実験ができる。llmId を CUSTOMER_CLIENT_V1 にすると②をこちらが持ち、enableAudioPassthrough を有効にすると②③までこちらが持つ。Anamは④だけを担当する。
実際のキーで回した数値はまだない。推測で埋めないよう、表は空けてある。測れば自前のパイプラインが不利に出るのも分かっている。段階ごとにサーバーを経由して往復し、ストリーミングで重ねていないからだ。その差がどれくらいかは、測ってから追記する。
どこから詰めるか
顔のモデルをいいものに替えるのは最後だ。まず段階ごとのmsを測る。重ねられる所をストリーミングで重ねる。割り込みを入れる。それでも遅ければ、そこで一番長い段階を替える。
アバターや音声エージェントをサービスに組み込んでいて遅延で詰まっているなら、negabaroに相談してほしい(お問い合わせ)。
キーコンセプト
① STT ② LLM ③ TTS ④ 顔 — 最初の3つは音声エージェント、新しいのは④だけ
まず段階ごとのmsを測る — 合計ではなく、どの段階が長いか
ストリーミングで重ねて「最初の音まで」を縮める
割り込みが来たら②③④をまとめて止める