これまで私自身、個人開発でエージェントに何かを任せるとき、計画・実行・検証のループを自分のコードで組んでいました。プロンプトを投げ、返ってきたツール呼び出しを解釈し、結果を戻し、また投げる。動きはしますが、状態管理とリトライの面倒はすべて自分のものです。
6月に Gemini API で公開プレビューになった antigravity-preview-05-2026 は、その面倒の大半をサーバー側に寄せてしまう選択肢です。サンドボックス内で計画・推論・コード実行・ファイル操作・ウェブ閲覧までを自律で回す Managed Agent で、呼び出す側は「目的」を渡し、結果を待つだけになります。
便利な反面、これは設計判断を必要とします。何を Managed に預け、何を手元に残すか。ここを曖昧にすると、コストも制御性も中途半端になります。この記事は、その線引きを実装とともに整理したメモです。
Managed Agent と自前オーケストレーションの責務境界
まず、両者は競合ではなく層が違います。私の整理はこうです。
- 手元で持つべきもの: いつ起動するか(スケジュール)、何を目的に渡すか、結果をどう検証して取り込むか。ここはビジネスロジックであり、外には出せません。
- Managed に預けてよいもの: 目的を達成するための中間ステップ。ファイルを書き、コマンドを試し、失敗したら別の手を打つ——この試行錯誤のループ自体です。
言い換えると、Managed Agent は「どうやるか」を引き受け、こちらは「何を・いつ・どう受け取るか」に集中します。自前でツールループを書いていたときに一番神経を使っていたのは中間の状態管理でしたから、そこが消えるのは大きい。
ただし、すべてを預けてよいわけではありません。出力の検証だけは手元に残します。エージェントが「できました」と言っても、それを信じて本番に取り込むのは別の話です。
最小の呼び出しから始める
公開プレビューのモデル名を指定して、目的を一つ渡すところから始めます。下は Node の例です。
import { GoogleGenerativeAI } from "@google/generative-ai";
const genai = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
// Managed Agent はサンドボックス付きの長時間ジョブとして起動する
async function startAgentJob(goal) {
const model = genai.getGenerativeModel({
model: "antigravity-preview-05-2026",
});
const job = await model.startAgentTask({
goal,
sandbox: { filesystem: true, network: "restricted" },
maxSteps: 24, // 暴走を止める上限を必ず置く
});
return job.id; // 同期で待たず、ジョブ ID を受け取る
}
ここでの要点は二つです。maxSteps で上限を必ず置くこと。そして同期で結果を待たず、ジョブ ID を受け取って後で取りに行く設計にすること。Managed Agent は分単位で動くことがあり、HTTP リクエストを開いたまま待つのは現実的ではありません。
長時間タスクをポーリングで回す
ジョブ ID を持ったら、状態をポーリングして完了を待ちます。私はバックグラウンドのスケジュールタスクから、この形で回しています。
async function waitForJob(model, jobId, { intervalMs = 5000, timeoutMs = 600000 } = {}) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const status = await model.getAgentTask(jobId);
if (status.state === "succeeded") return status.result;
if (status.state === "failed") {
// 失敗理由はログに残す。黙ってリトライしない
throw new Error(`agent failed: ${status.error?.reason ?? "unknown"}`);
}
// running の間は待つ。指数的に間隔を伸ばしてもよい
await new Promise((r) => setTimeout(r, intervalMs));
}
throw new Error("agent timeout");
}
failed のときに黙ってリトライしない、というのは経験から来ています。Managed Agent の失敗は、一時的なものと、目的そのものが曖昧で達成不能なものが混ざります。後者を機械的にリトライすると、同じ失敗にコストだけ払い続けます。失敗理由をログに残し、目的の渡し方を見直すほうが結果的に速い。
サンドボックスとネットワークの設計
sandbox.network を restricted にしているのは意図的です。Managed Agent はウェブ閲覧ができますが、目的に外部アクセスが要らないなら閉じておくべきです。理由は二つあります。
第一に、再現性です。ネットワークを開くと、同じ目的でも実行のたびに外部の状態に引きずられ、結果がぶれます。第二に、安全性です。自律エージェントに自由なネットワークとファイル書き込みを同時に許すのは、最小権限の原則から外れます。私はネットワークを既定で閉じることを強く推奨します。
私の運用では、外部情報の取得が必要なタスクは、まず手元で取得して目的のコンテキストに含め、Managed Agent には閉じたサンドボックスで加工だけ任せています。取得と加工を分けるこの形は、デバッグも楽になりました。どこで何が起きたかが切り分けやすいからです。
コストと冪等性の落とし穴
実運用で最初に効いてくるのがコストです。Managed Agent は中間ステップごとに推論を回すため、maxSteps を緩めに置くと、一回のジョブで想像以上のトークンを使います。私は最初、上限を 64 にして回し、軽いタスクでも上限近くまで歩き回った日に、月の API 予算の約30%を数日で削りました。
二つ目は冪等性です。Managed Agent はファイルを書き、コマンドを実行します。同じジョブを二度起動すれば、二度書きます。スケジュールタスクから呼ぶなら、目的に「すでに存在する場合は何もしない」という条件を明示するか、こちら側で実行済みフラグを持つべきです。
maxSteps は軽いタスクで 12〜24、重いタスクでも 48 を超えない範囲から始める
- 失敗は分類してから対応する。一時障害だけ自動リトライ、目的の曖昧さは人が見直す
- ジョブの起動前に「同じ目的を直近で投げていないか」を自分の側で確認する
- ネットワークは既定で閉じ、必要なときだけ明示的に開く
どこで Managed を選び、どこで自前を残すか
最後に、私の使い分けです。Managed Agent が向くのは、中間ステップが多く、試行錯誤が本質で、結果を最後にまとめて検証できるタスクです。たとえば、雑多な入力から構造化データを起こす、断片的な情報を一つの下書きにまとめる、といった作業です。
逆に、自前のツールループを残すのは、一手ごとに人の判断や厳密な検証を挟みたいタスクです。本番デプロイや課金まわりの操作は、私は今も中間で必ず止めます。自律に任せて速いことより、止められることのほうが価値が大きい領域だからです。
Managed Agent は「自律をどこまで預けるか」という古い問いに、新しい粒度を与えてくれます。まずは閉じたサンドボックスと小さな maxSteps で、捨ててよいタスクから一つ試してみてください。預けてよい範囲は、動かしてみて初めて手触りでわかります。