Python 3.11
OpenAI gpt-4o
Pydantic v2
FastAPI
Gobernanza-IA
Solicitudes / 24h
2.847
↑ 12% vs ayer
Injection Bloqueadas
14
0,49% del total
PII Redactadas
31
inputs + outputs
Latencia añadida
38ms
p95 guardarrailes
Rate-limited
6
usuarios hoy
Arquitectura del Pipeline
Usuario
Input raw
→
Input Guard
4 checks
bloqueado →
BLOCKED
GPT-4o
NutriBot LLM
output raw
→
Output Guard
4 checks
→
Respuesta
Safe output
Input Guardrails
Ejecutados antes de llamar a GPT-4o
✕
Prompt Injection Detection
Regex (7 patrones) + clasificación semántica gpt-4o-mini + canary token CANARY:a9f2b8c1e7d40f3a
!
PII Scrubbing — Entrada
Detección regex: email, teléfono, DNI/NIF, tarjeta. Reemplaza con [REDACTED_TYPE]
✓
Topic Restrictions
Solo temas: nutrición mascotas, pedidos NutriPaw, ingredientes. Off-topic → rechazo amable
✓
Rate Limiting
10 req/min por user_id · ventana deslizante 60s · fallback 429 con retry_after
Output Guardrails
Ejecutados antes de entregar al usuario
!
PII Scrubbing — Salida
Segunda pasada post-LLM. Riesgo de fuga PII de datos internos. Crítico para NutriPaw
✓
Validación Pydantic
Schema: answer (str ≥10ch), confidence (0-1), sources (list[str]). Fallo → fallback
✓
Hallucination Detection
Grounding check vs contexto RAG. Si score < 0.6 → "No tengo información suficiente"
✓
Content Policy
Thresholds: violence 0.7 · hate 0.5 · PII leak 0.3. Circuit breaker si anomalía > 3 en 1min
Demo: Scrubbing de PII en Output Real de NutriBot
Output crudo del LLM (INSEGURO)
Hola Carlos, he actualizado tu pedido.Te enviamos confirmación a carlos.ruiz@empresa.es y por SMS al 612-345-678.
Tu dirección de envío es Calle Mayor 42, 28013 Madrid.
Factura a nombre de B-12345678 (NIF empresa).
→
Output scrubbed (SEGURO)
Hola Carlos, he actualizado tu pedido.Te enviamos confirmación a [REDACTED_EMAIL] y por SMS al [REDACTED_PHONE].
Tu dirección de envío es [REDACTED_ADDRESS].
Factura a nombre de [REDACTED_NIF] (NIF empresa).
📄 injection_detector.py
INPUT GUARD
class InjectionDetector: PATTERNS = [ r"ignore\s+(all\s+)?(previous|above)", r"you\s+are\s+now\s+(an?\s+)?unrestricted", r"disregard\s+(your|the)\s+rules", r"system\s*prompt", r"override\s+(your|all)\s+safety", ] # CANARY token inyectado en system prompt CANARY = "CANARY:a9f2b8c1e7d40f3a" def check(self, text: str) -> GuardResult: # Layer 1: pattern match for p in self.PATTERNS: if re.search(p, text.lower()): return GuardResult( blocked=True, reason="injection_pattern", layer="regex" ) # Layer 2: semantic (gpt-4o-mini, <50ms) result = self.llm_classify(text) if result.confidence > 0.75: return GuardResult(blocked=True, layer="semantic") return GuardResult(blocked=False)
📄 output_validator.py
OUTPUT GUARD
from pydantic import BaseModel, field_validator class NutriBotResponse(BaseModel): answer: str confidence: float sources: list[str] grounding_score: float = 1.0 @field_validator('confidence', 'grounding_score') def score_in_range(cls, v: float) -> float: assert 0 <= v <= 1, f"Score {v} out of [0,1]" return v @field_validator('answer') def answer_not_empty(cls, v: str) -> str: assert len(v.strip()) >= 10 return v FALLBACK = NutriBotResponse( answer="Lo siento, no puedo responder " "esta consulta en este momento.", confidence=0.0, sources=[], grounding_score=0.0 )
Rate Limiting — Solicitudes por minuto (última hora)
Límite: 10 req/min por usuario · Ventana deslizante 60s
▐ Abuso detectado 14:32 — user_id: anon-8f3c bloqueado 5min
✅
CLOSED — Operativo
Pipeline funcionando con normalidad. Menos de 3 anomalías en la última ventana de 60s.
⚡
HALF-OPEN — Prueba
Después de un trip, deja pasar 1 request de prueba. Si pasa, vuelve a CLOSED. Si falla, vuelve a OPEN.
🚨
OPEN — Fallback activo
Respuesta fija: "Lo siento, NutriBot no está disponible en este momento. Inténtalo en unos minutos."
Log de Auditoria de Seguridad — Últimos eventos
2026-06-16 14:32:07
BLOCK
injection_detector user=anon-8f3c layer=regex pattern="ignore previous instructions" action=BLOCKED
2026-06-16 14:32:07
BLOCK
rate_limiter user=anon-8f3c requests_last_60s=43 limit=10 action=RATE_LIMITED retry_after=300s
2026-06-16 14:28:14
SCRUB
pii_scrubber layer=OUTPUT user=user-3a7f pii_types=["email","phone"] count=2 action=REDACTED
2026-06-16 14:21:55
WARN
hallucination_check user=user-9c2b grounding_score=0.48 threshold=0.60 action=FALLBACK_RESPONSE
2026-06-16 14:18:33
PASS
output_validator user=user-1d5e schema=NutriBotResponse confidence=0.91 grounding=0.87 action=PASS
2026-06-16 14:15:02
BLOCK
injection_detector user=anon-2x91 layer=semantic confidence=0.89 model=gpt-4o-mini action=BLOCKED
2026-06-16 14:09:47
SCRUB
pii_scrubber layer=INPUT user=user-7e3a pii_types=["nif"] count=1 action=REDACTED input_sanitized=true
2026-06-16 13:54:19
PASS
content_policy user=user-4f8c categories=all_clear max_score=0.12 threshold=0.30 action=PASS
2026-06-16 13:47:31
INFO
circuit_breaker state=CLOSED anomalies_last_60s=0 uptime=99.97% last_trip=2026-06-15T09:12:00
2026-06-16 13:44:08
WARN
canary_check user=anon-f12a canary_leaked=true token=a9f2b8c1 action=BLOCKED response_scrubbed=true