CLAUDE LABEN
FORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられていますFORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられています
記事一覧/API & SDK
API & SDK/2026-04-12上級

Claude Managed Agents のサンドボックス設計 ― 本番環境で安全に自律エージェントを動かす技術

Claude Managed Agents のサンドボックスアーキテクチャを解剖し、本番環境でエージェントを安全に稼働させるためのセキュリティパターンを実装コード付きで解説します。

managed-agents5sandbox2security9production87api38

自律型AIエージェントを本番サービスに組み込むとき、最初にぶつかる壁は「どこまで自由にさせるか」の線引きです。

2026年4月、AnthropicがパブリックベータとしてリリースしたClaude Managed Agentsは、この問題に対する明確な回答を持っています。コンテナベースのサンドボックス、サーバーサイドイベント(SSE)ストリーミング、そしてビルトインツールの組み合わせによって、エージェントの自律性とセキュリティを両立させる設計です。

しかし公式ドキュメントだけでは、本番運用で直面する「コンテナのリソース制限をどう設定するか」「ネットワークアクセスの許可範囲はどこまでが適切か」といった実務的な判断が難しいです。ここでは実際にManaged Agentsを本番環境に導入した経験をもとに、サンドボックスのセキュリティ設計パターンを具体的なコードとともに解説します。

サンドボックスアーキテクチャの3層構造

Managed Agentsのサンドボックスは、単なるDockerコンテナではありません。以下の3つのレイヤーで多層防御を実現しています。

import anthropic
 
client = anthropic.Anthropic()
 
# エージェントの作成時にサンドボックス設定を指定
agent = client.agents.create(
    model="claude-sonnet-4-6",
    instructions="データ分析タスクを実行するエージェント",
    tools=[
        {"type": "code_execution"},
        {"type": "file_read"},
        {"type": "file_write"},
    ],
    # サンドボックス設定
    sandbox={
        "type": "managed",
        "memory_mb": 512,
        "timeout_seconds": 300,
        "network_access": "restricted",
        "allowed_domains": [
            "api.example.com",
            "storage.googleapis.com"
        ]
    }
)

第1層:コンテナ分離は、各エージェントセッションが独立したLinuxコンテナで実行される仕組みです。ファイルシステムは完全に隔離され、あるセッションで作成したファイルが別セッションから見えることはありません。

第2層:リソース制限では、メモリ・CPU・実行時間に上限を設ける。上のコード例では512MBのメモリと300秒のタイムアウトを指定しているが、この値の決め方にコツがあります。

第3層:ネットワークポリシーが最も重要です。network_access"restricted" にすると、allowed_domains に明示したドメイン以外への外向き通信がすべてブロックされます。本番環境では "full" を使うべきケースはほぼありません。

リソース制限の実践的な設定値

公式ドキュメントでは memory_mb のデフォルトが1024MBと書かれているが、実際に本番で運用してみると、タスクの種類によって最適値は大きく異なります。

# タスク別のリソース設定テンプレート
 
SANDBOX_PROFILES = {
    # テキスト処理系(要約・分類・変換)
    "text_processing": {
        "memory_mb": 256,
        "timeout_seconds": 120,
        "network_access": "none",
    },
    # データ分析系(CSV/JSON解析、グラフ生成)
    "data_analysis": {
        "memory_mb": 1024,
        "timeout_seconds": 600,
        "network_access": "restricted",
        "allowed_domains": ["storage.googleapis.com"],
    },
    # コード生成・実行系
    "code_execution": {
        "memory_mb": 2048,
        "timeout_seconds": 900,
        "network_access": "restricted",
        "allowed_domains": ["pypi.org", "registry.npmjs.org"],
    },
    # 外部API連携系
    "api_integration": {
        "memory_mb": 512,
        "timeout_seconds": 300,
        "network_access": "restricted",
        # allowed_domains はタスクごとに動的に設定
    },
}
 
def create_agent_with_profile(profile_name: str, extra_domains: list[str] | None = None):
    """プロファイルに基づいてエージェントを生成する"""
    config = SANDBOX_PROFILES[profile_name].copy()
 
    if extra_domains and config.get("network_access") == "restricted":
        config.setdefault("allowed_domains", [])
        config["allowed_domains"].extend(extra_domains)
 
    return client.agents.create(
        model="claude-sonnet-4-6",
        instructions=f"Profile: {profile_name}",
        tools=[{"type": "code_execution"}],
        sandbox={"type": "managed", **config},
    )

ここで注目してほしいのは "text_processing" プロファイルの "network_access": "none" です。テキスト処理タスクでは外部通信が不要なケースがほとんどで、ネットワークを完全に遮断することでセキュリティリスクを最小化できます。「必要最小限の権限」という原則は、エージェント設計においても変わらありません。

SSEストリーミングによるリアルタイム監視

Managed Agentsの大きな特徴は、エージェントの実行状況をSSE(Server-Sent Events)でリアルタイムに取得できることです。これを活用すると、異常検知や自動停止の仕組みを構築できます。

import json
from collections import defaultdict
 
class AgentMonitor:
    """エージェントの実行を監視し、異常を検知する"""
 
    def __init__(self, max_tool_calls: int = 50, max_errors: int = 3):
        self.max_tool_calls = max_tool_calls
        self.max_errors = max_errors
        self.tool_call_count = 0
        self.error_count = 0
        self.accessed_files: list[str] = []
 
    def process_event(self, event) -> dict:
        """SSEイベントを処理し、異常があれば警告を返す"""
        result = {"action": "continue", "warnings": []}
 
        if event.type == "tool_use":
            self.tool_call_count += 1
 
            # ツール呼び出し回数の上限チェック
            if self.tool_call_count > self.max_tool_calls:
                result["action"] = "stop"
                result["warnings"].append(
                    f"ツール呼び出し上限超過: {self.tool_call_count}/{self.max_tool_calls}"
                )
                return result
 
            # ファイルアクセスの追跡
            if event.tool_name in ("file_read", "file_write"):
                path = event.tool_input.get("path", "")
                self.accessed_files.append(path)
 
                # 機微なパスへのアクセス検知
                sensitive_patterns = ["/etc/", "/proc/", "/sys/", ".env", "credentials"]
                for pattern in sensitive_patterns:
                    if pattern in path:
                        result["warnings"].append(
                            f"機微なパスへのアクセス検知: {path}"
                        )
 
        elif event.type == "error":
            self.error_count += 1
            if self.error_count >= self.max_errors:
                result["action"] = "stop"
                result["warnings"].append(
                    f"エラー上限到達: {self.error_count}/{self.max_errors}"
                )
 
        return result
 
async def run_monitored_agent(agent_id: str, task: str):
    """監視付きでエージェントを実行する"""
    monitor = AgentMonitor(max_tool_calls=30, max_errors=2)
 
    session = client.agents.sessions.create(agent_id=agent_id)
 
    with client.agents.sessions.turn_stream(
        session_id=session.id,
        messages=[{"role": "user", "content": task}],
    ) as stream:
        for event in stream:
            check = monitor.process_event(event)
 
            if check["warnings"]:
                for w in check["warnings"]:
                    print(f"⚠️ {w}")
                    # 本番ではここで Slack/PagerDuty に通知
 
            if check["action"] == "stop":
                print("🛑 エージェントを強制停止")
                client.agents.sessions.cancel(session_id=session.id)
                break
 
    return {
        "tool_calls": monitor.tool_call_count,
        "errors": monitor.error_count,
        "files_accessed": monitor.accessed_files,
    }

このコードの肝は process_event メソッドで、ツール呼び出しのたびに3つのチェックを走らせている点です。回数制限、ファイルパスの安全性チェック、エラー回数の累積。どれか1つでも閾値を超えたら即座にセッションをキャンセルします。

本番運用ではここにさらに、ツール実行時間の移動平均を監視して急激な遅延を検知するロジックや、特定のツールの連続呼び出し(無限ループの兆候)を検知するパターンを追加しています。

フェイルセーフ設計:エージェントが暴走したときの対処

どれだけ慎重にサンドボックスを設計しても、「想定外の振る舞い」は起こりうる。重要なのは、暴走したときのダメージを最小化する仕組みを事前に用意しておくことです。

import asyncio
from contextlib import asynccontextmanager
from dataclasses import dataclass, field
from datetime import datetime
 
@dataclass
class SessionGuard:
    """セッションのライフサイクルを管理するガード"""
    session_id: str
    started_at: datetime = field(default_factory=datetime.now)
    max_duration_seconds: int = 600
    max_output_bytes: int = 10 * 1024 * 1024  # 10MB
    total_output_bytes: int = 0
 
    @property
    def elapsed_seconds(self) -> float:
        return (datetime.now() - self.started_at).total_seconds()
 
    @property
    def is_expired(self) -> bool:
        return self.elapsed_seconds > self.max_duration_seconds
 
    def track_output(self, data: str) -> bool:
        """出力データを追跡し、上限超過でFalseを返す"""
        self.total_output_bytes += len(data.encode("utf-8"))
        return self.total_output_bytes <= self.max_output_bytes
 
@asynccontextmanager
async def guarded_session(agent_id: str, **guard_kwargs):
    """ガード付きセッションのコンテキストマネージャ"""
    session = client.agents.sessions.create(agent_id=agent_id)
    guard = SessionGuard(session_id=session.id, **guard_kwargs)
 
    # タイムアウト監視タスクを並行起動
    async def _watchdog():
        while not guard.is_expired:
            await asyncio.sleep(5)
        print(f"⏰ セッション {session.id} がタイムアウト")
        try:
            client.agents.sessions.cancel(session_id=session.id)
        except Exception:
            pass  # すでに終了済みの場合
 
    watchdog_task = asyncio.create_task(_watchdog())
 
    try:
        yield session, guard
    finally:
        watchdog_task.cancel()
        try:
            client.agents.sessions.delete(session_id=session.id)
        except Exception:
            pass

SessionGuard は時間制限と出力量制限の2つを同時に管理します。特に出力量制限は見落としがちだが、エージェントが巨大なファイルを生成し続けるケースへの対策として不可欠です。

_watchdog コルーチンは5秒間隔でタイムアウトを監視し、制限時間を超えた瞬間にセッションを強制キャンセルします。Managed Agents APIの timeout_seconds とは別に、アプリケーション側でも独立したタイムアウトを設けておくことで、API側の制御が何らかの理由で効かなかった場合のセーフティネットになります。

本番デプロイ時のチェックリスト

ここまでのパターンを踏まえて、Managed Agentsを本番にデプロイする際に確認すべき項目をまとめる。

ネットワーク制御として、network_access がタスクに応じて "none""restricted" に設定されていること。allowed_domains が必要最小限であること。内部APIへのアクセスが必要な場合は、エージェント専用のAPIゲートウェイを経由させること。

リソース制限として、memory_mbtimeout_seconds が実際のワークロードに基づいて設定されていること。負荷テストで最大メモリ使用量を計測し、20%のマージンを加えた値を設定すること。

監視・アラートとして、SSEイベントをログに記録し、異常パターン(ツール呼び出しの急増、エラーの連続発生)を検知する仕組みがあること。セッションの平均実行時間と成功率をダッシュボードで可視化していること。

フェイルセーフとして、アプリケーション側のタイムアウトがAPI側とは独立して機能すること。エージェントの出力量に上限があること。緊急停止の手段(全セッション一括キャンセル)が運用手順に含まれていること。

これらはManaged Agentsに限らず、自律型AIエージェントを運用する際の普遍的な原則です。エージェントに「何ができるか」を考えるのと同じくらい、「何をさせないか」を考えることが、本番環境での信頼性を左右します。


この記事はプレミアムコンテンツの見本として全文を無料公開しています。Claude Lab のプレミアム記事では、このような実践的な実装パターンや本番運用のノウハウを、動作するコード付きで詳しく解説しています。すべてのプレミアム記事を読むには、メンバーシップへの登録をご検討ください。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

API & SDK2026-04-10
Claude Managed Agents を本番で運用する設計パターン — サンドボックス実行・永続メモリ・認証管理・コスト最適化の実装
Claude Managed Agentsを本番環境で運用するための設計パターンを、サンドボックス実行、永続メモリ、認証情報管理、マルチエージェント連携、コスト最適化の観点から実装例とともに整理します。
API & SDK2026-06-27
Claude API のストリーミングが「エラーも出さずに」止まるとき — 沈黙する停止を検知して途中から続ける運用メモ
Claude API のストリーミングが例外も出さずに無言で止まる「沈黙停止」を、トークン間隔のウォッチドッグで検知し、受信済みテキストを引き継いで途中から再開する実装と、長時間の自動運用で崩れないためのタイムアウト予算の設計をまとめます。
API & SDK2026-06-23
Claude API のプロンプトキャッシュが本番で静かにヒットしなくなるとき — TTLと節約額の実測メモ
プロンプトキャッシュは設定した直後だけ効いて、本番では知らぬ間にヒットしなくなります。プレフィックスを壊す要因、5分と1時間TTLの選び方、節約額を推測でなく実測する計装を運用目線でまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →