◉ANTIGRAVITY LABEN
記事一覧/Agents & Manager
◈ Agents & Manager/2026-05-26上級

Antigravity マルチエージェントの状態タイプ階層 — ephemeral / journal / canonical の3層設計と引き継ぎパターン

Antigravity の Background Agent と Sub-agent の状態を ephemeral / journal / canonical の3層に分け、Cloudflare KV / Durable Objects / R2 / D1 へ落とす判断軸と、write-back に承認ゲートを噛ませる TypeScript 実装。ヘッドレス実行で承認が素通りしていた頃の失敗も書き残しました。

antigravity464agents100architecture13state-managementcloudflare-workers9

✦ プレミアム記事

ある朝、Antigravity の Background Agent が前日の AdMob レビュー結果を完全に忘れていて、同じ警告を3回続けて私のメールボックスに投げてきました。Agent run のログを追いかけると、メモリは持っているはずなのに、復元先のキーが微妙にずれて読み出せていなかった、というのが原因でした。個人でアプリを開発しながら、Antigravity を含むエディタ統合の AI エージェントで日々の運用を回しております。「Agent が情報を覚えていない/逆に覚えすぎている」現象に何度かやられてから、私自身の中で「Agent が抱える情報は、寿命の長さで3階層に分けないと必ず壊れる」という結論にたどり着きました。いま思えば、壊れていたのはメモリではなく、寿命の違う情報を同じ棚に並べていた私の設計だったのかもしれません。

本稿はその3階層 — ephemeral / journal / canonical — の責任分界と、Cloudflare Workers の物理ストア(KV / Durable Objects / R2 / D1)への落とし込み方、write-back 境界に承認ゲートを噛ませる実装をまとめたものです。Background Agent / Sub-agent / Browser Sub-agent を複数本並走させている方にとって、設計判断を1段落ずつ詰める材料になればと思います。

同じ Antigravity Agent でも、覚えていてほしい情報には3つの寿命がある

Antigravity の Agent が触る情報を雑に「メモリ」と呼んでしまうと、必ずどこかで破綻します。私が実運用で痛い目を見てから採用したのは、以下の3階層に責任を分ける考え方です。

階層寿命失われたときの被害例
ephemeral1 runほぼゼロ(再計算可能)中間プロンプト・思考ログ・LLM 出力の生テキスト
journal数日〜数週間中(再現に時間がかかる)意思決定ログ・実験結果・A/B 比較の中間スコア
canonical永続致命傷(サービス本体に直結)公開済み記事スラッグ・ユーザー購入記録・課金状態

ポイントは「失われたときに何が起きるか」で寿命を決めることです。情報量や物理的なサイズではありません。たとえば LLM の長い思考ログは数十万トークンあっても ephemeral で十分ですし、たった 1 件のスラッグ重複検知ログは canonical に置かないと事故ります。

この3階層に分けると、Agent コード側は次の3つだけを意識すればよくなります。

  1. その情報は、次の run で再計算できるか? → できるなら ephemeral
  2. 再計算できないが、最悪「やり直し」が許されるか? → 許されるなら journal
  3. 失えばユーザー体験そのものが壊れるか? → 壊れるなら canonical

これだけです。後述の通り、3層は別々の物理ストアにマッピングしますが、Agent 側コードからは統一的なインターフェースで扱えるようにアダプタを噛ませます。

ephemeral — 1回の Agent run 内だけで生きる作業メモリ

ephemeral は、Agent run の入口で生まれて出口で捨てられる情報です。中間プロンプト、LLM 応答の生テキスト、ファイル一覧の snapshot、検索結果、再計算の途中値、こういったものが該当します。失われても次の run で再生できるので、Cloudflare KV のような共有ストアに置く価値はほぼゼロです。

Antigravity の Background Agent では、私はこの層を Worker のローカルメモリ(つまり JavaScript の Map / Object)で完結させています。コードはこんな雛形です。

// state/ephemeral.ts
export class EphemeralStore {
  private bucket = new Map<string, unknown>();
 
  get<T = unknown>(key: string): T | undefined {
    return this.bucket.get(key) as T | undefined;
  }
 
  put<T = unknown>(key: string, value: T): void {
    this.bucket.set(key, value);
  }
 
  // run 終了時に必ず呼ぶ。意図的に明示する。
  dispose(): void {
    this.bucket.clear();
  }
}

意図的に dispose を明示しているのは、ephemeral を「黙って捨ててもいい」ではなく「能動的に捨てる」ものとして扱いたいからです。Sub-agent から戻ってきた中間 LLM 応答をうっかり journal や canonical に書き込んでしまうと、ストレージコストが青天井になります。私の場合、Background Agent 1本あたり ephemeral だけで 200〜800KB / run を扱うので、月単位だと GB スケールになります。これを真面目に KV に書いていたら月の運用予算 ¥800 では絶対に収まりません。

実装上の落とし穴も一つ書き残しておきます。Cloudflare Workers では同じ Isolate が次のリクエストにも再利用されることがあり、ephemeral として作った Map が次の run まで残ってしまう挙動を踏みました。これは Worker のグローバル変数として保持していた私のミスで、対処として EphemeralStore は必ず run のエントリ関数内で new するように変更しました。

この再利用は手元の wrangler dev では起きたり起きなかったりするので、テストで意図的に再現しておくのが確実だと思っております。私が置いているのは、同じ Worker に 2 回リクエストを投げ、モジュールスコープに漏れた Map が持ち越されていないかを見るだけの小さなものです。

// test/ephemeral-leak.test.ts — @cloudflare/vitest-pool-workers
import { SELF } from "cloudflare:test";
import { expect, it } from "vitest";
 
it("ephemeral は run をまたいで残らない", async () => {
  // Worker 側の /run?probe=1 は、その run で 1 件書いたあとの Map の件数を返す
  const first = await SELF.fetch("https://example.com/run?probe=1");
  const second = await SELF.fetch("https://example.com/run?probe=1");
  const a = await first.json<{ size: number }>();
  const b = await second.json<{ size: number }>();
  // どちらの run も、自分が書いた 1 件しか見えていないはず
  expect(a.size).toBe(1);
  expect(b.size).toBe(1);
});

テスト内の 2 回の呼び出しは同じ実行環境に載るので、Map がグローバルに漏れていれば 2 回目の size が 2 になります。このテストが赤くなった朝に初めて、自分がどこで new していたかを疑えるようになりました——落ちてくれるテストが 1 本あるだけで、Isolate の話は「たまに起きる怪現象」から「再現できる仕様」に変わるのです。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦ephemeral / journal / canonical の3階層分類で Agent 間の状態責任を明確化し、月¥800のサブ運用予算で破綻させない設計則
✦Cloudflare KV / Durable Objects / R2 / D1 のマッピング判断軸と TypeScript アダプタの最小実装、Isolate 再利用で ephemeral が漏れていないかを 2 リクエストで確かめる vitest
✦write-back を止める承認ゲートの最小実装(TypeScript)と、ヘッドレス実行の終了コード・--print-timeout と「保留」を取り違えないための判定表
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

◈ Agents & Manager2026-10-13
「いつもの感覚」で決めている判断を、エージェントに渡せる文章に直す手順
頭の中だけにある判断基準を、Antigravity のエージェントが同じように使える文章へ直す手順です。過去の事例で試し、ずれた箇所だけ直す小さな検証つきです。
◈ Agents & Manager2026-09-04
エージェントの実効スコープを書き出しておくと、既定が変わった日に気づけます
Antigravity 1.1.25 で、Markdown 定義のカスタムエージェントが既定で周囲のスキル・ルール・サブエージェントを継承するようになりました。絞ったつもりのエージェントが更新後に広がっていないかを、実効スコープの JSON スナップショットと差分で確かめる手順を書き残します。
◈ Agents & Manager2026-08-21
Antigravity CLI の継承設定は description の重なりを見てから決めています
CLI 1.1.14 で markdown 定義エージェントの継承が inheritCustomizations 一本にまとまりました。手元の 47 本のスキルを実際に棚卸しして、継承を有効にするかどうかをコンテキスト量ではなく description の重なりで決めるまでの記録です。