Open24

ボドゲのルール生成

shooooori0128shooooori0128

以下のプロンプトでClienのAgentモードで作成。

ポジション

あなたは優秀なプロのWebエンジニアです。
以下の仕様を満たすアプリケーションを作成してください。

仕様

  • このアプリケーションはボードゲームの遊び方を出力してくれる
  • ボードゲームの名前を入力するとボードゲームの詳細な遊び方を提示してくれる
  • AIエンジンはGemini2.0-flashを利用
  • その他のアプリケーションの構築に必要な技術は以下
    • 言語はJavaScript、TypeScript
shooooori0128shooooori0128

特に詰まることもなく成功。
最初に、Next.js使いたい、Hono使いたい等フレームワークをあれやこれやと指定するとやや詰まった。
以下が例。

  • フロントエンドはReact、Next.js
  • バックエンドはHono
  • LintはBiome
  • CSSフレームワークはTailwind
  • UIフレームワークはshadcn/ui

HonoのRPCを使いたかったんだけど、知識がほとんどない状態ではやっぱりムズい。
生成されたコードの成否が判断できないので、動かない時にエージェントが無限ループし始める。

shooooori0128shooooori0128

生成AI部分の処理。

export class Gemini {
  async generateText(gameTitle: string): Promise<string> {
    const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash" });
    const prompt = `
      **指示:**

      以下の情報に基づいて、「${gameTitle}」というボードゲームのルール手順を日本語かつマークダウンで詳細に出力してください。初回と通常ターンでルールが異なる場合は、それぞれ明確に分けて記述してください。

      **ゲーム名:** [ゲーム名]

      **ゲームの目的:** [ゲームの勝利条件、最終目標]

      **ゲームの準備:** [初期設定、盤面の配置、使用するコンポーネントの説明]

      **ターンの流れ:**

      * **初回数ターンのルール:**
          * [初回のみの特殊なルール、手順、ターン数を明記]
      * **通常ターンのルール:**
          * [通常のターンの基本的な流れをステップごとに記述]
          * [各ステップで可能なアクション、選択肢、制約など]
      * **アクションの詳細:**
          * [各アクションの種類、効果、実行条件などを具体的に記述]
      * **特殊ルール:**
          * [特定の条件で発生する特殊なルール(イベント、ボーナスなど)の詳細]

      **ゲームの終了条件:** [ゲームが終了する条件、勝利判定の方法]

      **その他:**

      * [特定のカードやコマ、地形などの効果についての詳細な説明]
      * [ルールに関する例外や補足事項]
      * [プレイヤー間のインタラクション(交渉、協力、攻撃など)に関するルール]
    `;

    const result = await model.generateContent(prompt);
    const response = result.response;
    return response.text();
  }
}
shooooori0128shooooori0128

若干ルールが間違っている。
ルールのような間違ってはいけないものには単純な生成AIはちょっと向かない気がしてきた。

shooooori0128shooooori0128

となるとRAGかな〜。
出力した内容を生成AI自体に1度評価させて、修正したものを出力させる場合はどうだろう?

shooooori0128shooooori0128

生成させたCode-Based gradingのロジック。

import { Hono } from 'hono';
import { Gemini } from '@/gemini';

export const config = {
  runtime: 'edge',
};

const app = new Hono();

// 評価ロジック
function gradeResult(gameName: string, result: string): { score: number; feedback: string } {
  let score = 100;
  let feedback = "";

  // 文字数チェック
  const textLength = result.length;
  if (textLength < 1000) {
    score -= 30;
    feedback += "文字数が1000文字未満です。情報を追加してください。\n";
  } else if (textLength > 2000) {
    score -= 30;
    feedback += "文字数が2000文字を超えています。情報を削減してください。\n";
  }

  // 文法チェック
  const grammarCheckRegexes = [
    /ゲームの目的:.*$/,
    /ゲームの準備:.*$/,
    /ターンの流れ:.*$/,
    /初回数ターンのルール:.*$/,
    /通常ターンのルール:.*$/,
    /ゲームの終了条件:.*$/,
    /その他:.*$/,
  ];
  let grammarScore = 0;
  for (const regex of grammarCheckRegexes) {
    if (regex.test(result)) {
      grammarScore += 1;
    }
  }
  if (grammarScore < grammarCheckRegexes.length) {
    score -= 20;
    feedback += "プロンプトの構成要素が不足しています。ゲームの目的、ゲームの準備、ターンの流れ、ゲームの終了条件、その他の情報を含めてください。\n";
  }

  // 曖昧性チェック
  if (!result.includes(gameName)) {
    score -= 20;
    feedback += "ゲームタイトルが回答に含まれていません。ゲームタイトルを含めてください。\n";
  }

  return { score, feedback };
}

export async function POST(req: Request) {
  const { gameName } = await req.json();
  const gemini = new Gemini();
  let result = await gemini.generateText(gameName);

  // 評価
  const { score, feedback } = gradeResult(gameName, result);

  // スコアが低い場合は再生成
  if (score < 70) {
    console.log(score, feedback);

    result = await gemini.generateText(gameName + "。" + feedback);
  }

  return new Response(JSON.stringify({ result, score, feedback }), {
    headers: { 'content-type': 'application/json' },
  });
}
shooooori0128shooooori0128

でやっていて気付いたが、結局評価基準を用意しなくてはいけなくて、色んなゲームタイトルが入力されることを考えると、各ゲームの評価基準の決めがムズい。

今回の「街コロ通」の場合で言うと、初回の3ターンは特殊ルールだが、何度やっても正確な回答が返ってこない。ただこれ自体は街コロ通のルールの話なのでそれを評価するためには正確なデータソースが必要という話であって、それであればRAGにした方が早いって話になる。

shooooori0128shooooori0128

なので結局、評価基準や回答の正確性を求めるアプリケーションには生成AI自体は向いていない。当たり前っちゃ当たり前なんだが、、、。

そういう意見もあるよね、っていうふんわりした回答が許されるものが相性が良い。
例えば筋トレのメニューを出力するとか。ベンチプレス、インクラインダンベルプレスで組まれることもあれば、ベンチプレスだけの場合もあるし、ダンベルプレス、インクラインベンチプレスで組まれることもあるっていう。
種目数は◯個〜とか、多関節種目、単関節種目の個数バランスとかで評価基準も定められるし。

shooooori0128shooooori0128

VertexAISearchを使うのが良いんだろうが、結局ボードゲームのルールのソースを集めるのは人力ってのがしんどいな〜。。。
クローリング&スクレイピングとかである程度やれる部分はありつつ、そもそも紙媒体なので公式でルールブックを載せていないものもたくさんあるし。

shooooori0128shooooori0128

ゲームルールをアップロードできるようにしておいて、誰でも検索できるように、みたいな話だと結局wikiと変わらんしな〜、、、

shooooori0128shooooori0128

悔しいので最後にVertex AI Searchの使い方だけ調べて終わる。

shooooori0128shooooori0128
  1. データストアのもとになるバケットの作成
  2. Agent Builderでデータストアに対象のバケットを指定。非構造化データを選択
shooooori0128shooooori0128
  1. Agent Builderでカスタムサーチを選択
  2. データストアを選択して少し待つ
shooooori0128shooooori0128

初回の3ターンは特殊ルールだが、何度やっても正確な回答が返ってこない。

見事解消された。

shooooori0128shooooori0128

データストアの同期自体は定期的にやることも出来る模様。今回は1回きり。

shooooori0128shooooori0128

作成したAgentはウィジェット、APIの2種類の方法でアプリに統合できる。
う〜ん便利。