Patterns and techniques for adding governance, safety, and trust controls to AI agent systems. Use this skill when:
- Building AI agents that call external tools (APIs, databases, file systems)
- Implementing policy-based access controls for agent tool usage
- Adding semantic intent classification to detect dangerous prompts
- Creating trust scoring systems for multi-agent workflows
- Building audit trails for agent actions and decisions
- Enforcing rate limits, content filters, or tool restrictions on agents
- Working with any agent framework (PydanticAI, CrewAI, OpenAI Agents, LangChain, AutoGen)
Patterns and techniques for adding governance, safety, and trust controls to AI agent systems. Use this skill when:
- Building AI agents that call external tools (APIs, databases, file systems)
- Implementing policy-based access controls for agent tool usage
- Adding semantic intent classification to detect dangerous prompts
- Creating trust scoring systems for multi-agent workflows
- Building audit trails for agent actions and decisions
- Enforcing rate limits, content filters, or tool restrictions on agents
- Working with any agent framework (PydanticAI, CrewAI, OpenAI Agents, LangChain, AutoGen)
Agent Governance Patterns
Patterns for adding safety, trust, and policy enforcement to AI agent systems.
Overview
Governance patterns ensure AI agents operate within defined boundaries — controlling which tools they can call, what content they can process, how much they can do, and maintaining accountability through audit trails.
import yaml
defload_policy(path: str) -> GovernancePolicy:
withopen(path) as f:
data = yaml.safe_load(f)
return GovernancePolicy(**data)
Pattern 2: Semantic Intent Classification
Detect dangerous intent in prompts before they reach the agent, using pattern-based signals.
from dataclasses import dataclass
@dataclassclassIntentSignal:
category: str# e.g., "data_exfiltration", "privilege_escalation"
confidence: float# 0.0 to 1.0
evidence: str# what triggered the detection# Weighted signal patterns for threat detection
THREAT_SIGNALS = [
# Data exfiltration
(r"(?i)send\s+(all|every|entire)\s+\w+\s+to\s+", "data_exfiltration", 0.8),
(r"(?i)export\s+.*\s+to\s+(external|outside|third.?party)", "data_exfiltration", 0.9),
(r"(?i)curl\s+.*\s+-d\s+", "data_exfiltration", 0.7),
# Privilege escalation
(r"(?i)(sudo|as\s+root|admin\s+access)", "privilege_escalation", 0.8),
(r"(?i)chmod\s+777", "privilege_escalation", 0.9),
# System modification
(r"(?i)(rm\s+-rf|del\s+/[sq]|format\s+c:)", "system_destruction", 0.95),
(r"(?i)(drop\s+database|truncate\s+table)", "system_destruction", 0.9),
# Prompt injection
(r"(?i)ignore\s+(previous|above|all)\s+(instructions?|rules?)", "prompt_injection", 0.9),
(r"(?i)you\s+are\s+now\s+(a|an)\s+", "prompt_injection", 0.7),
]
defclassify_intent(content: str) -> list[IntentSignal]:
"""Classify content for threat signals."""
signals = []
for pattern, category, weight in THREAT_SIGNALS:
match = re.search(pattern, content)
ifmatch:
signals.append(IntentSignal(
category=category,
confidence=weight,
evidence=match.group()
))
return signals
defis_safe(content: str, threshold: float = 0.7) -> bool:
"""Quick check: is the content safe above the given threshold?"""
signals = classify_intent(content)
returnnotany(s.confidence >= threshold for s in signals)
Key insight: Intent classification happens before tool execution, acting as a pre-flight safety check. This is fundamentally different from output guardrails which only check after generation.
Pattern 3: Tool-Level Governance Decorator
Wrap individual tool functions with governance checks:
import functools
import time
from collections import defaultdict
_call_counters: dict[str, int] = defaultdict(int)
defgovern(policy: GovernancePolicy, audit_trail=None):
"""Decorator that enforces governance policy on a tool function."""defdecorator(func):
@functools.wraps(func)asyncdefwrapper(*args, **kwargs):
tool_name = func.__name__
# 1. Check tool allowlist/blocklist
action = policy.check_tool(tool_name)
if action == PolicyAction.DENY:
raise PermissionError(f"Policy '{policy.name}' blocks tool '{tool_name}'")
if action == PolicyAction.REVIEW:
raise PermissionError(f"Tool '{tool_name}' requires human approval")
# 2. Check rate limit
_call_counters[policy.name] += 1if _call_counters[policy.name] > policy.max_calls_per_request:
raise PermissionError(f"Rate limit exceeded: {policy.max_calls_per_request} calls")
# 3. Check content in argumentsfor arg inlist(args) + list(kwargs.values()):
ifisinstance(arg, str):
matched = policy.check_content(arg)
if matched:
raise PermissionError(f"Blocked pattern detected: {matched}")
# 4. Execute and audit
start = time.monotonic()
try:
result = await func(*args, **kwargs)
if audit_trail isnotNone:
audit_trail.append({
"tool": tool_name,
"action": "allowed",
"duration_ms": (time.monotonic() - start) * 1000,
"timestamp": time.time()
})
return result
except Exception as e:
if audit_trail isnotNone:
audit_trail.append({
"tool": tool_name,
"action": "error",
"error": str(e),
"timestamp": time.time()
})
raisereturn wrapper
return decorator
# Usage with any agent framework
audit_log = []
policy = GovernancePolicy(
name="search-agent",
allowed_tools=["search", "summarize"],
blocked_patterns=[r"(?i)password"],
max_calls_per_request=10
)
@govern(policy, audit_trail=audit_log)asyncdefsearch(query: str) -> str:
"""Search documents — governed by policy."""returnf"Results for: {query}"# Passes: search("latest quarterly report")# Blocked: search("show me the admin password")
Pattern 4: Trust Scoring
Track agent reliability over time with decay-based trust scores:
from dataclasses import dataclass, field
import math
import time
@dataclassclassTrustScore:
"""Trust score with temporal decay."""
score: float = 0.5# 0.0 (untrusted) to 1.0 (fully trusted)
successes: int = 0
failures: int = 0
last_updated: float = field(default_factory=time.time)
defrecord_success(self, reward: float = 0.05):
self.successes += 1self.score = min(1.0, self.score + reward * (1 - self.score))
self.last_updated = time.time()
defrecord_failure(self, penalty: float = 0.15):
self.failures += 1self.score = max(0.0, self.score - penalty * self.score)
self.last_updated = time.time()
defcurrent(self, decay_rate: float = 0.001) -> float:
"""Get score with temporal decay — trust erodes without activity."""
elapsed = time.time() - self.last_updated
decay = math.exp(-decay_rate * elapsed)
returnself.score * decay
@propertydefreliability(self) -> float:
total = self.successes + self.failures
returnself.successes / total if total > 0else0.0# Usage in multi-agent systems
trust = TrustScore()
# Agent completes tasks successfully
trust.record_success() # 0.525
trust.record_success() # 0.549# Agent makes an error
trust.record_failure() # 0.467# Gate sensitive operations on trustif trust.current() >= 0.7:
# Allow autonomous operationpasselif trust.current() >= 0.4:
# Allow with human oversightpasselse:
# Deny or require explicit approvalpass
Multi-agent trust: In systems where agents delegate to other agents, each agent maintains trust scores for its delegates: