Nullstead

Cloudflare

Cloudflare Dynamic Workers実践ガイド:AI生成コードを安全に隔離実行する設計と運用

Cloudflare Dynamic Workersを使い、AIが生成したコードを安全かつ高速に実行するための実践ガイド。load/getの使い分け、globalOutboundによる通信制御、課金設計、Tailによる観測性まで個人開発目線で解説します。

約10分

AIエージェントにコードを書かせる流れは、もはや「未来の話」ではなく、今日の運用課題です。便利なのは間違いないのですが、eval() で本番に直結させるのは、さすがに心臓に悪いです。私の心拍数も、インシデントレスポンス体制も追いつきません。

そこで最近注目しているのが、Cloudflareの Dynamic Workers です。2026年3月にオープンベータが発表され、AI生成コードを隔離実行するための選択肢として一気に現実味が増しました。

この記事では、Dynamic Workersを「速いらしい新機能」として眺めるのではなく、個人開発・小規模SaaSでどう設計に落とし込むかを解説します。特に次の3点を中心に、実装と運用の両面から整理します。

  • どこが本当に速いのか(起動・スケール・体感遅延)
  • どこまで閉じ込められるのか(ネットワーク・権限・秘密情報)
  • どう観測して事故率を下げるか(Tail・ログ・再現性)

「AIが勝手にコードを書いて実行する世界、便利だけど怖いんだよな……」という方に向けて、怖さを設計に変える手順をまとめました。

なぜ今、Dynamic Workersなのか

Cloudflareの発表では、Dynamic Workersは「Workerが別のWorkerを実行時に生成・起動する仕組み」です。ポイントは、実行コードをデプロイ時ではなく実行時に決められることです。AIがその場で生成したコードを、その場で隔離環境に載せて処理できます。

ここで効くのが、Cloudflare Workers基盤のアイソレート(※V8 isolate: JavaScript実行エンジンの軽量隔離単位)です。公式ブログでは、コンテナと比べて「起動が数ミリ秒」「メモリ効率が高い」ことを打ち出しています。さらにDynamic Workersは、load() で都度実行、get(id, callback) で同一コードのウォーム再利用、という使い分けができます。

この2モードの違いは地味に重要です。

  • load():毎回新しいコードを1回だけ実行したいときに向く
  • get():同一ロジックを複数回呼ぶときに向く(ID単位で再利用されうる)

要するに「ワンショットなAI実行」と「アプリ機能としての継続実行」を同じ構文で扱えます。個人開発では、試作と本番導線が分断されがちなので、これはかなりありがたいです。

速さの正体:コンテナを速くしたではなく別物で設計した

Dynamic Workersを語るときに「100x速い」という数字が独り歩きしがちですが、ここは冷静に読み解くべきです。重要なのは魔法の最適化ではなく、実行モデルそのものが違うことです。

Cloudflareの説明を整理すると、速さの源泉は主に次の3つです。

  1. アイソレート起動が軽量(数ミリ秒オーダー)
  2. 同一エッジ上で処理が閉じやすく、遠距離往復が減る
  3. get() によるウォーム再利用で、再起動コストを抑えられる

ここでやりがちな誤解は「じゃあ全部Dynamic Workersに寄せれば勝ち?」です。実際には、ワークロード次第です。

  • 長時間の重い処理やネイティブ依存が強い処理は、従来のコンテナ系が適する場面もある
  • 逆に、短いステップを大量に安全実行する処理はDynamic Workersと相性が良い

つまり「速い=万能」ではありません。短く・小さく・頻繁に発生するAI実行にフォーカスすると価値が最大化されます。たとえば次のようなケースです。

  • エージェントがAPI呼び出し手順をコード化して1回だけ走らせる
  • ユーザー入力ごとに小さな変換ロジックを生成・実行する
  • ワークフローの途中で一時的な検証コードを差し込む

「大砲で蚊を撃つ」より「蚊取り線香を部屋ごとに配る」ほうが現実的、というイメージです。虫の例えで恐縮ですが、運用はだいたい虫との戦いに似ています。

セキュリティ設計の本丸:何を実行できるかより何に触れられないか

AI生成コードの実行で一番大事なのは、賢さではなく境界です。Dynamic WorkersのAPIで特に効くのが次の2点です。

  • env で渡したものしか触れさせない(明示的能力付与)
  • globalOutbound で外向き通信を遮断・中継できる

globalOutbound: null は最初のデフォルトにする

公式リファレンスでは globalOutbound: null にすると fetch() / connect() が失敗し、外部通信が全面遮断されます。これは、AI実行の初期設定として非常に強いです。

まずは通信禁止で始め、必要な送信先だけゲートウェイ経由で許可するほうが、事故率は大きく下がります。とくにプロンプトインジェクション(※入力文に紛れた誘導で想定外操作をさせる攻撃)を想定するなら、ネットワーク境界で止める設計はほぼ必須です。

秘密情報は「注入する」、見せない

Dynamic Workersでは、Service Binding(※Worker間RPC接続)を介して、親Worker側で認証情報を注入できます。実行コードにトークンを配る必要はありません。

これは実務上かなり効きます。

  • AI生成コードにAPIキーを文字列で渡さない
  • 呼び出し先ごとに代理APIを用意し、必要最小操作だけ公開する
  • 監査ログは代理API側で一元記録する

「鍵を渡さず、開ける操作だけ貸す」モデルです。金庫の前に立たせても、暗証番号を教えなければ破壊力は限定できます。

実装ミニマム:まずは3ファイルで試す

以下は、最小構成で動作イメージを掴むための例です(動作未検証のサンプルですが、公式API仕様に沿っています)。

// host-worker.ts
export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    const code = `
      export default {
        async run(input, env) {
          // 通信禁止なら fetch は使えない
          return { ok: true, echo: input.text.toUpperCase() };
        }
      }
    `;

    const worker = env.LOADER.load({
      compatibilityDate: '2026-03-24',
      mainModule: 'agent.js',
      modules: { 'agent.js': code },
      globalOutbound: null,
      env: {
        SAFE_CONFIG: { mode: 'demo' }
      }
    });

    const body = await request.json();
    const result = await worker.getEntrypoint().run(body, {});
    return Response.json(result);
  }
};

wrangler.jsonc 側は次のように worker_loaders を追加します。

{
  "name": "dynamic-host",
  "main": "src/index.ts",
  "compatibility_date": "2026-03-24",
  "worker_loaders": [{ "binding": "LOADER" }]
}

TypeScriptやnpm依存をその場で使いたい場合は @cloudflare/worker-bundler が用意されています。生成コードのビルド工程を親Worker内に取り込めるので、ツールチェーン分岐を減らせます。

コストの落とし穴:速いと安いは同義ではない

Dynamic Workersの料金は、公式ドキュメント上は3軸です。

  1. 生成されたDynamic Worker数(1日単位)
  2. リクエスト数
  3. CPU時間

さらに重要なのが、load() と get() で課金特性が変わる点です。load() は毎回新規扱いになりやすく、作成数が増えます。大量トラフィック時に無邪気に load() 連打すると、性能は出ても請求書で現実に引き戻されます。

実運用では、次のようなルールを先に決めておくのがおすすめです。

  • 同一コード再利用可能なら get() を優先
  • ID設計にハッシュを使い「同一コード判定」を明確化
  • ユーザー単位IDを乱発せず、ロジック単位IDに寄せる
  • 1リクエスト内のRPC呼び出し回数を抑える

「最適化は後で」でも良いのですが、Dynamic Workersは生成単位が料金軸に入るため、ID戦略だけは先に決めるのが安全です。

観測性(Observability)を最初から入れる

AI実行基盤は、失敗したときの再現が難しいです。だからこそTail Worker(※実行ログやエラーを受け取る仕組み)を初期から入れておく価値があります。

APIリファレンスでは tails オプションでTail Workerを紐付けられます。これを使って、最低限次の情報を残しましょう。

  • dynamic worker ID
  • コードハッシュ
  • 入力サイズ(中身は必要最小限・マスク済み)
  • 実行時間・失敗種別・拒否した外向き通信先

このログがあるだけで、障害対応の難易度が激減します。逆にここをケチると「昨日は動いたのに今日は動かない」が永久機関になります。開発者の睡眠時間を守るためにも、観測性は機能要件です。

私が採っている運用パターン(個人開発向け)

最後に、私が個人開発で採るならこうする、という現実的な構成を共有します。

  1. 入口Workerで入力検証(スキーマ・サイズ・禁止語)
  2. Dynamic Workerは globalOutbound: null で起動
  3. 必要な外部連携は親側RPC経由の「細いAPI」だけ公開
  4. get(codeHash) を基本にしてウォーム再利用
  5. Tailで実行証跡を記録し、失敗ケースを週次で見直し

この構成の良いところは、AIモデルの差し替えに強い点です。モデルが変わっても、境界(通信・権限・監査)は同じです。つまり「モデルの気分」に運用品質を委ねないで済みます。

もちろん、万能ではありません。CPU重い処理、長時間処理、ネイティブ依存が強い処理は別基盤が適することもあります。ただ、AIが小さなコード断片を量産する時代には、Dynamic Workersの「速く・狭く・観測付き」という性格はかなり実用的です。

AIエージェント時代の実行基盤は、派手なデモより地味な境界設計で差がつきます。今日のところは、globalOutbound: null を1行入れるところから始めるのが、いちばん効果が高いと思います。地味ですが、地味こそ正義です。運用はだいたい、地味な勝利の積み重ねなので。

参考リンク

Tags #Cloudflare #Dynamic Workers #AIエージェント #セキュリティ #自動化