Skip to content
Guide

AI Agent Capacity Planning Model

Size worker pools with formulas and reliability guardrails, not intuition.

Guide13 min readUpdated June 2026
TL;DR
  • -Capacity planning for agents fails when teams size for average load and ignore policy-path degradation.
  • -Use explicit utilization targets and queueing math before touching autoscaling settings.
  • -Treat retries and replay as capacity consumers, not background noise.
  • -Headroom should be validated against incidents, not only synthetic benchmarks.
Sizing math

Estimate required workers from arrival rate, service time, and utilization target.

Headroom policy

Keep enough reserve to absorb burst traffic and policy dependency hiccups.

Operational ownership

Tie capacity decisions to measurable SLO and incident thresholds.

Scope

This guide focuses on autonomous AI agent control planes that dispatch queued work and enforce governance checks before execution.

The production problem

Capacity planning failures in agent systems rarely look like one big crash. They show up as rising dispatch latency, retry churn, and deferred work that never catches up.

Most teams still size for average traffic and rely on autoscaling to save them. That works until retries, policy outages, or long-tail job durations break the scaling signal.

You need an explicit model that links worker count to reliability metrics and recovery behavior.

What top results miss

SourceStrong coverageMissing piece
Google SRE Book: Demand forecasting and capacity planningStrong requirement for demand forecast, load testing, and provisioning ownership.No guidance for policy-gated autonomous workflows with retries and replay behavior.
Google SRE Workbook: Data processing capacity planningConcrete example: provision around 50% CPU at peak and beware runaway autoscaling.No generic model for agent pipeline stages (dispatch, policy, output checks).
AWS Well-Architected Analytics Lens BP 11.2Practical right-sizing and autoscaling guidance for predictable and spiky workloads.No reliability budgeting link between scaling behavior and autonomous side-effect safety.

Capacity model

Use queueing math as baseline, then add retry and safety-path headroom. Do not jump straight to autoscaler tuning.

Model layerFormulaTarget valueWhy it matters
Ingress ratejobs_per_second (lambda)Use p95 traffic, not daily averageAverage hides burst pressure.
Service timeavg_execution_seconds (W)Use p90 service time for conservative sizingLong-tail jobs distort capacity fast.
Worker countceil((lambda * W) / target_utilization)Target utilization 0.60-0.75Lower target gives burst headroom.
Retry overheadbase_workers * retry_multiplierStart with 1.10 to 1.30 multiplierRetry storms are real capacity demand.

Sample worker sizing outcomes:

Ingress rateService timeUtilization targetRequired workers
80 jobs/s0.35s0.6544
120 jobs/s0.40s0.6574
200 jobs/s0.55s0.70158

Cordum runtime implications

ImplicationCurrent behaviorWhy it matters
Failure-rate guardrailExisting alert threshold uses failed ratio > 10% over 5mCapacity decisions should reduce this sustained risk signal, not only reduce queue depth.
Latency guardrailDispatch p99 warning threshold is > 1sA useful early signal that worker pools are under-provisioned.
Retry budget pressureMax scheduling retries = 50, backoff 1s-30s, `retryDelayNoWorkers` = 2sRetry mechanics directly affect effective throughput and backlog shape.
Policy dependency capacity impact`POLICY_CHECK_FAIL_MODE=closed` defaults to requeue on policy outagePolicy outages can consume capacity through safe requeue loops.
Recovery debt tracking`cordum_scheduler_stale_jobs` + `cordum_scheduler_orphan_replayed_total`Capacity planning should include post-incident recovery window, not only steady-state traffic.

Implementation examples

Worker sizing helper (TypeScript)

capacity-sizing.ts
TypeScript
type SizingInput = {
  ingressPerSecond: number;    // lambda
  avgServiceSeconds: number;   // W
  targetUtilization: number;   // e.g. 0.65
  retryMultiplier?: number;    // e.g. 1.2
};

export function requiredWorkers(input: SizingInput): number {
  const base = (input.ingressPerSecond * input.avgServiceSeconds) / input.targetUtilization;
  const retries = input.retryMultiplier ?? 1.0;
  return Math.ceil(base * retries);
}

// Example:
// 120 jobs/s * 0.40s / 0.65 = 73.8 -> 74 workers
// retry multiplier 1.2 -> 89 workers

Capacity planning policy config (YAML)

capacity-plan.yaml
YAML
capacity_planning:
  target_utilization: 0.65
  retry_multiplier: 1.2
  guardrails:
    dispatch_p99_seconds_warn: 1
    failed_ratio_5m_warn: 0.10
    stale_jobs_warn: 50
  policy_dependency:
    fail_mode: closed
    max_tolerated_safety_unavailable_rate_5m: 0.05
  headroom:
    minimum_spare_workers_percent: 20
    burst_window_minutes: 15

Core capacity validation queries (PromQL)

capacity-signals.promql
PromQL
# Dispatch p99
histogram_quantile(0.99, rate(cordum_scheduler_dispatch_latency_seconds_bucket[5m]))

# Failed completion ratio
rate(cordum_jobs_completed_total{status="failed"}[5m])
/ clamp_min(rate(cordum_jobs_completed_total[5m]), 0.001)

# Safety dependency degradation
rate(cordum_safety_unavailable_total[5m])

# Recovery debt
cordum_scheduler_stale_jobs
rate(cordum_scheduler_orphan_replayed_total[5m])

Worked example: sizing a refund agent

Make the model concrete. Say a support team runs an autonomous refund agent. Traffic peaks at a p95 of 90 jobs/second, each job takes a p90 of 0.5 seconds end to end (analysis plus the policy check plus the refund call), and the team wants a 0.65 utilization target.

Step 1 — Baseline workers

ceil(90 × 0.5 / 0.65) = ceil(69.2) = 70 workers. That is the floor for steady peak traffic.

Step 2 — Retry overhead

Refunds occasionally fail on a flaky payment API. With a 1.2 retry multiplier: ceil(70 × 1.2) = 84 workers.

Step 3 — Policy-outage headroom

If the Safety Kernel briefly degrades, POLICY_CHECK_FAIL_MODE=closed requeues jobs instead of dropping them, so backlog spikes. The 20% minimum spare-worker headroom in the capacity config absorbs this without tipping dispatch p99 over the 1s warning line.

Step 4 — Validate, don't trust

Run one load test at 90 jobs/s and one drill that makes the Safety Kernel unavailable for 60 seconds. Confirm the pool holds dispatch p99 under 1s and that cordum_scheduler_stale_jobs drains back to zero after recovery. If it does not, the retry multiplier or headroom is too low.

The point is that the final number (84 workers plus headroom) is defensible: every term traces to a measured input or a verified runtime behavior, not a guess.

Limitations and tradeoffs

  • - Simple sizing formulas assume stationarity; real workloads can shift faster than planning windows.
  • - Conservative utilization targets increase reliability but can reduce cost efficiency.
  • - Retry multipliers are rough estimates until measured under incident-like conditions.
  • - Autoscaling can still overshoot when its metric no longer tracks useful work.

Frequently asked questions

How do I calculate how many workers an AI agent pool needs?

Start from Little's Law: required workers = (arrival rate x average service time) / target utilization. For example, 120 jobs/second at 0.40s average execution and a 0.65 utilization target needs ceil(120 x 0.40 / 0.65) = 74 workers. Then multiply by a retry overhead factor (1.1-1.3 to start) because failed jobs re-enter the queue and consume real capacity. Size arrival rate from p95 traffic and service time from p90 execution, not daily averages, so a normal burst does not exhaust the pool.

What utilization target should I plan for?

Plan for 60-75% steady-state utilization, not 90%+. The gap is deliberate headroom: queueing latency rises non-linearly as utilization approaches 1.0, so a pool sized for 95% average load tips into runaway dispatch latency the moment traffic spikes. A 0.65 target leaves roughly 35% spare capacity to absorb bursts, retry storms, and the requeue pressure that appears when a downstream dependency degrades.

Why do retries and replay count as capacity demand?

Because they are real dispatch work, not background noise. In Cordum the scheduler retries a job up to maxSchedulingRetries (50) with exponential backoff from 1s to 30s before moving it to FAILED and the DLQ, and applies a 2s retryDelayNoWorkers delay when no worker is available. During an incident every in-flight job can spawn several extra attempts, so a pool sized only for first-attempt throughput will fall behind exactly when it matters most. Track recovery debt with cordum_scheduler_stale_jobs and cordum_scheduler_orphan_replayed_total.

How does the policy / Safety Kernel check affect capacity planning?

Every dispatch passes through a Safety Kernel check before a worker runs, so the policy path is part of your effective service time. When the kernel is unreachable the behavior depends on POLICY_CHECK_FAIL_MODE: the default closed mode requeues jobs with backoff, which means a policy outage consumes capacity through safe retry loops rather than dropping work. Plan headroom for that requeue pressure and alert on cordum_safety_unavailable_total so a degraded policy dependency does not silently eat your pool.

What metrics tell me a worker pool is under-provisioned?

Three early signals: dispatch p99 latency rising above ~1s (histogram_quantile over cordum_scheduler_dispatch_latency_seconds_bucket), the failed-completion ratio sustained above 10% over 5 minutes, and a climbing cordum_scheduler_stale_jobs gauge. Latency and stale-job growth usually precede outright failures, so treat them as the trigger to add workers rather than waiting for the failed-ratio alarm.

Is autoscaling enough, or do I still need a capacity model?

Autoscaling is reactive and only as good as the metric it scales on. If you scale on CPU or queue depth while retries are inflating both, the autoscaler can chase a signal that no longer tracks useful work and overshoot. A capacity model gives you the floor (minimum workers for p95 traffic), the right scaling metric, and the guardrails that tell you when scaling is masking a deeper problem like a policy outage or a long-tail job regression.

Next step

Run this in one sprint:

  1. 1. Baseline p95 ingress and p90 service time for your top three topics.
  2. 2. Compute worker targets with utilization 0.65 and retry multiplier 1.2.
  3. 3. Add guardrails for dispatch p99, failed ratio, and stale jobs.
  4. 4. Validate the plan with one controlled load test and one dependency-degradation drill.

Continue with AI Agent Chaos Engineering Playbook and AI Agent Backpressure and Queue Drain Strategy.

Capacity debt becomes reliability debt

If dispatch latency and retries are rising, your architecture is already voting on your next incident.