OpenAI Realtime API に映像を流せないので 1fps の静止画で代用した
OpenAI の Realtime API で、カメラの前で起きることを実況する音声 AI を作っています。音声の会話は速い。ところがカメラの前で何かが起きても反応できないか、反応しても古い絵に答えます。実測では、21 秒前の絵に対して、言い回しだけそれらしく反応していました。
Realtime API には映像ストリームの入力がありません。画像は「会話に写真を一枚入れる」扱いで、いつ・どの画像を見せるかはアプリが決めます。つまり「目」はアプリが作るしかありません。
最初の失敗: 画像を送ると返事を求めることになる
最初は、場面が変わったと思ったときに画像を送って応答を求めていました。これだと次の問題が起きます。
- 送った画像が「返事を求める入力」になるので、画像を送るたびに発話が発生する。黙って見ていてほしい場面でも喋る
- 「場面が変わった」の判定をアプリ側のラベル(動いた、止まった、明るさが変わった)で書くと、場面の種類が増えるたびに条件が増える。定義表のイタチごっこになる
- 判定と送信が遅れると、モデルが見ているのは何秒も前の絵になる
どう直したか: 見せると喋らせるを分ける
設計を 2 つに分けました。
見せる(文脈): カメラのフレームを 1fps で会話に積み続けます。返事を求めない文脈として送るので、画像が入っても発話は起きません。直近の N 枚だけを保持し、古いものは捨てます。モデルは常に「今の絵」を持っている状態になります。
喋らせる(トリガー): 「今、実況を切り替えるべき出来事が起きたか」だけを、軽量な視覚言語モデル(VLM)に一問で聞きます。出来事の種類を列挙した定義表は持ちません。問いは一つで、判断はモデルに委ね、アプリは配線だけを担当します。判定が「切るべき」なら、そこで初めて Realtime API に応答を求めます。
実測
- 判定の所要時間は中央値で 1.7〜1.9 秒
- 手の動きだけの場面は正しく「切るべきでない」と棄却された
- 手元に掲げた実物の名前を、判定モデルが言い当てた。ラベルの定義表なしで、モデル側が何を見ているかを理解している
限界: 人の手の速度と同じオーダー
反応までの時間を足し合わせると次のようになります。
- 検出 0.25 秒
- 判定 1.7 秒
- 発話開始まで 0.8〜1.9 秒
合計で 3〜4 秒。人が手元の対象を切り替える速度は 2〜4 秒に一つなので、反応は構造的に一つ遅れ気味です。これはモデルの賢さの問題ではなく、判定と発話の合計が人の動作と同じオーダーである、という物理的な限界です。
次に打つ手として考えているのは次の 2 つです。
- 判定を「MC が喋っている時だけ」に限定する。黙っている間は切り替えの必要がないので、判定そのものを省ける
- 発話側の推論量を最小(none)にして、発話開始までの時間を削る
どこで止まるか
- この構成は、Realtime API 側に映像入力が正式に来た時点で不要になります。鮮度は短い〜中です
- 1fps のフレームは会話の文脈として積まれるので、入力トークンを消費し続けます。直近 N 枚に絞っているのはそのためで、N を増やせば「過去」を見られますがコストが比例します
- 判定モデルへの一問は、問いの文面に体験の質が依存します。定義表を持たない代わりに、問いの書き方がそのまま仕様になります
この構成で気をつけること
- 状況をラベルで列挙して検出器を書くとイタチごっこになる。問いを一つに絞ってモデルに委ね、アプリは配線だけにする
- 「見せる(文脈)」と「喋らせる(トリガー)」を分ける。画像を送るたびに返事が来る設計にしない
- 反応時間は検出 + 判定 + 発話の合計で評価する。どれか一つが速くても、合計が人の動作より遅ければ一つ遅れる
映像ストリームのない API に目を付けるには、映像を「見せ続ける」経路と「今切るべきか」を問う経路を分ける必要がありました。目は作れましたが、人の手の速さには、まだ追いついていません。