AFP engineering series · Chapter 18 of 25
Limit repeated misuse and runaway workloads using shared budgets, behavioral evidence, and fair enforcement.
One request can represent very different amounts of work
A short question may use one model call. Another request may launch several agents, retrieve many documents, and retry multiple tools. Counting both as one API request hides the resource difference. Abuse controls need to account for the work a request can trigger, not only the number of HTTP calls received.
The same mechanism can protect against deliberate abuse and accidental runaway loops. Distinguish the cause during investigation, but enforce the resource boundary regardless. A legitimate programming mistake should not be able to consume every tenant's capacity any more than an attacker should.
Use budgets at several scopes
Define per-operation, per-user, per-tenant, and service-wide limits. Budget model input and output, tool calls, concurrent workers, wall-clock duration, and costly external operations where relevant. Give child agents a portion of the parent's allowance rather than a fresh unlimited budget.
Use a shared atomic store for enforcement across replicas. Process-local counters are useful for diagnostics but can be bypassed by load balancing. Reserve capacity before starting expensive work, debit actual usage, and reconcile abandoned reservations. Keep time and cost units explicit so different services do not interpret the same field differently.
Distinguish rate, burst, and total budget
| Control | Protects against | Does not establish |
|---|---|---|
| Rate limit | Sustained request volume | User intent |
| Burst limit | Sudden concurrency spikes | Total job cost |
| Job budget | Long loops and fan-out | Content safety |
| Tenant allocation | Noisy-neighbor impact | Identity authenticity |
| Action cap | Repeated high-impact effects | Legitimate eligibility |
A token bucket permits a controlled burst while limiting sustained rate. A total job budget stops work after a cumulative allowance is consumed. A concurrency limit controls simultaneous resource occupancy. Use the combination that matches the workload instead of expecting one rate limit to solve every problem.
Document retry behavior in the client contract. Returning a retryable error to every blocked child task can generate a storm of identical attempts. A terminal budget-exhausted result should propagate to the parent and stop further fan-out.
Reserve work before dispatch
Illustrative python; adapt the persistence and identity adapters to your service.
def admit(cost, balance):
# Pure arithmetic only; production read/update must be atomic.
if cost <= 0:
raise ValueError("cost must be positive")
if cost > balance:
return False, balance
return True, balance - cost
allowed, remaining = admit(30, 100)
assert allowed and remaining == 70
allowed, remaining = admit(80, remaining)
assert not allowed and remaining == 70Estimated cost and actual cost may differ. Reserve conservatively, then settle based on measured usage while preserving a hard ceiling for operations whose maximum cost is known. If a provider does not offer reliable usage before completion, use bounded inputs and outputs to limit exposure.
Do not let an agent lower its own estimated cost or reset the budget identifier. The server assigns the logical job identity and associates all child work with it. Cancellation should stop new dispatch and trigger cleanup without assuming that already-started external work can always be recalled.
Use behavioral signals carefully
Repeated denied actions, similar messages across many accounts, unusual destination patterns, and sudden workload changes can justify review. They are evidence, not a verdict. A classroom exercise or authorized load test can resemble coordinated activity. Keep the policy's intended population and legitimate exceptions explicit.
Correlate signals with privacy-conscious identifiers and limited retention. Avoid collecting broad personal profiles merely because they might be useful someday. Use graduated actions such as reduced concurrency, temporary capability restriction, or additional verification before account suspension. Provide a way to correct mistaken enforcement.
Test fairness and bypass resistance
Simulate multiple replicas sharing one budget, a burst at a window boundary, nested retries, child-agent fan-out, and a worker crash after reservation. Verify that balances do not become negative and that one tenant cannot consume another's allocation. Test legitimate bursts and administrative recovery paths too.
The budget lab uses deterministic arrivals and work costs so readers can inspect admissions and rejections. It is not a production traffic model. Use real workload distributions, with appropriate privacy protections, when sizing capacity and choosing limits. Report the assumptions behind any forecast.
Worked budget calculation: fan-out multiplies a harmless request
A parent job launches four child tasks. Each child can make three attempts, and each attempt reserves 20 work units. The maximum planned work is 240 units, even though the gateway saw one request. A request-only quota does not express this amplification. A shared job budget of 100 units should prevent dispatch of work that would exceed the allowance.
Reserve at the child-attempt boundary and associate every reservation with the parent job. If attempts are scheduled incrementally, admit only those that fit the remaining budget. If the application reserves the whole plan up front, reject or reduce the plan before launching it. Both approaches can work, but the accounting contract must be explicit and atomic.
Now add a worker crash after reservation. A lease or reconciliation mechanism eventually settles the reservation, but it must not assume external work never started. Record dispatch and completion states so abandoned reservations can be distinguished from uncertain external operations. Financial side effects require stronger reconciliation than a purely local compute task.
Simulate two tenants. Tenant A submits a burst while tenant B has ordinary interactive work. Compare a single shared pool with per-tenant allocations plus a controlled shared reserve. Measure B's delay and admitted work. Fairness is a product requirement as well as an infrastructure concern; an abuse control that lets one tenant starve another has not bounded the relevant harm.
Finally, test the client response when the job budget is exhausted. It should be terminal for that job, with a clear explanation of partial completion where appropriate. An automatic retry that creates a fresh job identifier can bypass the intended bound. The budget lab exposes this multiplication directly, while production tests must verify shared-store concurrency and identity binding across replicas.
Connect enforcement to incident response
When abuse is suspected, operators should be able to revoke a key, pause a capability, and stop queued work without taking down the entire service. Keep a record of the enforcement reason, scope, duration, and reviewer. Reinstatement should be a defined process rather than an ad hoc database edit.
Measure cost per completed legitimate task, denied work, retry amplification, queue delay, and appeal outcomes. A lower bill can reflect successful containment or a broken user experience. AFP improves when resource controls preserve useful service while making excessive or repeated misuse bounded and observable.
Practice and continue
Open the interactive companion lab to inspect the assumptions and outcomes with synthetic data. Then return to the 25-chapter AFP learning path.
Sources and implementation scope
Primary references checked October 15, 2026. Framework details follow the linked documentation; the Northstar cases, policy contracts, and test designs are original illustrative designs. Python snippets labeled illustrative are not complete production integrations. ADK package metadata checked for this series reported 2.12.0; pin and test the version used by your application.