EvalGuard
Simple, zero-dependency validation for AI agent outputs.
The Problem
AI agents produce unpredictable outputs. You need to validate them before using them, but existing tools are heavy:
- LangSmith: Requires cloud, vendor lock-in
- DeepEval: 50+ dependencies, expensive LLM-as-judge
- RAGAS: RAG-only, not general purpose
The Solution
from evalguard import check, expect
@check(contains=["SELECT"], not_contains=["DROP", "DELETE"])
def sql_agent(query: str) -> str:
return llm.complete(f"Write SQL for: {query}")
# Or inline validation
result = agent.run("Get all users")
expect(result).contains("SELECT").not_contains("DROP").valid_json()
Installation
pip install evalguard
Features
- Zero dependencies - Only Python stdlib
- Simple decorators -
@check()for validation rules - Fluent API -
expect(value).contains().matches().valid_json() - Deterministic checks - No LLM needed for basic validation
- pytest compatible - Works with existing test infrastructure
- Type hints - Full typing support
Usage
Fluent Validation with expect()
from evalguard import expect, ValidationError
result = agent.run("Generate SQL query")
# Chain multiple validations
expect(result).contains("SELECT").not_contains("DROP").max_length(1000)
# JSON validation
expect(response).valid_json()
# Regex matching
expect(date_str).matches(r"^\d{4}-\d{2}-\d{2}$")
# Custom predicates
expect(value).satisfies(lambda x: x > 0, "must be positive")
Decorator Validation with @check()
from evalguard import check
@check(
contains=["SELECT", "FROM"],
not_contains=["DROP", "DELETE", "TRUNCATE"],
max_length=1000,
not_empty=True,
)
def sql_agent(query: str) -> str:
return llm.complete(query)
# Raises ValidationError if any check fails
result = sql_agent("Get all active users")
Custom Failure Handler
@check(contains=["required"], on_fail=lambda e: "fallback value")
def risky_agent(query: str) -> str:
return llm.complete(query)
# Returns "fallback value" instead of raising on failure
Available Validations
| Method | Description |
|---|---|
.contains(s) |
Value must contain substring |
.not_contains(s) |
Value must not contain substring |
.matches(pattern) |
Value must match regex |
.not_matches(pattern) |
Value must not match regex |
.valid_json() |
Value must be valid JSON |
.max_length(n) |
Value length must be <= n |
.min_length(n) |
Value length must be >= n |
.not_empty() |
Value must not be empty/whitespace |
.equals(v) |
Value must equal v |
.is_type(t) |
Value must be instance of type |
.satisfies(fn) |
Custom predicate must return True |
API
expect(value)
Create a fluent expectation for chaining validations.
exp = expect(value)
exp.contains("x").not_contains("y")
exp.value # Access the original value
@check(**rules)
Decorator to validate function return values.
@check(
contains=["a", "b"], # List of required substrings
not_contains=["x", "y"], # List of forbidden substrings
matches=r"pattern", # Regex that must match (or list)
not_matches=r"pattern", # Regex that must not match (or list)
valid_json=True, # Must be valid JSON
max_length=100, # Max string length
min_length=10, # Min string length
not_empty=True, # Must not be empty
satisfies=lambda x: x > 0, # Custom predicate
on_fail=handler, # Optional failure handler
)
def my_function():
...
ValidationError
Raised when validation fails.
try:
expect(value).contains("required")
except ValidationError as e:
print(e.message) # "Expected value to contain 'required'"
print(e.value) # The actual value
print(e.rule) # "contains"
Part of the Guard Suite
EvalGuard is part of a reliability suite for AI agents:
- LoopGuard - Prevent infinite loops
- EvalGuard - Validate outputs (this package)
- FailGuard - Detect drift and silent failures (coming soon)
License
MIT
Metadata
Release files for evalguard 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| evalguard-0.1.0.tar.gz | 5.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| evalguard-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 11.2 kB
Release files / evalguard-0.1.0.tar.gz
| Download URL | evalguard-0.1.0.tar.gz |
|---|---|
| Size | 5.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2eae330b3925619750f680e10337d90f62cd6bbaec533510ee82fe63a5cd9a24
|
|
BLAKE2b-256 checksum How to use checksums |
285eadb44dff240235fe032311f1255f16260e1c4a2cb13eb7d13dcc421df2b1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / evalguard-0.1.0-py3-none-any.whl
| Download URL | evalguard-0.1.0-py3-none-any.whl |
|---|---|
| Size | 5.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
66d3f93c0bf872b0ac546fb700497ea7a5b688ed2f5c87ebf0f1ac49948c7d83
|
|
BLAKE2b-256 checksum How to use checksums |
20e35824384d689a2ae346f88a2ac8c8c07bde9333bdc23748da33513a57bf42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Security for evalguard 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.