Pythonで使うE2B Code Interpreter入門:AI Agentのための安全なサンドボックス構築

Artificial Intelligence tutorial - IT technology blog
Artificial Intelligence tutorial - IT technology blog

LLMにソースコードを直接実行させる危険性

AIにコード実行権限を与えることは絶大な力を生み出しますが、同時に最悪のセキュリティ悪夢にもなり得ます。

わずかなロジックの不具合や巧妙なプロンプトインジェクション(Prompt Injection)によって、モデルが誤ってos.system("rm -rf /")を実行してしまう恐れがあります。さらに危険なのは、データベースの認証情報を含む環境変数をすべて読み取られたり、無限ループによってサーバーのCPUリソースを100%消費されたりすることです。

実行環境を安全に分離(サンドボックス化)するため、エンジニアは通常次の3つのアプローチを検討します。

  • Dockerコンテナの自前運用: リクエストごとにバックエンドからDockerデーモンを呼び出して新規コンテナを起動し、コードを実行した後にコンテナを破棄する方式。
  • MicroVMの自前運用(Firecracker / gVisor): AWS Lambdaのアーキテクチャと同様に、ハードウェア仮想化レイヤーでカーネルを完全に分離する方式。
  • 専用クラウドサンドボックス(E2B Code Interpreter): SDK経由でマネージドなMicroVMインフラを利用する方式。Linux仮想マシンが約150〜200msで高速起動し、PythonやJupyterカーネルがプリインストールされており、API経由で即座にファイルのアップロード/ダウンロードが可能です。

実戦比較:Docker、Firecracker、それともE2Bか?

私たちは最終的なソリューションを決定する前に、これら3つのアプローチをすべて検証しました。

1. Docker Engineのセルフホスト

メリット: ライセンス費用が不要で、既存サーバーをそのまま活用でき、社内ライブラリを含めたカスタムイメージのビルドも容易です。

デメリット: ライフサイクル管理の手間がかかります。Dockerのコールドスタートには通常1.5〜3秒ほど要します。100人のユーザーが一斉にコードを実行した場合、ディスクI/Oが瞬時にボトルネックになります。何より深刻なのは、DockerがホストとLinuxカーネルを共有している点です。CVE-2024-21626のようなコンテナブレイクアウトの脆弱性が1つあるだけで、攻撃者にバックエンドサーバー全体を掌握される危険性があります。

2. Firecrackerを用いたMicroVMクラスタの自前構築

メリット: ハードウェアレベルでの高いセキュリティ分離。50ms未満という驚異的な超高速起動。

デメリット: DevOpsの運用負荷が極めて高い点です。仮想ネットワークの制御、不要なディスククリーンアップの仕組み、IPプーリング、そして24時間365日の監視体制を自前で構築・維持する必要があります。チームが5人未満の場合、保守運用に膨大なリソースを奪われてしまいます。

3. E2B Code Interpreter

メリット: 導入が極めてスムーズです。サンドボックスは約150msで起動します。Jupyterランタイムがあらかじめ用意されており、標準出力(stdout)や標準エラー出力(stderr)、グラフ画像(PNG/SVGのBase64形式)を正確に抽出できます。カーネルのパッチ適用やインフラのスケーリングを気にする必要もありません。

デメリット: E2Bのクラウドサービスに依存します。医療データや金融データなど、100%オンプレミス環境での運用が必須となる場合は、Enterprise向けのセルフホストプランについて相談する必要があります。

どのソリューションを選ぶべきか?

社内の同僚数名が試す程度の社内用Botであれば、--memory=512m や --cpus=1.0 などの制限を厳格に設定したDockerコンテナで十分でしょう。

しかし、課金ユーザー向けに一般公開するプロダクションサービスとなると話はまったく別です。たった1件のセキュリティインシデントやダウンタイムが、プロジェクトの信頼を失墜させる原因になります。このようなケースにおいて、E2Bを利用すれば低レイテンシと堅牢なセキュリティを両立しつつ、数週間に及ぶインフラ構築の手間を省くことができます。

PythonでE2B Code Interpreterを導入するステップ

ステップ1:SDKのインストールとAPIキーの取得

e2b.dev で無料アカウントを作成してAPIキーを取得します。その後、作業環境にSDKをインストールします。

pip install e2b-code-interpreter python-dotenv

プロジェクトのルートディレクトリに .env ファイルを作成します。

E2B_API_KEY=e2b_your_actual_api_key_here

ステップ2:サンドボックス内で最初のコードを実行する

コンテキストマネージャ with Sandbox() を使用することで、コードの実行完了時にリソースが自動的にクリーンアップされます。

import os
from dotenv import load_dotenv
from e2b_code_interpreter import Sandbox

load_dotenv()

# 隔離されたサンドボックスを初期化
with Sandbox() as sandbox:
    code = """
import math

def calculate_primes(limit):
    primes = []
    for num in range(2, limit):
        if all(num % i != 0 for i in range(2, int(math.sqrt(num)) + 1)):
            primes.append(num)
    return len(primes)

count = calculate_primes(1000)
print(f'1000未満の素数が {count} 個見つかりました。')
"""
    print("E2Bサンドボックスにコードを送信中...")
    execution = sandbox.run_code(code)
    
    # stdoutの結果を出力
    for log in execution.logs.stdout:
        print("Output:", log)
        
    # 構文エラーや実行時エラーのキャッチ
    if execution.error:
        print("エラー:", execution.error.name, execution.error.value)

ステップ3:データファイルのアップロードと分析グラフの出力

AI Agentの実用例として、ユーザーがアップロードしたCSVファイルを読み込み、計算処理を行ってグラフを描画するケースがよくあります。E2Bは双方向のファイルI/Oに対応しているため、この処理を非常にスムーズに行えます。

import base64
from e2b_code_interpreter import Sandbox

with Sandbox() as sandbox:
    # 1. CSVファイルをサンドボックスに直接書き込み
    csv_content = "Thang,DoanhThu\n1,120\n2,150\n3,180\n4,220\n5,210\n6,290"
    sandbox.files.write("data.csv", csv_content)
    
    # 2. matplotlibを使用したグラフ描画コード
    analysis_script = """
import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv('data.csv')
plt.figure(figsize=(8, 4))
plt.plot(df['Thang'], df['DoanhThu'], marker='o', color='royalblue')
plt.title('上半期の売上推移')
plt.xlabel('月')
plt.ylabel('売上(100万VND)')
plt.grid(True)
plt.show()
"""
    print("データ分析を実行中...")
    execution = sandbox.run_code(analysis_script)
    
    # 3. PNG画像(Base64文字列として返却)を取得してディスクに保存
    for i, result in enumerate(execution.results):
        if result.png:
            with open(f"chart_{i}.png", "wb") as f:
                f.write(base64.b64decode(result.png))
            print(f"グラフ画像の保存に成功しました: chart_{i}.png")

ステップ4:LLMのTool CallingループにE2Bを組み込む

インテリジェントなAgent(Claude 3.5 SonnetやGPT-4oなど)を完成させるには、E2Bをコード実行ツールとして定義します。基本的な動作フローは以下の5ステップです。

  1. ユーザーが「四半期ごとの売上グラフを作成して」とリクエストを送信。
  2. LLMがTool Callを介して対応するPythonコードを生成。
  3. バックエンドがコード文字列を受け取り、sandbox.run_code() に渡して実行。
  4. コードが正常に実行された場合、stdoutの結果や画像ファイルをLLMに返却して最終的な回答を生成。
  5. コードがエラー(Traceback)を吐いた場合、そのエラーログをそのままLLMに送信。LLMがTracebackを解析してコードを自己修正し、再実行を試行(セルフデバッグ)。

本番環境(Production)運用における3つの重要ポイント

以下の3つの設定を確認・適用するまでは、本番環境へのデプロイを急がないでください。

  • 必ず厳格なタイムアウトを設定する: AIが生成したコードは無限ループに陥りやすい傾向があります。run_code(code, timeout=30) のように指定して30秒で自動終了させ、無駄なコンピュートコストの消費を防ぎましょう。
  • セッション単位でサンドボックスを再利用する: 質問ごとにサンドボックスを新規作成するのではなく、ユーザーのチャットセッション中は同一の sandbox_id を保持します。これにより、変数やDataFrame、アップロード済み一時ファイルの状態を引き継ぐことができます。
  • サンドボックスを明示的に破棄(kill)する: ユーザーがブラウザタブを閉じた際やセッションタイムアウト時には、sandbox.kill() を呼び出してください。不要な仮想マシンがバックグラウンドで稼働し続け、クラウドアカウントの予算を圧迫するのを防ぎます。
Share: