Skip to content

Validation

Understanding content validation and guardrails in PromptKit.

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

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

Check user input before sending to LLM:

  • Banned words
  • PII (emails, phone numbers, SSNs)
  • Prompt injection attempts
  • Inappropriate content
  • Input length limits

Check LLM responses before returning to user:

  • Harmful content
  • Leaked sensitive data
  • Off-topic responses
  • Format compliance
  • Output length limits
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),
)
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
})
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

Blocks specific words or phrases:

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

Use for: Preventing inappropriate language, brand protection

Enforces min/max length:

validator := validators.NewLengthValidator(10, 1000)

Use for: Cost control, quality assurance

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

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"
}
pipe := pipeline.NewPipeline(
middleware.ValidatorMiddleware(inputValidators, &middleware.ValidatorConfig{
Stage: "pre", // Before LLM
FailOnViolation: true,
}),
middleware.ProviderMiddleware(provider, nil, nil, nil),
)
pipe := pipeline.NewPipeline(
middleware.ProviderMiddleware(provider, nil, nil, nil),
middleware.ValidatorMiddleware(outputValidators, &middleware.ValidatorConfig{
Stage: "post", // After LLM
FailOnViolation: true,
}),
)
pipe := pipeline.NewPipeline(
middleware.ValidatorMiddleware(inputValidators, &middleware.ValidatorConfig{
Stage: "pre",
}),
middleware.ProviderMiddleware(provider, nil, nil, nil),
middleware.ValidatorMiddleware(outputValidators, &middleware.ValidatorConfig{
Stage: "post",
}),
)
piiValidator := validators.NewRegexValidator(
regexp.MustCompile(`\b\d{3}-\d{2}-\d{4}\b`), // SSN pattern
"SSN detected",
)
moderationValidator := &ModerationValidator{
categories: []string{"hate", "violence", "sexual"},
threshold: 0.7,
}
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
}
rateLimitValidator := &RateLimitValidator{
maxRequests: 100,
window: time.Minute,
}

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’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

config := &middleware.ValidatorConfig{
FailOnViolation: true, // Block requests
LogViolations: true, // Track issues
}
config := &middleware.ValidatorConfig{
FailOnViolation: false, // Allow through
LogViolations: true, // But log for analysis
}
func GetValidationConfig(env string) *middleware.ValidatorConfig {
if env == "production" {
return &middleware.ValidatorConfig{FailOnViolation: true}
}
return &middleware.ValidatorConfig{FailOnViolation: false}
}
validators := []validators.Validator{
lengthValidator, // ~1µs - check first
bannedWordsValidator, // ~10µs
regexValidator, // ~100µs
apiValidator, // ~100ms - check last
}
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
}
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
}
type ValidationMetrics struct {
TotalValidations int
TotalViolations int
ViolationsByType map[string]int
}
func RecordViolation(validatorName string, err error) {
metrics.TotalViolations++
metrics.ViolationsByType[validatorName]++
}
if metrics.ViolationsByType["banned-words"] > 100 {
alert.Send("High rate of banned word violations")
}
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)
}
# 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

Validation provides:

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