Skip to lesson

Google CloudProfessional Agentic Architect2026-094.2 Deploying and scaling production workloads

Bound reasoning loops with conditions and budgets

Completed by the knowledge check

Learning objective

Bound a production reasoning loop with explicit termination conditions and execution budgets. This lesson focuses on deciding when a loop may continue, not on diagnosing a failed run or optimizing the whole production system.

Core idea

Treat every loop continuation as a request to spend from a finite budget envelope. The controller grants that request only when the task is unfinished, progress remains possible, policy permits the next action, and enough budget remains.

Use two complementary controls:

  • Outcome conditions stop the loop because its state has meaningfully changed: the goal is verified, input is missing, policy denies an action, an error is unrecoverable, progress has stalled, or the caller cancels.
  • Execution budgets stop the loop because further work is no longer permitted: an iteration, model-call, tool-call, retry, token, time, or cost limit is exhausted.

An outcome condition is the normal way out. A budget is the hard backstop. A prompt such as “stop after five attempts” is not the backstop because the model can ignore or miscount it. The orchestration layer must count and enforce the limit.

How it works

Represent the remaining budget as part of run state rather than as a loose set of timeouts:

budget = {
  iterations_left,
  llm_calls_left,
  tool_calls_left,
  retries_left_by_operation,
  tokens_left,
  deadline,
  estimated_cost_left
}

Before each iteration, evaluate deterministic stop predicates in a defined order:

  1. Accept success only when a completion predicate is true. A fluent answer or a model-produced DONE label is evidence, not proof. For example, require a persisted ticket ID before declaring that a ticket was created.
  2. Stop on terminal non-success states. These include a policy denial, missing user input, cancellation, and an unrecoverable error.
  3. Stop on stagnation. Compare a progress measure across iterations, such as unresolved findings or newly acquired evidence. Repeating the same tool call and observation does not count as progress.
  4. Reserve budget before starting work. Reject an action when its worst acceptable cost cannot fit in the remaining allowance. After it completes, reconcile the reservation with actual calls, tokens, time, and estimated cost.
  5. Run one bounded step, update state, and evaluate again. Record the stop reason separately from the task result.

The budgets must compose. A retry consumes both its operation-specific retry allowance and the parent run’s tool-call, time, and cost allowances. A subagent receives a slice of the parent’s remaining budget; it does not start with a new full budget. Otherwise, nested loops can multiply a small local bound into a large unbounded run.

Framework controls implement parts of this pattern. ADK’s current graph workflow documentation warns that a cycle is not bounded automatically and requires an exit condition or a programmatic loop with a controlled bound. ADK also documents max_llm_calls as a per-run runtime cap. These controls are complementary: a bounded graph iteration can make several model calls, while a model-call cap says nothing about long-running tools. See Graph routes and Runtime configuration.

Key distinctions and trade-offs

Termination condition versus execution budget: A completion predicate says the task is done. Budget exhaustion says the controller must stop trying. Do not report an exhausted run as successful. Return a safe partial result, request input, or escalate according to the product contract.

Per-call limit versus run-level budget: Gemini’s maxOutputTokens limits the generated output of one model request. It does not limit the number of requests, tool calls, input tokens, or elapsed time across the loop. Gemini responses expose prompt, candidate, and total token counts in usageMetadata, which an orchestrator can aggregate against a run budget. See the Gemini generate-content reference.

Service timeout versus cancellation: An infrastructure timeout can end the client’s wait without stopping application work. Cloud Run returns a 504 when the request timeout expires, but its documentation notes that the container may continue processing. Set the agent’s internal deadline earlier than the outer request timeout, propagate cancellation to model and tool calls, and leave time to save state and return a controlled outcome. See Configure request timeout for Cloud Run services.

Tight bounds reduce runaway cost, tail latency, and repeated side effects, but they can stop difficult tasks too early. Loose bounds can improve completion on hard cases but enlarge cost and reliability risk. Choose limits from measured task distributions and risk, then use different budget profiles for different request classes. Always retain one non-negotiable hard ceiling.

Architecture / decision scenario

An operations agent investigates a production alert by querying metrics and logs, revising a hypothesis, and either proposing a runbook action or escalating. The team gives one investigation a 45-second internal deadline, four iterations, eight model calls, six tool calls, and one retry per read-only query. The outer Cloud Run request timeout is longer, leaving time for cleanup and a response.

The success predicate requires a named service, a supporting signal from an approved tool, and a matching runbook action. A deterministic validator checks these fields. The loop also stops after two iterations add no new evidence. It stops immediately on cancellation or if policy rejects the proposed action.

On iteration three, the log query times out. A retry would exceed the remaining time reservation even though one tool call remains. The controller denies the retry, records deadline_budget_exhausted, and returns the known evidence with a human-escalation recommendation. It does not claim success, and it does not wait for the platform timeout.

This design uses the earliest exhausted dimension as the stop trigger. It also preserves unused call budget rather than treating every allowance as a target that should be consumed.

Common exam traps

  • Relying on an instruction to enforce a hard iteration or spending limit.
  • Using only maxOutputTokens and assuming it bounds the complete agent run.
  • Setting an iteration cap without defining success, stagnation, and failure exits.
  • Giving every nested agent and retry a fresh full budget instead of sharing the parent run’s allowance.
  • Treating a platform 504 or disconnected client as proof that model and tool work stopped.
  • Reporting budget exhaustion as successful completion because the agent produced a final sentence.
  • Retrying while one local allowance remains even though the global deadline or cost budget cannot cover the attempt.

What to remember

  • Let explicit outcome conditions provide normal exits and hard budgets provide the backstop.
  • Enforce limits in deterministic controller logic, not only in prompts.
  • Budget the whole run across iterations, calls, retries, tokens, time, and cost.
  • Make nested work consume a shared parent budget.
  • Distinguish success, exhaustion, cancellation, and infrastructure timeout.

Knowledge check

References