Customizing Guardrails with Vijil Dome
In Part 3 of our Vijil Dome series, learn how to build custom guardrails that enforce domain-specific protections—like PII detection—on top of Dome’s secure, production-ready AI safety infrastructure.
Welcome back to our Vijil Dome series! In Part 1, we explored how to get started with Dome and integrate it seamlessly with OpenAI clients. Part 2 showed you how to leverage Dome's powerful Langchain integrations for more complex AI workflows.
Today, we're diving into one of Dome's most powerful features: creating custom guardrails. While Dome comes with robust built-in detectors for common security, privacy, and moderation concerns, every application has unique requirements. Custom guardrails allow you to implement business-specific logic, domain-specific validations, and tailored protection mechanisms that align perfectly with your use case.
Why Custom Guardrails Matter
AI applications often need specialized protection beyond standard safety filters. Consider these scenarios:
- Financial services might need to detect and block queries attempting to manipulate trading decisions
- Healthcare applications require validation that medical advice requests are appropriate for the AI's scope
- Educational platforms may want to ensure student queries remain within curriculum boundaries
- Enterprise systems often need to enforce company-specific policies and compliance requirements
Custom guardrails give you the flexibility to implement these domain-specific protections while leveraging Dome's powerful infrastructure for detection, logging, and response handling.
Building Your First Custom Guardrail: PII Phone Number Detector
Let's walk through creating a practical custom guardrail that detects and blocks potential phone number sharing in user queries. This is particularly useful for applications that need to prevent users from accidentally sharing personal contact information.
Step 1: Setting Up the Custom Detector
First, let's create our phone number detection logic:
import re
from vijil_dome.detectors import (
DetectionCategory,
DetectionResult,
DetectionMethod,
register_method,
)
PHONE_NUMBER_DETECTOR = "phone-number-detector"
# Register with the Privacy category since we're protecting PII
@register_method(DetectionCategory.Privacy, PHONE_NUMBER_DETECTOR)
class PhoneNumberDetector(DetectionMethod):
def __init__(self, block_international=True, strict_mode=False):
super().__init__()
self.block_international = block_international
self.strict_mode = strict_mode
self.us_pattern = re.compile(
r'(\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}|\d{10})'
)
self.international_pattern = re.compile(
r'(\+\d{1,3}[-.\s]?\(?\d{1,4}\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9})'
)
async def detect(self, query_string: str) -> DetectionResult:
us_matches = self.us_pattern.findall(query_string)
intl_matches = []
if self.block_international:
intl_matches = self.international_pattern.findall(query_string)
flagged = bool(us_matches or intl_matches)
if self.strict_mode and not flagged:
digit_sequences = re.findall(r'\d{7,}', query_string)
flagged = len(digit_sequences) > 0
metadata = {
"type": type(self),
"query_string": query_string,
"us_phone_matches": us_matches,
"international_matches": intl_matches,
"response_string": (
"I can't process requests containing phone numbers to protect your privacy. "
"Please remove any phone numbers and try again."
) if flagged else "Query processed successfully"
}
return flagged, metadataStep 2: Integrating with Your Dome Configuration
Now let's integrate our custom detector into a Dome configuration. Remember to define your custom detector before instantiating your configuration:
# Define your custom detector before instantiating your configuration
from vijil_dome import Dome
dome_config = {
"pii-detection": {
"type": "privacy",
"methods": ["phone-number-detector"],
"early-exit": True,
},
"input-guards": ["pii-detection"],
"output-guards": ["pii-detection"],
"input-early-exit": True
}
dome = Dome(dome_config)Step 3: Testing Your Custom Guardrail
Let's test our phone number detector with various inputs:
import asyncio
async def test_phone_detector():
test_queries = [
"Call me at (555) 123-4567 when you're ready",
"My number is 555-123-4567",
"Contact support at +1-800-555-0123",
"I need help with my account balance", # Safe query
"The reference number is 1234567890", # Might trigger strict mode
]
for query in test_queries:
result = await dome.async_guard_input(query)
print(f"Query: '{query}'")
print(f"Result: flagged={result.flagged} response={result.response_string}")
print("-" * 50)
asyncio.run(test_phone_detector()) Expected Output
When you run this test, you should see something like:
Query: 'Call me at (555) 123-4567 when you're ready'
Result: flagged=True response="Blocked by input guardrail at Guard:pii-detection ..."
Query: 'My number is 555-123-4567'
Result: flagged=True response="Blocked by input guardrail at Guard:pii-detection ..."
Query: 'Contact support at +1-800-555-0123'
Result: flagged=True response="Blocked by input guardrail at Guard:pii-detection ..."
Query: 'I need help with my account balance'
Result: flagged=False response='Query processed successfully'
Query: 'The reference number is 1234567890'
Result: flagged=True response="Blocked by input guardrail at Guard:pii-detection ..."Best Practices for Custom Guardrails
1. Choose the Right Detection Category
- Security: Threats, injections, malicious content
- Privacy: PII, sensitive data, personal information
- Moderation: Inappropriate content, harassment, spam
- Integrity: Misinformation, bias, factual accuracy
- Generic: General-purpose, business logic, custom rules
2. Implement Comprehensive Logging
Always include detailed metadata in your DetectionResult. This helps with:
- Debugging and improving your detectors
- Compliance and audit requirements
- Understanding user behavior patterns
- Fine-tuning detection sensitivity
3. Test Thoroughly
Create comprehensive test suites covering:
- Expected positive cases (should be blocked)
- Expected negative cases (should be allowed)
- Edge cases and boundary conditions
- Performance with large inputs
4. Consider Performance
Custom detectors run on every request, so optimize for:
- Efficient regex patterns
- Minimal external API calls
- Appropriate caching strategies
- Asynchronous operations where possible
Conclusion
Custom guardrails in Vijil Dome provide the flexibility to implement domain-specific protection while leveraging a robust, battle-tested infrastructure. Whether you're building financial applications, healthcare platforms, or enterprise systems, custom detectors allow you to encode your unique business logic and compliance requirements directly into your AI safety layer.
In our phone number detector example, we've seen how to create a practical custom guardrail that protects user privacy while providing clear feedback. The same patterns can be applied to create detectors for industry-specific terminology, company policies, regulatory compliance, or any other custom logic your application requires.
As you build your custom guardrails, remember that they're most effective when combined with Dome's built-in detectors and integrated into a comprehensive AI safety strategy. Start with simple detectors, test thoroughly, and iterate based on real-world usage patterns.
Ready to implement your own custom guardrails? Check out the complete documentation for more advanced patterns and examples. And if you missed the earlier parts of this series, be sure to read Part 1 on getting started with OpenAI integration and Part 2 on Langchain workflows.
Have questions about implementing custom guardrails for your specific use case? We'd love to hear from you and help you build robust, domain-specific AI protection systems with Vijil Dome.