Guardrails

Validación de entrada/salida y seguridad de contenido usando adk-guardrail.

Resumen

Los guardrails validan y transforman las entradas y salidas de los Agent para garantizar la seguridad, el cumplimiento y la calidad. Se ejecutan en paralelo con la ejecución del Agent y pueden:

  • Bloquear contenido dañino o fuera de tema
  • Redactar PII (correos electrónicos, teléfonos, SSN, tarjetas de crédito)
  • Aplicar esquemas JSON a las salidas
  • Limitar la longitud del contenido

Instalación

[dependencies]
adk-guardrail = "0.2.0"

# For JSON schema validation
adk-guardrail = { version = "0.2.0", features = ["schema"] }

Conceptos Core

GuardrailResult

Cada guardrail devuelve uno de tres resultados:

pub enum GuardrailResult {
    Pass,                                    // Content is valid
    Fail { reason: String, severity: Severity },  // Content rejected
    Transform { new_content: Content, reason: String },  // Content modified
}

Niveles de Severity

pub enum Severity {
    Low,      // Warning only, doesn't block
    Medium,   // Blocks but continues other checks
    High,     // Blocks immediately
    Critical, // Blocks and fails fast
}

Redacción de PII

Detecta y redacta automáticamente la información de identificación personal:

use adk_guardrail::{PiiRedactor, PiiType};

// Default: emails, phones, SSNs, credit cards
let redactor = PiiRedactor::new();

// Or select specific types
let redactor = PiiRedactor::with_types(&[
    PiiType::Email,
    PiiType::Phone,
]);

// Direct redaction
let (redacted, found_types) = redactor.redact("Email: test@example.com");
// redacted = "Email: [EMAIL REDACTED]"
// found_types = [PiiType::Email]

Tipos de PII admitidos:

TypePatternRedaction
Emailuser@domain.com[CORREO ELECTRÓNICO REDACTADO]
Phone555-123-4567[TELÉFONO REDACTADO]
Ssn123-45-6789[SSN REDACTADO]
CreditCard4111-1111-1111-1111[TARJETA DE CRÉDITO REDACTADA]
IpAddress192.168.1.1[IP REDACTADA]

Filtrado de Contenido

Bloquea contenido dañino o aplica restricciones de tema:

use adk_guardrail::ContentFilter;

// Block harmful content patterns
let filter = ContentFilter::harmful_content();

// Block specific keywords
let filter = ContentFilter::blocked_keywords(vec![
    "forbidden".into(),
    "banned".into(),
]);

// Enforce topic relevance
let filter = ContentFilter::on_topic("cooking", vec![
    "recipe".into(),
    "cook".into(),
    "bake".into(),
]);

// Limit content length
let filter = ContentFilter::max_length(1000);

Filtro de Contenido Personalizado

use adk_guardrail::{ContentFilter, ContentFilterConfig, Severity};

let config = ContentFilterConfig {
    blocked_keywords: vec!["spam".into()],
    required_topics: vec!["rust".into(), "programming".into()],
    max_length: Some(5000),
    min_length: Some(10),
    severity: Severity::High,
};

let filter = ContentFilter::new("custom_filter", config);

Validación de Esquema

Aplica esquemas JSON a las salidas del Agent (requiere la feature schema):

use adk_guardrail::SchemaValidator;
use serde_json::json;

let schema = json!({
    "type": "object",
    "properties": {
        "name": { "type": "string" },
        "age": { "type": "integer", "minimum": 0 }
    },
    "required": ["name"]
});

let validator = SchemaValidator::new(&schema)?
    .with_name("user_schema")
    .with_severity(Severity::High);

El validador extrae JSON de:

  • Texto JSON sin procesar
  • Bloques de código Markdown (```json ... ```)

GuardrailSet

Combina múltiples guardrails:

use adk_guardrail::{GuardrailSet, ContentFilter, PiiRedactor};

let guardrails = GuardrailSet::new()
    .with(ContentFilter::harmful_content())
    .with(ContentFilter::max_length(5000))
    .with(PiiRedactor::new());

GuardrailExecutor

Ejecuta guardarraíles y obtén resultados detallados:

use adk_guardrail::{GuardrailExecutor, GuardrailSet, PiiRedactor};
use adk_core::Content;

let guardrails = GuardrailSet::new()
    .with(PiiRedactor::new());

let content = Content::new("user")
    .with_text("Contact: test@example.com");

let result = GuardrailExecutor::run(&guardrails, &content).await?;

if result.passed {
    // Use transformed content if available
    let final_content = result.transformed_content.unwrap_or(content);
    println!("Content passed validation");
} else {
    for (name, reason, severity) in &result.failures {
        println!("Guardrail '{}' failed: {} ({:?})", name, reason, severity);
    }
}

ExecutionResult

pub struct ExecutionResult {
    pub passed: bool,                              // Aprobación/rechazo general
    pub transformed_content: Option<Content>,      // Contenido modificado (si existe alguno)
    pub failures: Vec<(String, String, Severity)>, // (nombre, motivo, gravedad)
}

Guardarraíles Personalizados

Implementa el trait Guardrail:

use adk_guardrail::{Guardrail, GuardrailResult, Severity};
use adk_core::Content;
use async_trait::async_trait;

pub struct ProfanityFilter {
    words: Vec<String>,
}

#[async_trait]
impl Guardrail for ProfanityFilter {
    fn name(&self) -> &str {
        "profanity_filter"
    }

    async fn validate(&self, content: &Content) -> GuardrailResult {
        let text: String = content.parts
            .iter()
            .filter_map(|p| p.text())
            .collect();

        for word in &self.words {
            if text.to_lowercase().contains(word) {
                return GuardrailResult::Fail {
                    reason: format!("Contains profanity: {}", word),
                    severity: Severity::High,
                };
            }
        }

        GuardrailResult::Pass
    }

    // Ejecutar en paralelo con otros guardarraíles (predeterminado: true)
    fn run_parallel(&self) -> bool {
        true
    }

    // Fallar rápidamente ante el fallo de este guardarraíl (predeterminado: true)
    fn fail_fast(&self) -> bool {
        true
    }
}

Integración con Agentes

Los guardarraíles se integran con LlmAgentBuilder:

use adk_agent::LlmAgentBuilder;
use adk_guardrail::{GuardrailSet, ContentFilter, PiiRedactor};

let input_guardrails = GuardrailSet::new()
    .with(ContentFilter::harmful_content())
    .with(PiiRedactor::new());

let output_guardrails = GuardrailSet::new()
    .with(SchemaValidator::new(&output_schema)?);

let agent = LlmAgentBuilder::new("assistant")
    .model(model)
    .instruction("You are a helpful assistant.")
    .input_guardrails(input_guardrails)
    .output_guardrails(output_guardrails)
    .build()?;

Flujo de Ejecución

Entrada del Usuario
    │
    ▼
┌─────────────────────┐
│  Guardarraíles de Entrada   │ ← Redacción de PII, filtrado de contenido
│  (paralelo)         │
└─────────────────────┘
    │
    ▼ (transformado o bloqueado)
┌─────────────────────┐
│  Ejecución del Agente    │
└─────────────────────┘
    │
    ▼
┌─────────────────────┐
│  Guardarraíles de Salida  │ ← Validación de esquema, controles de seguridad
│  (paralelo)         │
└─────────────────────┘
    │
    ▼
Respuesta Final

Ejemplos

# Filtrado básico de PII y contenido
cargo run --example guardrail_basic --features guardrails

# Validación de esquema JSON
cargo run --example guardrail_schema --features guardrails

# Integración completa del agente
cargo run --example guardrail_agent --features guardrails

Mejores Prácticas

PrácticaDescripción
Capas de barreras de seguridadUtilice barreras de seguridad de entrada para la seguridad, y de salida para la calidad
PII en la entradaRedacte la PII antes de que llegue al modelo
Esquema en la salidaValide las salidas estructuradas con un esquema JSON
Severidad apropiadaUtilice Crítica con moderación, Baja para advertencias
Pruebe a fondoLas barreras de seguridad son código crítico para la seguridad

Anterior: ← Control de Acceso | Siguiente: Memoria →