分析エージェントの設計
「モデルができた。だが、これをデータサイエンティストだけが使えるツールにしてどうする?」
田中VPoEが問いかける。
「営業やCSチームが『この顧客は離反しそうですか?理由は?どう対策すればいいですか?』と聞いたら、自然言語で答えてくれるAIエージェントにしたい。LangGraphを使って実装しよう。」
AIエージェントとは
AIエージェント = LLM + ツール + ワークフロー
- LLM: ユーザーの意図を理解し、自然言語で応答
- ツール: データ取得、推論、分析、可視化の実行
- ワークフロー: ツール呼び出しの順序と条件分岐を制御
離反分析エージェントの要件
| 機能 | 入力 | 出力 |
|---|---|---|
| 顧客の離反リスク予測 | 顧客ID or 属性 | 離反確率、リスクレベル |
| 離反要因の説明 | 顧客ID | SHAP値に基づく要因Top5 |
| リテンション施策の提案 | 顧客ID | 具体的な施策リスト |
| セグメント分析 | セグメント条件 | セグメント別離反率、統計 |
| バッチ予測 | 顧客リスト | リスクスコア一覧 |
ツールの分解
エージェントが使用するツールを設計する。
# ツール一覧
tools = {
"get_customer_data": {
"description": "顧客IDからデータを取得する",
"input": "customer_id: str",
"output": "dict (顧客属性)",
},
"preprocess_data": {
"description": "生データを前処理してモデル入力形式に変換する",
"input": "raw_data: dict",
"output": "np.ndarray (特徴量ベクトル)",
},
"predict_churn": {
"description": "離反確率を予測する",
"input": "features: np.ndarray",
"output": "dict (probability, risk_level)",
},
"explain_prediction": {
"description": "SHAP分析で予測の要因を説明する",
"input": "features: np.ndarray",
"output": "list[dict] (feature, shap_value, direction)",
},
"suggest_retention": {
"description": "リテンション施策を提案する",
"input": "shap_results: list, customer_data: dict",
"output": "list[dict] (action, priority, expected_impact)",
},
"visualize_analysis": {
"description": "分析結果を可視化する",
"input": "analysis_results: dict",
"output": "str (画像パス)",
},
}
ワークフロー設計
ユーザー入力
↓
[意図分類] → "個別顧客分析" / "セグメント分析" / "バッチ予測"
↓
┌─────────────────────────────────┐
│ 個別顧客分析の場合: │
│ 1. get_customer_data │
│ 2. preprocess_data │
│ 3. predict_churn │
│ 4. explain_prediction │
│ 5. suggest_retention │
│ 6. visualize_analysis │
│ 7. 結果を自然言語で回答 │
└─────────────────────────────────┘
状態管理の設計
LangGraphではStateとして管理するデータ構造を定義する。
from typing import TypedDict, Optional, Annotated
from operator import add
class ChurnAnalysisState(TypedDict):
# ユーザー入力
messages: Annotated[list, add]
query_type: Optional[str] # "individual", "segment", "batch"
# データ
customer_id: Optional[str]
raw_data: Optional[dict]
processed_features: Optional[list]
# 予測結果
churn_probability: Optional[float]
risk_level: Optional[str] # "HIGH", "MEDIUM", "LOW"
# 分析結果
shap_explanations: Optional[list]
retention_actions: Optional[list]
visualization_path: Optional[str]
# エラーハンドリング
error: Optional[str]
ノード設計
# 各ノードの責務
nodes = {
"classify_intent": "ユーザーの意図を分類する",
"fetch_data": "顧客データを取得する",
"preprocess": "データを前処理する",
"predict": "離反確率を予測する",
"explain": "SHAP分析で要因を説明する",
"recommend": "リテンション施策を提案する",
"visualize": "結果を可視化する",
"respond": "自然言語で回答を生成する",
"handle_error": "エラーを処理する",
}
条件分岐の設計
# 分岐ロジック
def route_by_intent(state: ChurnAnalysisState) -> str:
"""意図に応じて次のノードを決定"""
if state.get("error"):
return "handle_error"
query_type = state.get("query_type")
if query_type == "individual":
return "fetch_data"
elif query_type == "segment":
return "segment_analysis"
elif query_type == "batch":
return "batch_prediction"
return "handle_error"
def route_after_prediction(state: ChurnAnalysisState) -> str:
"""予測後の分岐"""
if state.get("error"):
return "handle_error"
if state["risk_level"] == "HIGH":
return "explain" # 高リスクのみ詳細分析
return "respond" # 低リスクは即回答
エージェントのアーキテクチャ
┌───────────┐
│ classify │
│ intent │
└─────┬─────┘
┌─────────┼─────────┐
▼ ▼ ▼
┌──────────┐ ┌──────┐ ┌───────┐
│individual│ │segment│ │ batch │
└────┬─────┘ └──┬───┘ └───┬───┘
▼ ▼ ▼
┌──────────┐ │ │
│fetch_data│ │ │
└────┬─────┘ │ │
▼ │ │
┌──────────┐ │ │
│preprocess│ │ │
└────┬─────┘ │ │
▼ │ │
┌──────────┐ │ │
│ predict │ │ │
└────┬─────┘ │ │
HIGH │ LOW │ │
┌────┴────┐ │ │
▼ ▼ │ │
┌─────────┐ │ │ │
│ explain │ │ │ │
└────┬────┘ │ │ │
▼ │ │ │
┌──────────┐ │ │ │
│recommend │ │ │ │
└────┬─────┘ │ │ │
▼ ▼ ▼ ▼
┌──────────────────────────┐
│ respond │
└──────────────────────────┘
まとめ
| 項目 | ポイント |
|---|---|
| エージェント構成 | LLM + ツール + ワークフロー |
| ツール数 | 6つ(データ取得/前処理/推論/説明/施策/可視化) |
| State管理 | TypedDictで型安全に管理 |
| 条件分岐 | 意図分類、リスクレベルで分岐 |
| アーキテクチャ | DAG(有向非巡回グラフ)で設計 |
チェックリスト
- AIエージェントの3要素(LLM/ツール/ワークフロー)を説明できる
- 必要なツールを分解・定義できる
- State構造を設計できる
- 条件分岐のロジックを設計できる
- ワークフローのDAGを描ける
次のステップへ
エージェントの設計ができた。次は各ツールを実装していこう。
推定読了時間: 30分