Operations & Cost
From a $50/month proof-of-concept to an $800+/month production deployment. Cost tiers, scaling knobs, CI/CD pipelines, governance runtime, and the operational playbook for keeping the harness healthy.
Cost tiers
The harness runs on a flexible Azure footprint that ranges from nearly-free development to a high-availability production deployment. The tiers below represent natural breakpoints where cost, reliability, and performance trade off.
- Container Apps: Consumption plan (scale to 0), 1 container
- Azure OpenAI: Pay-as-you-go, S0 tier, ~1K TPM
- Data: SQLite on local disk, FAISS in-memory, Kuzu embedded
- AI Search: Free tier (50MB, 3 indexes)
- Monitoring: Application Insights (first 5GB free)
- Container Apps: Consumption plan, 2 containers (API + Hub)
- Azure OpenAI: S0 with 10K TPM allocation
- Data: Azure SQL Basic ($5/mo) for plan state, graph backend — Neo4j on AKS or managed PostgreSQL (~$30/mo)
- AI Search: Basic tier ($75/mo, 15GB, semantic ranker)
- Blob Storage: LRS, hot tier
- Monitoring: Application Insights + Log Analytics
- Container Apps: Dedicated plan with workload profiles (2 vCPU/4GB minimum)
- Azure OpenAI: Provisioned throughput (PTU) for predictable latency
- Data: Azure SQL S1+ (plan state), graph backend in HA — Neo4j on AKS or managed PostgreSQL (4 vCore), Blob Storage GRS
- AI Search: Standard tier (3 replicas for HA, semantic ranker)
- Front Door: Standard tier with WAF
- Key Vault: Standard tier
- VNet + Private Endpoints
- Monitoring: Full OTel stack (Grafana/Tempo/Prometheus or Azure Monitor)
Azure OpenAI dominates the bill. A typical agent conversation uses 5K–20K tokens. At current Azure OpenAI pricing, 10,000 conversations/month can cost $250–1000+ in OpenAI alone depending on the model you deploy. Provisioned Throughput Units (PTU) reduce per-token cost at high volume.
Cost breakdown by category
Where the money goes at each tier. Use this to identify your largest cost levers and optimize accordingly.
| Category | Dev | Staging | Production | Key Driver |
|---|---|---|---|---|
| Compute | $0–5 | $20–40 | $100–300 | Container Apps replicas, vCPU/memory |
| AI (OpenAI) | $30–50 | $100–200 | $300–1000+ | Token volume, model choice (larger vs smaller models) |
| Search | $0 | $75 | $225–750 | AI Search tier, replica count |
| Database | $0 | $35–65 | $100–300 | Graph backend size (Neo4j/PostgreSQL), Azure SQL tier |
| Storage | $0–1 | $5–10 | $20–50 | Document volume, retention |
| Networking | $0 | $0 | $50–100 | Front Door, private endpoints, egress |
| Monitoring | $0 | $10–20 | $50–200 | Log volume, retention period |
Scaling patterns
The harness has three independent scaling dimensions: compute (Container Apps), AI throughput (Azure OpenAI), and search capacity (AI Search). Each has its own throttles and tuning knobs.
Container Apps autoscaling
Container Apps supports HTTP-based, CPU-based, and custom (queue-depth) scaling rules. Combine them for responsive scaling under mixed workloads.
- HTTP concurrent requests: scale when >50 concurrent requests per replica
- CPU threshold: scale when >70% CPU utilization
- Custom: scale on Azure Service Bus queue depth (for async agent jobs)
- Cold start: always keep
minReplicas=1for the API to avoid cold start on first request
scale: {
minReplicas: 1
maxReplicas: 20
rules: [
{
name: 'http-requests'
http: { metadata: { concurrentRequests: '50' } }
}
{
name: 'cpu-utilization'
custom: {
type: 'cpu'
metadata: { type: 'Utilization', value: '70' }
}
}
]
}
Azure OpenAI scaling
TPM (Tokens Per Minute) is the primary throttle for Azure OpenAI. When you hit the
limit, requests return HTTP 429 with a Retry-After header. Strategies
for managing throughput:
- Start with pay-as-you-go, move to PTU when you have predictable load and want guaranteed latency.
- Isolate quotas: use different deployments for agent chat vs. embeddings so one workload doesn’t starve the other.
- Multi-region fallback: configure a secondary Azure OpenAI resource in a different region. The harness Polly circuit breaker chain handles failover automatically.
- Monitor 429s: the harness has no dedicated throttle counter — watch the HTTP client instrumentation (
http.client.request.durationwithhttp.response.status_code = 429) or the Azure Monitordependenciesfailure rate for the OpenAI endpoint. Sustained 429s mean you need more quota or a PTU commitment.
AI Search scaling
- Replicas: 1 (dev), 3 (prod HA with SLA). Each replica can handle ~15 QPS.
- Partitions: add when index size exceeds tier limits.
- Semantic ranker: adds ~200ms per query. Enable only when quality improvement justifies the latency.
Governance runtime
The harness includes in-app governance systems that directly affect operational behavior. These run inside the agent process and require monitoring and configuration.
Drift Detection (EWMA)
Monitors RAG quality scores against a rolling baseline using Exponentially Weighted Moving Average. Three severity levels control the response:
| Severity | Behavior | Threshold |
|---|---|---|
| INFO | Log only — quality dipped but within normal variance | 1σ below baseline |
| WARNING | Alert via DriftEscalationBridge — operator attention needed | 2σ below baseline |
| CRITICAL | Circuit-break — halt affected pipeline until manual reset | 3σ below baseline |
Baseline requires a calibration period (~100 queries). Configure thresholds via
AppConfig.AI.Governance.Drift.
Circuit Breakers (Polly)
Every external service call (OpenAI, AI Search, graph DB) is wrapped in a Polly circuit breaker. When a provider fails 5 consecutive times, the circuit opens for 30 seconds. During open state, requests fail fast (no timeout wait). The fallback chain:
Escalation Workflows
Multi-approval system for high-risk agent actions. Three approval modes are supported:
- AllOf: all approvers must approve before the action proceeds.
- AnyOf: first approval wins — fastest path for low-risk escalations.
- Quorum: majority of approvers must agree.
Audit trail is stored in JSONL format in Blob Storage for compliance and post-incident review.
Circuit breaker state is in-memory by default. If a Container App replica restarts,
the circuit resets. For production, configure the
ICircuitBreakerStateStore to use Redis or Cosmos DB for shared state
across replicas.
CI/CD pipeline
The five-stage deploy pipeline below is the recommended delivery flow for a
consumer running this harness on Azure — it is forward-looking and not yet built
(per .github/RAILS.md, no cloud deployment exists). What the repo
actually runs today is its PR-time governance: build/test, the OWASP
Agentic eval gate, security review, and the grader. For those live rails see the
Developer Guide's
Delivery & CI Governance
chapter.
The deployment pipeline runs on GitHub Actions and progresses through five stages. Each stage gates the next — failures halt the pipeline and notify the team.
dotnet build src/AgenticHarness.slnx — compiles all projects.
Runs in a .NET 10 SDK container image for reproducibility.
dotnet test with coverage collection. 80% minimum threshold enforced
via coverlet. Fails the pipeline if coverage drops below the gate.
Container image scan (Trivy), SAST (dotnet security analyzers), and dependency
audit (dotnet list package --vulnerable). Any HIGH or CRITICAL
vulnerability blocks the pipeline.
Build and push container images to Azure Container Registry (ACR). Images are
tagged with both the commit SHA and latest for the branch.
Bicep template applies infrastructure changes. Container Apps revisions are deployed with traffic splitting — 10% canary receives traffic first. After health checks pass, traffic is promoted to 100%.
Each resource group has its own Bicep module under infra/. Run
az deployment group create to apply changes incrementally. The modules
are idempotent — safe to run multiple times.
Operational runbook
Quick-reference for the most common operational scenarios. Diagnosis steps use the OTel trace and metric names from the Observability chapter.
| Scenario | Diagnosis | Action |
|---|---|---|
| Agent returning empty responses | Check invoke_agent spans for errors. Check OpenAI quota (429s). |
Increase TPM quota or switch to fallback deployment |
| RAG returning irrelevant results | Check the rag.grounding_score histogram in traces. Run CRAG evaluation. |
Retune chunking strategy, check embedding model, rebuild index |
| High latency (>10s per turn) | Check span waterfall — which child span is slowest? | Scale AI Search replicas, enable caching, check network latency to OpenAI |
| Knowledge graph queries timing out | Check the rag.retrieval.duration histogram. Check backend health (Neo4j on AKS pod, or the Postgres/Kuzu store). |
Scale the graph backend, tune queries, add graph indexes |
| Circuit breaker stuck open | Check the agent.governance.violations counter and the provider health dashboard (Polly breaker state is logged, not a dedicated metric). |
Verify provider is back up, manually reset circuit, check fallback chain |
| Cost spike | Check the agent.tokens.total histogram. Compare to baseline. |
Identify high-token conversations, enable context budget enforcement, switch to smaller model for simple queries |
Disaster recovery
The harness itself is stateless — all persistent state lives in external stores. Recovery planning focuses on data durability and geographic availability.
Backup
- Knowledge graph backend: use the backend's native backup — Neo4j on AKS (scheduled dumps to Blob) or Azure Database for PostgreSQL Flexible Server (automated backups, point-in-time restore). The store is plain relational (
kg_nodes/kg_edges), so any managed Postgres backup applies. - Azure SQL: Automated backups with geo-redundant storage.
- Blob Storage: Soft-delete enabled. GRS for production (cross-region replication).
Geo-redundancy
- Deploy to paired Azure regions for failover.
- Use Azure Front Door for geographic routing and automatic failover.
- AI Search geo-replication for read replicas in the secondary region.
RTO/RPO targets
| Metric | Target | How |
|---|---|---|
| RTO (Recovery Time Objective) | <4 hours | Container Apps redeploy (~5 min) + data store failover |
| RPO (Recovery Point Objective) | <1 hour | Graph-backend point-in-time restore + Blob GRS + SQL geo-replication |
The harness itself is stateless (all state is in external stores). This means compute recovery is just redeploying containers — typically under 5 minutes with Container Apps. Data recovery is the longer pole.