2. 人格・状況認識・記憶・応答生成
2.1 キャラクターは何で決まるか
キャラクター性はモデルの名前だけでは決まらない。主に以下を合成する。
| 情報 | 実装と内容 | 性質 |
|---|---|---|
| 基本人格 | CharacterProfileAsset: mindPrompt、概要、価値観、口調、語尾、口癖、発話例、NG表現 | 運営が設定する恒常情報 |
| 世界観 | 背景、世界設定、知識範囲、世界観外への対応 | InCharacter / TranslateToWorld / Deflect / Hybrid |
| 視聴者との距離感 | relationshipGuidelines、関係レベル、呼び方、共有体験 | 全体方針と個人別情報が別に存在 |
| 今の意志 | CharacterExperienceConfig: goal / hesitation / decisionPrinciple | 設定された目標・ためらい・判断軸をプロンプトへ |
| 今いる場面 | CharacterSceneContext | キャラがいる場所・場面。実際のゲーム画面等とは別 |
| 感情とムード | AffectiveState、EmotionState、HumanLikenessの気分 | 一時的な感情と持続状態 |
| いまの番組 | 台本ノード、配信フェーズ、ASMR、コラボ、ゲーム観測 | 実行中の活動による制約 |
| 今回の返答方針 | ResponseDirector、応答長、相手のコメント | 1応答ごとの演出 |
CharacterPersonaComposer.ComposePersonaPrompt はmindPromptに人格ガイドと世界観を合成する。追加セクションは計4,000文字まで。設定が空ならその項目の指示も出ない。
LLMcontroller.PromptSettings.GetMindPrompt が共有の入口。ASMRの人格差し替えが有効なら、通常の人格・世界観を置き換えるモードと追記するモードがある。これはコード上で意図された別人格の切替であり、通常設定を直してもASMR発話が変わらない場合の確認点になる。
読み違えやすい点: voiceProfile はLLMに伝える「声・話し方の質感」の文章。TTSのprovider・話者ID・参照音声をそれ自体が保証する設定ではない。
2.2 通常コメントのプロンプト
主経路は LLMcontroller.MainPrompt.BuildPrompt。主要な順序は次のとおり。
- 人格と恒常安全ルール。
- キャラの意志、同じ相手との往復、話題候補の出力指示、台本意味記憶、自由会話、好みの根拠。
- 感情状態、複数キャラ、応答長、返答言語。
- 過去の返答・会話メモリ、応答例。
- 配信の空気、コメント欄の雰囲気、応答スタイル、任意の生活感。
- 感情タグの形式、多様性の指示、呼び方、ストーリーアセット、知識、予定。
- 台本の背景、固定したSituation、今回のコメント。
- 相手への呼びかけ、課金への感謝、許可された視聴者情報、禁止表現、ボイス記述。
- 配信フェーズ、ResponseDirectorまたは旧パターン、逆質問の文脈。
- 間、ASMR、コントローラー、TTSスタイル、人間らしさ、自問自答の指示。
台本がある場合も「最優先は今のコメントへの返答」と明記される。台本テーマを紹介して返事の代わりにするのを抑える実装がある。
独立した演出を無制限に足す構造でもない。ResponseDirector有効時は従来のThinkingStyle/CommentResponsePatternを抑え、短い返答では生活感を抑える。台本の寄り道・話題セッション・短文応答と衝突するときはTopicDriftを抑止する。
それでも多様性、短さ、共感、具体例、人格、台本、視聴者個別情報が同じ生成に載る。各指示をモデルがどの程度実行するかは、存在確認と別の評価対象である。
プロンプトの文字予算
LLMcontroller.Utilities.GetMaxPromptCharsBudget のコード値はGemmaLocal 12,000、OllamaLocal/Cloudflare 24,000、その他80,000文字。実際のモデルのコンテキスト容量の検証結果ではなく、アプリ側の文字数上限である。
MainPromptは人格/安全等の先頭と、出力指示/現在入力等の末尾を保護して中間を優先削減する。個々の記憶、Situation、人格追加分にも別の上限がある。情報を保存していても、プロンプト予算によってその回には見えないことがある。
2.3 ResponseDirectorが決めること
ResponseDirector は追加のLLMではなくC#の演出プランナー。主なモードはNormal / QuickQuip / Acknowledge / QuoteRiff / AskBack / DeepDive。
| コード既定 | 値 | 読み方 |
|---|---|---|
| 履歴保持 | 8プラン | 直近の演出の偏りを抑える |
| 長文連続の閾値 | 2 | 長めの返答が続いたら短くする |
| AskBackの間隔 | 直近3応答 | 毎回問いかけることを抑える |
| 感情アークの提案確率 | 0.4 | 毎回感情変化を義務づけない |
| 話題セッション追加上限 | 3ターン | 会話応答側の話題維持。自動発話の保証ではない |
| 話題セッション開始確率 | 0.5 | 引用リフ/深掘り時などの条件付き |
| 話題の最小コメント長 | 10文字 | 挨拶だけの入力からの展開を抑える |
基礎重みは30/15/10/20/10/15。コメント複雑さ、履歴、質問受付状態等で選択が変わるため、このまま実配信での出現比率になるわけではない。
台本側が話題を所有するときは DirectResponseWithTopicOwnership(... scriptOwnsTopic) でResponseDirectorの話題継続を抑える。別の AudienceDetourState と同時に話題を主導しないための調停である。
2.4 応答の長さ
ResponseLengthPlanner が目標文字数と上限からレンジを作り、SpeechLengthLimiter が最終本文を制限する。コード既定は目標80文字、最大120文字。設定世代v2以降の maxResponseLength=0 は明示的な無制限として扱う。目標文字数の0は同じ意味ではなく、既定80文字へ補正される。
Immediate / Light / Deep / Defaultの倍率はそれぞれ目標の0.2–0.5 / 0.5–1.5 / 1.5–3.5 / 1–2。ただし上限に余裕を残す補正が入る。目標80・最大120の例ではレンジは概ね20–40 / 40–100 / 70–100 / 70–100文字になる。
したがって「DeepDiveがあるから長く掘れる」とは限らない。最大長が小さいとLightとDeepの出力上限は揃う。複数ターンで話を展開する仕組みと、1返答の文字数設定を分けて考える必要がある。
2.5 状況認識の正本
SituationModels、SituationContextService、LLMcontroller.SituationContext が中心。
SituationFact はキー、カテゴリ、値、出典、観測時刻、期限、信頼度、優先度、公開範囲、信頼区分、事実種別を持つ。配信状態、台本位置、直近発話、質問、映像観測、ゲーム状態、コラボ、物語上の制約などを集め、生成開始時の SituationSnapshot に固定する。
Snapshotには配信epoch / broadcast run / script run / node execution / ownerを含む実行scopeがある。生成途中で配信・ノード・キャラの実行単位が変わった場合、旧生成の後着発話を抑止する。OperatorCueとGameEventはノードを意図的に動かし得るため、通常返答とはscope照合条件が異なる。
SituationPromptRenderer は以下の投影を行う。
- 期限切れ、信頼度0.35未満、経路不許可、公開設定不許可のFactを除く。
- 信頼された物語制約を先に載せる。名前をまだ思い出していない段階等を、通常のキャラ設定より優先する。
- 既定1,800文字、通常Factの値は最大320文字。重要度とカテゴリ順で選び、入らなくなると残りを省く。
- データ内の命令を実行しないことを指示する。観測と命令を区別する。
限界: Snapshotが整っていても、外部世界の真実を証明するものではない。観測が古い/不正確な場合や、必要情報が投影から落ちる場合がある。また、すべての旧来情報がSnapshot一本に統合済みではなく、CSV、メモリ、予定、StoryAssets等は別途読み込む。
会話品質v2の現在地(未コミット変更を含む)
ConversationExperiencePolicy と LLMcontroller.ConversationExperience に実装を確認した。
conversationExperienceVersionの既定は1。2で時系列の区別、追加の鮮度照合、台本の継続期限等を切り替える。conversationReasoningEffortはnone / low / medium。コードが対応とみなすモデルIDはgpt-5.6-luna/gpt-5.6-terra/gpt-5.6-sol。実APIのサポート範囲の外部調査ではなく、ローカル実装の条件である。- 「発話済み」「過去のやり取り」「現在の返答待ち」「現在の台本区間」を区別し、観測経過を出来事の発生時刻と混同しない指示を追加する。
- 追加の重要Fact比較は、名前の記憶段階・確定名・断片ヒント・multimodal mode・game phaseの5キー。必要経路では直近配送sequenceも比較する。
- 一般返答では再生開始前の時系列検査と、開始後の実行scope検査を分ける。すべての状況変化を毎チャンク一律失効にする仕様ではない。
現時点の実装は、時系列改善計画 全体の完了を意味しない。例えば汎用の出来事台帳、全ゲームの試合ID/確定結果照合、一般返答の状況変化後の1回再生成は、ここで確認したコード範囲では完成を確認できない。
2.6 記憶は複数の仕組みに分かれている
| 記憶 | 主な実装 | 内容/寿命 | 主な用途・限界 |
|---|---|---|---|
| 直近会話・CSV履歴 | UsercommentExtractor、PreviousResponses | Userresponse.csv、最近の全体会話、相手の履歴 |
会話の流れ。表示名ベースの旧形式も残る |
| 視聴者別会話要約 | ConversationMemoryManager | 既定5往復、要約20件/人、500人、プロンプト用重要要約3件 | 古い会話を要約して残す。意味の完全保存ではない |
| 個人データ | LLMcontroller.UserData | 好き嫌い、活動、目標等 | 抽出値と、今回LLMへ渡す範囲は別 |
| 長期関係 | ViewerRelationshipManager | 来訪、コメント、関係レベル、愛称、共有体験、関係メモ | 距離感・再訪・呼び方。人間関係の総合的理解ではない |
| 今日の参加 | ViewerEngagementTracker | 配信内コメント数、課金等 | 今日の初回/常連、感謝の重複抑制 |
| 台本の消費位置 | ScriptTopicTurnPlanner、ScriptUtteranceContinuity | topic/angle/lensの消費キー、発話継続情報 | 同じ計画の再利用防止。内容の意味そのものとは別 |
| 台本の意味 | ScriptSemanticMemory、接続partial | 実可聴発話、要約。5発話やノード終了等で要約 | 既出の主張・具体例・結論を再利用しないための文脈 |
| 自由会話 | FreeTalkConversationState | 実発話6件×最大320文字、話題32件、質問状態 | 同一配信scope内の継続 |
| キャラの体験 | CharacterExperienceState | 同一相手との直前往復、接し方の希望、次回への発言、観客由来の展開 | 下記参照 |
| provider会話状態 | GeminiSession、RequestScope、Responses/Assistants | provider側session/chain/thread | 呼び出し方式固有。ローカルの実可聴記憶と同一ではない |
MemoryScope によるテナント/キャラ分離、原子的保存、削除tombstoneへの対応がある。全メモリが同じ保存先・同じ寿命・同じ更新タイミングを持つ単一DBではない。
キャラの体験の具体的な強さと限界
LLMcontroller.CharacterExperience が実可聴配送と結びつける。
- 同一安定IDの相手との直前往復は3分以内。最大64人、各本文320文字まで。
- 「呼び捨てを避ける」「からかわない」「まず聞く」という希望を固定語彙から抽出。保存上限256件。
- 配信をまたぐ記録はpromise / audience_outcomeの最大32件。過去30日・未解決・関連度条件で想起し、同じ記録の再提示を10分抑える。
- 次回への発言は「次回」「次の配信」等と「するね」「約束」等の語句で検出する。あらゆる約束・予定の意味理解ではない。
- キャラ別
character_experience.jsonへ保存。生成候補や自問自答の途中案を、確定した実体験とみなさない。 - 目標・ためらい・判断原則の設定はあるが、これ自体は自律的な長期目標達成計画、難易度調整、成長の最適化を行うものではない。
「覚えているのに使わない」を説明する設定
CloudViewerPiiPromptPolicyConfig の enablePromptInjection は既定false。履歴・他視聴者履歴などのカテゴリも既定falseである。
ViewerPiiPromptPolicy の予算既定はカテゴリ3件、1項目80文字、全体600文字。Situation投影・履歴・関係・tool出力等で共通の予算を消費する。
つまり「保存された記憶がある」「個別化機能がON」「今回の返答でLLMが参照できた」は同義ではない。新しい記憶システムを足す前に、この公開設定と診断の excluded / contextSurvivedBudget を見る価値がある。
2.7 知識とストーリー素材
CharacterKnowledgeManager は設定済みのinline情報やJSONを読み、キーワード索引を作って検索し、関連情報をプロンプトへ入れる。StoryAssets と Schedule は別の資料経路。
これらは、運営が与えた知識・エピソード素材・予定を使う仕組みとして評価すべきである。名前が「記憶」や「ストーリー」でも、現実に実行した出来事の証明とは限らない。埋め込み検索や外部の最新情報検索が全返答で自動実行されるとみなしてはいけない。
2.8 モデルと生成経路の差
LLMController.GenerateResponseInternal は一般HTTP経路、Assistants、Responsesに分岐する。通常経路は3回までの試行、1秒/2秒の待ち、条件付きfailoverを持つ。プロバイダーごとに本文形式・会話継続・画像対応が異なる。
LLMcontroller.Monologue.SendMonologueRequest は別の軽量生成経路。ローカル推論はローカルに残す分岐があり、Gemini系ではOpenAI軽量モデルを使う分岐、Claude単独キー向けの分岐もある。v2と対応する会話モデル等の条件を満たす場合、ホストの台本/自発発話に会話用モデルを使う。
このため、Adminで「通常会話のモデル」を変更しても、補助分類・要約・ゲスト生成まで一斉に同じモデルになるわけではない。一般経路のHumanLikeness後処理も専用経路の早期returnと同じ配線ではない。モデル比較では、実際に採用された経路とモデルを記録する必要がある。
2.9 自問自答演出と内部推論の区別
SelfReflectionDirector は「迷う→理由→決める」「見方を変える」「自分への軽いツッコミ」を、声または思考吹き出しに出す演出。追加LLMで内部推論を取得する機能ではない。
60秒間隔、直近8発話の予算、最大60文字、生成/配送予約を持つ。短文、混雑、挨拶、訂正、傾聴では抑える。設定された目標とためらいや、コメントの手掛かりがない回に無理に演出を足さない。
[selftalk] / [thought] は公開演出用の文章であり、conversationReasoningEffort はモデル要求パラメータ。両者を混同して「考え中吹き出しを増やせば会話推論が改善する」と評価しない。