目次

LLMエージェントのデバッグは通常のプログラムのデバッグより難しい。同じ入力でも異なる結果が出ることがあり、問題が再現しにくいためだ。適切なログ設計と体系的なデバッグアプローチを持つことで、エージェントの問題を効率よく特定・修正できる。

エージェントの典型的な問題パターン

1. 無限ループ・堂々巡り

エージェントが同じツールを繰り返し呼び出したり、同じ思考ステップを繰り返したりするパターンだ。

原因の多く:

  • 停止条件が曖昧でエージェントがタスク完了を判断できない
  • ツールの結果をエージェントが正しく解釈できていない
  • エラーをリカバリしようとして同じ操作を繰り返す

2. ツール呼び出しエラー

エージェントが存在しないツール・パラメータ・関数を呼び出そうとするパターンだ。

原因の多く:

  • ツールのスキーマ定義と実際のツール実装のズレ
  • プロンプトでのツール説明が不十分
  • モデルがハルシネーション(幻覚)でツール名を作り出す

3. 幻覚(Hallucination)

エージェントが存在しない情報を事実として返すパターンだ。特に外部システムへの参照が必要なタスクで発生しやすい。

ログ設計のベストプラクティス

適切なロギングがないと、エージェントが何をしていたかの追跡が困難になる。最低限、以下の情報をログに記録する。

import logging
import json
from datetime import datetime
from typing import Any

# 構造化ログの設定
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("agent")

def log_agent_step(
    step_type: str,
    content: Any,
    metadata: dict = None
) -> None:
    """エージェントの各ステップをログに記録する"""
    log_entry = {
        "timestamp": datetime.now().isoformat(),
        "step_type": step_type,  # "think", "tool_call", "tool_result", "respond"
        "content": content,
        "metadata": metadata or {}
    }
    logger.debug(json.dumps(log_entry, ensure_ascii=False, indent=2))

ステップタイプ別のログ

class AgentLogger:
    def __init__(self, session_id: str):
        self.session_id = session_id
        self.step_count = 0

    def log_thinking(self, thought: str):
        self.step_count += 1
        log_agent_step(
            "think",
            thought,
            {"session_id": self.session_id, "step": self.step_count}
        )

    def log_tool_call(self, tool_name: str, parameters: dict):
        log_agent_step(
            "tool_call",
            {"tool": tool_name, "params": parameters},
            {"session_id": self.session_id, "step": self.step_count}
        )

    def log_tool_result(self, tool_name: str, result: Any, success: bool):
        log_agent_step(
            "tool_result",
            {"tool": tool_name, "result": result, "success": success},
            {"session_id": self.session_id, "step": self.step_count}
        )

ループ検出と安全な停止

無限ループを防ぐには、繰り返しパターンの検出と最大ステップ数の制限を組み合わせる。

class LoopDetector:
    def __init__(self, max_steps: int = 20, window_size: int = 5):
        self.max_steps = max_steps
        self.window_size = window_size
        self.history = []

    def add_step(self, action: str) -> None:
        self.history.append(action)

    def is_looping(self) -> bool:
        """直近のアクションが繰り返しパターンを持つか判定する"""
        if len(self.history) < self.window_size * 2:
            return False

        recent = self.history[-self.window_size:]
        before = self.history[-self.window_size * 2:-self.window_size]
        return recent == before

    def is_max_steps_reached(self) -> bool:
        return len(self.history) >= self.max_steps

    def should_stop(self) -> tuple[bool, str]:
        if self.is_max_steps_reached():
            return True, f"最大ステップ数({self.max_steps})に達しました"
        if self.is_looping():
            return True, "繰り返しパターンを検出しました"
        return False, ""

幻覚の検出と対処

エージェントの回答を別のLLMで検証するダブルチェックパターンが有効だ。

def verify_agent_response(
    claim: str,
    context: str,
    verifier_model: str = "gpt-4o-mini"
) -> dict:
    """エージェントの主張を別のLLMで検証する"""
    prompt = f"""
以下の主張が、提供されたコンテキストに基づいているか検証してください。

【主張】
{claim}

【コンテキスト】
{context}

回答形式:
- verified: true/false
- confidence: 0.0〜1.0
- reason: 判断の根拠
"""
    response = client.chat.completions.create(
        model=verifier_model,
        messages=[{"role": "user", "content": prompt}],
        response_format={"type": "json_object"}
    )
    return json.loads(response.choices[0].message.content)

デバッグ用のトレース可視化

複雑なエージェントのデバッグには、処理のトレースを視覚化することが効果的だ。LangSmithやWeightbiases Tracesなどのツールを使うと、ステップの流れ・各ステップのトークン消費・エラーの発生箇所をグラフィカルに確認できる。

オープンソースではPhoenix(Arize AI)が無料で使えるLLMトレーシングツールとして導入しやすい。

!pip install arize-phoenix openinference-instrumentation-openai

import phoenix as px
from openinference.instrumentation.openai import OpenAIInstrumentor

# トレース収集の開始
px.launch_app()
OpenAIInstrumentor().instrument()

# 以降のOpenAI API呼び出しが自動でトレースされる

まとめ

AIエージェントのデバッグは、適切なログ設計から始まる。ステップタイプ別の構造化ログを記録し、ループ検出機構と最大ステップ数制限を組み合わせることで、無限ループを安全に検出・停止できる。幻覚にはダブルチェックパターン(別モデルによる検証)が有効だ。複雑なエージェントには、PhoenixやLangSmithなどのトレーシングツールを導入することで、問題の特定が格段に楽になる。デバッグのしやすさはエージェント設計の品質に直結するため、ログ設計は実装と並行して考えることを強く推奨する。

免責事項 — 掲載情報は執筆時点のものです。料金・機能は変更される場合があります。最新情報は各公式サイトをご確認ください。