AIツールの舞台裏:Planningモジュールの作り方 〜生成AIの思考を設計する〜
1. はじめに:なぜPlanningが必要なのか?
最近、ChatGPTやCopilotなどのAIツールは、単なる質問応答だけでなく、「旅行の計画を立ててください」「この仕様書をもとにコードを書いてください」といった複雑で多段階のタスクをこなすようになりました。これらは、内部で「まず目的地をリストアップし、次に交通手段を検討し、その後予算配分を...」というように、タスクを細かいステップに分解し、順序立てて実行しています。この「分解」と「順序立て」を担当するのが、まさに 「Planningモジュール」 の核心です。
本記事では、このPlanningモジュールを自前で実装する方法について、理論だけでなく、クラウドネイティブな環境での実践的な実装例とノウハウを交えて紹介します。
2. Planningモジュールとは?
Planningモジュールは、大きな目標(Goal)を入力とし、それを達成するための一連の具体的なサブタスク(Plan)を出力するソフトウェアコンポーネントです。AIシステムの「実行エンジン」の直前で動作し、何を、どの順番で実行すべきかの青写真を提供します。
キーコンセプト
- Goal: 「PythonでTODOリストAPIを作成する」といった最終的な目標。
-
Plan:
["1. FastAPIのプロジェクトを作成", "2. データモデル(TodoItem)を定義", "3. GET/POSTエンドポイントを実装", ...]
といったタスクのリスト。 - Agent: Planに基づいて実際に行動(コード実行、API呼び出しなど)を起こす実行主体。
3. 実装例:LLMを活用したシンプルなPlanner
最近では、高い推論能力を持つ大規模言語モデル(LLM)自体をPlannerとして利用するのが一般的です。ここでは、PythonとOpenAI APIを使用したシンプルながら強力なPlannerの実装例を示します。
環境構築
まずは必要なパッケージをインストールします。クラウド関数(AWS LambdaやGCP Cloud Functions)での実行も見据えて、シンプルに保ちます。
pip install openai
コアモジュールの実装
import openai
import json
from typing import List, Dict
class SimpleOpenAIPlanner:
"""
OpenAIのGPTモデルを使用して、GoalからPlanを生成するシンプルなPlanner
"""
def __init__(self, api_key: str, model: str = "gpt-3.5-turbo"):
openai.api_key = api_key
self.model = model
# プロンプトを外部設定ファイルから読み込むのも良い practice
self.plan_prompt_template = """
あなたは優秀なソフトウェアアーキテクトです。以下のゴールを達成するための具体的なステップに分解してください。
ステップはできるだけ細かく、明確にし、順序立ててください。出力はJSON形式の配列で、各要素がステップの文字列であるものとします。
ゴール: {goal}
出力例: ["ステップ1", "ステップ2", "ステップ3"]
JSON出力:
"""
def generate_plan(self, goal: str) -> List[str]:
"""Goalを元にPlanを生成する"""
try:
# LLMに対するプロンプトを組み立てる
prompt = self.plan_prompt_template.format(goal=goal)
response = openai.ChatCompletion.create(
model=self.model,
messages=[
{"role": "system", "content": "あなたはタスクを細かいステップに分解する専門家です。"},
{"role": "user", "content": prompt}
],
temperature=0.1, # 創造性を低くし、再現性を高める
max_tokens=1000
)
# LLMの出力からテキストを取得
content = response.choices[0].message['content'].strip()
# JSON形式の出力をパースする
plan_steps = json.loads(content)
return plan_steps
except json.JSONDecodeError as e:
print(f"LLM出力のJSONパースに失敗しました: {e}. 出力内容: {content}")
# フォールバック: 改行で分割するなど
return [f"Error: Generated plan was not valid JSON. Raw output: {content}"]
except Exception as e:
print(f"Plan生成中にエラーが発生しました: {e}")
return []
# 使用例
if __name__ == "__main__":
import os
planner = SimpleOpenAIPlanner(api_key=os.getenv("OPENAI_API_KEY"))
goal = "PythonとFastAPIを使って、認証機能付きのTODOリストAPIを実装する"
plan = planner.generate_plan(goal)
print("生成されたプラン:")
for i, step in enumerate(plan, 1):
print(f"{i}. {step}")
実行結果例
生成されたプラン:
1. プロジェクトのディレクトリを作成し、Python仮想環境をセットアップする
2. FastAPI, SQLAlchemy, Pydanticなどの必要なライブラリをインストールする(pip install fastapi uvicorn sqlalchemy python-jose[cryptography] passlib[bcrypt])
3. データベースモデル(User, TodoItem)を定義する
4. Pydanticスキーマ(UserCreate, UserOut, TodoCreate, TodoOut)を定義する
5. データベース接続とセッションの設定を行う
6. パスワードのハッシュ化を行うユーティリティ関数を作成する
7. JWTトークンを生成・検証するユーティリティ関数を作成する
8. ユーザー登録(signup)とログイン(login)のエンドポイントを実装する
9. 認証が必要なTODOアイテムのCRUDエンドポイント(作成、読み取り、更新、削除)を実装する
10. ミドルウェアでJWTトークンを検証する
4. 実践的なTipsとよくある落とし穴
✅ Tips
- プロンプトエンジニアリング: LLMベースのPlannerの性能はプロンプトで決まります。出力形式(今回のJSONなど)を明確に指示し、具体例(Few-shot Learning)を含めると精度が劇的に向上します。
-
温度(Temperature)パラメータ: Planningでは再現性が重要です。
temperature
は0.1〜0.3程度に設定し、ランダム性を抑えましょう。 -
フォールバック処理: LLMの出力は必ずしも正確ではありません。JSONのパースに失敗した時のためのエラーハンドリングは必須です(実装例内の
try-except
のように)。 - クラウドコスト最適化: OpenAI APIの呼び出しはコストがかかります。プランをキャッシュする(同じGoalなら同じPlanを返す)仕組みを入れると、特に繰り返し実行される環境では非常に有効です。
❌ よくある落とし穴
- 無限ループプラン: 「ステップ1: ステップ2を実行する、ステップ2: ステップ1を実行する」といった非現実的なプランが生成されることがあります。プロンプトで「現実的で実行可能なステップ」と明記するのが予防策です。
- コンテキスト長不足: 非常に複雑なGoalの場合、生成するステップ数が多すぎてLLMの出力トークン数制限を超えることがあります。この場合は、Planを複数の階層に分ける(大まかなPlanを生成→各ステップをさらに詳細化)などの対策が必要です。
- 過剰な依存: Plannerは完璧ではありません。生成されたプランは必ず実行エージェントがチェックし、場合によっては人間の確認を入れる仕組み(Human-in-the-Loop)を設計すべきです。
5. 発展:より現実的なシステムへの応用
シンプルなPlannerを土台に、より現実的なAIエージェントシステムを構築できます。
- Re-Planning(再計画): エージェントがタスク実行に失敗した場合、そのエラー結果をフィードバックとしてPlannerに渡し、プラン自体を修正させます。
- ツール使用(Function Calling)との連携: 生成したプランの各ステップが「Web検索をする」「コードを実行する」などの具体的なツール(関数)に対応するように設計します。OpenAIのFunction Calling機能と連携させるのが効果的です。
- クラウドインフラとの統合: Plannerをサーバーレス関数(AWS Lambda)としてデプロイし、APIゲートウェイ経由で呼び出す。プランの実行状態や結果は、DynamoDBなどのマネージドデータベースに保存するといった構成が現実的です。
6. 結論
✅ 优点
- 汎用性の高さ: LLMの力を借りることで、あらゆるドメインのタスクに対して柔軟にプランを生成できる。
- 開発効率: 自前で膨大なif文やルールベースのロジックを書く必要がなく、比較的少ないコードで強力な機能を実現できる。
- 自然言語インターフェース: ユーザーは自然な言葉で複雑なタスクを指示できる。
⚠️ 缺点と課題
- コストとレイテンシ: LLM APIの呼び出しにはコストと時間がかかる。リアルタイム性が要求される場面には不向き。
- 出力の不安定性: LLMは時に不合理なプランを生成するため、常に検証と監視の機制が必要。
- セキュリティリスク: ユーザー入力(Goal)を直接LLMに送信するため、機密情報の扱いには十分な注意が必要。
未来展望
Planningモジュールは、AIが単なるチャットボットを超えて、真に自律的に複雑な作業を完了させる「AIエージェント」の実現に不可欠な技術です。今後は、より軽量で specialized なモデルの登場、LangChainやLlamaIndexといったフレームワークとの連携の深化、そして信頼性の高い完全自律実行への発展が期待されます。
まずは小さなGoalからで構いません。本記事で紹介したシンプルなPlannerを実装し、AIの「思考」の一端を体感してみてください。そこから、ご自身の業務やプロジェクトにどう応用できるか、その可能性が広がっていくはずです。