A lightweight, dataset-driven testing harness for evaluating the behavioral reliability of large language model (LLM) chatbots across multiple providers and models. It focuses on validating response invariants rather than exact outputs, reflecting the non-deterministic nature of generative AI systems.
The goal of this project is to explore practical testing strategies for AI systems using a traditional QA mindset: constraint validation, edge-case detection, repeatable evaluation, and cross-model behavioral comparison.
- Multi-provider support: run evaluations against OpenAI and Anthropic (Claude) from a single harness
- CLI-driven execution: filter test runs by provider (
--bots), model (--models), and suite (--suites) without editing code - Suite-based test organization: group related test cases into named suites via
suites.jsonfor targeted or full evaluation runs - Dataset-driven test cases: define test cases in JSON; no code changes required to add new scenarios
- Invariant-based evaluation: assert behavioral constraints (e.g. max word count, refusing dangerous prompts) rather than exact outputs
- Configurable repeated execution: run each test case multiple times to measure consistency across probabilistic outputs
- Pass/fail aggregation with pass-rate metrics: understand reliability at a glance
- Persistent, timestamped result artifacts: every run generates a JSON result file for trend analysis
- Clean separation of concerns: chatbot routing, model interaction, and response evaluation are fully decoupled
Unlike traditional software, AI chatbot responses are probabilistic and may vary between runs and across providers. This project demonstrates how to test such systems by asserting behavioral constraints instead of exact outputs — and how to compare model behavior across providers using the same evaluation framework.
Examples of tested behaviors include:
- Response length limits
- Format compliance
- Behavioral consistency across repeated runs
- Cross-model comparison (OpenAI vs. Claude)
- Create a virtual environment (recommended)
python3 -m venv venv
source venv/bin/activate- Install dependencies
pip install -r requirements.txt- Configure environment variables
cp .env.example .env
# Add your API keys:
# OPENAI_API_KEY=your_openai_key
# ANTHROPIC_API_KEY=your_anthropic_keyRun all test cases:
python runner.pyFilter by provider:
python runner.py --bots openai
python runner.py --bots claudeFilter by model:
python runner.py --models gpt-4o-mini
python runner.py --models claude-sonnet-4-6Run a specific suite:
python runner.py --suites max_word_count
python runner.py --suites safety_checksCombine filters:
python runner.py --bots claude --suites max_word_countExample Output: Running suite: max_word_count [openai / gpt-4o-mini] max words: 100 | word count: 83 | PASS [claude / claude-sonnet-4-6] max words: 100 | word count: 91 | PASS Summary: 2/2 tests passed
├── chatbots/ # Provider integrations (OpenAI, Claude)
├── evals/ # Invariant evaluation logic
├── test_cases/ # Individual JSON test case definitions
├── suites.json # Named groupings of test cases
├── results/ # Timestamped JSON result artifacts
├── analysis/ # Result trend analysis
├── runner.py # Main entry point with CLI args
└── requirements.txt
Each test case specifies the provider, model, prompt, and behavioral invariant to evaluate:
{
"id": "openai_max100words_test1",
"bot": "openai",
"model": "gpt-4o-mini",
"prompt": "Summarize the plot of Hamlet in under 100 words.",
"invariant_type": "max_words",
"max_words": 100
}Group related test cases into named suites in suites.json:
{
"max_word_count": ["openai_max100words_test1", "claude_max100words_test1"],
"safety_checks": ["openai_safety_test1", "claude_safety_test1"]
}Each run generates a timestamped JSON artifact:
{
"run_timestamp": "2026-07-10T14-32-00",
"results": {
"openai_max100words_test1": {
"bot": "openai",
"model": "gpt-4o-mini",
"passes": 3,
"fails": 0,
"pass_rate": 100.0
},
"claude_max100words_test1": {
"bot": "claude",
"model": "claude-sonnet-4-6",
"passes": 3,
"fails": 0,
"pass_rate": 100.0
}
}
}- No statistical significance testing across runs
- No automated cross-model comparison reporting
- Additional invariants: format compliance, factual consistency
- Automated cross-model behavioral comparison reports
- Bias and edge-case test suites
- Safety and content policy evaluation suite