ボドゲのルール生成
以下のプロンプトでClienのAgentモードで作成。
ポジション
あなたは優秀なプロのWebエンジニアです。
以下の仕様を満たすアプリケーションを作成してください。
仕様
- このアプリケーションはボードゲームの遊び方を出力してくれる
- ボードゲームの名前を入力するとボードゲームの詳細な遊び方を提示してくれる
- AIエンジンはGemini2.0-flashを利用
- その他のアプリケーションの構築に必要な技術は以下
- 言語はJavaScript、TypeScript
特に詰まることもなく成功。
最初に、Next.js使いたい、Hono使いたい等フレームワークをあれやこれやと指定するとやや詰まった。
以下が例。
- フロントエンドはReact、Next.js
- バックエンドはHono
- LintはBiome
- CSSフレームワークはTailwind
- UIフレームワークはshadcn/ui
HonoのRPCを使いたかったんだけど、知識がほとんどない状態ではやっぱりムズい。
生成されたコードの成否が判断できないので、動かない時にエージェントが無限ループし始める。
とりあえず、動いたやつ。
マークダウンの表示
生成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();
}
}
若干ルールが間違っている。
ルールのような間違ってはいけないものには単純な生成AIはちょっと向かない気がしてきた。
となるとRAGかな〜。
出力した内容を生成AI自体に1度評価させて、修正したものを出力させる場合はどうだろう?
試しに評価させる場合の処理を書いてみる。
生成させた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' },
});
}
でやっていて気付いたが、結局評価基準を用意しなくてはいけなくて、色んなゲームタイトルが入力されることを考えると、各ゲームの評価基準の決めがムズい。
今回の「街コロ通」の場合で言うと、初回の3ターンは特殊ルールだが、何度やっても正確な回答が返ってこない。ただこれ自体は街コロ通のルールの話なのでそれを評価するためには正確なデータソースが必要という話であって、それであればRAGにした方が早いって話になる。
なので結局、評価基準や回答の正確性を求めるアプリケーションには生成AI自体は向いていない。当たり前っちゃ当たり前なんだが、、、。
そういう意見もあるよね、っていうふんわりした回答が許されるものが相性が良い。
例えば筋トレのメニューを出力するとか。ベンチプレス、インクラインダンベルプレスで組まれることもあれば、ベンチプレスだけの場合もあるし、ダンベルプレス、インクラインベンチプレスで組まれることもあるっていう。
種目数は◯個〜とか、多関節種目、単関節種目の個数バランスとかで評価基準も定められるし。
VertexAISearchを使うのが良いんだろうが、結局ボードゲームのルールのソースを集めるのは人力ってのがしんどいな〜。。。
クローリング&スクレイピングとかである程度やれる部分はありつつ、そもそも紙媒体なので公式でルールブックを載せていないものもたくさんあるし。
ゲームルールをアップロードできるようにしておいて、誰でも検索できるように、みたいな話だと結局wikiと変わらんしな〜、、、
悔しいので最後にVertex AI Searchの使い方だけ調べて終わる。
- データストアのもとになるバケットの作成
- Agent Builderでデータストアに対象のバケットを指定。非構造化データを選択
データはPDFになるので、ParserはOCRを指定。
- Agent Builderでカスタムサーチを選択
- データストアを選択して少し待つ
RAGを民主化した仕組みがNotebookLMってことか。
ちなみに結構時間かかってる
4頁程度のPDFで15分ぐらいかかった
初回の3ターンは特殊ルールだが、何度やっても正確な回答が返ってこない。
見事解消された。
データストアの同期自体は定期的にやることも出来る模様。今回は1回きり。
作成したAgentはウィジェット、APIの2種類の方法でアプリに統合できる。
う〜ん便利。