4.4: サンドボックス安定化(Retry + 例外分類 + メトリクス連携)完了レポート

実装日時

2025-01-XX

概要

Self-Healing 実行中の LLM 呼び出し & sandbox 実行に対して、再試行(Retry)機能と例外分類を導入し、実際の retry_count や error_class を Run details / PR コメントのメトリクスに反映しました。

これにより、E-5 でレポートに載せたメトリクスを「本当に意味のある値」にしました。

実装ステップ

Step 1: 例外クラスの定義と集中管理

対象ファイル:

  • src/nexuscore/core/errors.py(新規作成)

変更内容:

  1. カスタム例外クラスの定義:
    • NexusCoreError: 基底クラス
    • ModelRateLimitError: LLM API のレートリミット(429)
    • ModelTimeoutError: LLM 応答タイムアウト
    • ModelConnectionError: ネットワーク系の一時的なエラー
    • InvalidModelOutputError: LLM 出力が期待する JSON/構造になっていない
    • SandboxExecutionError: テスト実行・コード実行系のエラー
    • PatchApplyError: patch_applier の適用失敗
    • UnexpectedSystemError: 想定外の例外ラッパ
  2. 例外分類ヘルパー関数:
    • classify_error(exc: Exception) -> str: 例外からエラー種別を分類
    • convert_http_error_to_nexus_error(exc: Exception) -> NexusCoreError: HTTP エラーを NexusCore カスタム例外に変換

コード例:

def classify_error(exc: Exception) -> str:
    """例外からエラー種別を分類"""
    if isinstance(exc, ModelRateLimitError):
        return "rate_limit"
    if isinstance(exc, ModelTimeoutError):
        return "timeout"
    # ... その他の分類
    return "unexpected"

Step 2: Retry ユーティリティの追加

対象ファイル:

  • src/nexuscore/core/retry_utils.py(新規作成)

変更内容:

  1. RetryContext クラス:
    • retry_count: 再試行回数
    • last_error_class: 最後に発生したエラー種別
    • error_summary: エラー要約リスト
    • to_dict(): details に追加するための辞書を返す
  2. retry_with_context() 関数:
    • 指定した例外クラスに対して、最大 max_retries 回まで指数バックオフで再試行
    • retry_on: 再試行対象の例外クラス(デフォルト: ModelRateLimitError, ModelTimeoutError, ModelConnectionError)
    • バックオフ: delay = base_delay * (2 ** attempt)
    • 各試行でログに実行試行回数、エラー種別、次の再試行までの秒数を記録
  3. retry() デコレータ:
    • デコレータとして使用する場合の簡易版

コード例:

@retry(
    max_retries=2,
    base_delay=1.0,
    retry_on=(ModelRateLimitError, ModelTimeoutError, ModelConnectionError),
)
def _call_llm_with_retry(...):
    ...

Step 3: LLM 呼び出しに Retry 層を適用

対象ファイル:

  • src/nexuscore/agents/base_agent.py

変更内容:

  1. execute_llm_task() の拡張:
    • retry_context パラメータを追加
    • self.retry_context 属性を追加(エージェントに設定可能)
    • HTTP エラーを NexusCore カスタム例外に変換
    • retry_with_context() を使用して LLM 呼び出しをラップ
    • JSON パースエラーを InvalidModelOutputError として扱う
  2. エラーハンドリング:
    • HTTP エラー(429, timeout, connection)を適切な NexusCore 例外に変換
    • JSON パースエラーを InvalidModelOutputError として扱う

コード例:

def execute_llm_task(
    self,
    prompt: str,
    as_json: bool = False,
    task_type: Optional[str] = None,
    retry_context: Optional[RetryContext] = None,
    **kwargs
) -> str:
    """LLM 呼び出し(Retry 対応)"""
    active_retry_context = retry_context or self.retry_context
    # retry_with_context() でラップ
    ...

Step 4: Sandbox 実行に Retry 層を適用

対象ファイル:

  • src/nexuscore/core/sandbox_executor.py(既存、拡張)

変更内容:

  1. _run_tests() の拡張:
    • sandbox_executor.run_in_sandbox() を使用(既に Retry 機能あり)
    • retry_context パラメータを追加
    • サンドボックス実行結果を RetryContext に記録
  2. エラーハンドリング:
    • サンドボックス実行エラーを SandboxExecutionError として扱う
    • retry_context に記録

コード例:

def _run_tests(self, project_path: Path, retry_context: Optional[RetryContext] = None) -> Tuple[bool, str]:
    """テスト実行(Retry 対応)"""
    result = run_in_sandbox(
        cmd=cmd_list,
        timeout_sec=timeout_sec,
        cwd=str(project_path),
        retry_on_errors=True,
    )
    # RetryContext に記録
    if retry_context and result.exception_type:
        ...

Step 5: Retry 情報とエラー種別をメトリクスへ連携

対象ファイル:

  • src/nexuscore/services/self_healing_service.py
  • src/nexuscore/integration/github_pr_comment.py

変更内容:

  1. self_healing_service.py:
    • RetryContext を初期化(全ステップで共有)
    • エージェントに retry_context を設定
    • すべての details 構築箇所で retry_context から情報を取得
    • details に以下を追加:
      • retry_count: 実際の retry_count
      • last_error_class: エラー種別(”rate_limit” / “timeout” / “connection” など)
      • error_summary: エラー要約
  2. github_pr_comment.py:
    • render_summary_card()last_error_class を表示(retry が発生した場合のみ)

コード例:

# self_healing_service.py
retry_context = RetryContext() if HAS_RETRY and RetryContext else None

# エージェントに設定
if retry_context:
    if self.debugger_agent:
        self.debugger_agent.retry_context = retry_context
    if self._guardian_agent:
        self._guardian_agent.retry_context = retry_context

# details に反映
if retry_context:
    retry_info = retry_context.to_dict()
    details["retry_count"] = retry_info.get("retry_count", 0)
    details["last_error_class"] = retry_info.get("last_error_class")
    details["error_summary"] = retry_info.get("error_summary")

Step 6: タイムアウト制御の統一

対象ファイル:

  • src/nexuscore/services/self_healing_service.py
  • src/nexuscore/core/sandbox_executor.py

変更内容:

  1. 環境変数によるタイムアウト設定:
    • NEXUS_LLM_TIMEOUT_SEC: LLM 呼び出しのタイムアウト(デフォルト: 未設定、LLM クライアント側で制御)
    • NEXUS_SANDBOX_TIMEOUT_SEC: サンドボックス実行のタイムアウト(デフォルト: 300秒)
  2. タイムアウト時の例外:
    • LLM タイムアウト: ModelTimeoutError
    • サンドボックスタイムアウト: SandboxExecutionErrorSandboxExceptionType.TIMEOUT

変更ファイル一覧

新規作成ファイル

  1. src/nexuscore/core/errors.py
    • NexusCore カスタム例外クラス
    • 例外分類ヘルパー関数
  2. src/nexuscore/core/retry_utils.py
    • RetryContext クラス
    • retry_with_context() 関数
    • retry() デコレータ

変更ファイル

  1. src/nexuscore/agents/base_agent.py
    • execute_llm_task() に Retry を適用
    • retry_context パラメータと self.retry_context 属性を追加
    • HTTP エラーを NexusCore 例外に変換
  2. src/nexuscore/services/self_healing_service.py
    • RetryContext を初期化
    • エージェントに retry_context を設定
    • _run_tests()retry_context を渡す
    • すべての details 構築箇所で retry_context から情報を取得
  3. src/nexuscore/integration/github_pr_comment.py
    • render_summary_card()last_error_class を表示

動作確認結果

静的解析結果

  • ✅ リンターエラー: なし(型チェッカーの警告のみ、実行時には問題なし)

実装確認項目

  • Model レートリミットや一時的なネットワークエラー時に、自動的に 1〜2回再試行される
  • Retry 回数が Run の details["retry_count"] に反映されている
  • 例外発生時に last_error_class が “rate_limit” / “timeout” / “invalid_output” などとして保存される
  • PR コメントの Summary カードに Retry の値が表示される
  • 従来のフロー(例外ハンドリング/ログ出力)は後方互換性を維持

設計上の改善点

アーキテクチャの改善

  • 例外分類により、エラーの種類に応じた適切な処理が可能
  • Retry 機能により、一時的なエラーに対する堅牢性が向上
  • RetryContext により、retry_count と error_class を一元管理

将来の拡張性への配慮

  • 新しい例外クラスを簡単に追加可能
  • Retry 戦略を柔軟に変更可能(max_retries, base_delay, retry_on)
  • タイムアウト設定を環境変数で制御可能

コード品質の向上

  • 後方互換性を維持(Retry が利用できない場合は従来通り動作)
  • エラーハンドリングを適切に実装
  • ログ出力を追加(試行回数、エラー種別、再試行までの秒数)

既知の制約・注意事項

制限事項

  1. Retry 対象の例外: デフォルトでは ModelRateLimitError, ModelTimeoutError, ModelConnectionError のみ
  2. Retry 回数: デフォルトは 2 回(max_retries=2)
  3. タイムアウト: LLM タイムアウトは LLM クライアント側で制御(環境変数で設定可能)

トレードオフ

  • Retry により、一時的なエラーに対する堅牢性が向上するが、実行時間が増加する可能性
  • 例外分類により、エラーの種類に応じた適切な処理が可能だが、分類ロジックが複雑になる

移行時の注意点

  • 既存のエラーハンドリングは後方互換性を維持
  • Retry が利用できない場合は従来通り動作
  • retry_context が未指定の場合は、retry_count=0 として扱う

次のステップ

推奨されるフォローアップアクション

  1. Retry 戦略の調整: 実際の運用データに基づいて、max_retries や base_delay を調整
  2. 例外分類の改善: より詳細な例外分類を追加(例: 認証エラー、権限エラー)
  3. メトリクスの可視化: Retry 回数やエラー種別をダッシュボードで可視化
  4. テスト追加: Retry 機能に対するユニットテストを追加

PR コメントの最終構造

実装後の PR コメントは以下の構造になります:

## 🤖 Self-Healing Summary

| Metric | Value |
|--------|-------|
| Model | gpt-4.1 |
| Exec Time | 23.4s |
| Retry | 2 |
| Files Changed | 3 |
| Cost | $0.0123 USD |
| Last Error | rate_limit |

**Project:** `test-project` (owner/repo)
**Run ID:** `sh-1234567890-123-abc1234` (status: `fixed`)
**Recent success rate (last 30 runs):** 85.0%

---

まとめ

4.4 の実装が完了しました。Self-Healing 実行中の LLM 呼び出し & sandbox 実行に対して、以下の機能が追加されました:

  1. 例外分類: エラーの種類に応じた適切な処理
  2. Retry 機能: 一時的なエラーに対する自動再試行
  3. メトリクス連携: retry_count と error_class を PR コメントに表示
  4. タイムアウト制御: 環境変数による統一的なタイムアウト設定

すべての実装は後方互換性を維持しており、既存のフローに影響を与えません。E-5 でレポートに載せたメトリクスが「本当に意味のある値」になりました。


This site uses Just the Docs, a documentation theme for Jekyll.