
巷ではAIエージェントのファクトチェック機能などが急速に進化していますが、「じゃんけんくらいはできるのでは?」と思い、試してみました。LLMを使わなくてもプログラムで実装できますが、今回はシンプルなケースとしてLLMを用いて試してみました。
はじめに
「AIに推論させる」といえば、情報検索や文章生成が一般的ですが、今回はちょっと変わったアプローチで、複数のAIエージェントを作成して「じゃんけん」をさせてみました。さらに、別のAIエージェントを審判として配置し、勝敗を判定させるシステムを構築しました。
この記事では、Pydantic AIライブラリを使用して、以下のようなシステムを実装します:
- マルチエージェントシステム(複数のエージェントが協調動作)
- 構造化出力による型安全な実装
なぜPydantic AI?
Pydantic AIは、LLMとのやり取りをより構造化し、型安全にできるライブラリです。以下のような特徴があります:
- 型による安全な出力の定義
- 複数のエージェントの管理が容易
- エージェント間での情報の受け渡しがシンプル
環境構築
まずは必要なライブラリをインストールします。Google Colaboratoryでの実行を想定しています。
!pip -q install pydantic-ai
!pip -q install nest_asyncio
import nest_asyncio
nest_asyncio.apply()
print("Setup complete!")
次に、APIキーを設定します。この例ではGemini APIを使用していますが、他のLLMプロバイダーも使用可能です。
from google.colab import userdata
import os
os.environ["GEMINI_API_KEY"] = userdata.get('GEMINI_API_KEY')
from pydantic_ai import Agent
from pydantic_ai.models.gemini import GeminiModel
model = GeminiModel('gemini-2.0-flash', provider='google-gla')
基本:構造化出力
まずはPydantic AIの基本的な使い方として、構造化された出力を得る例を見てみましょう。
from pydantic import BaseModel
from pydantic_ai import Agent
class CityLocation(BaseModel):
city: str
country: str
# CityLocation で構造化
agent = Agent(
model,
result_type=CityLocation
)
# Q1: 2012年のオリンピック開催都市はどこ?
question1 = "Where were the olympics held in 2012?"
result1 = agent.run_sync(question1)
print("[Q1]", question1)
print("[A1]", result1.data) # -> CityLocation型
print("Usage1:", result1.usage())
このように、LLMの出力をPydanticモデルとして定義することで、型安全な結果を得ることができます。
実装: マルチエージェントによるじゃんけん
プレイヤーエージェントの定義
まず、じゃんけんをするプレイヤーエージェントを作成します。
system_prompt_player = """\
あなたはじゃんけんプレイヤーです。「rock」(グー)、「paper」(パー)、または「scissors」(チョキ)のいずれかを
選んでください。選択したら、単にその選択だけを返してください。
例: 「rock」または「paper」または「scissors」
"""
# プレイヤーエージェントを作成
player_a = Agent(
model,
deps_type=str,
system_prompt=system_prompt_player,
)
player_b = Agent(
model,
deps_type=str,
system_prompt=system_prompt_player,
)
審判エージェントの定義
次に、勝敗を判定する審判エージェントを作成します。
system_prompt_referee = """\
あなたはじゃんけん(rock-paper-scissors)の審判です。
2人のプレイヤーの選択を比較し、ルールに基づいて勝者を判定します。
ルール:
- Rock(グー)はScissors(チョキ)に勝つ
- Scissors(チョキ)はPaper(パー)に勝つ
- Paper(パー)はRock(グー)に勝つ
- 同じ選択の場合は引き分け
プレイヤー1の名前と選択、プレイヤー2の名前と選択が与えられるので、
それに基づいて勝者を判定し、結果を説明してください。
"""
# 審判エージェントを作成
referee = Agent(
model,
deps_type=dict,
system_prompt=system_prompt_referee,
)
じゃんけんの実行
実際にじゃんけんを実行してみましょう。
# プレイヤーAの選択を取得
player_a_result = player_a.run_sync('じゃんけんをしましょう。何を出しますか?', deps='Yashar')
player_a_choice = player_a_result.output.strip().lower()
# プレイヤーBの選択を取得
player_b_result = player_b.run_sync('じゃんけんをしましょう。何を出しますか?', deps='Anne')
player_b_choice = player_b_result.output.strip().lower()
print(f"プレイヤーA (Yashar)の選択: {player_a_choice}")
print(f"プレイヤーB (Anne)の選択: {player_b_choice}")
# 審判に判定してもらう - 両プレイヤーの情報を明示的に渡す
referee_input = f"""
プレイヤー1の名前: Yashar
プレイヤー1の選択: {player_a_choice}
プレイヤー2の名前: Anne
プレイヤー2の選択: {player_b_choice}
上記の情報に基づいて、勝者を判定してください。
"""
referee_result = referee.run_sync(referee_input, deps={})
print("\n審判の判定:")
print(referee_result.output)
実行結果
プレイヤーA (Yashar)の選択: paper
プレイヤーB (Anne)の選択: rock
審判の判定:
Yashar (paper) は Anne (rock) に勝ちます。なぜなら、Paper(パー)はRock(グー)に勝つからです。
**結果:Yashar の勝ち!**
実装のポイント
1. エージェントの独立性
各エージェントは独自のシステムプロンプトと役割を持ち、それぞれが独立して動作します。
2. 責任の分離
- プレイヤーエージェント:じゃんけんの手を選択する責任
- 審判エージェント:勝敗を判定する責任
このように責任を明確に分離することで、シンプルで理解しやすいシステムになります。
3. deps(依存関係)の活用
deps
パラメータを使用して、エージェントに追加のコンテキスト(プレイヤー名など)を渡すことができます。
4. 型安全性
Pydanticの型システムを活用することで、エージェント間のデータやり取りが型安全になります。
マルチエージェントアプローチの利点
マルチエージェントアプローチでは、各エージェントが独立した役割を持つことで責任が明確に分離されます。プレイヤーは手の選択に、審判は勝敗判定に専念できるため、システムの拡張や変更が容易になります。また、実際のじゃんけんゲームと同じ構造を再現しているため、コードの理解が直感的になります。
拡張のアイデア
このシステムは様々な方向に拡張できます。複数のプレイヤーによるトーナメント戦の実装、対戦履歴を分析して相手の傾向を学習する戦略的なエージェントの開発、StreamlitやGradioを使用した対話型UIの追加などが考えられます。さらに、あいこが続いた場合の特殊ルールの導入や、勝率・手の使用頻度の統計分析を行うことで、より高度なゲームシステムに発展させることができます。
まとめ
AIエージェントが急速に進化する中、「じゃんけん」という誰もが知るシンプルなゲームでその可能性を探ってみました。プログラムで簡単に実装できる内容ですが、あえてLLMとPydantic AIを使うことで、マルチエージェントシステムの本質が見えてきます。
各エージェントに明確な役割を与え、責任を分離することで、単純なじゃんけんも拡張性の高いシステムに変貌します。この考え方は、カスタマーサポートやデータ処理パイプラインなど、実務での複雑な問題解決にも応用できる強力なアプローチです。
ぜひこのシンプルな例を出発点に、独自のAIエージェントシステムを作ってみてください!
参考資料
感想
Pydantic AIでじゃんけんAIを作ってみて感じたのは、「プログラムなのか自然言語なのか」「非構造なのか構造化なのか」の境界線のコントロールが想像以上に難しいということ。
こんなシンプルなゲームでも、どこまでLLMに任せてどこからコードで制御するか、その判断が設計の要になる。
AIシステム設計の本質的な難しさと面白さがここにある気がする。
Views: 2