Skip to main content

guardrails-api

Purpose

guardrails-api is the guardrails-plane orchestrator. Receives a text (or structured payload) from openbox-core, fans out to 3 CPU-based ML model hosts (PII / NSFW / toxicity), aggregates results, and returns a verdict. Optionally calls llamafirewall-server for deep prompt-injection detection (GPU-backed).

Plane: Guardrails plane.

Ports & endpoints

PortProtocolPurposeExposed via
8000HTTP/RESTGuardrails API (/v1/scan, /v1/verdict)Istio Gateway (optional; typically cluster-internal only)
8000/healthHTTPLivenessK8s kubelet
9464HTTPPrometheus scrapeCluster-internal

Typical request: POST /v1/scan with JSON body {"text": "..."} → response includes verdicts per model.

Runtime

PropertyValue
Container count per pod1
Resource requests500m CPU / 1 Gi RAM
Resource limits1 vCPU / 2 Gi RAM
HPA min → max replicas2 → 10 (most-scaled service)
HPA targetCPU 60%
Node placementDedicated guardrails node group in prod (c7i.xlarge in reference); general CPU pool acceptable
StatefulSet?No

Why min 2? guardrails-api sits on the hot path for every agent action — single-pod restart = brief agent stall. Prod baseline is 2, scales up to 10 under bursts.

Configuration

Chart values keys (top-level guardrails-api.*)

KeyPurpose
image.repository / image.tagContainer image
autoscaling.{minReplicas,maxReplicas,targetCPUUtilizationPercentage}HPA — do not lower minReplicas below 2 in prod
resourcesRequests/limits
llamafirewall.enabledToggle deep prompt-injection detector (requires GPU node + vllm)
llamafirewall.vllm.gpuGPU resource type (default nvidia.com/gpu: 1)
models.pii.enabled / .nsfw.enabled / .toxicity.enabledToggle individual classifiers

Runtime env vars

  • MODEL_HOST_PII_URL — points at model-host-detect-pii.<ns>.svc:8011
  • MODEL_HOST_NSFW_URL — points at model-host-nsfw.<ns>.svc:8014
  • MODEL_HOST_TOXICITY_URL — points at model-host-toxicity.<ns>.svc:8013
  • LLAMAFIREWALL_URLllamafirewall-server.<ns>.svc:8000 (only if enabled)

Dependencies

Downstream

TargetProtocolPurpose
model-host-detect-piiHTTP :8011PII detection (CPU)
model-host-nsfwHTTP :8014NSFW classification (CPU)
model-host-toxicityHTTP :8013Toxicity classification (CPU)
llamafirewall-serverHTTP :8000Deep prompt-injection (optional; forwards to vllm on GPU)

Upstream

  • openbox-core-server — primary caller (via internal Service DNS)
  • openbox-backend — occasional direct calls for admin scans

Deployment guidelines

Prod

  • minReplicas: 2 non-negotiable — hot path for agent actions
  • Isolate on guardrails node group (taint workload-line=guardrails) if you follow the prod reference NodePool layout
  • Enable llamafirewall only if you have GPU capacity (single g5.xlarge handles most workloads)
  • Add PodDisruptionBudget with minAvailable: 1

GPU-free deployments

If your cluster has no GPU nodes:

guardrails-api:
llamafirewall:
enabled: false

Consequence: PII/NSFW/toxicity classifiers still work; deep prompt-injection detection is unavailable. Callers should not fail-closed if guardrails-api returns a partial verdict — check response schema.

Local PoC

  • autoscaling.minReplicas: 1, maxReplicas: 1
  • Disable llamafirewall (laptop has no GPU)
  • Model hosts each need ~3.5 Gi RAM — total footprint ~11 Gi for the guardrails plane. Ensure Minikube has enough (--memory=12g).

Troubleshooting

HPA panics under sudden traffic burst → Default HPA uses 2-min stabilization window. Pre-warm before load tests: temporarily set minReplicas: 5 before ramping traffic.

One model host down but scans still returning "ok"guardrails-api does NOT fail-closed on individual model-host failures. Response includes verdict.partial: true — callers must check. Fix the failing model host (usually OOM — bump resources.limits.memory to 4 Gi).

All requests slow (~2000 ms) — llamafirewall path → vllm cold-start / model reload. First-request-after-restart takes ~10-20 sec while Qwen3-8B loads into GPU. Pre-warm with a curl on pod startup.

503 no available model hosts → All 3 model-host Services have no Ready endpoints. kubectl get pods -l app=model-host-* and check crashloop reasons. Common: OOM (model weights need 3.5 Gi guaranteed).

Guardrails endpoints unreachable from openbox-core → Service DNS misresolution. Verify kubectl get svc guardrails-api -n openbox. If exposed via Istio, check namespace has istio-injection=enabled.