GuidesOneMux

APIインシデント診断用のLangGraphエージェントを構築する

読み取り専用の診断ツールを呼び出し、実行を制限し、失敗を明示して、リスクのある操作の前に一時停止するLangGraphインシデント診断エージェントを構築します。

AI

要約 · TL;DR

有用なインシデントエージェントは、制御不能な操作を実行するのではなく、証拠を収集するべきです。このチュートリアルでは、読み取り専用の診断ツール、明示的な失敗シグナル、実行範囲の制限、修復前の人による確認を備えたLangGraphワークフローを紹介します。

要点

  • 診断ツールは読み取り専用にし、失敗も含めた構造化データを返します。
  • 実行制限を設定し、インシデントの診断結果ではなく安全上の境界として扱います。
  • 本番環境の状態を変更するツールを使う前に、人の承認を必須にします。
  • interruptを使う場合は、グラフの状態を永続化して一時停止した実行を再開できるようにします。
  • 推測を事実として示さず、ツールの失敗や証拠の不足を報告します。
目次 (8)

方針:診断は自動化し、修復は慎重に行う

APIインシデント対応では、ログ、ヘルスチェック、直近のデプロイ情報から証拠を集めることで、エージェントが作業時間を短縮できます。一方で、サービスの再起動、リリースのロールバック、設定変更を、エージェントが黙って実行してはなりません。より安全な設計では、読み取り専用の診断と副作用のある修復を分け、エージェントの作業範囲を制限し、証拠が取得できなかった場合や不足している場合も担当者に明示します。

これは実践的な設計例であり、テスト済みの統合や本番環境ですぐに利用できるサービスではありません。以下のツール本体は説明用です。実際には、認証を備え、権限を制限した独自のオブザーバビリティクライアントに置き換えてください。

前提条件とワークフロー

Python、アプリケーションで設定済みのLangGraph互換チャットモデル、そして利用中の診断システム用クライアント関数が必要です。この例では、クライアント関数がデータを返すか、例外を発生させることを想定しています。特定のモデルプロバイダー、エンドポイント、ツール統合は前提としていません。

インシデント対応では、次のように範囲を制限したループが役立ちます。

  1. 対象サービスと時間範囲を指定し、事前に定めた少数のシグナルを収集する。
  2. 結果ごとに成功、失敗、利用不可のいずれかを記録する。
  3. モデルに証拠の要約と未解明の点の特定を依頼する。
  4. グラフのステップ数に上限を設け、その範囲で処理を終了する。状態を変更する操作を行う前には、人による確認を求める。

ステータスフィールドが重要なのは、運用上の理由からです。ログ検索の失敗を、該当イベントが見つからなかった正常な検索と同じように扱ってはなりません。

失敗を明示する診断ツールを定義する

ツールの契約は必要最小限に保ちます。サービス名と上限を設けた時間範囲を必須にし、固定クエリで十分な場合はモデルに任意のクエリ実行権限を与えないようにします。結果は構造化データで返し、後続ノードやインシデントレポートで、証拠が空だった場合とツールが失敗した場合を区別できるようにします。

from typing import Literal, TypedDict
from langchain.tools import tool

class Signal(TypedDict):
    status: Literal["ok", "error", "unavailable"]
    source: str
    data: str
    error: str | None


def query_logs(service: str, minutes: int) -> Signal:
    if not 1 <= minutes <= 60:
        return {
            "status": "error", "source": "logs", "data": "",
            "error": "minutes must be between 1 and 60",
        }
    try:
        # Replace with a read-only, scoped observability client call.
        rows = logs_client.search(service=service, minutes=minutes)
        return {
            "status": "ok", "source": "logs",
            "data": str(rows), "error": None,
        }
    except TimeoutError as exc:
        return {
            "status": "unavailable", "source": "logs", "data": "",
            "error": f"timeout: {exc}",
        }

@tool
def inspect_api(service: str, minutes: int = 15) -> dict:
    """Collect scoped, read-only API incident signals."""
    return query_logs(service, minutes)

ヘルスチェックやデプロイ情報についても、同じ形式の結果を返す個別ツールを追加します。あらゆる例外を捕捉して空文字列を返すのは避けてください。統合の不具合を調査できるだけのエラー情報を保持しつつ、ログやモデルのコンテキストに秘密情報や機密性の高いペイロードを含めないようにします。

実行を制限し、未完了の処理を明示する

LangGraphのcreate_agentで構築したエージェントでは、呼び出し時にグラフの再帰制限を設定します。この制限によってグラフのステップ数は抑えられますが、有用な回答が保証されるわけではなく、ツール単位のタイムアウトの代わりにもなりません。周辺アプリケーションで制限への到達を処理し、診断が完了したと見なすのではなく、明確に「未完了」として返してください。

from langchain.agents import create_agent

agent = create_agent(
    model=your_configured_chat_model,
    tools=[inspect_api],
    system_prompt=(
        "Diagnose API incidents using available evidence. "
        "Report each source as ok, error, or unavailable. "
        "Do not claim a cause without supporting evidence. "
        "Do not perform remediation."
    ),
)

try:
    result = agent.invoke(
        {"messages": [{"role": "user", "content":
            "Investigate elevated errors for payments-api over the last 15 minutes."}]},
        config={"recursion_limit": 12},
    )
except Exception as exc:
    # Map known graph-limit and provider/tool failures to your app's
    # incident-run status; do not expose credentials or raw secrets.
    result = {"status": "incomplete", "reason": type(exc).__name__}

制限値は一例であり、あらゆるケースに適した推奨値ではありません。許可するツール数とモデルのターン数に応じて決め、ツール層とアプリケーション層の両方にタイムアウトとリクエストサイズの上限を設けてください。実行ID、対象サービスと時間範囲、実行したツール、ツールのステータス、終了理由を記録します。これらの情報があれば、担当者は「エラーは見つからなかった」と「ログバックエンドがタイムアウトした」を区別できます。

修復の前に人の確認を加える

本番環境の状態を変更するツールを後から追加する場合は、LangChainのhuman-in-the-loopミドルウェアとチェックポインターを使って、その実行を制御します。ドキュメントに記載されたミドルウェアでは、条件に一致するツール呼び出しを一時停止し、承認、編集、拒否、または直接応答を行えます。状態は保存され、判断後に実行を再開できます。本番利用では、プロトタイピング向けに示されているインメモリの選択肢ではなく、永続的なチェックポインターが必要です。LangChainのhuman-in-the-loopドキュメントを参照してください。

実用的な方針として、読み取り専用の診断は中断せずに許可し、再起動、ロールバック、設定変更を行うツールには承認を必須にします。操作を拒否する場合は、提案されたアクションを拒否してください。ドキュメントでは、「respond」は副作用のある呼び出しを拒否するためではなく、ツールとして動作するためのものだと注意されています。編集された引数は、ツール実装側で検証してください。ドキュメントに記載されたミドルウェアは、表示されたスキーマに照らして編集内容を検証しません。

想定しておくべき失敗ケース

  • 結果が空の場合:「サービスは正常です」ではなく、「一致するイベントは返されませんでした」と報告する。
  • ツールのタイムアウトまたは認証失敗: 失敗したソースとエラーの種類を保持し、いつまでも黙って再試行しない。
  • ツール呼び出しの繰り返し: グラフの実行を制限し、ツールへの入力を制約する。再試行を追加する場合は、少数の明示的な再試行ポリシーを設定し、試行回数を示す。
  • interrupt後に再開できない: チェックポインターが設定されていることと、再開時に同じスレッド識別子が使われていることを確認する。元のドキュメントでは、人による確認にチェックポイントが必要とされています。
  • 誤解を招く最終要約: レポート内で各主張の根拠となる収集済みシグナルを示し、利用できなかった情報源と未解決の疑問を列挙する。

インシデント対応のチェックリスト

デプロイ前に、診断ツールが読み取り専用で対象範囲を絞っていること、時間範囲とクエリ量が制限されていること、ツールのエラーを確認できること、グラフの実行回数に上限があること、副作用のある操作ごとに人の判断を待つことを確認します。タイムアウト、結果が空の場合、操作が拒否された場合、中断後に再開する場合の各経路をテストしてください。優れたエージェントは、もっともらしい根本原因を示すだけではありません。実際に得られた証拠と、診断がどこまでしか行えないかも明確にします。

参考資料

よくある質問

LangGraphエージェントの実行を制限するにはどうすればよいですか?

呼び出し設定で再帰制限を設定し、制限到達や実行時エラーを周辺アプリケーションで処理します。さらに、ツール単位のタイムアウトと入力の上限も設けてください。グラフの制限によって診断の完了が保証されるわけではありません。

インシデントエージェントは、診断ツールの失敗をどのように報告すべきですか?

ソース名と、内容を安全に扱えるエラー種別を含め、「error」や「unavailable」などの構造化ステータスを返します。これは、一致するイベントが見つからなかった成功済みの検索とは区別してください。

本番環境を変更するLangGraphツールに承認を必須にするにはどうすればよいですか?

human-in-the-loopミドルウェアを使って対象のツール呼び出しを中断し、チェックポインターを設定してグラフを一時停止・再開できるようにします。読み取り専用ツールは許可し、副作用のあるツールには確認を必須にします。

human-in-the-loopミドルウェアは、編集されたツール引数を検証しますか?

提示されているドキュメントによると、表示されたレスポンススキーマに照らして編集内容を検証することはありません。操作を実行する前に、ツールまたはアプリケーションで引数を検証してください。

関連記事