Sandboxes GAによりエージェントが独自のコンピューターを持つ
2026年4月13日 | Kate Reznykova、Mike Nomitch | 6分で読める
昨年6月にCloudflare Sandboxesをローンチした際、前提はシンプルでした:AIエージェントはコードを開発・実行する必要があり、それを安全な場所で行う必要があります。エージェントが開発者のように動作するということは、リポジトリのクローン、多言語でのコード構築、開発サーバーの実行などを意味します。これらを効果的に行うには、多くの場合フルコンピューターが必要です(必要でない場合は、軽量なものを選択できます!)。
多くの開発者がVMや既存のコンテナソリューションを使用してソリューションを組み合わせていますが、解決すべき困難な問題が多数あります:
- バースト性 - 各セッションが独自のサンドボックスを必要とするため、多くのサンドボックスを迅速にスピンアップする必要がありますが、待機中のアイドルコンピューティングに対して支払いたくありません。
- 迅速な状態復元 - 各セッションは迅速に開始し、迅速に再開して、過去の状態を復元する必要があります。
- セキュリティ - エージェントはサービスに安全にアクセスする必要がありますが、認証情報を信頼することはできません。
- 制御 - サンドボックスのライフサイクルをプログラム的に制御し、コマンドを実行し、ファイルを処理することなどを簡単に行える必要があります。
- エルゴノミクス - 人間とエージェントの両方が一般的な操作を行うためのシンプルなインターフェースを提供する必要があります。
私たちはこれらの問題を解決するために時間を費やしてきたので、あなたがその必要はありません。
パートナーとの協力
初期ローンチ以来、Sandboxesをエージェントを大規模に実行するためのさらに優れた場所にしてきました。Figma Make でコンテナ内でエージェントを実行するFigmaなどの初期パートナーと協力してきました:
「Figma Makeは、あらゆる背景を持つビルダーやメーカーがアイデアから本番環境まで、より迅速に進むのを支援するために構築されています。その目標を達成するために、信頼できない、エージェントやユーザーが作成したコードを実行できる信頼性が高く、高度にスケーラブルなサンドボックスを提供できるインフラストラクチャソリューションが必要でした。Cloudflare Containersがそのソリューションです。」
- Alex Mullans、FigmaのAI・開発者プラットフォーム担当
Sandboxesをさらに多くの優れた組織に提供したいと考えており、本日、SandboxesとCloudflare Containersの両方が一般提供開始されることを発表できることを嬉しく思います。
Sandboxesの最近の変更
Sandboxesの最近の変更をいくつか見てみましょう:
- 安全な認証情報注入 - エージェントが認証情報にアクセスすることなく認証済み呼び出しを行えます
- PTYサポート - あなたとエージェントに本物のターミナルを提供します
- 永続的なコードインタープリター - エージェントがステートフルなPython、JavaScript、TypeScriptをすぐに実行できる場所を提供します
- バックグラウンドプロセスとライブプレビューURL - 開発サーバーとやり取りし、進行中の変更を検証するシンプルな方法を提供します
- ファイルシステム監視 - エージェントが変更を行う際の反復速度を向上させます
- スナップショット - エージェントのコーディングセッションを迅速に復旧できます
- より高い制限とActive CPU Pricing - 未使用のCPUサイクルに対して支払うことなく、エージェントのフリートを大規模にデプロイできます
Sandboxes 101
最近の変更について詳しく説明する前に、基本を簡単に見てみましょう。
Cloudflare SandboxはCloudflare Containersによって動力を得る永続的で分離された環境です。名前でサンドボックスを要求します。実行中の場合は、それを取得します。実行中でない場合は、開始します。アイドル状態の場合は、自動的にスリープし、リクエストを受信すると起動します。
exec、gitClone、writeFileなどのメソッドを使用してサンドボックスとプログラム的にやり取りするのは簡単です。
import { getSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
export default {
async fetch(request: Request, env: Env) {
const sandbox = getSandbox(env.Sandbox, "agent-session-47");
await sandbox.gitCheckout("https://github.com/org/repo", {
targetDir: "/workspace",
depth: 1,
});
return sandbox.exec("npm", ["test"], {
stream: true
});
},
};
同じIDを提供する限り、後続のリクエストは世界中のどこからでもこの同じサンドボックスにアクセスできます。
安全な認証情報注入
エージェントワークロードにおける最も困難な問題の1つは認証です。多くの場合、エージェントがプライベートサービスにアクセスする必要がありますが、生の認証情報を完全に信頼することはできません。
Sandboxesは、プログラム可能なエグレスプロキシを使用してネットワーク層で認証情報を注入することでこれを解決します。これは、サンドボックスエージェントが認証情報にアクセスすることがなく、必要に応じて認証ロジックを完全にカスタマイズできることを意味します:
class OpenCodeInABox extends Sandbox {
static outboundByHost = {
"my-internal-vcs.dev": (request, env, ctx) => {
const headersWithAuth = new Headers(request.headers);
headersWithAuth.set("x-auth-token", env.SECRET);
return fetch(request, { headers: headersWithAuth });
}
}
}
これがどのように動作するかの詳細については、アイデンティティ対応認証情報注入、動的ルール変更、Workers bindingsとの統合を含む、Sandbox認証に関する最近のブログ投稿をお読みください。
本物のターミナル、シミュレーションではない
初期のエージェントシステムは、多くの場合シェルアクセスをリクエスト-レスポンスループとしてモデル化していました:コマンドを実行し、出力を待ち、トランスクリプトをプロンプトに戻し、繰り返す。これは機能しますが、開発者が実際にターミナルを使用する方法ではありません。
人間は何かを実行し、出力がストリーミングされるのを見て、それを中断し、後で再接続し、続行します。エージェントも同じフィードバックループから恩恵を受けます。
2月に、PTYサポートを出荷しました。SandboxでのPseudo-terminalセッション、WebSocket経由でプロキシされ、xterm.jsと互換性があります。バックエンドを提供するにはsandbox.terminalを呼び出すだけです:
export default {
async fetch(request: Request, env: Env) {
const url = new URL(request.url);
if (url.pathname === "/terminal") {
const sandbox = getSandbox(env.Sandbox, "my-session");
return sandbox.terminal(request, { cols: 80, rows: 24 });
}
return new Response("Not found", { status: 404 });
},
};
クライアントからxtermアドオンを使用して呼び出します:
import { Terminal } from "xterm";
import { SandboxAddon } from "@cloudflare/sandbox/xterm";
const term = new Terminal();
const addon = new SandboxAddon({
getWebSocketUrl: ({ origin }) => `${origin}/terminal`,
});
term.loadAddon(addon);
term.open(document.getElementById("terminal-container")!);
addon.connect({ sandboxId: "my-session" });
これにより、エージェントと開発者がフルPTYを使用してこれらのセッションをライブでデバッグできます。各ターミナルセッションは独自の分離されたシェル、独自の作業ディレクトリ、独自の環境を取得します。必要なだけ開き、自分のマシンで行うのと同じように使用できます。出力はサーバー側でバッファリングされるため、再接続すると見逃したものが再生されます。
記憶するコードインタープリター
データ分析、スクリプト作成、探索的ワークフローのために、より高レベルの抽象化も提供しています:永続的なコード実行コンテキスト。
キーワードは「永続的」です。多くのコードインタープリター実装は各スニペットを分離して実行するため、呼び出し間で状態が消失します。1つのステップで変数を設定し、次のステップで読み取ることができません。
Sandboxesでは状態を永続化する「コンテキスト」を作成できます。変数とインポートは、Jupyterノートブックと同じように呼び出し間で永続化されます:
ctx = await sandbox.createCodeContext({ language: "python" });
await sandbox.runCode(`
import pandas as pd
df = pd.read_csv('/workspace/sales.csv')
df['margin'] = (df['revenue'] - df['cost']) / df['revenue']
`, { context: ctx });
const result = await sandbox.runCode(`
df.groupby('region')['margin'].mean().sort_values(ascending=False)
`, {
context: ctx,
onStdout: (line) => console.log(line.text)
});
// resultにはmatplotlibチャート、構造化json出力、HTMLのPandasテーブルが含まれる
サーバーを開始。URLを取得。出荷。
エージェントは何かを構築してユーザーにすぐに表示できるときにより有用です。Sandboxesはバックグラウンドプロセス、準備チェック、プレビューURLをサポートします。これにより、エージェントは開発サーバーを開始し、会話を離れることなくライブリンクを共有できます。
const server = await sandbox.startProcess("npm run dev", {
cwd: "/workspace",
});
await server.waitForLog(/Local:.*localhost:(\d+)/);
const { url } = await sandbox.exposePort(3000);
console.log(`Preview: ${url}`);
waitForPort()とwaitForLog()により、エージェントは推測ではなく実行中のプログラムからの実際のシグナルに基づいて作業をシーケンスできます。これは一般的な代替手段よりもはるかに優れており、通常はsleep(2000)の何らかのバージョンに続いて希望的観測です。
ファイルシステムを監視して即座に反応
現代の開発ループはイベント駆動です。ファイルを保存し、ビルドを再実行。設定を編集し、サーバーを再起動。テストを変更し、スイートを再実行。
3月にsandbox.watch()を出荷しました。これは、Linuxがファイルシステムイベントに使用するカーネルメカニズムであるネイティブinotifyによってサポートされるSSEストリームを返します。
import { parseSSEStream, type FileWatchSSEEvent } from '@cloudflare/sandbox';
const stream = await sandbox.watch('/workspace/src', {
recursive: true,
include: ['*.ts', '*.tsx']
});
for await (const event of parseSSEStream<FileWatchSSEEvent>(stream)) {
if (event.type === 'modify' && event.path.endsWith('.ts')) {
await sandbox.exec('npx tsc --noEmit', { cwd: '/workspace' });
}
}
これは、エージェントができることを静かに変える原始的な機能の1つです。リアルタイムでファイルシステムを観察できるエージェントは、人間の開発者と同じフィードバックループに参加できます。
スナップショットで迅速な起動
ラップトップで作業している(人間の)開発者を想像してください。リポジトリをgit clone し、npm install を実行し、コードを書き、PRをプッシュし、コードレビューを待つ間ラップトップを閉じます。作業を再開する時が来たら、ラップトップを再び開いて中断したところから続行するだけです。
エージェントがナイーブなコンテナプラットフォームでこのワークフローを複製したい場合、問題に遭遇します。中断したところから迅速に再開するにはどうすればよいでしょうか?サンドボックスを実行し続けることもできますが、その場合はアイドルコンピューティングに対して支払うことになります。コンテナイメージから新しく開始することもできますが、その場合は長いgit cloneとnpm installを待つ必要があります。
私たちの答えはスナップショットで、今後数週間でロールアウトされる予定です。スナップショットはコンテナの完全なディスク状態、OS設定、インストールされた依存関係、変更されたファイル、データファイルなどを保存します。その後、後で迅速に復元できます。
Sandboxがスリープ状態になったときに自動的にスナップショットを取るように設定できます。
class AgentDevEnvironment extends Sandbox {
sleepAfter = "5m";
persistAcrossSessions = {type: "disk"};
}
プログラム的にスナップショットを取得し、手動で復元することもできます。これは作業のチェックポイントやセッションのフォークに有用です。たとえば、エージェントの4つのインスタンスを並行して実行したい場合、同じ状態から4つのサンドボックスを簡単に起動できます。
class AgentDevEnvironment extends Sandbox {}
async forkDevEnvironment(baseId, numberOfForks) {
const baseInstance = await getSandbox(baseId);
const snapshotId = await baseInstance.snapshot();
const forks = Array.from({ length: numberOfForks }, async (_, i) => {
const newInstance = await getSandbox(`${baseId}-fork-${i}`);
return newInstance.start({ snapshot: snapshotId });
});
await Promise.all(forks);
}
スナップショットはアカウント内のR2に保存され、耐久性と場所の独立性を提供します。R2の階層キャッシュシステムにより、Region: Earth全体で高速復元が可能です。
将来のリリースでは、ライブメモリ状態もキャプチャされ、実行中のプロセスが中断したところから正確に再開できるようになります。ターミナルとエディターが再び開かれます。