Validation

Understanding content validation and guardrails in PromptKit.

What is Validation?

Validation checks content for safety, quality, and compliance. It acts as guardrails to ensure LLM applications behave correctly.

Why Validate?

Safety: Block harmful content
Compliance: Enforce regulations (GDPR, HIPAA)
Quality: Ensure response meets standards
Cost: Prevent expensive requests
Brand: Maintain company reputation

Types of Validation

Input Validation

Check user input before sending to LLM:

Output Validation

Check LLM responses before returning to user:

Validation in PromptKit

Runtime Validators

import "github.com/AltairaLabs/PromptKit/runtime/validators"

// Create validators
bannedWords := validators.NewBannedWordsValidator([]string{
    "hack", "crack", "pirate",
})

lengthValidator := validators.NewLengthValidator(1, 1000)

// Add to pipeline
pipe := pipeline.NewPipeline(
    middleware.ValidatorMiddleware([]validators.Validator{
        bannedWords,
        lengthValidator,
    }, nil),
    middleware.ProviderMiddleware(provider, nil, nil, nil),
)

SDK Validation

conv := sdk.NewConversation(provider, nil)

// Add custom validator
conv.AddValidator(func(message string) error {
    if strings.Contains(message, "password") {
        return errors.New("do not share passwords")
    }
    return nil
})

PromptArena Validation

guardrails:
  banned_words:
    - hack
    - crack
  
  max_length: 1000
  min_length: 1

tests:
  - name: Block Banned Words
    prompt: "How do I hack the system?"
    assertions:
      - type: validation_error
        expected: true

Built-In Validators

BannedWordsValidator

Blocks specific words or phrases:

validator := validators.NewBannedWordsValidator([]string{
    "hack", "crack", "pirate", "steal",
})

Use for: Preventing inappropriate language, brand protection

LengthValidator

Enforces min/max length:

validator := validators.NewLengthValidator(10, 1000)

Use for: Cost control, quality assurance

RegexValidator

Matches patterns:

validator := validators.NewRegexValidator(
    regexp.MustCompile(`\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b`),
    "emails not allowed",
)

Use for: PII detection, format validation

CustomValidator

Implement custom logic:

type CustomValidator struct{}

func (v *CustomValidator) Validate(message string) error {
    if containsToxicContent(message) {
        return errors.New("toxic content detected")
    }
    return nil
}

func (v *CustomValidator) Name() string {
    return "custom-toxicity"
}

Validation Patterns

Pre-Execution (Input)

pipe := pipeline.NewPipeline(
    middleware.ValidatorMiddleware(inputValidators, &middleware.ValidatorConfig{
        Stage:           "pre",  // Before LLM
        FailOnViolation: true,
    }),
    middleware.ProviderMiddleware(provider, nil, nil, nil),
)

Post-Execution (Output)

pipe := pipeline.NewPipeline(
    middleware.ProviderMiddleware(provider, nil, nil, nil),
    middleware.ValidatorMiddleware(outputValidators, &middleware.ValidatorConfig{
        Stage:           "post",  // After LLM
        FailOnViolation: true,
    }),
)

Both Stages

pipe := pipeline.NewPipeline(
    middleware.ValidatorMiddleware(inputValidators, &middleware.ValidatorConfig{
        Stage: "pre",
    }),
    middleware.ProviderMiddleware(provider, nil, nil, nil),
    middleware.ValidatorMiddleware(outputValidators, &middleware.ValidatorConfig{
        Stage: "post",
    }),
)

Common Use Cases

Block Sensitive Data

piiValidator := validators.NewRegexValidator(
    regexp.MustCompile(`\b\d{3}-\d{2}-\d{4}\b`),  // SSN pattern
    "SSN detected",
)

Content Moderation

moderationValidator := &ModerationValidator{
    categories: []string{"hate", "violence", "sexual"},
    threshold:  0.7,
}

Format Compliance

jsonValidator := &JSONValidator{}

func (v *JSONValidator) Validate(message string) error {
    var js json.RawMessage
    if err := json.Unmarshal([]byte(message), &js); err != nil {
        return fmt.Errorf("invalid JSON: %w", err)
    }
    return nil
}

Rate Limiting

rateLimitValidator := &RateLimitValidator{
    maxRequests: 100,
    window:      time.Minute,
}

Best Practices

Do’s

Validate both input and output

// Input: User safety
// Output: Response quality

Be specific about violations

return fmt.Errorf("banned word '%s' found at position %d", word, pos)

Log violations for monitoring

if err := validator.Validate(message); err != nil {
    logger.Warn("validation failed", zap.Error(err))
    return err
}

Test validators thoroughly

# PromptArena tests
tests:
  - prompt: "test banned word: hack"
    assertions:
      - type: validation_error

Don’ts

Don’t validate everything - Performance cost
Don’t expose violation details to users - Security
Don’t block legitimate use - False positives
Don’t skip output validation - LLMs can hallucinate

Validation Strategies

Strict (Production)

config := &middleware.ValidatorConfig{
    FailOnViolation: true,   // Block requests
    LogViolations:   true,    // Track issues
}

Permissive (Development)

config := &middleware.ValidatorConfig{
    FailOnViolation: false,   // Allow through
    LogViolations:   true,     // But log for analysis
}

Adaptive

func GetValidationConfig(env string) *middleware.ValidatorConfig {
    if env == "production" {
        return &middleware.ValidatorConfig{FailOnViolation: true}
    }
    return &middleware.ValidatorConfig{FailOnViolation: false}
}

Performance Considerations

Fast Validators First

validators := []validators.Validator{
    lengthValidator,      // ~1µs - check first
    bannedWordsValidator, // ~10µs
    regexValidator,       // ~100µs
    apiValidator,         // ~100ms - check last
}

Parallel Validation

func ValidateParallel(message string, validators []Validator) error {
    var wg sync.WaitGroup
    errors := make(chan error, len(validators))
    
    for _, v := range validators {
        wg.Add(1)
        go func(validator Validator) {
            defer wg.Done()
            if err := validator.Validate(message); err != nil {
                errors <- err
            }
        }(v)
    }
    
    wg.Wait()
    close(errors)
    
    for err := range errors {
        return err  // Return first error
    }
    return nil
}

Caching

type CachedValidator struct {
    inner Validator
    cache map[string]error
}

func (v *CachedValidator) Validate(message string) error {
    if cached, ok := v.cache[message]; ok {
        return cached
    }
    
    err := v.inner.Validate(message)
    v.cache[message] = err
    return err
}

Monitoring Validation

Track Violations

type ValidationMetrics struct {
    TotalValidations int
    TotalViolations  int
    ViolationsByType map[string]int
}

func RecordViolation(validatorName string, err error) {
    metrics.TotalViolations++
    metrics.ViolationsByType[validatorName]++
}

Alert on Patterns

if metrics.ViolationsByType["banned-words"] > 100 {
    alert.Send("High rate of banned word violations")
}

Testing Validation

Unit Tests

func TestBannedWordsValidator(t *testing.T) {
    validator := validators.NewBannedWordsValidator([]string{"hack"})
    
    // Should pass
    err := validator.Validate("normal message")
    assert.NoError(t, err)
    
    // Should fail
    err = validator.Validate("how to hack")
    assert.Error(t, err)
}

Integration Tests

# arena.yaml
tests:
  - name: Input Validation
    prompt: "hack the system"
    assertions:
      - type: validation_error
        expected: true
  
  - name: Valid Input
    prompt: "how do I reset my password?"
    assertions:
      - type: success

Summary

Validation provides:

Safety - Block harmful content
Compliance - Enforce regulations
Quality - Ensure standards
Cost Control - Prevent expensive requests
Monitoring - Track issues