Z3 SMT verification engine for LLM compliance
Project description
aare-core
Core verification engine for aare.ai - Z3 SMT solver for LLM compliance verification.
Overview
aare-core provides formal verification (Z3 SMT solver) to validate LLM outputs against structured constraints. The key innovation is the Formula Compiler - constraints are defined entirely in JSON, with no code changes needed.
JSON Formula → Formula Compiler → Z3 Expression → Formal Verification
This is the core library used by all cloud deployments:
- aare-aws - AWS Lambda
- aare-azure - Azure Functions
- aare-gcp - Google Cloud Functions
- aare-watsonx - IBM Cloud Code Engine
Documentation: Rule Authoring Guide | Web Docs
Performance benchmarks: Benchmarks | Web
Installation
# Create a virtual environment (recommended)
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Core library only
pip install aare-core
# With HTTP server support (quotes required for zsh)
pip install "aare-core[server]"
Quick Start
Command Line (Easiest)
# Verify compliant text (outputs JSON with proof certificate) - this passes
aare-verify --input "Loan approved: 3% rate, DTI 35%, credit score 720" --ontology mortgage-compliance-v1
# Verify non-compliant text - this fails with violation details
aare-verify --input "Approved despite DTI of 55%" --ontology mortgage-compliance-v1
# Verify from a file
aare-verify --file response.txt --ontology hipaa-v1
# Pipe from another command
echo "The loan amount is $350,000 with DTI of 35%" | aare-verify --ontology fair-lending-v1
# List all available ontologies (10 bundled + custom)
aare-ontologies
# Compact human-readable output (instead of JSON)
aare-verify --input "..." --ontology mortgage-compliance-v1 --compact
HTTP Server
# Start local server (requires: pip install "aare-core[server]")
aare-serve
# Or with custom port
aare-serve --port 9000
# Test it
curl -X POST http://localhost:8080/verify \
-H "Content-Type: application/json" \
-d '{"llm_output": "DTI is 35%", "ontology": "mortgage-compliance-v1"}'
As a Library
from aare_core import FormulaCompiler, LLMParser, SMTVerifier, OntologyLoader
# Load ontology (verification rules)
loader = OntologyLoader()
ontology = loader.load("example")
# Parse LLM output
parser = LLMParser()
data = parser.parse("The value is 50, option A is selected.", ontology)
# Verify against constraints
verifier = SMTVerifier()
result = verifier.verify(data, ontology)
print(result["verified"]) # True or False
print(result["violations"]) # List of constraint violations
With Docker (Self-hosted Server)
# Clone the repository
git clone https://github.com/aare-ai/aare-core.git
cd aare-core
# Start with Docker Compose
docker-compose up -d
# Verify it's running
curl http://localhost:8080/health
Run Server Directly
# Clone and install
git clone https://github.com/aare-ai/aare-core.git
cd aare-core
pip install -e .
pip install flask gunicorn
# Run
python app.py
# or with gunicorn
gunicorn --bind 0.0.0.0:8080 app:app
Architecture
┌───────────────────────────────────────────────────────────────┐
│ aare.ai Framework │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ /verify endpoint │ │
│ │ ┌──────────┐ ┌──────────┐ ┌────────────────────┐ │ │
│ │ │ LLM │→ │ Ontology │→ │ Z3 SMT Verifier │ │ │
│ │ │ Parser │ │ Loader │ │ + Formula Compiler│ │ │
│ │ └──────────┘ └──────────┘ └────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ │
│ Bundled Ontologies + Custom ($ONTOLOGY_DIR) │
└───────────────────────────────────────────────────────────────┘
Formula Compiler
The formula compiler translates JSON constraint definitions into Z3 expressions. This enables:
- No code changes to add new constraints
- Domain-agnostic - works for any verification domain
- Formally verified - mathematically provable correctness
Supported Operators
| Category | Operators |
|---|---|
| Logical | and, or, not, implies, ite (if-then-else) |
| Comparison | ==, !=, <, <=, >, >= |
| Arithmetic | +, -, *, /, min, max |
| Constants | true, false, numeric values |
Formula Examples
// Simple comparison: value ≤ 100
{"<=": ["value", 100]}
// Negation: ¬prohibited
{"==": ["prohibited", false]}
// Implication: condition_a → condition_b
{"implies": [
{"==": ["condition_a", true]},
{"==": ["condition_b", true]}
]}
// Disjunction: option_a ∨ option_b
{"or": [
{"==": ["option_a", true]},
{"==": ["option_b", true]}
]}
// Complex: (dti ≤ 43) ∨ (compensating_factors ≥ 2)
{"or": [
{"<=": ["dti", 43]},
{">=": ["compensating_factors", 2]}
]}
// If-then-else: conditional value
{"ite": [{">": ["score", 700]}, "approved", "denied"]}
// Min/max: fee capped at lesser of $500 or 3% of loan
{"<=": ["fee", {"min": [500, {"*": ["loan", 0.03]}]}]}
API Reference
POST /verify
Verifies LLM output against compliance constraints.
curl -X POST http://localhost:8080/verify \
-H "Content-Type: application/json" \
-d '{
"llm_output": "The value is 50, option A is selected.",
"ontology": "example"
}'
Response:
{
"verified": true,
"violations": [],
"warnings": ["Variables defaulted (not found in input): ['variable_name']"],
"parsed_data": {
"value": 50,
"option_a": true
},
"ontology": {
"name": "example",
"version": "1.0.0",
"constraints_checked": 5
},
"proof": {
"method": "Z3 SMT Solver",
"version": "4.12.1"
},
"verification_id": "uuid",
"execution_time_ms": 45,
"timestamp": "2024-01-01T00:00:00Z"
}
Note: The warnings field appears when variables couldn't be extracted from the LLM output and were defaulted. This helps auditors understand verification scope.
GET /ontologies
List available ontologies.
curl http://localhost:8080/ontologies
GET /ontologies/{name}
Get a specific ontology definition.
curl http://localhost:8080/ontologies/example
GET /health
Health check endpoint.
curl http://localhost:8080/health
GET /verifications (requires persistence)
List recent verification records.
curl http://localhost:8080/verifications?limit=50
GET /verifications/{id} (requires persistence)
Retrieve a specific verification record by ID.
curl http://localhost:8080/verifications/abc-123-uuid
Bundled Ontologies
aare-core ships with 10 production-ready ontologies covering common compliance domains:
| Ontology | Domain | Constraints | Use Case |
|---|---|---|---|
mortgage-compliance-v1 |
Lending | 5 | ATR/QM, HOEPA, UDAAP compliance |
hipaa-v1 |
Healthcare | 52 | HIPAA Privacy & Security Rule |
medical-safety-v1 |
Healthcare | 5 | Drug interactions, dosing limits |
financial-compliance-v1 |
Finance | 5 | Investment advice, disclaimers |
fair-lending-v1 |
Lending | 5 | DTI limits, credit score requirements |
data-privacy-v1 |
Security | 5 | PII detection, credential exposure |
customer-service-v1 |
Support | 5 | Discount limits, delivery promises |
trading-compliance-v1 |
Trading | 5 | Position limits, sector exposure |
content-policy-v1 |
Content | 5 | Real people, medical advice |
contract-compliance-v1 |
Legal | 5 | Usury limits, late fee caps |
Use any ontology by name:
aare-verify --input "Your response" --ontology hipaa-v1
Creating Custom Ontologies
Create your own verification rules in a custom directory and set ONTOLOGY_DIR to point to it.
Full Documentation: See the comprehensive Rule Authoring Guide for detailed instructions, examples, and best practices. Also available at aare.ai/docs.
Ontology Structure
{
"name": "my-custom-ontology",
"version": "1.0.0",
"description": "Description of your ontology",
"constraints": [
{
"id": "UNIQUE_CONSTRAINT_ID",
"category": "Category Name",
"description": "What this constraint checks",
"formula_readable": "human-readable formula",
"formula": {"<=": ["value", 100]},
"variables": [
{"name": "value", "type": "real"}
],
"error_message": "Error shown when violated",
"citation": "Reference to regulation/policy"
}
],
"extractors": {
"value": {
"type": "float",
"pattern": "value[:\\s]*(\\d+(?:\\.\\d+)?)"
}
}
}
Variable Types
| Type | Z3 Type | Use For |
|---|---|---|
bool |
Bool |
True/false flags |
int |
Int |
Whole numbers |
real or float |
Real |
Decimal numbers |
Extractor Types
| Type | Description | Example |
|---|---|---|
boolean |
True if any keyword found | {"keywords": ["approved", "accepted"]} |
int |
Extract integer from regex | {"pattern": "score[:\\s]*(\\d+)"} |
float |
Extract decimal number | {"pattern": "(\\d+\\.\\d+)%"} |
money |
Extract currency (handles k/m/b) | {"pattern": "\\$([\\d,]+)k?"} |
percentage |
Extract percentage | {"pattern": "(\\d+(?:\\.\\d+)?)%"} |
Configuration
Environment Variables
| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
HTTP port |
ONTOLOGY_DIR |
./ontologies |
Directory for custom ontologies |
CORS_ORIGINS |
https://aare.ai,... |
Comma-separated allowed origins |
DEBUG |
false |
Enable debug mode |
AARE_PERSISTENCE |
(none) | Enable audit trail persistence (see below) |
Persistence (Audit Trail)
Enable optional persistence to store verification records for audit trails, compliance reporting, and historical analysis.
# SQLite (recommended for single-node deployments)
AARE_PERSISTENCE=sqlite://verifications.db aare-serve
# In-memory (testing only - data lost on restart)
AARE_PERSISTENCE=memory aare-serve
When persistence is enabled:
- Each verification is stored with a
certificate_hash(SHA256 of verification metadata) - The original LLM output is hashed (not stored) for integrity verification
- New endpoints become available:
GET /verificationsandGET /verifications/{id} - The
/healthendpoint includes"persistence": true
Programmatic usage:
from aare_core import SQLiteStore, InMemoryStore
from aare_core.server import create_app
# Use SQLite
store = SQLiteStore("verifications.db")
app = create_app(store=store)
# Or create a custom backend
from aare_core import VerificationStore, VerificationRecord
class PostgresStore(VerificationStore):
def store(self, record: VerificationRecord) -> str:
# Store record, return certificate_hash
...
def retrieve(self, verification_id: str) -> VerificationRecord | None:
# Retrieve by ID
...
app = create_app(store=PostgresStore(connection_string))
Docker Compose Configuration
version: '3.8'
services:
aare:
image: ghcr.io/aare-ai/aare:latest
ports:
- "8080:8080"
environment:
- CORS_ORIGINS=https://your-domain.com
- AARE_PERSISTENCE=sqlite:///data/verifications.db
volumes:
- ./ontologies:/app/ontologies:ro
- ./data:/data
restart: unless-stopped
Production Deployment
With Nginx (SSL)
server {
listen 443 ssl;
server_name api.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
With Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: aare-ai
spec:
replicas: 3
selector:
matchLabels:
app: aare-ai
template:
metadata:
labels:
app: aare-ai
spec:
containers:
- name: aare-ai
image: ghcr.io/aare-ai/aare:latest
ports:
- containerPort: 8080
env:
- name: CORS_ORIGINS
value: "https://your-domain.com"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "2Gi"
cpu: "2"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
Integration Example
import requests
def verify_llm_output(llm_response: str, ontology: str = "example") -> dict:
"""Verify LLM output before returning to user"""
result = requests.post(
"http://localhost:8080/verify",
json={
"llm_output": llm_response,
"ontology": ontology
}
).json()
if not result["verified"]:
raise ComplianceError(
f"Verification failed: {result['violations']}"
)
return result
# Usage
llm_output = my_llm.generate(prompt)
verification = verify_llm_output(llm_output)
if verification["verified"]:
return llm_output
Performance
aare-core is optimized for high-throughput verification. Benchmarks on Apple M4:
| Test | Throughput | p99 Latency |
|---|---|---|
| Single-threaded | 312.9 req/s | 6.91 ms |
| HIPAA ontology (76 constraints) | 31.2 req/s | 32.89 ms |
Run the stress test yourself:
python tests/stress_test.py --requests 100 --hipaa-requests 500
The multi-process mode achieves near-linear scaling. Z3 is not thread-safe, so we use separate processes for concurrent workloads.
Full benchmarks: BENCHMARKS.md
Running Tests
pip install -e ".[dev]"
pytest tests/ -v
License
MIT License - see LICENSE for details.
Support
- Documentation: https://aare.ai/about
- Issues: https://github.com/aare-ai/aare-core/issues
- Contact: info@aare.ai
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aare_core-0.2.9.tar.gz.
File metadata
- Download URL: aare_core-0.2.9.tar.gz
- Upload date:
- Size: 56.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6dcc5a28e4713f5f798eb9fa247cb2d0d44c0e7a9975fb57cd54c3c538d327b
|
|
| MD5 |
59fb11bd96e7aaed99b4ee8a3b057216
|
|
| BLAKE2b-256 |
b6eb46f1806993f7b93d84ca86aabd6124c6a207671212f47715e092908b8ea0
|
File details
Details for the file aare_core-0.2.9-py3-none-any.whl.
File metadata
- Download URL: aare_core-0.2.9-py3-none-any.whl
- Upload date:
- Size: 55.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
53ada32af74c1f91fa76d4fcbc56e21a710102305bf1aded66d29452e15ee34b
|
|
| MD5 |
5e65f81bb8f4c40e72371aa9e56ed51b
|
|
| BLAKE2b-256 |
89f74bcc3db365157d1f9d40f9853dc0d9f6b2277f9d8bdb8a9cbdbf38014b2f
|