This document explains how all the pieces fit together in this example.
A simple FAQ bot that answers customer questions:
- Input: Customer question (string)
- Output: Answer with confidence score and latency
- Implementation: In-memory knowledge base with keyword matching
- Purpose: Represents a real AI agent that needs evaluation
Using Promptfoo to evaluate the agent:
- Framework: Promptfoo (open-source, easy to run locally)
- Tests: 10+ test cases covering common questions
- Metrics: Pass rate, latency, cost, etc.
- Output: JSON results file (
outputs/results.json)
Why Promptfoo?
- Open-source and free
- Easy to run locally (no API keys needed)
- Well-documented
- Geval has built-in adapter support
Decision contracts that define release gates:
- Production: Strict thresholds (90% pass rate, <500ms latency)
- Staging: Moderate thresholds (70% pass rate, <1000ms latency)
- Development: Permissive (only blocks toxicity)
Contract Features Demonstrated:
- ✅ Policy-based rules
- ✅ Environment-specific policies
- ✅ Eval metric conditions
- ✅ Signal support (via
--signalsflag) - ✅ Default actions
Geval consumes eval results and produces decisions:
- Input: Eval results + Contract + Signals (optional)
- Output: Decision (PASS / BLOCK / REQUIRES_APPROVAL)
- Artifacts: Decision record with cryptographic hash
GitHub Actions workflow that:
- Runs evals on every PR
- Checks results with Geval
- Blocks merge if contract violated
- Requires approval for
REQUIRES_APPROVALstatus
┌──────────────┐
│ Developer │
│ Makes Change│
└──────┬───────┘
│
▼
┌──────────────┐
│ Agent │ FAQ bot code changes
│ (Code) │
└──────┬───────┘
│
▼
┌──────────────┐
│ Promptfoo │ Runs test suite
│ (Evals) │ → outputs/results.json
└──────┬───────┘
│
▼
┌──────────────┐
│ Geval │ Evaluates against contract
│ (Decision) │ → PASS / BLOCK / REQUIRES_APPROVAL
└──────┬───────┘
│
▼
┌──────────────┐
│ CI/CD │ Enforces decision
│ (Enforce) │ → Deploy or Block
└──────────────┘
- Simple but Realistic: FAQ bot is easy to understand but demonstrates real patterns
- Complete Flow: Shows agent → evals → decision → enforcement
- Local First: Everything runs locally, no external dependencies
- Extensible: Easy to add more complex scenarios
- Open Source: No vendor lock-in
- Local Execution: No API keys or cloud services needed
- Geval Integration: Built-in adapter support
- Well Documented: Easy for users to understand and extend
- Flexible: Supports both eval metrics and signals
- Environment-Aware: Different rules for dev/staging/prod
- Future-Proof: Easy to extend with new signal types
- Edit
evals/provider.jsto calculate new metrics - Update
contracts/*.yamlto use new metrics - Run
npm run workflowto test
- Create signal files in
signals/ - Update contracts to use signal conditions
- Run with
--signalsflag
- Save a baseline eval result
- Update contract to use
baseline: previous - Pass
--baselineflag togeval check
- Replace
agent/src/bot.tswith real API calls - Update
evals/provider.jsto call real endpoint - Add API keys to environment variables
✅ Eval-based contracts - Quality gates on metrics
✅ Policy-based contracts - Signal-driven decisions
✅ Environment-aware - Different rules per environment
✅ Baseline comparison - Regression detection (via --baseline)
✅ Signal integration - Human reviews, risk flags
✅ Decision records - Auditable artifacts
✅ CI/CD integration - Exit codes and automation
- Run the example:
npm install && npm run workflow - Modify contracts: Edit
contracts/production.yaml - Add tests: Extend
evals/promptfoo.yaml - Integrate: Copy patterns to your own project
See README.md for quick start guide.