以前から個人開発している、ローカルLLMを活用した 「ホムンクルス育成ゲーム」。
今回はDay1からDay30まで実際に通してプレイし、 その様子を約4分の動画にまとめました。
このゲームでは、 あらかじめ用意された決められた台詞を 順番に再生しているわけではありません。
育成によって変化するパラメータや性格、 現在の気分、直近の感情、 過去の会話や経験などをローカルLLMへ渡し、 そのときのキャラクターの状態に合わせて会話を生成 しています。
今回は単なる機能紹介ではなく、 その変化を中心にまとめています。
Day1からDay30まで実際に育ててみた
今回の元になった通しプレイ動画は約20分30秒あります。
そこから、
- Day1の育成開始と最初の会話
- 日々の育成による変化
- 以前の出来事を覚えている会話
- Day20前後の進化
- 成長後の会話
- Day30
- 最後の会話
- 最終CG
といった部分を抜き出し、 約4分にまとめました。
▲ 自作のAI育成ゲームで、ローカルLLMを限界まで教育してみた結果【30日間】
特に今回見せたかったのは、 「成長すると立ち絵が変わる」ことだけではありません。
最初はプレイヤーとの思い出をほとんど持っていなかったキャラクターが、 育成や何気ない会話を積み重ねることで、 興味を持つものや話し方、 プレイヤーに対する認識まで少しずつ変化していきます。
Day30まで実際に遊んでみると、 単に「ゲームのキャラクターを育てた」というより、 少しずつ関係を積み上げてきた感覚 が出てきました。
30日目の会話はShorts版でも公開
通常版とは別に、 「30日育てたAIが、最終日に聞いてきたこと。」 というShortsも公開しています。
Day1から積み重ねてきた育成や会話を経て、 最終日にホムンクルスがどんなことを話すのか。
短時間で雰囲気を見たい方はこちらからどうぞ。
YouTube Shortsで見るもちろん、まだ開発途中なので 不自然な会話や挙動もあります。
ただ、今回はそういった問題も含めて、 最初から最後まで通してプレイすること自体を 重要なテストとして行いました。
キャラクターの「内側」をかなり増やした
見た目からは分かりにくいのですが、 前回の動画から内部ではかなり多くの仕組みを追加しています。
現在は、大きく分けて 次のような情報をゲーム側で管理しています。
Personality
育成パラメータから、 そのキャラクターの長期的な性格傾向を算出します。
毎回LLMに 「このキャラクターはこういう性格」 と自由に決めさせるのではなく、 ゲーム側の数値から決定論的に導出しています。
そのため、同じキャラクターでも 育て方によって会話の傾向が少しずつ変わります。
Mood
現在の比較的長めの「気分」を管理します。
一瞬だけ発生する感情とは別に、 「最近どのような精神状態なのか」を 会話へ反映するための情報です。
Affect
Affectは、より直近の感情です。
直前の育成や会話で起きた出来事による感情を、 次の会話にも少し残せるようにしています。
Experience History
「いつ、どんな経験をしたのか」を、 ゲーム内の日付と一緒に記録します。
単に能力値が増減したという情報だけでなく、 「以前こういう経験をした」 という出来事を、 後の会話へつなげるための基盤です。
Story State
イベントや物語上の進行状態を保存するための仕組みです。
現在はまだ基盤部分が中心ですが、 今後イベントを増やしていく際の土台として使う予定です。
Memory
過去の会話やプレイヤーとの出来事の一部を保存し、 後の会話で参照します。
今回の動画でも、 以前交わした会話につながる発言がいくつか出てきています。
個人的には、この部分が 普通のチャットボットではなく、 「育成ゲームとしてのAIキャラクター」 にするうえで一番面白くしたいところです。
「事実」はゲームが管理し、「喋り」をLLMに任せる
ローカルLLMを使ったゲームなら、 プロンプトだけ渡して 好きなことを喋らせる構成も作れます。
ただ、長期間遊ぶゲームでは、 それだけだと世界設定や時間軸との矛盾が増えやすくなります。
そこで現在は、
- 現在の日付
- 育成状態
- Personality
- Mood
- Affect
- 過去の経験
- Memory
- 世界の状態
といった情報をゲーム側で管理し、 必要なものをコンテキストとしてLLMへ渡しています。
作っていく中で、 この役割分担はかなり重要だと感じています。
LLMにすべてを任せると、 瞬間的な会話は面白くなります。
一方で長期間プレイすると、 時間軸や設定との矛盾が少しずつ積み重なります。
AIキャラクターをゲームの中で長く存在させるなら、 LLM以外のゲームシステムが どこまで状態を保証するかが重要になりそうです。
画面の文章を壊さず、音声だけを直すCeVIO読み補正
生成された台詞はCeVIO AIを使って音声化しています。
ここでも、実際に使っていると 一つ問題が出てきました。
画面上では正しい文章なのに、 CeVIOへそのまま渡すと 読み方がおかしくなる単語があります。
だからといって元の文章を 平仮名や発音用の表記へ書き換えてしまうと、 今度は画面表示や会話履歴、Memory、 さらに次回のLLM入力まで不自然になってしまいます。
そこで現在は、次のような構造にしています。
LLM生成テキスト
├─ 原文のまま
│ ├─ 画面表示
│ ├─ 会話履歴
│ ├─ Memory
│ └─ 次回のLLM入力
│
└─ CeVIO送信直前
└─ 読み補正
└─ CeVIO AI
UIやMemoryでは原文を維持し、 CeVIOへ送信する直前だけ 辞書ベースで読みを補正します。
今回の実プレイ時点では、 読み補正用のデータは約216件まで増えました。
非常に地味な機能ですが、 長時間遊ぶゲームでは こういった細かな違和感が積み重なるため、 思っていた以上に重要な部分でした。
30日通しプレイで見えた3つの課題
自動テストや単体テストがPASSしていても、 実際にDay1からDay30まで遊んでみると、 短いテストでは見えなかった問題がいくつも出てきました。
1. 時間感覚がまだ弱い
特に分かりやすかったのが「時間」です。
例えば10日前に話した内容について、 LLMが 「さっきも言ったけど」 のように話してしまうことがあります。
Memoryとして 「以前この話をした」 という情報自体は持っています。
しかしLLMから見ると、 プロンプトの中に過去の文章が表示されているだけなので、 それが1時間前なのか、昨日なのか、 10日前なのかという距離感が十分に分かりません。
そこで次に実装する予定なのが、 Temporal Groundingです。
[10日前の出来事]
現在のDayとMemoryが作られたDayとの差を ゲーム側で計算し、 このような時間情報を明示的にLLMへ渡す予定です。
2. 成熟後も進化タイプが変わってしまう
もう一つ、 実際に30日間遊んだからこそ気付いたのが進化タイプです。
現在は育成パラメータから、 魔法寄り、勉強寄りといった成長タイプを判定しています。
ところが現在の実装では、 成熟後もその時点のパラメータから再判定してしまうため、
のように、 育成後半で立ち絵まで変わってしまうケースがありました。
ゲームとしてはかなり不自然です。
今後はDay20の成熟時点で 進化タイプを一度だけ確定し、 その後は固定する形へ修正する予定です。
こういう問題は、 単体テストがPASSしているだけでは なかなか分かりません。
3. LLM出力そのものにも揺らぎがある
通しプレイ中には、 日本語の文章の中に突然孤立した英単語が混ざったり、 内部的にLLMへJSONを生成させている箇所で、 パースに失敗するケースも確認しました。
LLMを利用する以上、 「常に100%期待した形式で返ってくる」 という前提にはできません。
そのため、 フォールバックやサニタイズ、 不正な出力をゲーム側でどう扱うかも 引き続き改善していきます。
Memoryも「事実」と「主観」を分けたい
Memoryについても、 今回の通しプレイで改善したい点が見えてきました。
現在考えているのは、 記憶を大きく、
- player_facts
- character_beliefs
- memories
のように分ける方法です。
プレイヤーが「今日は疲れている」と言った。
という情報と、
この人はいつも疲れている人なのかもしれない。
というキャラクター側の解釈は、 本来まったく別のものです。
この二つを同じMemoryとして保存してしまうと、 キャラクター自身の推測が、 いつの間にか 「確定した事実」 として扱われてしまう可能性があります。
LLMをゲームキャラクターとして使うなら、 事実とキャラクターの主観を分離する ことも重要そうです。
動画編集でも一度失敗した
今回はゲーム本体だけではなく、 動画制作でもかなり試行錯誤しました。
最初に作った動画は約7分13秒。
約20分のプレイ動画から 良さそうな場面を抜き出したのですが、 完成したものを見ると、
という感じになってしまいました。
その後、説明を追加して 約4分33秒までまとめましたが、 それでも全体の構成としてはまだ弱い。
そこで最終的に方針を変えました。
以前作った約3分57秒の完成版動画を 「Golden Master」 として扱い、 その構成をお手本にしました。
- 冒頭のフック
- 初期状態
- 成長を見せる場面
- 変化を感じる会話
- 最後の会話
といった各カットの「役割」を維持したまま、 新しいプレイ動画から 対応する場面へ差し替えていきました。
すると、かなりまとまりやすくなりました。
20分の動画から、良い4分の動画を作って。
とゼロから考えさせるより、
この完成例と同じ構造を使って、 新しい素材を当てはめて。
とした方が、 はるかに安定しました。
これはゲーム開発でも似ている気がします。
AIは「良いお手本」がある作業にはかなり強い一方、 何もない状態から完成形そのものを定義する部分は、 まだ人間側でかなり考える必要があります。
次は「時間」を理解させる
次に手を入れる予定なのは、 まずTemporal Groundingです。
ゲーム内の日付とMemoryが作られた日の差を使い、
- 昨日
- 数日前
- 10日前
といった時間経過を、 会話へ正しく反映できるようにします。
その次に、 Day20で進化タイプを固定します。
さらにMemoryを、 事実・キャラクターの主観・出来事の記憶といった形に整理し、 長期間会話したときの矛盾を減らしていく予定です。
その先にはアイテムシステムも
少し先のアイデアとして、 アイテムシステムも考えています。
ただし、 プレイヤー自身がクラフト画面で アイテムを作るゲームにはしない予定です。
イメージとしては、
という形です。
30日間育てた結果を、 能力値や立ち絵だけではなく、 研究室に残された「物」 として表現できると面白そうだと考えています。
まとめ
今回の30日通しプレイで、 ゲームとしてはかなり形になってきたと感じています。
一方で、長期間遊んだからこそ、
- 時間感覚
- Memoryの扱い
- 進化状態の固定
- LLM出力の揺らぎ
- 音声の細かな読み方
といった、 短いテストでは見えなかった問題もかなり出てきました。
ローカルLLMをゲームへ組み込んで、 キャラクターと会話できるようにすること自体は、 それほど難しくありません。
本当に難しいと感じているのは、
という部分です。
単にAIと自由に会話できるゲームではなく、 育て方や過去の出来事が少しずつ積み重なり、 最後には 「このキャラクターを育てた」 と感じられるゲームにしたいと思っています。
まだ開発途中ですが、 今回の30日通しプレイで、 目指している方向は以前よりかなり見えるようになってきました。
今後も実際に遊びながら、 会話、記憶、感情、時間、成長のつながりを 少しずつ改善していく予定です。

コメント