場面別の生成予算と観客反応の引継ぎ(2026-09-22)

初期実装に続き、§5.9の時間予算と観客反応の参照を実装した。会話品質v2とSituation有効時に適用する。本番設定の変更やデプロイ、実配信での品質比較は行っていない。

続く9章で、複数往復の参照・反復抑制・比較と実音声検証の画面・限定導入の証拠照合を追加した。実環境での評価/適用の状態は9章を参照。

場面に応じた生成予算

ConversationGenerationPlan が生成開始時に、生コメントと不変Snapshotから計画を固定する。追加の分類用LLM要求は発生しない。

場面 生成上限 判断
短い挨拶・相槌・礼 5秒 限定した定型句の全文一致のみ。例: こんにちは!, ありがとう, Thanks!。推論量はnone
訂正の候補 20秒 それじゃない, じゃなく, 訂正, I meant等を含む入力。時間配分のための候補判定であり、意味や真偽を確定しない
その他の通常応答 15秒 質問を含む挨拶や未知の表現はここへ戻す
自発発話 8秒 指定mediumlowを上限にする
台本生成 25秒 残尺と音声準備時間でも制限する

推論量はユーザーの指定値を上限にする。生成開始からの経過時間をStopwatchで測り、retry/failoverの要求時にもその時点の残り時間を見る。残り10秒未満はmediumからlowへ、4秒未満はnoneへ下げる。noneを自動で引き上げない。取消の期限はretryで延長しない。

通常コメントは投稿TTLから音声準備時間を引いた絶対期限を呼出側で作る。生成側で同じ留保を二重に引かない。課金・System入力には通常コメントの投稿TTLを適用しない。

台本・自発発話は、Snapshotに有効な通常ノードの残尺があれば、観測からの経過時間と音声準備時間を引く。残尺が正で、停止中・巻き進行・scriptOnlyではないノードに限って残尺Factを公開する。通常コメントへの回答は、この台本生成用の枠では短縮しない。残尺が未定義または既に過ぎている場合はroute上限と既存の進行ゲートへ戻す。ノードを強制終了したり固定の台詞を省略したりする処理は追加しない。

時間切れ・割込みは、台本のLLM障害カウンターを増やさずに生成予約を解放する。生成内容の失敗や通信障害による既存の失敗処理は継続する。

音声準備時間の実測

SpeechPreparationLatencyTTScontroller.ConversationTiming が、tracked TTSの依頼開始から最初の音声開始までを測る。semaphore等の待ちも含み、発話全体の再生時間は含めない。

実測値はSnapshot内の runtime.speech_preparation_reserve_seconds、ノード残尺は script.generation_remaining_seconds。どちらも内部制御用で、LLMの発話文脈には表示しない。外部由来・期限切れ・未来時刻・不正数値のFactは予算計算に使わない。

発話の後に届いた反応を次の生成へ渡す

安全フィルターを通過したコメントを、SituationContextService.RecordAudienceFeedback に渡す。応答対象に選ばれたかどうかとは独立に、通常受付と台本ゲートでの温存経路から観測する。

短いや相槌も、会話品質v2では視聴者用の安全フィルターを通して観測できる。これだけで応答キューへ投入したり、台本のCommentCountや質問への回答数を増やしたりしない。空入力・リスナー同士の@会話・期限切れ・System・練習用入力は観測対象にしない。

対応付けは次の条件に限定する。

  1. 生成候補ではなく、Situationの実可聴履歴を参照する。
  2. 受信時点ではなく投稿時点より前の、最後のホスト発話を候補にする。遅着したコメントを、新しい発話へ付け替えない。
  3. 発話確定から投稿まで2秒以上、受信まで45秒未満。未来の投稿時刻、窓外、古い実行scopeを拒否する。
  4. 間にカンペやゲストの発話がある場合、以前のホスト発話への反応としない。同一時刻なら配送sequenceで順序を判定する。
  5. メッセージIDで二重受信を排除。重複判定は最大128件、観測Factは最大12件、期限は対象発話の確定から45秒。

保存は audience.observed_feedback.<sequence> のFact。本文はフィルター後のコメント最大320字、SourceIdは対応する実発話Factのキー、ObservedAtは投稿時刻。viewer名・viewer ID・元message IDはプロンプトへ付与しない。元IDはハッシュ化して重複判定に使う。

LLMへは「発話『…』の後のコメント『…』(関連未確認)」の組で渡す。時間上の対応は因果関係や意味上の対象を保証しないので、内容の関連を確認して続きを選ぶよう指示する。笑い・困惑・訂正・詳しい説明の希望をモデルが参照できるが、システム側で賛否、人気、質問への回答を自動確定しない。未取得や無言を不評として保存しない。

公開と寿命の境界

反応は既存の「ほかの視聴者の履歴をプロンプトに含める」許可と、件数・項目文字数・総PII予算を適用する。元発話とコメントを組で収められない場合は両方を省略する。省略記号も予算に含める。元発話Factが失効・消去された場合は、その反応もプロンプトに出さない。

カンペ、認証済みGameEvent、コラボゲスト、v1には反応Factを注入しない。配信・人格・場面の切替、短期会話消去、視聴者消去では共有履歴と一緒に破棄する。生成開始後のSnapshotは、後から届いた反応で書き換えない。

検証と残る範囲

Unity 2022.3.15f1のEditModeで309件成功、失敗0件、スキップ0件(2026-09-22 19:40 JST)。予算選択・投稿時刻による対応付け・重複・期限・scope・公開境界・省略時の文字数・短文観測とキューの分離を検証した。TTSは、実際の開始と完了receiptのどちらが先に通知されても互換イベントは一度だけとし、完了時刻を準備時間の実測にしないことを確認した。既存のSituation、台本、自発発話、TTS、コメントレーンの回帰テストも含む。

再実行コマンド:

/Applications/Unity/Hub/Editor/2022.3.15f1/Unity.app/Contents/MacOS/Unity \
  -batchmode -nographics -projectPath "$PWD" -runTests -testPlatform EditMode \
  -testFilter 'ConversationProgression|ConversationReasoning|ConversationExperiencePolicyTest|SituationSnapshotTest|SituationPromptRendererTest|SituationAutonomy|CharacterExperience|OperatorCueLlmIsolationTest|LlmOpenAiRouteHardeningTest|LiveChatFreshnessTest|AudienceDetourStateTest|Monologue|TtsCircuitBreakerIntegrationTest|CommentWorkLaneTest' \
  -testResults /tmp/aituber-conversation-stage2-tests.xml \
  -logFile /tmp/aituber-conversation-stage2-unity.log

実際の配信遅延に合わせた観測窓の調整、語彙に依存しない訂正対象の解決、実音声での会話品質・待ち時間・初見への伝わりやすさのA/B比較は残る。今回は実発話の確定後に届いた反応だけを扱い、発話途中の反応の厳密な対応付けや、providerごとの将来のTTS時間予測は行わない。