ANTIGRAVITY LABEN
記事一覧/Agents & Manager
Agents & Manager/2026-04-26上級

Antigravity エージェントに「失敗の理由が一発で分かる」トレースを設計する — 可観測性の実践

Antigravity でエージェントを動かすほど、「なぜ失敗したのか分からない」運用負債が蓄積します。スパン構造、属性設計、失敗モードのタグ付け、ダッシュボード設計、コスト可視化、リトライポリシーまで、本番投入後のデバッグ時間を短縮するためのトレース設計を、実運用 6 ヶ月の数値とともに整理します。

Antigravity338エージェント64可観測性2トレース2運用9OpenTelemetry

プレミアム記事

Antigravity でエージェントを本番に出してから半年が経ち、最初に積み上げた技術的負債は「失敗トレースが読めない」という問題でした。最初の頃は、console.log を散らかしてエージェント実行のステップを記録していました。1 日数十回の実行までは「ログを上から目で追う」で何とかなっていましたが、月数千回のオーダーになった途端、エラーが起きても「どのステップで何が起きたのか」が読めなくなりました。

可観測性ツールを導入して半年運用してきて、いまは「失敗トレースを 3 行読めば原因が分かる」状態に持っていけています。インシデント検知から原因特定までの平均時間(MTTR)も、導入前の 47 分から 11 分まで縮まりました。以下では、Antigravity エージェントに対するトレース設計の考え方と、私が実際にリポジトリで運用しているスパン構造・属性設計・失敗タグ付け・ダッシュボード・リトライポリシーまで、手を動かせる粒度でまとめます。

個人開発者として 2014 年からアプリ開発を続け、累計 5,000 万ダウンロードに到達するなかで、最初の壁紙アプリを App Store に出したとき、本番でのクラッシュレポートをまともに読める形に整えるまでに 3 ヶ月かかったことを覚えています。AdMob のレポートと Crashlytics のスタックトレースを毎晩突き合わせて、エラー分類を 1 つずつ手で増やしていった作業に近いものでした。今回エージェントの可観測性を整備した過程は、その経験をアーティスト・実装者として AI 時代の文脈に翻訳する作業に近いものでした。

なぜエージェントは「失敗の理由が分からない」状態に陥るのか

私が観測した中で、原因はおおよそ次の 3 つに集約されます。

ひとつ目は、ステップ境界が曖昧なケースです。エージェントは「ツール呼び出し → LLM 推論 → 状態更新」のサイクルを回しますが、この境界をログに記録していないと、エラーが「どのサイクルの、どのステップで」起きたのかが追えません。タイムスタンプ付きの平文ログだけ眺めても、サイクル間の構造が見えません。

ふたつ目は、入出力が黒箱になっているケースです。LLM 呼び出しの中で何が起きたかは記録するのに、その前後で渡したコンテキスト・受け取った生レスポンスが残っていない、という状態です。エラーは「LLM が変な返事をした」で終わってしまい、再現できません。

みっつ目は、失敗の分類が無いケースです。エラーログは出ているが「これがリトライすべきものか、ユーザーに通知すべきものか、コードのバグか」を後で判断できません。アラート疲れや、リトライポリシーの破綻に直結します。

可観測性の設計とは、この 3 つを構造化して残す仕組みを最初に作っておくことです。

トレースの基本単位 — スパン構造を決める

私は OpenTelemetry の概念に揃えて、エージェント実行を次の階層構造でスパン化しています。これは Antigravity 固有ではなく汎用的な構造ですが、エージェント特有の「サイクル」を 1 階層挟むのが大事です。

- agent.run               (ルートスパン: 1 回のエージェント実行全体)
  - agent.cycle           (推論・実行サイクル 1 回ぶん)
    - agent.plan          (LLM による次アクション決定)
    - agent.tool_call     (ツール実行 — 個別ツールごとに別スパン)
    - agent.observe       (実行結果を観測してコンテキストに反映)
  - agent.cycle
    - ...

このうち、agent.cycle を独立したスパンにするのが要点です。エージェントが 8 サイクル回って 5 サイクル目で失敗した場合、サイクル単位のスパンが無いと「5 サイクル目でツールが落ちた」という事実を取り出すのに人間がログを目で追う必要が出ます。

実装は、エージェント実行ループの中でサイクルを開始するタイミングで tracer.start_as_current_span("agent.cycle") を呼ぶだけです。Python なら次のような形になります。

from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode
 
tracer = trace.get_tracer("antigravity.agent")
 
def run_agent(task):
    with tracer.start_as_current_span("agent.run") as run_span:
        run_span.set_attribute("task.id", task.id)
        run_span.set_attribute("task.kind", task.kind)
        run_span.set_attribute("agent.policy", task.policy_name)
        run_span.set_attribute("agent.tools_available", list(task.tools))
 
        for cycle_idx in range(MAX_CYCLES):
            with tracer.start_as_current_span("agent.cycle") as cycle_span:
                cycle_span.set_attribute("cycle.index", cycle_idx)
 
                try:
                    action = plan_next_action(task)
                    if action is None:
                        cycle_span.set_attribute("cycle.terminated", True)
                        run_span.set_attribute("result.status", "success")
                        return success(task)
 
                    result = execute_tool(action)
                    observe(task, result)
                    cycle_span.set_attribute("cycle.action_type", action.kind)
                except AgentError as e:
                    cycle_span.set_status(Status(StatusCode.ERROR, str(e)))
                    cycle_span.set_attribute("result.failure_class", e.failure_class)
                    run_span.set_attribute("result.status", "failure")
                    run_span.set_attribute("result.failure_class", e.failure_class)
                    raise

TypeScript(Node.js)なら、@opentelemetry/api を使って同じ構造をこう書きます。

import { trace, SpanStatusCode } from "@opentelemetry/api";
 
const tracer = trace.getTracer("antigravity.agent");
 
export async function runAgent(task: Task): Promise<Result> {
  return await tracer.startActiveSpan("agent.run", async (runSpan) => {
    runSpan.setAttribute("task.id", task.id);
    runSpan.setAttribute("task.kind", task.kind);
    runSpan.setAttribute("agent.policy", task.policyName);
 
    try {
      for (let cycleIdx = 0; cycleIdx < MAX_CYCLES; cycleIdx++) {
        const done = await tracer.startActiveSpan(
          "agent.cycle",
          async (cycleSpan) => {
            cycleSpan.setAttribute("cycle.index", cycleIdx);
            const action = await planNextAction(task);
            if (action === null) {
              cycleSpan.setAttribute("cycle.terminated", true);
              return true;
            }
            cycleSpan.setAttribute("cycle.action_type", action.kind);
            const result = await executeTool(action);
            observe(task, result);
            cycleSpan.end();
            return false;
          }
        );
        if (done) {
          runSpan.setAttribute("result.status", "success");
          return success(task);
        }
      }
    } catch (e) {
      runSpan.setStatus({ code: SpanStatusCode.ERROR, message: String(e) });
      runSpan.setAttribute("result.failure_class", classify(e));
      throw e;
    } finally {
      runSpan.end();
    }
  });
}

注意点として、agent.cycle には必ず cycle.index を属性として乗せておきます。後で「3 サイクル目の挙動を見たい」というクエリが必ず必要になるためです。

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

この記事の続きを読む

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

この記事で得られること
OpenTelemetry に揃えた 4 階層のスパン構造(agent.run / agent.cycle / agent.plan / agent.tool_call)を、そのまま貼り付けられる Python・TypeScript の実装コードで提示します
失敗を 8 種類に分類する failure_class タクソノミーと、各クラスに対応するリトライポリシー・ユーザー通知文言の対応表を共有します
実運用 6 ヶ月で得られた具体的な改善数値(平均サイクル数 4.2 → 2.8、トークン消費 35% 削減、MTTR 47 分 → 11 分)と、ダッシュボード 3 種のクエリ例まで踏み込みます
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

Agents & Manager2026-07-17
エージェントに渡した参照メモの7割は届いていませんでした — head で切る運用の限界を測った記録
定期実行のエージェントに参照メモを cat と head で渡していたところ、肝心な行が黙って落ちていました。切り取り位置を実測し、行数ではなくセクション単位の契約に置き換えるまでの記録です。
Agents & Manager2026-07-12
Antigravity のエージェントに任せる作業と任せない作業を2週間の運用で見直す
個人開発の日々のタスクを2週間ほど Antigravity のエージェントに任せてみて、任せて正解だったものと手元に残すべきだったものの線引きを、運用ログを添えて振り返ります。
Agents & Manager2026-06-28
組み込み Guide スキルを使い捨てにせず、設計資産として育てる
Antigravity v2.2.1 で加わった組み込み Guide スキルを、一度きりの指示で終わらせず、バージョン管理されたチーム共有の設計資産として運用するための具体的な構成と判断基準を整理します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →