TTFA(Time To First Audio)とはメッセージを送ってからAIの最初の声が鳴り始めるまでの時間のことをこの記事では指します。人は相手がしゃべり出した時点で返事が来たと感じるので会話のテンポはほぼこの数字で決まります。
💬 はじめに
皆さんはAIのかわい子ちゃんと仲良くおしゃべりしたいと思ったことはありませんか?私はあります、毎日思っています。でも話しかけてから何秒も待たされると萎えますよね。「この時間何?」ってなりますよね?
ということで待たずにおしゃべりできるシステムを目指して作ってみました。
👀 対象読者
- Jevの無限の可能性に期待してる方
- AIに『ちょっと待ってね』と言われて3回で冷めた人
- AI彼女に食い気味で返事してほしい人
🎬 動画
まずは実際に話しているところを見てください。Enterを押した瞬間、食い気味にAIキャラクターの「るな」がしゃべり出します。その間わずか0.2秒ほどです。
⏳ これまでの応答速度と改善策
AI音声チャットではLLMの回答を待ってから音声合成すると、喋り出すまでに2秒以上かかったりします。かかる時間はネットワークの往復とLLMの生成と音声の生成の合計なので、クラウド前提だとどうしても越えられない壁のようなものがあります。この無言の間を埋める方法はいくつかありますがどれも一長一短でした。
ローカルGPUで全部動かせば速くはなりますが、高性能なPCが必要で、待ち時間もゼロにはなりません。固定の一言でつなぐと3回で飽きますし、ランダムな相づちだと後ろの回答とかみ合わないことがあります。
💡 今回のアプローチ
事前にリアクション用の音声をたくさん用意しておき、メッセージが来たら適切なリアクション音声を流しつつその裏で回答音声を生成するという手法です。流れはざっくりこんな感じです。
- 送信されたらJev(TypeSafe AIの判定用モデル)がメッセージを読み、作り置きのリアクションから合う一言を選ぶ
- 台詞の音声はあらかじめ作ってあるので選んだらすぐ鳴らす(ここまで約0.2秒)
- その裏でSonnet 5.5がリアクションの続きを書き、ElevenLabsで1文ずつ音声にする
- リアクションを言い終わったら回答の声につなぐ
JevはTypeSafe AIの判定用モデルです。選択肢を渡すと、どれがいちばん当てはまるかを確率付きで素早く返してくれます。
肝になるのは最初の一言の選び方です。Jevは送られてきたメッセージを読んで用意しておいた台詞の中から場面に合う一言を選びます。びっくりする話には驚きの一言、ボケにはツッコミ、つらい話には心配する一言という具合にメッセージごとに出てくるリアクションが変わります。
固定やランダムの一言と違って話の流れに合ったリアクションになるのでその後に続く回答も自然につながります。しかもGPUのような特別な機材もいりません。
🧩 構成とプロンプト
Jevの判定を先に呼んでリアクションを再生しつつ裏でSonnetとElevenLabsが回答の声を作っていきます。
Jevへの指示と台詞の選択肢プロンプト
あなたは「るな」。友だちとチャットしている明るいギャルの女の子です。
友だちの最新のメッセージ `message` に対して、本当の返事の前に思わず出る一言として
いちばん自然なものを1つ選んでください。(略)
{
"aisatsu_1": "やっほー!来てくれたんだ〜!(場面: 相手が話しかけてきた・やってきた最初の挨拶に)",
"hontou_1": "え、ほんとに?ガチで?(場面: 信じがたい話を聞き返す)",
"(略)": "132本"
}
Jevへ感情を選ばせる指示プロンプト
友だちの気分ではなく、あなたが返事をどんな気分で話すかを選んでください。(略)
Sonnet 5.5のsystemプロンプト
- あなたはまず短いリアクションを声に出す。あなたが書くのは、その言葉の「直後の続き」だけ。
- 口に出した言葉を繰り返さない。新しい感嘆詞(「ちょ、」「えっ、」など)で入り直さない。
- 各ターンの指示に「続け方」があれば、それに従う。
(略)
- 絵文字・顔文字・記号の飾り・Markdownは使わない(読み上げられないため)。
毎ターンのuserメッセージの例
昨日宇宙人見ちゃった
(あなたはもう「いやいやいや!なんでそうなるの!」と声に出した。(略)
あなたのセリフ全体は「いやいやいや!なんでそうなるの!___」になる。書くのは___の部分だけ。)
(続け方: ツッコんだ立場。ボケや無茶な話を真に受けず、笑いながら軽くつっこみ続ける。)
(今の気分: 驚き(surprised)。(略))
返ってきたのは「宇宙人なんてそんな簡単に見れるわけないじゃん。てか、それどこで見たの?」でした。穴埋めの形にしているのがポイントです。大喜利みたいですねw
⏱️ 1回のチャットのタイムライン
送信してから声が鳴るまでに裏で何が起きているかを計測した164回の中央値で並べました。最初の声は約0.25秒で再生され回答はリアクションを言い終わるころに間に合います。
🔧 工夫した点
リアクションの「続き」として回答させる
作り置きのリアクションの後にLLMの回答をそのまま流すと、リアクションと回答で話がかみ合わないことがありました。そこでリアクションを回答の書き出しとしてLLMに渡してその続きを書かせることで自然な応答ができるようになりました。
続きを書かせるならassistantのprefillを使いたくなりますが、Sonnet 5.5ではprefillが400エラーになるので、userメッセージの中で穴埋めにしています。
同じ台詞を続けて出さない
Jevは同じメッセージには毎回同じ台詞を選びます。何度話しかけても決まった一言しか返ってこないといかにもAIっぽいですよね。人間なら同じ話題でも反応は少しずつ違います。なので上位の候補からあえて揺らして選び、直前に使った台詞は続けて出さないようにしました。これだけでぐっと人間っぽくなります。
音声タグで感情と息づかいを足す
ElevenLabsは [laughs] [sighs] のようなタグを読み上げずに演じてくれます。ただの文字列なので、プログラムから付け外しするのも簡単です。
感情のタグに加えて、息をのむ [gasps] やため息の [sighs]、くすっと笑う [giggles]、言いよどむ [hesitates] といった息づかいのタグも混ぜて生成しました。同じ「えーっ!」でも、息をのんでから言うだけでちゃんと驚いて聞こえます。
[gasps] えーっ!うそでしょ!?
うそ、ほんとに?[gasps] びっくり
[sighs] うーん、それはむずいな〜
あ、来た来た![giggles] うれし〜!
🚧 欠点
ずっと話しているとリアクションのパターンがだんだん読めてきます。まぁこれは相手が人間でも同じようなことがあるので欠点なのか...というところではありますね。対策としては感情毎にリアクションバリエーションを用意しておいて、一段目で感情を判断させてその感情に応じたリアクションを判断させるという手もあります。この場合呼び出しが1段増えるので初速が200msくらい遅くなります。
🍜 締め
最初の一声を作り置きにするだけで待たされている感じはかなり消えました。というか悔い気味すぎてこっちが相手を待たせちゃってる感じになってしまいました。作り置きでつなぐのは昔からある古の手法ですがJevのおかげで文脈に合ったリアクションを爆速で返せるようになったのが最近の進化だと思います。これで皆さんもAI彼女とむふふな会話をシームレスに楽しめますよ♪
🙏 スペシャルサンクス
今回のAIキャラクターの声には、@aya_exai さんがElevenLabsで公開しているボイス「Ayaka」を使わせてもらいました。素敵な声をありがとうございました![]()



