AIエージェントが自律的にタスクを解決する上で、「生成したコードを実際に動かして検証する機能」(Code Interpreter)は極めて重要です。しかし、ユーザーが任意のPythonコードを実行できる環境を安全に構築・維持するのは簡単ではありません。ホストマシンのリソース破壊や不正アクセスといったセキュリティリスクが常に伴うからです。

こうした課題を解決するのが、AIエージェント向けに設計されたセキュアなコード実行サンドボックス「E2B Sandbox」です。E2Bは極めて軽量なMicroVM(マイクロ仮想マシン)をクラウド上で瞬時に起動し、安全に分離された環境でのコード実行を提供します。

本記事では、Pythonを用いてE2B Sandboxを使いこなし、LLM(大規模言語モデル)と連携して「安全な自作Code Interpreter」を構築する実装手順を徹底解説します。


E2B Sandboxとは? AIエージェントに最適な理由

E2B Code Interpreter SDKは、AIエージェントがコードを実行するためのクラウド型サンドボックス環境です。Dockerのように動作しますが、AIエージェントのライフサイクルに合わせて瞬時に起動・破棄できるのが大きな特徴です。

E2BがAI開発において推奨される理由は以下の3点に集約されます。

  1. 強力なセキュリティ隔離: 各サンドボックスは仮想化技術(Firecracker)によって完全に隔離されており、悪意のあるコードや無限ループがホストサーバーに影響を与えるのを防ぎます。
  2. ステートフルな環境: 同一のセッション(Sandbox)内であれば、ファイル操作やライブラリのインストール、変数の状態が維持されます。対話的に処理を進めるAIエージェントに最適です。
  3. リッチなプリインストール環境: 標準でPython、Node.js、主要なデータ分析・機械学習ライブラリ(pandas, matplotlib, numpy等)がプリインストールされており、追加設定なしでデータ解析を実行できます。

開発環境の準備

まずはE2Bを利用するための環境を整えます。

1. APIキーの取得

E2Bの公式サイトにアクセスし、ダッシュボードから無料のAPIキーを取得します。取得したAPIキーは環境変数 E2B_API_KEY として設定します。

export E2B_API_KEY="sbx_your_actual_api_key_here"

2. ライブラリのインストール

E2Bの公式Python SDKをインストールします。また、今回はLLMとの連携も行うため、OpenAIのSDKもあわせてインストールしておきましょう。

pip install e2b-code-interpreter openai python-dotenv

これで準備は完了です。まずは基本的な使い方から確認していきます。


E2B Sandboxの基本的な使い方

E2B Sandboxは、主に「コード実行」と「ファイル操作」の2つの役割を持っています。それぞれの基本操作を見てみましょう。

Pythonコードの実行

E2Bの CodeInterpreter クラスを使用すると、Pythonコードのブロックをサンドボックス内で実行し、その標準出力や生成されたファイル(画像など)を取得できます。

import os
from e2b_code_interpreter import CodeInterpreter

# E2B Sandboxの起動と実行
with CodeInterpreter() as sandbox:
    # シンプルなPythonコードの実行
    code = """
    import math
    result = math.sqrt(256)
    print(f"Result: {result}")
    """
    execution = sandbox.notebook.exec_cell(code)
    
    # 実行結果の確認
    print("--- 標準出力 ---")
    print(execution.text)

notebook.exec_cell() メソッドは、Jupyter Notebookのセルを実行するような挙動を示します。そのため、直前のセルで定義した変数やインポートしたライブラリは、次の実行時にも引き継がれます。

ファイルの書き込みと読み込み

AIエージェントがCSVファイルを読み込んでグラフを描画するようなタスクでは、ファイルの送受信が必要です。E2Bは簡単なAPIでサンドボックス内のファイルシステムにアクセスできます。

with CodeInterpreter() as sandbox:
    # 1. サンドボックス内にデータを書き込む
    csv_content = "name,age\nAlice,30\nBob,25\nCharlie,35"
    sandbox.files.write("data.csv", csv_content)
    
    # 2. サンドボックス内でpandasを使って処理し、グラフ画像を生成するコードを実行
    analysis_code = """
    import pandas as pd
    import matplotlib.pyplot as plt

    df = pd.read_csv('data.csv')
    print("--- DataFrame Summary ---")
    print(df.describe())

    df.plot(kind='bar', x='name', y='age')
    plt.title('Age by Name')
    plt.savefig('age_plot.png')
    """
    execution = sandbox.notebook.exec_cell(analysis_code)
    print(execution.text)

    # 3. 生成された画像ファイルをダウンロードしてローカルに保存する
    if execution.results:
        for result in execution.results:
            # matplotlibのグラフ出力(PNG等)はresultsに含まれます
            if result.png:
                with open("output_chart.png", "wb") as f:
                    # base64デコードして書き込み
                    import base64
                    f.write(base64.b64decode(result.png))
                print("グラフ画像を 'output_chart.png' として保存しました。")

このように、ローカルのファイルをサンドボックスにアップロードし、内部で加工して結果を連れ戻すという一連のパイプラインが非常に直感的に記述できます。


OpenAI APIと連携した「自作Code Interpreter」の実装

それでは、LLMとE2B Sandboxを連携させ、ユーザーの指示に応じて自動的にPythonコードを書き、実行して結果を返す「自律型Code Interpreter」を実装します。

ここでは、LLMに「コード実行ツール」としてE2B Sandboxを提供します。

import json
from openai import OpenAI
from e2b_code_interpreter import CodeInterpreter

client = OpenAI()

# 1. LLMに提供するツールの定義
tools = [
    {
        "type": "function",
        "function": {
            "name": "execute_python_code",
            "description": "セキュアなサンドボックス環境でPythonコードを実行します。データの分析や可視化、複雑な計算に利用できます。",
            "parameters": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "実行するPythonコード。print()などで結果を出力するようにしてください。"
                    }
                },
                "required": ["code"]
            }
        }
    }
]

def run_code_interpreter_agent(user_prompt: str):
    print(f"User Request: {user_prompt}\n")
    
    # メッセージの初期化
    messages = [
        {"role": "system", "content": "あなたは優秀なデータアナリストです。提供されたツールを使ってPythonコードを実行し、ユーザーの課題を解決してください。"},
        {"role": "user", "content": user_prompt}
    ]
    
    # OpenAIのChat Completion呼び出し
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        tools=tools,
        tool_choice="auto"
    )
    
    response_message = response.choices[0].message
    
    # ツール呼び出しがあるか確認
    if response_message.tool_calls:
        tool_call = response_message.tool_calls[0]
        function_name = tool_call.function.name
        arguments = json.loads(tool_call.function.arguments)
        
        if function_name == "execute_python_code":
            target_code = arguments["code"]
            print("--- AIが生成したコード ---")
            print(target_code)
            print("-------------------------\n")
            
            # E2B Sandboxで実行
            print("E2B Sandboxを起動してコードを実行中...")
            with CodeInterpreter() as sandbox:
                execution = sandbox.notebook.exec_cell(target_code)
                
                # 実行結果を取得
                stdout_result = execution.text
                error_result = execution.error
                
                # エラーがある場合はエラー内容を、なければ標準出力を返す
                tool_output = stdout_result if not error_result else f"Error: {error_result.name}\n{error_result.value}\n{error_result.traceback}"
            
            print("--- 実行結果 ---")
            print(tool_output)
            print("-----------------\n")
            
            # 実行結果をLLMにフィードバックして、最終回答を得る
            messages.append(response_message)
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "name": function_name,
                "content": tool_output
            })
            
            final_response = client.chat.completions.create(
                model="gpt-4o-mini",
                messages=messages
            )
            
            print("--- AIの最終回答 ---")
            print(final_response.choices[0].message.content)

# 実行例
run_code_interpreter_agent("1から1000までの素数をすべて数え上げて、その個数を教えてください。")

このように、LLMが自らPythonコードを生成し、E2B Sandboxで安全に実行し、その結果をもとに日本語で最終回答を作成するという一連のサイクルが綺麗に回ります。もちろん、より本格的なマルチエージェントや型安全なLLMツール連携を行う場合、以下のようなモダンなフレームワークとE2Bを組み合わせることも可能です。

型安全なエージェント設計についてはPydantic AIの実践ガイド、あるいは軽量なエージェント開発についてはsmolagentsの解説記事などを参考に、適したフレームワークにE2Bを組み込んでみてください。


トラブルシューティング:よくあるエラーと対策

E2B Sandboxを本番環境やローカル開発で実装する際、開発者がよく直面する代表的なエラーとその解決策を紹介します。

1. E2B_API_KEY の未設定エラー

症状:

e2b.exceptions.ContextException: API key is not set. Please set the E2B_API_KEY environment variable.

原因: SDKがE2Bのクラウドサービスと認証するためのAPIキーを読み込めていません。

対策: コード内で with CodeInterpreter() as sandbox: を呼び出す前に、必ず環境変数がロードされているか確認してください。Pythonスクリプトの先頭で dotenv を利用して明示的に読み込むのが最も安全です。

from dotenv import load_dotenv
import os

load_dotenv() # .envファイルから E2B_API_KEY をロードする
assert os.getenv("E2B_API_KEY") is not None, "E2B_API_KEYが設定されていません"

2. サンドボックスが閉じられずリソースが枯渇する

症状: 同時接続数(Concurrency Limit)の制限に達してしまい、新しいSandboxが起動できなくなる。

原因: CodeInterpreter() を使用する際に with ステートメント(コンテキストマネージャー)を使用していないか、あるいは明示的な sandbox.close() の呼び出しを怠っているため、バックエンドでインスタンスが生き残っています。

対策: 原則として、E2Bの操作は必ず with ブロック内で行ってください。もし長期間生存させるステートフルなエージェントを作る場合は、明示的に終了処理を挟む設計にしてください。

sandbox = CodeInterpreter()
try:
    # 何らかの処理
    sandbox.notebook.exec_cell("...")
finally:
    # 例外が発生しても必ずクローズする
    sandbox.close()

3. インターネットアクセスや外部API呼び出しの失敗

症状: サンドボックス内で urllibrequests を使って外部のWebサイトからスクレイピングしようとするとタイムアウト、もしくは接続拒否が発生する。

原因: E2Bの無料枠(Free Tier)では、セキュリティ上の制限からサンドボックス内から外部インターネットへのアウトバウンド通信が制限されている場合があります。

対策: 外部通信が必要な場合は、E2Bのダッシュボードでプランを確認し、必要に応じて有料枠へのアップグレードを行うか、カスタムの「Sandbox Template」を構築して通信許可を設定してください。公式ドキュメントに沿ってカスタムテンプレートを作成することで、必要なパッケージを事前に焼き込んだ状態の専用サンドボックスを作成できます。


まとめ

E2B Sandboxを導入することで、これまで開発者にとって大きな障壁であった「AIエージェントによるコード実行のセキュリティリスク」を容易にクリアできます。PythonのシンプルなSDKを用いて安全な環境を数秒でデプロイし、LLMに強力な演算・データ処理能力を与えることができます。

データ分析、自動スクレイピング、複雑な計算処理を自律的にこなす真のAIエージェントを構築する第一歩として、ぜひE2B Sandboxをお試しください。