AIサンドボックス:分離、コード実行、コスト

AIサンドボックス(AI sandbox)は、AIエージェントがコードを実行し、パッケージをインストールし、ファイルを操作できる隔離された環境です。その役割は、コードがアクセスできる範囲(ホストマシン、他のユーザーの作業データ、認証情報、外部サービスなど)を制限することです。
エージェントのランタイムを選ぶ前に、コードをどのように分離するか、ワークロードに対応しているか、実行中の料金はいくらかを確認してください。本ガイドではこれらの選択肢を説明し、Lizard SDKを使った小規模な実行フローを紹介します。
AIサンドボックスとは
エージェントアプリケーションでは、モデルがアクションを提案し、アプリケーションがそれをどこでどのように実行するかを決定します。サンドボックスは、コード実行が必要なアクションのためにコンピューティング環境を提供します。モデルはそこでPythonスクリプトを書いたり、リポジトリを編集したり、ウェブアプリを起動したりします。
この用語は、AI製品をテストするためのビジネスプログラムを指すこともあります。しかしここでは、エージェントのコードを実行するランタイムを意味します。
ランタイムには、ユーザーごとのフォルダ以上のものが必要です。実用的な設計では、プロセスとファイルを分離し、CPUとメモリに上限を設け、アプリケーションが作業を停止する手段を提供します。認証情報、ネットワークアクセス、永続ストレージには独自のルールが必要です。
例えば、アップロードされたCSVを分析するエージェントには、そのファイルと処理に十分な計算リソースを渡す必要があります。ウェブサーバーの環境変数や他の顧客のアップロードデータを読み取る権限は不要です。
AIサンドボックスの仕組み
一般的なリクエストは以下の流れで処理されます。
- バックエンドがタスクを受け取り、モデルにコードまたはツール呼び出しの生成を要求します。
- バックエンドがサンドボックスを作成し、タスクに必要なファイルをコピーします。
- サンドボックスがコードを実行します。バックエンドは標準出力、標準エラー出力、ファイル、終了コードを収集します。
- バックエンドは結果を確認してから、ユーザーに表示するか別のサービスに送信します。
- バックエンドは必要な出力を保存し、サンドボックスを停止します。
モデルプロバイダーのキーとサンドボックスの管理キーはバックエンドに保持してください。生成されたコードに管理キーを渡すと、あなたのアカウントを使ってさらにリソースを要求できてしまいます。
コーディングセッションでは、複数回のやり取りで同じサンドボックスが必要になる場合があります。単発の計算であれば、ジョブごとに新しいサンドボックスを使用できます。再利用を導入する前に、状態をどのくらい保持するか、どのユーザーがそれを所有するかを決定してください。
Docker、gVisor、Firecrackerの違い
これらの技術は異なる分離境界を提供します。コードがアクセスできるファイル、ネットワーク、認証情報は、引き続きシステムの他の部分が決定します。
| アプローチ | 境界の位置 | 確認事項 |
|---|---|---|
| 標準のDockerコンテナ | Linux名前空間とリソース制御がプロセスを分離します。コンテナはホストカーネルを共有します。 | ケーパビリティ、特権モード、ホストマウント、デーモンアクセス、ホストのパッチ適用。 |
| gVisor | ユーザースペースのアプリケーションカーネルがアプリケーションのシステムコールを処理し、ホストカーネルへの直接的な露出を減らします。 | ワークロードにおけるシステムコールの互換性とパフォーマンス。 |
| Firecracker microVM | 仮想マシンは独自のゲストカーネルを持ち、ハードウェア仮想化にKVMを使用します。 | ゲストとホストのパッチ適用、ネットワークポリシー、マウントされたデータ、ライフサイクル制御。 |
Dockerは、信頼レベルが既知であり、ホストが慎重に設定されているワークロードに適しています。そのセキュリティは実行方法に依存します。Dockerソケットを公開したり、広範なホストマウントを許可したりすると、ワークロードが制御できる範囲が変わります。Dockerのセキュリティドキュメントを参照してください。
gVisorはユーザースペースのカーネル境界を追加しますが、互換性とのトレードオフがあります。Firecrackerは小規模な仮想マシンモニターと限定的なデバイスモデルを使用します。どちらを使用しても、シークレットを保護し、機密サービスへのアクセスを制限する必要性は変わりません。
Lizard SandboxesはFirecrackerを使用します。古いボリュームやスナップショット、またはFirecrackerの起動に失敗した後のフォールバックでは、コンテナランタイムを使用する場合があります。アプリケーションがmicroVMを必要とする場合は、getInfo().runtimeを確認してください。以下の例では、他のランタイムを拒否します。Lizard Sandboxesのドキュメントを参照してください。
分離によって保護されるものとされないもの
サンドボックスはコード実行の影響を制限します。ユーザーやエージェントがどのアクションを実行できるかは、引き続きアプリケーション側で決定する必要があります。
認証情報とネットワークアクセス
サンドボックスにコピーしたものはすべて、付与した権限の下でワークロードから利用可能になります。.env全体、SSHディレクトリ、クラウドの認証情報をコピーするのは避けてください。タスクが外部APIを必要とする場合は、権限を絞った短命の認証情報を渡すか、各リクエストを検証するバックエンドツールを経由して操作をルーティングします。
分離されているからといって、インターネットアクセスが遮断されているとは限りません。コードがシークレットを読み取り、外部へのリクエストを行える場合、そのシークレットを外部に送信できる可能性があります。アウトバウンドネットワークの要件を満たすプロバイダーと設定を選択してください。製品の制御機能を確認せずに、ネットワークの許可リストが存在すると思い込まないでください。
ユーザーと保存されたファイル
各サンドボックスを認証済みのユーザーまたはジョブに割り当てます。コードの実行、ファイルのダウンロード、セッションの再開のリクエストごとに所有権を確認してください。推測されたサンドボックスIDでアクセスを許可してはいけません。
永続化されたファイルもユーザーごとに分離してください。無関係な顧客間で書き込み可能なワークスペースを再利用すると、実行ごとに新しい仮想マシンが割り当てられてもデータが漏洩する可能性があります。
時間制限と返される出力
実行タイムアウトとサンドボックスの有効期間を設定します。クライアント側のタイムアウトは、リモートプロセスを停止せずに待機を打ち切ることができます。クリーンアップとサーバー側の有効期限は、それぞれ異なる障害からシステムを保護します。
返されたファイルやテキストは信頼できない入力として扱います。JSONはアプリケーションが期待する形式と照らし合わせて検証してください。テキストをレンダリングする際はエスケープ処理を行い、生成されたHTMLをアカウントダッシュボードと同じオリジンで配信することは避けてください。
対話的な承認をスキップするエージェントの場合、最初のコマンドを実行する前にこれらの制御が重要になります。このワークフローについては、Claude Codeの権限ガイドで解説しています。
Lizard SandboxesでPythonタスクを実行する
この例では、バックエンドコントローラーにNode.jsを使用し、サンドボックス内でPythonを使用します。モデルを追加する前に実行パスを確認できるよう、固定の計算を実行します。LLMは呼び出しません。
Node.js 22以降、Lizardプロジェクト、およびLizard APIキーを使用します。バックエンド環境でLIZARD_API_KEYとLIZARD_PROJECT_IDを設定してください。どちらもブラウザのコードには含めず、APIキーはシークレットストアに保管してください。
JavaScriptクライアントをインストールします。
npm install @lizard-build/sdk@0.1.69これをrun-task.mjsとして保存します。
import { Lizard } from "@lizard-build/sdk";
const project = process.env.LIZARD_PROJECT_ID;
if (!project || !process.env.LIZARD_API_KEY) {
throw new Error("Set LIZARD_PROJECT_ID and LIZARD_API_KEY");
}
const lizard = new Lizard({ project });
const sandbox = await lizard.create("base", {
size: "small",
timeoutMs: 120_000,
});
try {
const info = await sandbox.getInfo();
if (info.runtime !== "firecracker") {
throw new Error("This task requires the Firecracker runtime");
}
const script = [
"import json",
"values = [12, 8, 5]",
"print(json.dumps({'total': sum(values)}))",
].join("\n");
await sandbox.fs.write("/tmp/task.py", script);
const result = await sandbox.process.exec(
["python3", "/tmp/task.py"],
{ user: "user", timeoutMs: 30_000 },
);
if (result.exitCode !== 0 || result.truncated) {
throw new Error("Task failed or returned incomplete output");
}
if (Buffer.byteLength(result.stdout, "utf8") > 4096) {
throw new Error("Task output exceeds the application limit");
}
const output = JSON.parse(result.stdout);
if (
output === null ||
typeof output !== "object" ||
Array.isArray(output) ||
Object.keys(output).length !== 1 ||
output.total !== 25
) {
throw new Error("Unexpected task output");
}
console.log(output);
} finally {
await sandbox.kill();
}バックエンドマシンから実行します。
node run-task.mjs2026年10月17日、codexテンプレートとNode.js 22.23.2を使用して、Lizard Sandboxesからこのスクリプトをそのまま実行しました。baseテンプレートからSmallサイズのFirecrackerサンドボックスを作成し、Pythonをuserとして実行し、{ total: 25 }を出力して、終了コード0でクリーンアップを完了しました。
SDKはコントローラーの環境からLIZARD_API_KEYを読み取ります。このコードは、Pythonを実行するサンドボックスにはそれを渡しません。
引数配列は、シェルの展開なしでPythonを実行します。それでもPythonは、サンドボックスが許可するあらゆる操作を実行できます。30秒のコマンドタイムアウトはクライアントの待機時間を制限し、2分間のサンドボックス有効期間はそれとは別の有効期限を設定します。finallyブロックは、出力の検証に失敗した場合でもクリーンアップを要求します。Lizard SDKリファレンスを参照してください。
これをエージェントツールにするには、固定のスクリプトをモデルが返すコードに置き換え、そのタスクの結果スキーマを定義します。認可、リソース制限、出力の確認はバックエンドで行ってください。終了コードが成功したというだけでは、答えが正しいことの証明にはなりません。
AIサンドボックスで構築できるもの
データ分析: ユーザーのアップロードを処理し、Pythonを実行して、チャートや小さなJSON結果を返します。ファイルサイズと実行時間を制限し、ユーザーが必要とする出力のみを保持します。
コーディングエージェント: タスク固有のリポジトリのコピーをチェックアウトし、ファイルを編集してテストを実行します。別のワークフローが変更をマージまたはデプロイする前に、差分とテスト結果をレビューします。
アプリビルダー: 依存関係をインストールし、開発サーバーを起動して、プライベートプレビューを提供します。プレビューは、ダッシュボードのオリジンや認証とは分離しておきます。Lovableスタイルのアプリビルダーガイドで、より広範なアプリケーションフローを紹介しています。
ブラウザエージェント: タスクにUI操作が必要な場合は、ブラウザとデスクトップを備えたランタイムを使用します。ログイン済みのセッションは、そのアカウントへのアクセス権を持つ認証情報として扱ってください。
Lizard Sandboxesは、シェルコマンド、ファイルアクセス、プライベートHTTPSプレビューを提供します。ブラウザやデスクトップの作業にはdesktopテンプレートを使用します。開発プレビューとデプロイされたアプリケーションでは有効期間が異なります。ユーザーが必要とする方を選択してください。Lizard Sandboxesを参照してください。
AIサンドボックスのコスト
コマンド間の待機時間を含む、総実行時間から計算を始めます。そこにストレージ、モデル呼び出し、アプリケーションが使用するその他のサービスを追加します。
2026年10月17日時点のLizardのコンピューティング料金は以下の通りです。
| サイズ | vCPU | RAM | 1時間あたりのコンピューティング |
|---|---|---|---|
| Small | 2 | 4 GB | $0.0162 |
| Medium | 4 | 8 GB | $0.0324 |
| Large | 8 | 16 GB | $0.0648 |
Lizardは、アイドル時間を含め、サンドボックスの実行中は秒単位でコンピューティングを計量します。Lizard Proは月額$19で、$19分の利用枠が含まれます。超過分はpay as you go(従量課金)となります。Persistent Volumesは1GBあたり月額$0.14です。予算を立てる前に最新の料金を確認してください。
サンドボックスを5分間実行し続けるSmallジョブを1,000回実行する場合:
1,000 × (5 / 60 hours) × $0.0162 = $1.35 in compute usageこれはワークロードのコンピューティング部分です。総請求額には、Proのサブスクリプションと利用枠を超えた使用量が含まれます。モデルのトークンは別途費用がかかります。
これらのジョブがそれぞれサンドボックスをさらに1時間実行したままにすると、コンピューティング使用量に**$16.20**が追加されます。明示的な有効期間と確実なクリーンアップは、時間あたりの料金のわずかな違いよりも重要になる場合があります。
AIサンドボックスの選び方
ユーザーが実行するジョブでテストしてください。簡単なシェルコマンドを実行しただけでは、リポジトリのビルドやブラウザセッションについてはほとんどわかりません。
起動時間、依存関係のインストール時間、タスクの合計時間、失敗回数、総実行秒数を記録します。中央値だけでなく、最も遅いリクエストも確認してください。E2B、Daytona、Modalの比較は、実行ワークフローを比較する際の出発点となります。
ランタイムを採用する前に、以下の質問に答えてください。
- ある顧客のコードやファイルを、他の顧客のものとどのように分離するか?
- 生成されたコードは、どのシークレットや外部サービスにアクセスできるか?
- ランタイムは、タスクに必要な言語、パッケージ、ブラウザツールを実行できるか?
- コントローラーがクラッシュしたり接続が切れたりした場合はどうなるか?
- シャットダウン後も残るファイルはどれで、どのようにバックアップするか?
- アイドル時間、ストレージ、モデル呼び出しを含めたワークロード全体のコストはいくらになるか?
最初は、1つのタスク、1つの一時的なサンドボックス、そして検証済みの小さな結果から始めてください。Lizard Sandboxesを作成してそのフローを測定し、アプリケーションで必要になった時点で永続化や長時間のセッションを追加します。
AI で構築。Lizard で公開。
本番公開にプラットフォームチームは必要ありません。クラウド全体が、1 つの CLI コマンドですぐ使えます。
- サービス
- —
- アドオン
- —
- デプロイ
- —
- Sandboxes の起動数
- —