guardflow
Validators and a retry-until-valid guard for LLM output — the core pattern behind Python's Guardrails AI. No Rust equivalent as of 2026.
Install
The pattern: format checks are free, real checks need a model call
Guard runs cheap sync checks (length, regex, PII shape, JSON schema). AsyncGuard adds checks that need a network call — an LLM-as-judge, a moderation API — and only makes that call once the free checks already pass:
use NoPii;
use ;
let guard = from_guard
.with_async;
let reply = guard_with_retry_async.await;
Run it: cargo run --example support_bot — a fake LLM leaks an email (rejected by the free no_pii check), then over-promises a refund (rejected by the async policy check, which only ran because the free check passed first), then succeeds on the third try.
Built-in validators
NotEmpty, MaxLength, MinLength, MatchesRegex, OneOf, ValidJson, NoPii (heuristic regex, not ML), Profanity (bring your own word list), JsonSchema (feature json-schema). Implement Validator (sync) or AsyncValidator for your own checks.
Auto-fix instead of reject: some validators can repair input instead of just failing it — Truncate shortens instead of rejecting on length. Guard::fix(text) applies every fixable validator in order and returns the corrected text; Guard::check never rewrites anything, so Truncate counts as a failure there.
Rule files
Load a rule set from YAML or JSON instead of Rust code (feature spec):
# rules.yaml
rules:
- rule: not_empty
- rule: max_length
max: 500
- rule: no_pii
let guard = guard_from_file?;
graph-flow integration
With the graphflow feature, GuardedTask<T> wraps any graph_flow::Task, retrying until its response passes:
use GuardedTask;
let guarded = new.with_max_attempts;
Works with graphflow-stream — wrap a task before passing it to spawn_task/spawn_graph.
Examples
Benchmarks
cargo bench (benches/overhead.rs):
| Scenario | Time |
|---|---|
Guard::check, 1 validator |
~27 ns |
Guard::check, 5 validators (incl. NoPii) |
~1.2 µs |
License
MIT