Async Guardrails¶
AsyncGuardrail runs a guard
concurrently with the LLM call — if the guard fails first, the LLM is cancelled to
save cost.
The guard must be a capability
AsyncGuardrail.guard expects an AbstractCapability (for example an
InputGuard), not a bare
function. AsyncGuardrail drives it by calling the guard's before_run hook.
To wrap a plain check function, pass InputGuard(guard=your_func).
Timing Modes¶
| Mode | Behavior |
|---|---|
"concurrent" |
Guard runs alongside LLM. If guard fails, LLM result is discarded. |
"blocking" |
Guard completes before LLM starts (traditional). |
"monitoring" |
LLM runs first, guard runs after (fire-and-forget for audit/logging). |
Concurrent Mode (Default)¶
from pydantic_ai import Agent
from pydantic_ai_shields import AsyncGuardrail, InputGuard
async def check_policy(prompt: str) -> bool:
# Call your policy API
return await policy_api.check(prompt)
agent = Agent(
"openai:gpt-4.1",
capabilities=[AsyncGuardrail(
guard=InputGuard(guard=check_policy),
timing="concurrent",
cancel_on_failure=True,
timeout=5.0,
)],
)
If check_policy returns False before the model finishes, the result is discarded
and InputBlocked is raised — no
tokens wasted.
cancel_on_failure and timeout¶
Both cancel_on_failure and timeout apply only to concurrent mode:
cancel_on_failure(defaultTrue) — when the guard fails, the LLM result is rejected andInputBlockedis raised. Set it toFalseto keep the result and merely log the failure. This flag is ignored inblockingandmonitoringmodes.timeout— the maximum time to wait for the guard after the model finishes. If the guard is still running and exceeds the timeout, it is cancelled, a warning is logged, and the run is not blocked on that guard. With no timeout, the run waits for the guard to complete.
Blocking Mode¶
Traditional sequential execution — guard completes before model starts:
Monitoring Mode¶
Fire-and-forget — the model runs first, then the guard is launched as a detached background task for logging/audit:
Monitoring never blocks and swallows errors
In monitoring mode the result is returned immediately and the guard runs in a
background task. Any exception the guard raises is caught and logged (at
debug level) — it never propagates, never blocks the run, and never raises
InputBlocked. cancel_on_failure and timeout have no effect here. Use this
mode strictly for observation, not enforcement.