Runtime guardrails for AI agents β configurable, extensible, and production-ready.
Agent Control provides a control-based runtime layer that sits between your AI agents and the outside world. It evaluates inputs and outputs against configurable rules, blocking harmful content, prompt injections, PII leakage, and other risks β all without changing your agent's code.
AI agents are powerful but unpredictable. They can:
- Generate toxic or harmful content
- Be manipulated via prompt injection attacks
- Leak sensitive information (PII, secrets)
- Hallucinate incorrect facts
- Execute unintended actions
Agent Control gives you runtime control over what your agents can do.
Understanding these core concepts will help you get the most out of Agent Control:
A Control is a single rule that defines what to check and what to do when a condition is met.
Control = Scope + Selector + Evaluator + Action
Example: "If the output contains an SSN pattern, block the response."
{
"name": "block-ssn-in-output",
"execution": "server",
"scope": { "step_types": ["llm"], "stages": ["post"] },
"selector": { "path": "output" },
"evaluator": {
"name": "regex",
"config": { "pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b" }
},
"action": { "decision": "deny" }
}A Control Set is a named group of related controls. Use them to organize controls by purpose.
| Control Set | Controls |
|---|---|
safety-controls |
block-toxicity, block-harassment, block-violence |
compliance-controls |
block-pii, block-phi, audit-logging |
quality-controls |
check-hallucination, verify-sources |
Controls can be linked directly to agents and reused across multiple agents. This keeps rollout and tuning fast without redeploying application code.
Controls β Agents
A Selector defines what data to extract from the payload for evaluation.
| Path | Description | Example Use |
|---|---|---|
input |
Step input (tool args or LLM input) | Check for prompt injection |
output |
Step output | Check for PII leakage |
input.query |
Tool input field | Block SQL injection |
name |
Step name (tool name or model/chain id, required) | Restrict step usage |
context.user_id |
Context field | User-based rules |
* |
Entire step | Full payload analysis |
Step scoping: Controls can also scope by step type/name/stage:
{
"scope": {
"step_types": ["tool"],
"step_names": ["search_database", "execute_sql"],
"step_name_regex": "^db_.*",
"stages": ["pre"]
}
}An Evaluator defines how to analyze the selected data. Agent Control provides built-in evaluators and supports custom evaluators.
An Action defines what to do when a control matches:
| Action | Behavior |
|---|---|
deny |
Block the request/response |
steer |
Raise error with steering context for correction and retry |
allow |
Explicitly permit (override other controls) |
warn |
Log a warning but allow |
log |
Silent logging for monitoring |
Controls run at different stages (configured via scope.stages):
| Stage | When | Use Case |
|---|---|---|
pre |
Before execution | Block bad inputs, prevent tool misuse |
post |
After execution | Filter bad outputs, redact PII |
Agent Control includes powerful evaluators out of the box:
Pattern matching using Google RE2 (safe from ReDoS attacks).
Configuration:
| Option | Type | Description |
|---|---|---|
pattern |
string | Regular expression pattern (RE2 syntax) |
flags |
list | Optional: ["IGNORECASE"] |
Examples:
// Block Social Security Numbers
{
"name": "regex",
"config": {
"pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b"
}
}
// Block credit card numbers (case-insensitive "card" + digits)
{
"name": "regex",
"config": {
"pattern": "card.*\\d{4}[- ]?\\d{4}[- ]?\\d{4}[- ]?\\d{4}",
"flags": ["IGNORECASE"]
}
}
// Block AWS access keys
{
"name": "regex",
"config": {
"pattern": "AKIA[0-9A-Z]{16}"
}
}Use Cases:
- PII detection (SSN, credit cards, phone numbers)
- Secret detection (API keys, passwords)
- Pattern-based blocklists
- Data format validation
Flexible value matching with multiple modes and logic options.
Configuration:
| Option | Type | Default | Description |
|---|---|---|---|
values |
list | required | Values to match against |
logic |
string | "any" |
"any" = match any value, "all" = match all |
match_on |
string | "match" |
"match" = trigger when found, "no_match" = trigger when NOT found |
match_mode |
string | "exact" |
"exact" = full string, "contains" = substring/keyword |
case_sensitive |
bool | false |
Case sensitivity |
Examples:
// Block admin/root keywords (any match, contains, case-insensitive)
{
"name": "list",
"config": {
"values": ["admin", "root", "sudo", "superuser"],
"logic": "any",
"match_mode": "contains",
"case_sensitive": false
}
}
// Require approval keyword (trigger if NOT found)
{
"name": "list",
"config": {
"values": ["APPROVED", "VERIFIED"],
"match_on": "no_match",
"logic": "any"
}
}
// Block competitor mentions
{
"name": "list",
"config": {
"values": ["CompetitorA", "CompetitorB", "CompetitorC"],
"match_mode": "contains",
"case_sensitive": false
}
}
// Allowlist: only permit specific tools
{
"name": "list",
"config": {
"values": ["search", "calculate", "lookup"],
"match_on": "no_match"
}
}Use Cases:
- Keyword blocklists/allowlists
- Required terms validation
- Competitor mention detection
- Tool restriction lists
- Profanity filtering
AI-powered detection using Galileo's Luna-2 small language models. Provides real-time, low-latency evaluation for complex patterns that can't be caught with regex or lists.
Configuration:
| Option | Type | Default | Description |
|---|---|---|---|
metric |
string | required | Metric to evaluate (see below) |
operator |
string | required | "gt", "lt", "gte", "lte", "eq" |
target_value |
number | required | Threshold value (0.0-1.0) |
stage_type |
string | "local" |
"local" or "central" |
galileo_project |
string | optional | Project name for logging |
on_error |
string | "allow" |
"allow" (fail open) or "deny" (fail closed) |
Available Metrics:
| Metric | Description |
|---|---|
input_toxicity |
Toxic/harmful content in user input |
output_toxicity |
Toxic/harmful content in agent response |
input_sexism |
Sexist content in user input |
output_sexism |
Sexist content in agent response |
prompt_injection |
Prompt manipulation attempts |
pii_detection |
Personally identifiable information |
hallucination |
Potentially false or fabricated statements |
tone |
Communication tone analysis |
Examples:
// Block toxic inputs (score > 0.5)
{
"name": "galileo.luna2",
"config": {
"metric": "input_toxicity",
"operator": "gt",
"target_value": 0.5,
"galileo_project": "my-project"
}
}
// Block prompt injection attempts
{
"name": "galileo.luna2",
"config": {
"metric": "prompt_injection",
"operator": "gt",
"target_value": 0.7,
"on_error": "deny"
}
}
// Flag potential hallucinations (warn but allow)
{
"name": "galileo.luna2",
"config": {
"metric": "hallucination",
"operator": "gt",
"target_value": 0.6
}
}
// Using a central stage (pre-defined server-side rules)
{
"name": "galileo.luna2",
"config": {
"stage_type": "central",
"stage_name": "production-safety",
"galileo_project": "my-project"
}
}Use Cases:
- Toxicity and harassment detection
- Prompt injection protection
- PII leakage prevention
- Hallucination flagging
- Tone and sentiment analysis
Add guardrails to any agent with a simple decorator. No need to modify your agent's core logic.
from agent_control import control
@control()
async def chat(message: str) -> str:
return await llm.generate(message)Update controls without redeploying your application. Critical for:
- Responding to emerging threats
- Tuning thresholds based on real-world data
- A/B testing different safety controls
Define controls once, apply them to multiple agents. Security teams can manage controls independently from development teams.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Control Collection β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β Control Set β β Control Set β β Control Set β β
β β (Safety) β β (Compliance)β β (Quality) β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌβββββββββββββββββ
βΌ βΌ βΌ
βββββββββββ βββββββββββ βββββββββββ
β Agent A β β Agent B β β Agent C β
βββββββββββ βββββββββββ βββββββββββ
Every evaluation is logged with:
- Trace IDs for debugging
- Execution timestamps
- Match confidence scores
- Detailed metadata
Answer questions like: "Why was this blocked?" or "What threats did we stop this week?"
Use built-in evaluators or bring your own. The evaluator system supports:
- Simple pattern matching (regex, word lists)
- AI-powered detection (toxicity, prompt injection, hallucination)
- Custom business logic
Choose how to handle failures:
on_error: "deny"β Fail closed (block on error)on_error: "allow"β Fail open (permit on error)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your Application β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β @control() decorator β β
β β β β β
β β βΌ β β
β β ββββββββββββ βββββββββββββββββββ ββββββββββββββββ β β
β β β Input βββββΆβ Agent Control βββββΆβ Output β β β
β β β β β Engine β β β β β
β β ββββββββββββ βββββββββββββββββββ ββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Agent Control Server β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ ββββββββββββββ β
β β Controls β βControl Linkβ β Evaluators β β Agents β β
β β API β β API β β Registry β β API β β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ ββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Evaluator Ecosystem β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ ββββββββββββββ β
β β Regex β β List β β Luna-2 β β Custom β β
β β Evaluator β β Evaluator β β Evaluator β β Evaluators β β
β ββββββββββββββ ββββββββββββββ ββββββββββββββ ββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Component | Description |
|---|---|
| SDK | Python client library with @control() decorator |
| Server | FastAPI service that stores and evaluates controls |
| Engine | Core evaluation logic (can run locally or server-side) |
| Evaluators | Extensible evaluators for different detection methods |
| Models | Shared Pydantic models for type-safe communication |
Partners and developers can create custom evaluators to extend Agent Control with their own detection capabilities.
Every evaluator implements the Evaluator base class:
from typing import Any
from agent_control_models import EvaluatorResult
from agent_control_evaluators import (
Evaluator,
EvaluatorConfig,
EvaluatorMetadata,
register_evaluator,
)
class MyEvaluatorConfig(EvaluatorConfig):
"""Configuration schema for your evaluator."""
threshold: float = 0.5
custom_option: str = "default"
@register_evaluator
class MyEvaluator(Evaluator[MyEvaluatorConfig]):
"""Your custom evaluator."""
metadata = EvaluatorMetadata(
name="my-evaluator",
version="1.0.0",
description="Detects custom patterns using proprietary logic",
requires_api_key=True, # Set to True if you need credentials
timeout_ms=5000,
)
config_model = MyEvaluatorConfig
def __init__(self, config: MyEvaluatorConfig) -> None:
"""Initialize with validated configuration."""
super().__init__(config)
# Set up any clients, load models, etc.
async def evaluate(self, data: Any) -> EvaluatorResult:
"""
Evaluate the input data.
Args:
data: The content to evaluate (string, dict, etc.)
Returns:
EvaluatorResult with:
- matched: bool β Did this trigger the control?
- confidence: float β How confident (0.0-1.0)?
- message: str β Human-readable explanation
- metadata: dict β Additional context for logging
"""
# Your detection logic here
score = await self._analyze(data)
return EvaluatorResult(
matched=score > self.config.threshold,
confidence=score,
message=f"Custom analysis score: {score:.2f}",
metadata={
"score": score,
"threshold": self.config.threshold,
}
)
async def _analyze(self, data: Any) -> float:
"""Your proprietary analysis logic."""
# Call your API, run your model, etc.
return 0.0Evaluators are discovered automatically via Python entry points. To make your evaluator available:
- Create a Python package with your evaluator class decorated with
@register_evaluator - Register as an entry point in your
pyproject.toml:[project.entry-points."agent_control.evaluators"] my-evaluator = "my_package.evaluator:MyEvaluator"
- Install it in the Agent Control environment
# Install your evaluator
pip install my-custom-evaluator
# It's now availableIf your evaluator has optional dependencies, override is_available():
try:
import optional_dep
AVAILABLE = True
except ImportError:
AVAILABLE = False
@register_evaluator
class MyEvaluator(Evaluator[MyEvaluatorConfig]):
@classmethod
def is_available(cls) -> bool:
return AVAILABLEWhen is_available() returns False, the evaluator is silently skipped during registration.
| Practice | Why |
|---|---|
| Use Pydantic for config | Automatic validation and documentation |
| Implement timeouts | Prevent slow evaluators from blocking agents |
| Return confidence scores | Enable threshold-based filtering |
| Include metadata | Helps with debugging and observability |
| Handle errors gracefully | Respect the on_error configuration |
| Make API calls async | Don't block the event loop |
Here's how a partner might integrate their content moderation API:
@register_evaluator
class ContentModerationEvaluator(Evaluator[ContentModerationEvaluatorConfig]):
"""Integration with Acme Content Moderation API."""
metadata = EvaluatorMetadata(
name="acme-content-mod",
version="1.0.0",
description="Acme Inc. content moderation",
requires_api_key=True,
timeout_ms=3000,
)
config_model = ContentModerationEvaluatorConfig
def __init__(self, config: ContentModerationEvaluatorConfig) -> None:
super().__init__(config)
self.client = AcmeClient(api_key=os.getenv("ACME_API_KEY"))
async def evaluate(self, data: Any) -> EvaluatorResult:
result = await self.client.moderate(str(data))
return EvaluatorResult(
matched=result.flagged,
confidence=result.confidence,
message=result.reason,
metadata={"categories": result.categories}
)# Core SDK
pip install agent-control
# Server
pip install agent-control-server
# With Galileo Luna-2 evaluator support
pip install agent-control-evaluator-galileo
# Or via convenience extra:
pip install agent-control-server[galileo]import agent_control
from agent_control import control
# Initialize
agent_control.init(
agent_name="my-agent",
server_url="http://localhost:8000"
)
# Protect your agent
@control()
async def process_message(message: str) -> str:
# Your agent logic here
return await llm.generate(message)# Start the server
make server-run
# Or with Docker
docker-compose up| Use Case | Controls Used |
|---|---|
| Customer Support Bot | Toxicity, PII detection, tone |
| Code Assistant | Prompt injection, secret detection |
| Research Agent | Hallucination detection, source verification |
| Sales Copilot | Compliance rules, competitor mentions |
| Healthcare Agent | PHI detection, medical advice disclaimers |
- Web UI for control management
- More built-in evaluators (OpenAI Moderation, Perspective API, etc.)
- Metrics and analytics dashboard
- Multi-language SDK support (TypeScript, Go)
- Webhook notifications for violations
We welcome contributions! See CONTRIBUTING.md for guidelines.
- Fork the repository
- Create your evaluator in
evaluators/builtin/src/agent_control_evaluators/(for builtins) or inevaluators/contrib/(for external packages) - Add tests in
evaluators/builtin/tests/(for builtins) orevaluators/contrib/<your-evaluator>/tests/(for contrib) - Submit a pull request
Apache 2.0 β See LICENSE for details.