본문으로 건너뛰기
이 페이지는 아직 사용자의 언어로 번역되지 않았거나 번역이 기술 검토를 기다리고 있습니다. 아래에는 영어 원문이 표시됩니다. 영어 페이지 열기

Advanced Playbooks

This guide covers advanced patterns for using Control Zero in production environments: multi-agent systems, environment-based policies, gradual rollouts, custom action conventions, and error handling strategies.

Playbook 1: Multi-Agent System with Per-Agent Policies​

When you have multiple agents with different trust levels, use conditions to apply different rules per agent.

The Setup​

from controlzero import Client
from controlzero.integrations.openai import wrap_openai
import openai

cz = Client(api_key="cz_live_your_api_key_here")

# Each agent gets its own wrapped client with a unique agent_id
premium_client = wrap_openai(openai.OpenAI(), cz, agent_id="premium-support")
basic_client = wrap_openai(openai.OpenAI(), cz, agent_id="basic-support")
admin_client = wrap_openai(openai.OpenAI(), cz, agent_id="admin-internal")

The Policy​

{
"name": "multi-agent-governance",
"description": "Different model access per agent tier",
"rules": [
{
"effect": "allow",
"action": "llm:generate",
"resource": "model/gpt-5.4",
"conditions": { "agent_id": "premium-*" }
},
{
"effect": "allow",
"action": "llm:generate",
"resource": "model/gpt-5.4",
"conditions": { "agent_id": "admin-*" }
},
{
"effect": "allow",
"action": "llm:generate",
"resource": "model/gpt-3.5-turbo"
},
{
"effect": "deny",
"action": "llm:generate",
"resource": "model/gpt-5.4",
"conditions": { "agent_id": "basic-*" }
},
{
"effect": "deny",
"action": "llm:generate",
"resource": "model/*"
}
]
}

Behavior:

  • premium-support can use GPT-4 and GPT-3.5 Turbo.
  • basic-support can only use GPT-3.5 Turbo (GPT-4 explicitly denied for basic-*).
  • admin-internal can use GPT-4 and GPT-3.5 Turbo.
  • All agents are denied any other model.

Playbook 2: Environment-Based Policies​

Use different policies for development, staging, and production. The same code runs everywhere. Only the policies change.

Your Code (Same Everywhere)​

from controlzero import Client
from controlzero.integrations.openai import wrap_openai
import openai

cz = Client(api_key="cz_live_your_api_key_here") # or omit and set CONTROLZERO_API_KEY
client = wrap_openai(openai.OpenAI(), cz)

# This code is identical in dev, staging, and production
response = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Hello"}],
)

Your Policies (Different per Environment)​

Development project (proj_dev_001):

{
"name": "dev-permissive",
"rules": [{ "effect": "allow", "action": "*", "resource": "*" }]
}

Staging project (proj_staging_001):

{
"name": "staging-moderate",
"rules": [
{ "effect": "allow", "action": "llm:generate", "resource": "model/*" },
{ "effect": "deny", "action": "data:write", "resource": "*" },
{ "effect": "deny", "action": "mcp.tool:call", "resource": "mcp://shell/*" }
]
}

Production project (proj_prod_001):

{
"name": "production-strict",
"rules": [
{ "effect": "allow", "action": "llm:generate", "resource": "model/gpt-5.4" },
{ "effect": "deny", "action": "llm:generate", "resource": "model/*" },
{ "effect": "deny", "action": "mcp.tool:call", "resource": "mcp://shell/*" },
{ "effect": "deny", "action": "data:write", "resource": "*" },
{ "effect": "deny", "action": "*", "resource": "*" }
]
}

How to switch: Change CONTROLZERO_API_KEY to the key for the target project. Each key belongs to one project and the project identity travels inside the signed bundle, so the code stays the same.


Playbook 3: Gradual Rollout with Log-Only Mode​

When deploying Control Zero for the first time, start in log-only mode to see what would be blocked without actually blocking anything.

Step 1: Enable Log-Only Mode​

In the dashboard, go to your project settings and set Log-Only Mode to true.

Step 2: Deploy with Governance​

cz = Client(api_key="cz_live_your_api_key_here")
client = wrap_openai(openai.OpenAI(), cz)

# All calls are evaluated against policies and logged,
# but NOTHING is blocked. PolicyDeniedError is never raised.
response = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Hello"}],
)
# Works fine even if the policy would deny it

Step 3: Review the Audit Log​

In the dashboard, check the audit log. You will see entries like:

ActionResourceDecisionMode
llm:generatemodel/gpt-5.4allowlog-only
llm:generatemodel/gpt-5.4deny (logged only)log-only

Step 4: Tune Policies​

Adjust your policies based on the audit data until you are confident nothing critical will be blocked.

Step 5: Switch to Enforcement Mode​

In the dashboard, set Log-Only Mode to false. Now denials are enforced for real.


Playbook 4: Custom Action Conventions​

You are not limited to the built-in action names. Define your own action conventions for your domain:

Financial Services Example​

# Custom actions for a trading agent
cz.guard("trade", method="execute", args={"asset": "AAPL"})
cz.guard("trade", method="execute", args={"asset": "BTC"})
cz.guard("report", method="generate", args={"report": "portfolio-summary"})
cz.guard("notification", method="send", args={"channel": "slack-alerts"})
{
"name": "trading-agent-policy",
"rules": [
{ "effect": "allow", "action": "trade:execute", "resource": "asset/AAPL" },
{ "effect": "allow", "action": "trade:execute", "resource": "asset/MSFT" },
{ "effect": "deny", "action": "trade:execute", "resource": "asset/BTC" },
{ "effect": "allow", "action": "report:generate", "resource": "report/*" },
{ "effect": "allow", "action": "notification:send", "resource": "channel/slack-*" },
{ "effect": "deny", "action": "notification:send", "resource": "channel/email-*" }
]
}

Healthcare Example​

cz.guard("patient", method="read", args={"record": "demographics"})
cz.guard("patient", method="read", args={"record": "lab-results"})
cz.guard("patient", method="write", args={"record": "notes"})
{
"name": "healthcare-agent-policy",
"rules": [
{ "effect": "allow", "action": "patient:read", "resource": "record/demographics" },
{ "effect": "allow", "action": "patient:read", "resource": "record/lab-results" },
{ "effect": "deny", "action": "patient:read", "resource": "record/billing" },
{ "effect": "allow", "action": "patient:write", "resource": "record/notes" },
{ "effect": "deny", "action": "patient:write", "resource": "record/*" }
]
}

Playbook 5: Error Handling Patterns​

Pattern A: Fail Fast (Default)​

Let PolicyDeniedError propagate. The action stops immediately:

# If denied, the error propagates up and the request stops
response = client.chat.completions.create(model="gpt-5.4", messages=[...])

Pattern B: Fallback to Approved Alternative​

try:
response = client.chat.completions.create(model="gpt-5.4", messages=[...])
except controlzero.PolicyDeniedError:
response = client.chat.completions.create(model="gpt-5.4-mini", messages=[...])

Pattern C: Check Before Calling​

Use guard() and check the decision effect to avoid exceptions entirely:

decision = cz.guard("llm", method="generate", args={"model": "gpt-5.4"})
if decision.effect == "allow":
response = client.chat.completions.create(model="gpt-5.4", messages=[...])
else:
# Use a different model or skip the action
print(f"Not allowed: {decision.reason}")

Pattern D: Graceful Degradation with Logging​

import logging

logger = logging.getLogger("agent")

def safe_generate(prompt: str, preferred_model: str, fallback_model: str) -> str:
try:
response = client.chat.completions.create(
model=preferred_model,
messages=[{"role": "user", "content": prompt}],
)
return response.choices[0].message.content
except controlzero.PolicyDeniedError as e:
logger.warning(
"Model %s denied by policy, falling back to %s: %s",
preferred_model, fallback_model, e.decision.reason,
)
response = client.chat.completions.create(
model=fallback_model,
messages=[{"role": "user", "content": prompt}],
)
return response.choices[0].message.content

Playbook 6: Combining Auto-Wrap with Manual Enforcement​

In a real application, you will use both patterns:

from controlzero import Client
from controlzero.integrations.openai import wrap_openai
import openai

cz = Client(api_key="cz_live_your_api_key_here")
client = wrap_openai(openai.OpenAI(), cz, agent_id="research-agent")

def research(query: str) -> str:
# AUTOMATIC: LLM calls are governed by the wrapper
# The policy controls which models this agent can use

# MANUAL: Vector store access is a custom action
cz.guard("vectorstore/research-papers", method="read")

# MANUAL: External API access is a custom action
cz.guard("api", method="request", args={"url": "https://api.scholar.google.com/"})

# Proceed with the research pipeline
# (LLM calls within this pipeline are auto-enforced)
results = search_vector_store(query)
response = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": f"Summarize: {results}"}],
)
return response.choices[0].message.content

The rule of thumb:

  • Auto-wrap for LLM API calls (OpenAI, Anthropic, LangChain).
  • Manual guard() for everything else (data sources, APIs, tools, custom actions).

Next Steps​