Gardes-fous

Validation des entrées/sorties et sécurité du contenu à l'aide de adk-guardrail.

Aperçu

Les gardes-fous valident et transforment les entrées et sorties des agents pour garantir la sécurité, la conformité et la qualité. Ils s'exécutent en parallèle de l'exécution de l'agent et peuvent :

  • Bloquer le contenu nuisible ou hors sujet
  • Supprimer les informations personnelles identifiables (PII) (e-mails, téléphones, SSN, cartes de crédit)
  • Appliquer un schéma JSON sur les sorties
  • Limiter la longueur du contenu

Installation

[dependencies]
adk-guardrail = "0.2.0"

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

Concepts fondamentaux

GuardrailResult

Chaque garde-fou retourne l'un des trois résultats suivants :

pub enum GuardrailResult {
    Pass,                                    // Le contenu est valide
    Fail { reason: String, severity: Severity },  // Contenu rejeté
    Transform { new_content: Content, reason: String },  // Contenu modifié
}

Niveaux de gravité

pub enum Severity {
    Low,      // Avertissement uniquement, ne bloque pas
    Medium,   // Bloque mais continue les autres vérifications
    High,     // Bloque immédiatement
    Critical, // Bloque et échoue rapidement
}

Suppression des PII

Détecte et supprime automatiquement les informations personnelles identifiables :

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]

Types de PII pris en charge :

TypeModèleSuppression
Emailuser@domain.com[EMAIL REDACTED]
Phone555-123-4567[PHONE REDACTED]
Ssn123-45-6789[SSN REDACTED]
CreditCard4111-1111-1111-1111[CREDIT CARD REDACTED]
IpAddress192.168.1.1[IP REDACTED]

Filtrage du contenu

Bloquer le contenu nuisible ou appliquer des contraintes de sujet :

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);

Filtre de contenu personnalisé

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);

Validation de schéma

Appliquer un schéma JSON sur les sorties de l'agent (nécessite la fonctionnalité 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);

Le validateur extrait le JSON de :

  • Texte JSON brut
  • Blocs de code Markdown (```json ... ```)

GuardrailSet

Combiner plusieurs gardes-fous :

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

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

GuardrailExecutor

Exécutez les garde-fous et obtenez des résultats détaillés :

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,                              // Succès/échec global
    pub transformed_content: Option<Content>,      // Contenu modifié (le cas échéant)
    pub failures: Vec<(String, String, Severity)>, // (nom, raison, gravité)
}

Garde-fous personnalisés

Implémentez le 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
    }

    // Exécute en parallèle avec d'autres garde-fous (par défaut : true)
    fn run_parallel(&self) -> bool {
        true
    }

    // Échec rapide en cas de défaillance de ce garde-fou (par défaut : true)
    fn fail_fast(&self) -> bool {
        true
    }
}

Intégration avec les Agents

Les garde-fous s'intègrent avec 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()?;

Flux d'exécution

Entrée utilisateur
    │
    ▼
┌─────────────────────┐
│  Garde-fous d'entrée   │ ← Rédaction de PII, filtrage de contenu
│  (parallèle)         │
└─────────────────────┘
    │
    ▼ (transformé ou bloqué)
┌─────────────────────┐
│  Exécution de l'Agent    │
└─────────────────────┘
    │
    ▼
┌─────────────────────┐
│  Garde-fous de sortie  │ ← Validation de schéma, vérifications de sécurité
│  (parallèle)         │
└─────────────────────┘
    │
    ▼
Réponse finale

Exemples

# Filtrage basique des PII et du contenu
cargo run --example guardrail_basic --features guardrails

# Validation de schéma JSON
cargo run --example guardrail_schema --features guardrails

# Intégration complète de l'agent
cargo run --example guardrail_agent --features guardrails

Bonnes Pratiques

PratiqueDescription
Superposer les garde-fousUtilisez les garde-fous d'entrée pour la sécurité, ceux de sortie pour la qualité
PII en entréeExpurgez les PII avant qu'elles n'atteignent le modèle
Schéma en sortieValidez les sorties structurées avec un schéma JSON
Gravité appropriéeUtilisez Critical avec parcimonie, Low pour les avertissements
Tester minutieusementLes garde-fous sont du code critique pour la sécurité

Précédent: ← Contrôle d'Accès | Suivant: Mémoire →