【検証】LLMはミニクエストを攻略できるのか?

プログラミング

はじめに

「最短1分で遊べる DQ 風ミニ探索ゲーム」を作りました。
村で武器を拾い、外にいる魔王っぽい敵を倒して宝箱を開ける――という昔ながらのミニクエストを、ブラウザだけで完結できるようにしました。

狙いは、AIに指示すればこのミニクエストを本当にクリアできるのかを検証することです。
「どのくらいの情報を渡せば迷わず進むのか」
「逆に情報が多すぎるとどう破綻するのか」
「モデルによって挙動やコストはどれくらい変わるのか」
を1つの短いゲームで観察するための実験台です。

プレイヤーは通常操作とAI提案モードをワンクリックで切替できるようにし、
モデル別のトークン/コストもUIで可視化しました。
操作とコスト表示が同じ画面に収まるので、遊びながら「この指示でいくらかかるか」を直感的に確認できるようにしました。


ソースコード

👉 GitHub

GitHub - daiki3027/app-ai-quest at quest-ai
Contribute to daiki3027/app-ai-quest development by creating an account on GitHub.

デモ動画

  • AIモデルは3つ試しました。
  • gpt-5 / gpt-5-mini / gpt-5-nano の3本を YouTube に投稿しました。
    プレイ差分と挙動の違いが一目で分かるよう、同じシナリオを同じ指示で試しました。
  • 目安コスト(入力/出力/1MトークンあたりUSD)は次の通りです。
  • gpt-5 $1.25 / $0.125 / $10.00
  • gpt-5-mini $0.25 / $0.025 / $2.00
  • gpt-5-nano $0.05 / $0.005 / $0.40
  • クリア可否: gpt-5-nano は宝箱までたどり着けず、gpt-5-mini と gpt-5 は宝箱まで到達しました。

🎥 YouTube gpt-5

🎥 YouTube gpt-5-mini

🎥 YouTube gpt-5-nano


AIに渡した情報とレスポンス例

  • 基本プロンプト:
    役割を「ドット絵RPGの案内役」に設定し、
    可能アクション(MOVE/INTERACT)、禁止事項、優先順位、10手のJSONプラン形式を明示しました。
    行動の自由度を保ちつつ、形式を固定してパースを安定させる狙いです。
  • 追加情報(JSON): buildStateSummary で生成したサマリを user メッセージに渡します。
    内容はマップ名/サイズ、プレイヤー座標、武器/敵/宝箱の座標と生存フラグ、近傍4方向の地形ラベル、
    NPCの位置と会話済みフラグ、最近のログ(5件)、入口ラベルと遷移先/要件、クリア目標です。
    ヒントの最小セットだけを渡し、マップ全体の文字列を送らないことでトークン削減を狙いました。
  • なぜこの構成か:
    地図全体を投げずに必要最小の構造化情報だけ渡し、トークンを節約しつつ経路判断をさせるためです。
    最近のログと会話済みフラグで同じNPCに話し続ける無限ループを防ぎ、
    入口の要件を渡して「門を開けるには敵撃破が必要」などの条件を理解させる狙いです。
    結果として、gpt-5/gpt-5-mini は宝箱まで到達しましたが、gpt-5-nano は情報があっても探索が足りず未クリアとなりました。
  • 実際のリクエスト例(gpt-5-mini):
    下記は送信ペイロードの主要部のみです(ヘッダーや不要フィールドは省略)。
  {
    "model": "gpt-5-mini",
    "input": [
      {
        "role": "system", 
        "content": 
            "あなたはシンプルなドット絵RPGの案内役です。返答は必ずJSONのみ。
            \nゲームの目的: 宝箱に到達して開ける。
            \n可能なアクション:
            \n- MOVE: dx, dy を -1,0,1 のいずれかで指定して1マス移動する(斜め不可)。
            \n- INTERACT: 隣接マスのNPC/敵/宝箱/ドア/門/武器を調べる。
            \n禁止: 壁やNPC/敵/宝箱/門/ドアの上には移動できない。
            \nstate.recentLog には直近のイベント/NPC会話が入っているので参考にすること。
            \nstate.talked は NPCごとの会話済みフラグ。
            \nstate.npcs, state.entrances, state.weapon, state.enemy, state.treasure を使い、
            \nまだ話していないNPCが近くにいれば優先して話しに行く。
            \n武器未取得なら武器の位置に移動→取得。その後は敵を倒し、門/ドアを抜けて宝箱へ向かう。
            \n返答は10手のリストをJSONで返すこと。
            \n形式例:
            \n{\"plan\":
              [
                  {\"type\":\"MOVE\",\"dx\":0,\"dy\":1,\"reason\":\"北へ進む\"},
                  {\"type\":\"INTERACT\",\"reason\":\"宝箱を開ける\"}
              ]
            }
            \ntype は \"MOVE\" か \"INTERACT\" のどちらかのみ。dx, dy が無い場合は 0 とすること。"
      },
      {
        "role": "user", 
        "content": 
            "現状サマリ: 
            {
              \"map\":\"village\",
              \"mapSize\":{\"width\":15,\"height\":11},
              \"player\":{\"x\":7,\"y\":7},
              \"hasWeapon\":false,
              \"enemyDefeated\":false,
              \"gameClear\":false,
              \"nearby\":{\"up\":\"npc\",\"down\":\"empty\",\"left\":\"empty\",\"right\":\"empty\"},
              \"talked\":{\"A\":false,\"B\":false,\"C\":false},
              \"recentLog\":[\"村にやってきた。\"],
              \"npcs\":[
                  {\"id\":\"A\",\"position\":{\"x\":5,\"y\":6},\"talked\":false},
                  {\"id\":\"B\",\"position\":{\"x\":7,\"y\":6},\"talked\":false},
                  {\"id\":\"C\",\"position\":{\"x\":9,\"y\":6},\"talked\":false}
              ],
              \"entrances\":[
                  {\"label\":\"外へ続く門\",\"x\":7,\"y\":0,\"target\":\"fieldA\"},
                  {\"label\":\"家のドア\",\"x\":13,\"y\":5,\"target\":\"house\"}
              ],
              \"goal\":\"宝箱を開けてクリア\"
            }
            \nJSONのみで次の一手を提案してください。"}
    ],
    "text": {"format": {"type": "json_object"}}
  }
  • 実際のレスポンス例(gpt-5-mini):
    下記は plan 部分のみを抜粋しています(実際のレスポンスには usage や reasoning なども含まれます)。
  {
    "plan": [
      {"type":"INTERACT","dx":0, "dy":0, "reason":"上にいるNPC(B)に話しかける"},
      {"type":"MOVE",    "dx":-1,"dy":0, "reason":"左へ移動してAに近づく準備"},
      {"type":"MOVE",    "dx":0, "dy":-1,"reason":"上へ移動してAに隣接する位置へ"},
      {"type":"INTERACT","dx":0, "dy":0, "reason":"左のNPC(A)に話しかける"},
      {"type":"MOVE",    "dx":0, "dy":-1,"reason":"上へ回り込んでCへ向かう経路に入る"},
      {"type":"MOVE",    "dx":1, "dy":0, "reason":"右へ移動して経路を進む"},
      {"type":"MOVE",    "dx":1, "dy":0, "reason":"さらに右へ移動してCに近づく"},
      {"type":"MOVE",    "dx":0, "dy":1, "reason":"下へ移動してCの隣接位置に着く"},
      {"type":"INTERACT","dx":0, "dy":0, "reason":"右のNPC(C)に話しかける"},
      {"type":"INTERACT","dx":0, "dy":0, "reason":"周囲を調べて武器や門の情報を探す"}
    ]
  }
  • ここでは近くのNPCを順に回ってヒントを得るプランを提案していました。dx/dy は MOVE での移動量でしたが、
    INTERACT でも0指定が含まれていました(許容してパースしました)。
  • 実際のレスポンス全体には usage(トークン数)や reasoning(思考過程トークン)などが含まれていましたが、
    ゲーム側で使用したのは plan の配列のみで、各要素を1手ずつ承認実行しました。

おわりに

明確な指示文とAIが処理しやすいパラメータを用意したら、AIがミニクエストをクリアできました。

一方で、情報を盛り込みすぎるとノイズになり、逆に動きが鈍りました。
どの情報を渡し、どの余計な情報を省くか、そして指示文をどう書くかが難しくかったです。


コメント

タイトルとURLをコピーしました