所要時間: 約40分 | 難易度: ★★★☆☆

この記事で作るもの

  • LLMが生成した「何をするか分からないコード」を、ホストPCから完全に隔離された環境で安全に実行し、結果だけを回収するPythonスクリプト
  • ローカルLLM(Ollama)やクラウドAPI(Claude/GPT)と連携し、データ分析やグラフ作成を自動で行うエージェントの基礎
  • 実行後に自動で破棄され、ファイルシステムやネットワークへの不正アクセスを防止するサンドボックス環境

📦 この記事に関連する商品(楽天メインで価格確認)

Dell U2723QE

AIの生成コードと実行結果のグラフを左右に並べてデバッグするのに最適な4K解像度。

楽天で価格を見る Amazonでも確認

※アフィリエイトリンクを含みます

前提知識

  • Pythonの基本的な文法(関数の定義、ライブラリのインポート)
  • ターミナルまたはコマンドプロンプトの基本操作
  • APIキーの概念と環境変数への設定方法

必要なもの

  • Python 3.10以上
  • E2B APIキー(無料枠あり)
  • OpenAI または Anthropic のAPIキー(ローカルLLMを使う場合は不要)

先に確認するスペック・料金

AIエージェントを動かす際、最も怖いのは「生成されたコードがローカル環境のファイルを消去する」ことや「無限ループでリソースを食いつぶす」ことです。これを防ぐためにサンドボックスが必要になります。

自前でDockerを立てて運用することも可能ですが、ポートの管理やリソース制限、セッションのクリーンアップを自前で実装するのは苦行です。SIer時代、社内サーバーにDockerで実験場を作りましたが、ゾンビコンテナが溜まってディスクを圧迫し、インフラ担当に怒られたのは苦い思い出です。

今回は「E2B(Code Interpreter SDK)」を使います。これは、エージェント専用のクラウド型サンドボックスで、Firecrackerという軽量VMの上で動きます。

料金面では、E2Bには強力な無料枠があります。執筆時点では120GB-hour/月まで無料で、個人開発や小規模な業務自動化ならこれで十分足ります。 ハードウェア性能は、クラウド上でコードを動かすため、操作側のPCはMacBook Airや安価なWindows機で全く問題ありません。RTX 4090を積んだ私のマシンも、この構築に関しては暇を持て余すほどです。

なぜこの方法を選ぶのか

サンドボックス構築には、他にも「Docker SDKを直接叩く」「Wasm(WebAssembly)で動かす」といった選択肢があります。 しかし、Dockerはセキュリティ設定を誤ると容易にホストへ脱獄されます。Wasmは実行できるライブラリに制限が多く、pandasmatplotlibを使ったデータ分析をさせるには不向きです。

E2Bを選ぶ最大の理由は「ステートフル(状態保持)」と「環境構築の速さ」です。 1つのセッション内で「ライブラリをインストールし、データを読み込み、分析してグラフを保存する」という一連の流れを、LLMと対話しながら継続できます。 この「前後の文脈を物理的な環境として維持できる」点が、他のサンドボックスにはない圧倒的なメリットです。

Step 1: 環境を整える

まずはプロジェクト用のディレクトリを作成し、必要なライブラリをインストールします。依存関係の衝突を防ぐため、必ず仮想環境を作ってください。

# プロジェクトディレクトリの作成
mkdir agent-sandbox-test && cd agent-sandbox-test

# Python仮想環境の作成と有効化
python -m venv venv
source venv/bin/activate  # Windowsの場合は venv\Scripts\activate

# 必要なライブラリのインストール
pip install e2b-code-interpreter python-dotenv openai

e2b-code-interpreterは、E2Bが提供するコード実行に特化したSDKです。 python-dotenvは、APIキーを.envファイルから安全に読み込むために使用します。ハードコードは絶対に避けましょう。

⚠️ 落とし穴: Python 3.9以下を使っている場合、SDKが正しく動作しないことがあります。特に非同期処理(asyncio)周りの挙動が安定しないため、必ず python --version で3.10以上であることを確認してください。

Step 2: 基本の設定

次に、APIキーを管理するための設定ファイルを作成します。

プロジェクトのルートディレクトリに .env という名前のファイルを作成し、以下の内容を書き込みます。

E2B_API_KEY=あなたのE2B_APIキー
OPENAI_API_KEY=あなたのOpenAI_APIキー

次に、E2Bのサンドボックスが正しく起動するかを確認する最小構成のコードを書きます。main.pyを作成してください。

import os
from dotenv import load_dotenv
from e2b_code_interpreter import Sandbox

# .envファイルから環境変数を読み込む
load_dotenv()

def test_sandbox():
    # E2Bのサンドボックスを初期化
    # 実行後、このブロックを抜けると自動的にVMは破棄される
    with Sandbox() as sandbox:
        print("サンドボックスを起動しました...")

        # Pythonコードを実行する
        # ここでは単純な計算とライブラリのインポートテスト
        code = "import sys; print(f'Python version: {sys.version}'); print(1 + 1)"
        execution = sandbox.run_code(code)

        # 実行結果の出力
        print("実行結果:", execution.logs.stdout)

        if execution.error:
            print("エラー発生:", execution.error.name, execution.error.value)

if __name__ == "__main__":
    test_sandbox()

ここで with Sandbox() as sandbox: という書き方をしているのがポイントです。 実務でエージェントを動かす際、エラーでスクリプトが止まっても、このコンテキストマネージャを使っていればクラウド上のVMが確実にシャットダウンされます。これを忘れると、バックグラウンドでインスタンスが動き続け、無料枠を無駄に消費する原因になります。

Step 3: 動かしてみる

作成した main.py を実行してみましょう。

python main.py

期待される出力

サンドボックスを起動しました...
実行結果: ['Python version: 3.10.12 (main, ...)', '2']

E2Bのデフォルト環境では、最新の安定版Pythonがプリインストールされた隔離環境が提供されます。 この時点で、あなたの手元のPCとは完全に切り離された「使い捨ての実行マシン」がクラウド上に確保されたことになります。

独自の切り口:なぜ run_code なのか

一般的なLLM連携では exec() などを使いがちですが、E2Bの run_code はJupyter Kernelのように動作します。 つまり、変数の値がメモリ上に保持されるため、後から別のコードブロックを投げても、前の実行結果を引き継げるのです。これは複雑なタスクを分解して実行するエージェントにとって必須の機能です。

Step 4: 実用レベルにする

ここからが本番です。「LLMにコードを書かせ、それをサンドボックスで実行し、生成された画像ファイルを回収する」という実用的なエージェントを実装します。

import os
from dotenv import load_dotenv
from openai import OpenAI
from e2b_code_interpreter import Sandbox

load_dotenv()
client = OpenAI()

def run_ai_agent(prompt):
    # 1. LLMにPythonコードを生成させる
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": "あなたはデータサイエンティストです。Pythonコードのみを出力してください。コードブロックの記号は不要です。"},
            {"role": "user", "content": prompt}
        ]
    )

    code = response.choices[0].message.content
    print(f"--- 生成されたコード ---\n{code}\n-----------------------")

    # 2. E2Bサンドボックスでコードを実行
    with Sandbox() as sandbox:
        # 必要なライブラリのインストール(実行時に動的に追加可能)
        # sandbox.commands.run("pip install matplotlib pandas")

        execution = sandbox.run_code(code)

        # 3. コンソール出力の表示
        for log in execution.logs.stdout:
            print(f"[Stdout]: {log}")

        # 4. 生成されたファイルの回収(グラフなど)
        if execution.results:
            for i, result in enumerate(execution.results):
                # matplotlibなどのグラフは自動的に検知される
                if result.png:
                    file_name = f"output_{i}.png"
                    with open(file_name, "wb") as f:
                        f.write(result.png)
                    print(f"画像を保存しました: {file_name}")

if __name__ == "__main__":
    task = "1から10までの数値の2乗を計算し、matplotlibで折れ線グラフを作成してください。日本語フォントの設定は不要です。"
    run_ai_agent(task)

このコードの肝は execution.results です。 E2BのSDKは、コード内でグラフが描画されたり、画像が表示されたりしたことを自動的に検知し、そのバイナリデータを返してくれます。 ローカル環境で「画像ファイルがどこに保存されたか」を気にする必要がなく、API経由で直接受け取れるため、Webアプリケーションへの組み込みも非常にスムーズです。

⚠️ 落とし穴: LLMが生成するコードには、時折 plt.show() が含まれます。E2B環境ではGUIが表示できないため、これが原因で処理が止まることはありませんが、画像データを正しく受け取るためには、LLMに対して「ファイルとして保存するコード」を書かせるか、E2Bの自動検知機能に頼る構成にする必要があります。上記のコードでは自動検知を利用しています。

よくあるトラブルと解決法

エラー内容原因解決策
ModuleNotFoundErrorサンドボックス内にライブラリがないsandbox.commands.run("pip install xxx") を実行前に追加する
SandboxTimeoutError処理が制限時間を超えたSandbox(timeout=300) のように引数で秒数を指定する
APIキーが無効環境変数が読み込めていない.envファイルのパスを確認するか、os.environで直接確認する

次のステップ

ここまでで、安全なコード実行環境を手に入れました。 次に挑戦すべきは「マルチエージェント化」です。

例えば、「分析プランを立てるエージェント」「コードを書くエージェント」「実行結果をレビューするエージェント」の3人を登場させます。 実行結果にエラーが含まれていた場合、そのエラーメッセージを「レビュー担当」に渡し、修正案を「コード担当」にフィードバックさせるループを作ってみてください。

また、実務で使うなら、特定のディレクトリをサンドボックスにマウントする機能も重要です。 E2Bにはローカルファイルをアップロードする sandbox.upload_file() メソッドがあります。社内のCSVデータを一時的にアップロードし、分析が終わったら環境ごと消し去る。このフローを組めば、セキュリティポリシーが厳しい現場でも「一時的な作業用コンテナ」としてAIエージェントを導入できるはずです。

私が以前、大量のログ解析を自動化した際は、この手法で解析時間を80%削減しました。手元でスクリプトを回すのと違い、並列で複数のサンドボックスを立ち上げられるのも、クラウド型ならではの強みです。

よくある質問

Q1: E2Bを使わずに、完全にローカル(オフライン)で構築する方法はありますか?

Docker SDK for Pythonを使い、mem_limitnetwork_disabled=Trueを設定したコンテナを都度起動すれば可能です。ただし、ファイルの回収やJupyter形式の逐次実行を実装するにはかなりのコード量が必要になります。

Q2: 実行されるコードの安全性をどう担保すればいいですか?

E2B側でネットワーク制限をかける設定が可能です。また、LLMへのプロンプトで「システムコマンド(os.systemなど)の使用を禁止する」といった制約を加えることと、万が一突破されてもVMごと消滅する今回の構成を組み合わせるのが、現状のベストプラクティスです。

Q3: グラフ以外のファイル(CSVやPDF)を生成した場合はどう受け取りますか?

sandbox.files.read("path/to/file") メソッドを使えば、サンドボックス内の任意のファイルをバイナリとして読み込めます。LLMに「結果をresult.csvに保存して」と指示し、そのパスを読みに行く実装にします。


1. X投稿用ツイート本文 (TWEET_TEXT) 2. アフィリエイト商品情報 (AFFILIATE_CONTEXT)

3. SNS拡散用ハッシュタグ (HASHTAGS) 4. SEOタグ (SEO_TAGS) 5. URLスラッグ (SLUG)


あわせて読みたい