Chapter 06 · Operations

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.

Development ($50–80/mo)
  • 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)
~$50–80/mo (mostly OpenAI usage)
Staging ($200–400/mo)
  • 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
~$200–400/mo
Production ($800+/mo)
  • 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)
~$800–2000/mo (scales with usage)
The single biggest cost driver

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=1 for the API to avoid cold start on first request
bicep
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.duration with http.response.status_code = 429) or the Azure Monitor dependencies failure 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:

Primary
Main provider
Secondary
Fallback provider
Cache
Cached response
Degrade
Graceful degradation

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 ephemeral

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

i
Target topology, not what the repo ships today

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.

Build
GitHub Actions
Test
dotnet test
Scan
Trivy + SAST
Push
ACR
Deploy
Bicep + Container Apps
Build

dotnet build src/AgenticHarness.slnx — compiles all projects. Runs in a .NET 10 SDK container image for reproducibility.

Test

dotnet test with coverage collection. 80% minimum threshold enforced via coverlet. Fails the pipeline if coverage drops below the gate.

Scan

Container image scan (Trivy), SAST (dotnet security analyzers), and dependency audit (dotnet list package --vulnerable). Any HIGH or CRITICAL vulnerability blocks the pipeline.

Push

Build and push container images to Azure Container Registry (ACR). Images are tagged with both the commit SHA and latest for the branch.

Deploy

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%.

Infrastructure as Code with Bicep

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
i
Stateless compute, fast recovery

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.