自律型エージェントのスケジュール設定

大規模なドキュメント合成や長期間にわたる調査など、複数のステップからなるエージェント ワークフローをデプロイする場合、リアルタイム モデルでバックグラウンド エージェントを実行すると、インフラストラクチャに不要な負荷がかかり、リソースの枯渇(429)エラーが発生する可能性があります。

Gemini Enterprise Agent Platform には、遅延を許容できるワークロード専用に設計された、スループット最適化スケジューラである遅延階層が用意されています。スケジューラは、長時間実行される自律型タスクをライブチャット クエリと同じように緊急度の高いものとして扱うのではなく、複雑なマルチステップ エージェント ワークフローをオフピーク時にキューに入れて、成功率と全体的なスループットを高めることを目指します。

遅延階層を使用してリクエストを送信すると、API はタスクを非同期で受け入れ、すぐにインタラクション ID を返します。遅延階層には次の特徴があります。

  • 割引料金: 標準リクエストと比較してモデル推論の料金が 50% 割引されるため、本番環境でのエージェント費用を管理できます。詳細は、 料金をご覧ください。

  • スループットの向上: 遅延階層では、負荷の高い非同期ワークロードをオフピーク時に移動することで、429 エラー(モデル容量 の制約)とレート制限を軽減し、リアルタイムの本番環境のニーズに対応できるように標準階層の割り当てを解放します。

  • 完了タイムアウト: 遅延階層では、タスクの 95% を 24 時間以内に完了することを目指しています。この期間内にタスクが完了しない場合、タスクは期限切れとなり、failed 状態に移行します。キューで費やされる実際の時間は、現在のリージョン クラスタの容量と需要によって異なります。

ユースケース

遅延階層は、次の例のように、数時間のターンアラウンド時間を許容できるユースケースに適しています。

  • 金融: 株式と市場の調査(毎日または毎週)。

  • 法とコンプライアンス: 複数のドキュメントにわたる規制、M &A のデュー デリジェンス。

  • 戦略: 継続的な競合他社のインテリジェンスとトレンドの統合。

  • セキュリティ: コードベースの脆弱性スキャンと修正。

サポートされているエージェント

Deep Research Agent の自律型エージェント スケジュールを構成できます。

遅延タスクを作成する

次の例は、Deep Research タスク を遅延階層で client.interactions.create() を使用して開始する方法を示しています。

import time
from google import genai

client = genai.Client(
    enterprise=True,
    project="PROJECT_ID",
    location="global",
)

PROMPT = "Analyze the latest market trends in renewable energy storage."
DEEP_RESEARCH_AGENT = "deep-research-preview-04-2026"

interaction = client.interactions.create(
    input=PROMPT,
    agent=DEEP_RESEARCH_AGENT,  # Agent identifier
    service_tier="deferred",  # Run on deferred tier for off-peak scheduling
    background=True,  # Return immediately instead of waiting for the answer
    store=True,  # Persist interaction state to poll or stream later
    stream=False,  # `stream` must be set to False during task creation
)

print(f"Interaction ID: {interaction.id}")
print(f"Status:         {interaction.status}")
print(f"Service tier:   {interaction.service_tier}")

このメソッドは、status="in_progress"service_tier="deferred" を返してすぐに終了します。

タスクの進行状況をモニタリング

オフピーク時の容量を待機している間、またはアクティブに実行されている間、インタラクションの statusin_progress のままになります。エージェントが計画、検索、分析の手順を実行すると、新しいアイテムが steps リストに追加されます。

インタラクションを定期的にポーリングするか、更新をストリーミングすることで、タスクのステータスをプログラムで追跡できます。

ポーリング

インタラクションがターミナル状態(completedfailedcancelled)のいずれかに達するまで、インタラクションを定期的に(15 ~ 30 秒ごとなど)ポーリングします。

TERMINAL_STATES = ("completed", "failed", "cancelled")
POLL_INTERVAL_SECONDS = 15
TIMEOUT_MINUTES = 60

started = time.time()
deadline = started + TIMEOUT_MINUTES * 60

while True:
  current = client.interactions.get(interaction.id)
  elapsed = int(time.time() - started)
  steps = getattr(current, "steps", None) or []
  print(f"[{elapsed:>4}s] status={current.status} steps={len(steps)}")

  if current.status in TERMINAL_STATES:
    break
  if time.time() >= deadline:
    raise TimeoutError(
        f"Still {current.status} after {TIMEOUT_MINUTES} min. The interaction "
        "continues running server-side; re-run the check to resume polling."
    )
  time.sleep(POLL_INTERVAL_SECONDS)

print(f"\nFinished in {int(time.time() - started)}s with status={current.status}.")

ストリーミング

background=Truestore=True の横に stream=True を設定すると、インタラクションが in_progress ステータスになったら、更新をリアルタイムでストリーミングできます。ストリームは、中間的な思考、テキストの差分、ステータスの更新などのイベントが発生すると、それらをプッシュします。

タスクが in_progress の間に接続が切断された場合は、client.interactions.get() を使用して stream=True でストリームに再接続し、最後に受信したイベント ID を last_event_id に渡すことができます。last_event_id を省略すると、API はすべてのイベントを最初から再生します。

INTERACTION_ID = interaction.id  # from the create step
MAX_RECONNECTS = 5
STREAM_TIMEOUT = 300  # seconds

print(
    f"streaming interaction: {INTERACTION_ID} (status={interaction.status})\n"
)

def render(event):
  """Prints one SSE event. Returns True once the interaction has finished."""
  if event.event_type == "step.delta":
    delta = event.delta
    if delta.type == "text":
      print(delta.text, end="", flush=True)
    elif delta.type == "thought_summary":
      summary = (getattr(delta.content, "text", "") or "").strip()
      if summary:
        print(f"\n[thinking] {summary[:200]}", flush=True)
    elif delta.type.endswith("_call"):
      queries = getattr(getattr(delta, "arguments", None), "queries", None)
      print(
          f"\n[{delta.type}] {', '.join(queries) if queries else ''}",
          flush=True,
      )
  elif event.event_type == "interaction.status_update":
    print(f"[status] {event.status}", flush=True)
  elif event.event_type == "interaction.completed":
    print(f"\n\n[status] {event.interaction.status}", flush=True)
    return True
  elif event.event_type == "error":
    print(f"\n[error] {event.error.message}", flush=True)
    return True
  return False

last_event_id = None
finished = False

for attempt in range(MAX_RECONNECTS):
  try:
    # stream=True turns the GET into a live subscription. last_event_id=None on
    # the first pass, so the server starts from the beginning of the run.
    for event in client.interactions.get(
        INTERACTION_ID,
        stream=True,
        last_event_id=last_event_id,
        timeout=STREAM_TIMEOUT,
    ):
      last_event_id = event.event_id or last_event_id
      finished = render(event) or finished
  except Exception as e:  # pylint: disable=broad-except
    # A dropped connection loses nothing: the run continues server-side and the
    # next iteration reattaches from last_event_id.
    print(f"\n[stream dropped: {type(e).__name__}] reattaching...", flush=True)

  if finished:
    break
  # The server also closes the stream when the run ends, without an error.
  if (
      client.interactions.get(INTERACTION_ID, timeout=STREAM_TIMEOUT).status
      != "in_progress"
  ):
    break
else:
  print(f"\n[gave up after {MAX_RECONNECTS} reconnects]")

print(f"\n\nStreamed interaction: {INTERACTION_ID}")

タスクをキャンセルする

タスクのステータスが queuedin_progressrequires_action の場合は、タスクをキャンセルできます。タスクをキャンセルすると、ステータスが cancelled に移行します。

タスクをキャンセルするには、client.interactions.cancel() を使用します。

client.interactions.cancel(INTERACTION_ID)

最終出力とトークン使用量を取得する

インタラクションが completed 状態になると、完全なトランスクリプトが steps リストに表示されます。最終的な回答は、出力が生成された最後のステップのテキスト コンテンツです。

インタラクションは保存されるため(store=True)、任意のセッションのインタラクション ID を使用して、いつでも結果を取得できます。

def get_final_text(completed_interaction):
  """Returns the text of the last step that produced output."""
  for step in reversed(getattr(completed_interaction, "steps", None) or []):
    text = "".join(
        part.text for part in (getattr(step, "content", None) or [])
        if getattr(part, "text", None)
    )
    if text:
      return text
  return ""


final = client.interactions.get(interaction.id)
print(f"Status: {final.status}\n")
print(get_final_text(final) or "(No text output)")

if final.usage:
  print(
      f"\nToken usage:\n"
      f"  Input tokens:  {final.usage.total_input_tokens}\n"
      f"  Output tokens: {final.usage.total_output_tokens}\n"
      f"  Total tokens:  {final.usage.total_tokens}"
  )