昨年6月にCloudflare Sandboxesをローンチしたときの前提条件はシンプルでした。AIエージェントはコードを開発・実行する必要があり、それを安全な場所で行う必要があるということでした。
エージェントが開発者のように行動している場合、これは、リポジトリのクローン、多くの言語でのコードの構築、開発サーバーの実行などを意味します。これらのことを効果的に行うには、しばしばフルコンピューターが必要になります(そうでなくても、軽量のものを入手することもできます!)。
多くの開発者は、VMや既存のコンテナソリューションを使ったソリューションを組み合わせてはいますが、まだまだ解決の難しい問題がたくさんあります。
バースト性 - 各セッションに固有のサンドボックスが必要なため、多くの場合、多くのサンドボックスを迅速に立ち上げる必要がありますが、待機中のアイドル状態のコンピューティングに対する支払いはしたくないと考えます。
迅速な状態復元 - 各セッションは迅速に開始および再開され、過去の状態を復元します。
セキュリティ - エージェントはサービスに安全にアクセスする必要がありますが、資格情報を信頼することはできません。
制御 - サンドボックスのライフサイクルの制御、コマンドの実行、ファイルの処理などをプログラムで簡単に行える必要があります。
人間工学 - 人間とエージェントが一般的な操作を行えるように、シンプルなインターフェースを提供する必要があります。
お客様がこれらの問題に悩まされることがないよう、当社は、これらの問題を解決するために多大な時間を費やしました。最初のリリース時と比較し、サンドボックスは大規模にエージェントを実行するのにさらに優れた場所となっています。Figma Makeなど、コンテナ内でエージェントを実行している初期パートナー企業と協力してきました。
「Figma Makeは、あらゆるバックグラウンドを持つビルダーやメーカーがアイデアから本番環境まで、より速く移行できるよう構築されています。その目標を達成するためには、信頼性の低いエージェントやユーザーが作成したコードでも実行でき、尚且つ信頼性が高く、拡張性に優れたサンドボックス環境を提供できるインフラソリューションが必要でした。Cloudflareのコンテナこそがその解決策なのです。」
- Alex Mullans、Figma AI・開発者プラットフォーム担当
サンドボックスをさらに多くの素晴らしい企業に提供すべく、本日、SandboxesとCloudflare Containersの両方が一般提供開始となったことを発表いたします。
サンドボックスへの最近の変更:
セキュアなクレデンシャルインジェクションにより、エージェントが資格情報にアクセスすることなく、認証済みの呼び出しが可能
PTYサポートは、ご自身とエージェントに実際の端末を提供
永続的なコードインタープリターは、エージェントにステートフルなPython、JavaScript、およびTypeScriptをすぐに実行できる場所を提供
バックグラウンドプロセスとライブプレビューURLで、開発サーバーと簡単にやり取りし、実行中の変更を検証
ファイル監視は、エージェントが変更を行う際の反復速度を向上
スナップショットでエージェントのコーディングセッションがすぐに回復
より高い上限とアクティブCPU課金により、未使用のCPUサイクルに支払うことなく、エージェントを大規模に展開
最近の変更点について説明する前に、まず基本事項を確認しましょう。
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) {
// Ask for a sandbox by name. It starts on demand.
const sandbox = getSandbox(env.Sandbox, "agent-session-47");
// Clone a repository into it.
await sandbox.gitCheckout("https://github.com/org/repo", {
targetDir: "/workspace",
depth: 1,
});
// Run the test suite. Stream output back in real time.
return sandbox.exec("npm", ["test"], { stream: true });
},
};
同じIDを提供している限り、後続のリクエストは世界中どこからでも同じサンドボックスに到達できます。
エージェンティックワークロードで最も難しい問題の1つが認証です。プライベートサービスにアクセスするにはエージェントが必要な場合が多くありますが、未加工の認証情報は完全に信頼することはできません。
サンドボックスは、プログラム可能なエグレスプロキシを使って、ネットワーク層で認証情報を挿入することにより、これを解決します。つまり、サンドボックスエージェントは決して認証情報にアクセスできないため、状況に合わせて認証ロジックを完全にカスタマイズすることができます。
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 });
}
}
}
ID認識型認証情報インジェクション、ルールの動的変更、Workersバインディングとの統合など、この仕組みの詳細については、サンドボックス認証に関する最近のブログ記事をお読みください。
初期のエージェントシステムでは、多くの場合、シェルへのアクセスをリクエストレスポンスのループとしてモデル化していました。つまり、コマンドを実行し、出力を待ち、そのログをプロンプトに戻し、これを繰り返すという仕組みだったのです。動作はするものの、これは開発者が実際に端末を使用する方法ではありません。
人間は何かを実行し、アウトプットストリームを見て、中断し、後で再接続し、作業を継続します。エージェントも同じフィードバックループの恩恵を受けます。
2月にPTYサポートの提供を開始しました。xterm.jsと互換性があり、WebSocketを介してプロキシされるSandboxの擬似端末セッションです。
sandbox.terminalを呼び出すだけで、バックエンドを提供できます。
// Worker: upgrade a WebSocket connection into a live terminal session
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アドオンを使ってクライアントから呼び出します。
// Browser: connect xterm.js to the sandbox shell
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つのステップで変数を設定し、次のステップで読み取ることはできません。
サンドボックスを使用すると、状態を保持する「コンテキスト」を作成できます。変数とインポートは、Jupyterノートブックの場合と同様、以下のように関数呼び出しをまたいで保持されます。
// Create a Python context. State persists for its lifetime.
const ctx = await sandbox.createCodeContext({ language: "python" });
// First execution: load data
await sandbox.runCode(`
import pandas as pd
df = pd.read_csv('/workspace/sales.csv')
df['margin'] = (df['revenue'] - df['cost']) / df['revenue']
`, { context: ctx });
// Second execution: df is still there
const result = await sandbox.runCode(`
df.groupby('region')['margin'].mean().sort_values(ascending=False)
`, { context: ctx, onStdout: (line) => console.log(line.text) });
// result contains matplotlib charts, structured json output, and Pandas tables in HTML
エージェントは、何かを構築してユーザーにすぐに表示できる場合、より有用だと言えます。サンドボックスは、バックグラウンドプロセス、準備状況チェック、プレビューURLをサポートします。これにより、エージェントは開発サーバーを起動し、会話を離れることなくライブリンクを共有できます。
// Start a dev server as a background process
const server = await sandbox.startProcess("npm run dev", {
cwd: "/workspace",
});
// Wait until the server is actually ready — don't just sleep and hope
await server.waitForLog(/Local:.*localhost:(\d+)/);
// Expose the running service with a public URL
const { url } = await sandbox.exposePort(3000);
// url is a live public URL the agent can share with the user
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設定、インストールされた依存関係、変更されたファイル、データファイルなどを保持します。その後、迅速な復元が可能です。
サンドボックスがスリープ状態になる時に自動的にスナップショットするように設定することができます。
class AgentDevEnvironment extends Sandbox {
sleepAfter = "5m";
persistAcrossSessions = {type: "disk"}; // you can also specify individual directories
}
プログラムでスナップショットを作成し、手動で復元することもできます。これは、作業のチェックポイントやセッションをフォークするのに便利です。たとえば、エージェントの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の階層型キャッシングシステムにより、地球上のすべてのリージョンで高速リストアが可能です。
将来のリリースでは、ライブメモリの状態もキャプチャされ、実行中のプロセスが中断した場所から再開できるようになります。端末とエディターは、最後に閉じたときの正確な状態で再開します。
スナップショットが公開される前のセッション状態を復元することに興味がある方は、今すぐバックアップと復元の方法をご利用いただけます。これらも、R2を使ってディレクトリを永続化して復元しますが、真のVMレベルのスナップショットほどパフォーマンスは高くありません。それでも、セッションの状態を単純に再作成するよりも、かなりの速度改善につながる可能性があります。
サンドボックスの起動、「axios」のクローン、npmのインストールには30秒かかります。バックアップからの復元には2秒かかります。
公式スナップショットのリリースにご期待ください。
設立以来、着実に容量を拡大しています。Standard料金プランのユーザーは、ライトインスタンスタイプを15,000、基本インスタンスを6,000、そして1,000以上の大規模インスタンスを同時に実行できるようになりました。それ以上の規模での運用をお望みなら、ぜひお問い合わせください!
また、大規模に運用するために、より費用対効果の高いものにするために価格設定モデルを変更しました。サンドボックスは、アクティブに使用されたCPUサイクルに対してのみ課金されるようになりました。つまり、エージェントがLLMの応答を待つ間、アイドル状態のCPU料金を支払わなくて済むということです。
9か月前、当社はコマンドを実行し、ファイルシステムにアクセスできるサンドボックスを出荷しました。概念を証明するのに十分なものでした。
今あるものは異なる種類のものです。今日のサンドボックスは、ブラウザを接続できるターミナル、永続的な状態を持つコードインタープリター、ライブプレビューURLを備えたバックグラウンドプロセス、リアルタイムで変更イベントを出力するファイルシステム、安全なクレデンシャルインジェクションのためのエグレスプロキシ、そしてウォームスタートをほぼ瞬時に可能にするスナップショットメカニズムを備えた、完全な開発環境です。
その上に、満足のいくパターンが生まれます。それは、真のエンジニアリング作業を行うエージェントです。レポジトリをクローンし、インストールし、テストを実行し、失敗を読み取り、コードを編集し、再度テストを実行します。人間のエンジニアを効果的にする密接なフィードバックループが、今やエージェントにももたらされます。
現在、SDKのバージョン 0.8.9を使用しています。今すぐ始める:
npm i @cloudflare/sandbox@latest