LESSON

演習:診断支援エージェントを構築しよう

「設計は整った。LangGraphで診断支援エージェントを組み上げよう。」

田中VPoEが開発環境を開く。

「画像分類、所見生成、リスク判定、レポート生成まで一気通貫のエージェントを実装してくれ。」

ミッション概要

LangGraphを使って、画像診断支援AIエージェントを構築する。Kaggle Chest X-Ray / Plant Pathologyデータセットで動作確認する。

前提条件

  • Python 3.10+、PyTorch、LangGraph
  • 画像分類モデル(ResNet Fine-tuning済み)
  • OpenAI API(GPT-4o)

Mission 1: ツール実装(40分)

以下のツールを実装せよ。

  1. classify_image: ResNet分類 + Grad-CAM生成
  2. generate_findings: VLMによる構造化所見
  3. assess_risk: リスクレベル判定
解答例
@tool
def classify_image(image_path: str) -> dict:
    """画像を分類"""
    result = classifier.predict(image_path)
    grad_cam = generate_grad_cam(image_path, classifier.model)
    result['grad_cam_path'] = grad_cam
    return result

@tool
def generate_findings(image_path: str, classification_json: str) -> str:
    """所見を生成"""
    import json
    classification = json.loads(classification_json)
    prompt = f"分類: {classification['class']}(確信度: {classification['confidence']}\n構造化された所見を生成"
    return call_vlm(image_path, prompt)

@tool
def assess_risk(severity: int, confidence: float) -> dict:
    """リスク判定"""
    risk_score = severity * 0.6 + (1 - confidence) * 0.4 * 3
    if risk_score >= 2.5:
        return {'risk_level': 'critical', 'urgency': '即時'}
    elif risk_score >= 1.5:
        return {'risk_level': 'high', 'urgency': '優先'}
    elif risk_score >= 0.8:
        return {'risk_level': 'medium', 'urgency': '通常'}
    return {'risk_level': 'low', 'urgency': '経過観察'}

Mission 2: LangGraphワークフロー構築(40分)

以下を実装せよ。

  1. DiagnosisAgentState の定義
  2. 各ノード(分類、所見、リスク、レポート生成)
  3. conditional_edges による専門家レビュー分岐
  4. グラフのコンパイルと実行
解答例
from langgraph.graph import StateGraph, END

def classify_node(state):
    result = classify_image.invoke({"image_path": state['image_path']})
    return {'classification': result}

def findings_node(state):
    findings = generate_findings.invoke({
        "image_path": state['image_path'],
        "classification_json": json.dumps(state['classification']),
    })
    return {'findings': findings}

def risk_node(state):
    result = assess_risk.invoke({
        "severity": 2, "confidence": state['classification']['confidence'],
    })
    needs_review = result['risk_level'] in ('critical', 'high')
    return {'risk_level': result['risk_level'], 'needs_expert_review': needs_review}

def report_node(state):
    report = f"""
    === 診断支援レポート ===
    分類: {state['classification']['class']}
    確信度: {state['classification']['confidence']}
    リスク: {state['risk_level']}
    所見: {state['findings']}
    """
    return {'report': report}

def route_review(state):
    return "expert_review" if state['needs_expert_review'] else "report"

graph = StateGraph(DiagnosisAgentState)
graph.add_node("classify", classify_node)
graph.add_node("findings", findings_node)
graph.add_node("risk", risk_node)
graph.add_node("report", report_node)
graph.add_node("expert_review", lambda s: {'messages': [AIMessage(content="専門家レビューを要請")]})
graph.set_entry_point("classify")
graph.add_edge("classify", "findings")
graph.add_edge("findings", "risk")
graph.add_conditional_edges("risk", route_review)
graph.add_edge("report", END)
graph.add_edge("expert_review", "report")
app = graph.compile()

Mission 3: テストと品質検証(40分)

以下を実施せよ。

  1. 正常画像、軽度異常、重度異常の各ケースでテスト
  2. Grad-CAMの注目領域と所見の整合性を確認
  3. リスク判定の妥当性を検証
解答例
=== テスト結果 ===

| ケース | 分類 | 確信度 | リスク | 専門家レビュー | Grad-CAM整合 |
|--------|------|--------|--------|---------------|-------------|
| 正常 | normal | 0.95 | low | 不要 | OK |
| 軽度 | mild | 0.82 | medium | 不要 | OK |
| 重度 | severe | 0.91 | critical | 必要 | OK |
| 不明瞭 | mild | 0.45 | high | 必要(低確信度) | 要確認 |

所見: 4ケース中4ケースで構造化フォーマットに準拠
Grad-CAM: 3ケースで注目領域と所見が整合、1ケースは追加確認が必要
リスク判定: 全ケースで妥当な判定

達成度チェック

  • 3つのツールを実装した
  • LangGraphワークフローをコンパイル・実行できた
  • 専門家レビュー分岐が正しく動作した
  • 3ケース以上でテスト・検証した
  • Grad-CAMと所見の整合性を確認した

推定所要時間: 120分