This repository contains a production-ready LLM evaluation and observability harness designed to run offline evaluation checks in CI/CD pipelines and sample/observe traffic quality in live production environments.
The harness relies on a shared scoring core and adheres to a "failure-first" design philosophy, degrading gracefully during third-party LLM API failures, rate limits, or malformed responses.
- Robust Offline Evaluations: Runs evaluation suites using rule-based metrics (JSON syntax, Regex match, character length) and multiple-trial LLM-as-a-judge scoring.
- Regression Detection CLI: Automatically detects quality regressions by comparing test run scores against designated baseline versions.
- Structured Observability Logs: Outputs structured logs in JSON format with built-in PII redaction.
- Live Production Sampler: Wrap outbound LLM requests with configured sampling rates, safety-mask PII, and push to an database-backed queue.
- Background Queue Worker: An independent queue consumer that evaluates sampled requests asynchronously, exposing liveness (
/health) and readiness (/ready) endpoints. - Hardened Containerization: Fully containerized utilizing a multi-stage Docker build running under non-root privilege contexts.
├── .github/workflows/
│ └── regression.yml # GitHub Actions CI workflow
├── eval_harness/
│ ├── __init__.py
│ ├── alerts.py # Webhook alerting logic for quality regression alerts
│ ├── client.py # Third-party LLM API client with tenacity retries
│ ├── config.py # Pydantic configuration validation
│ ├── dashboard.py # Streamlit interactive UI dashboard
│ ├── database.py # SQLite database connection & execution wrapper
│ ├── logging.py # Structured JSON logger with secret redaction
│ ├── runner.py # CLI entrypoint for database initialization & runs
│ ├── sampler.py # PII masking & production traffic sampler
│ ├── schema.sql # SQLite database schema definition
│ ├── scorers.py # Rule-based & LLM-as-judge scoring implementations
│ └── worker.py # Background queue consumer & health check HTTP server
├── tests/ # Pytest test suite targeting all components
├── Dockerfile # Hardened multi-stage Docker configuration
├── .dockerignore # Excludes build environment, credentials, and databases
├── pyproject.toml # Poetry packaging configuration
└── requirements.txt # Pinned python package dependencies
- Python 3.10 or higher
- SQLite 3
Initialize your virtual environment and install package dependencies:
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txtCreate a .env file in the workspace root using the template below:
GEMINI_API_KEY=YOUR_GEMINI_DEVELOPER_API_KEY
OPENAI_API_KEY=YOUR_OPENAI_API_KEY
DATABASE_PATH=eval.db
SAMPLING_RATE=0.1
MAX_SAMPLING_RATE=0.5
SAMPLER_KILL_SWITCH=False
REGRESSION_THRESHOLD=0.05Note: The harness checks for placeholder keys (like CHANGE_ME) and suspiciously short credentials, raising validation errors on startup if present.
Create database tables and run schema migrations:
python -m eval_harness.runner init-dbRun your evaluation test sets. By default, this mock-evaluates results unless --real-llm is passed:
python -m eval_harness.runner run-eval --test-set tests/test_set_example.json --run-id pr_run_123To mark this run as the baseline target, add the --is-baseline flag.
Compare a recent run's quality scores against its active baseline configuration:
python -m eval_harness.runner compare-regression --run-id pr_run_123This CLI exits with status code 1 if regressions exceed the REGRESSION_THRESHOLD or if no baseline exists.
Use the sampler utility inside your application middleware or route handlers:
from eval_harness import sampler
sampler.log_production_traffic(
config_hash="your_config_hash",
input_data="User input email user@example.com",
actual_output="Output text containing SSN: 111-22-3333",
latency_ms=120.5,
cost=0.000075
)This masks standard PII fields and pushes the sampled request to the SQLite database queue.
Spin up the worker to process, score, and persist logs:
python -m eval_harness.workerThe worker starts an HTTP server (defaulting to port 8000) exposing /health and /ready checks, and intercepts SIGTERM / SIGINT signals for graceful process shutdown.
To start the Streamlit web dashboard to visualize evaluation run histories and production traffic trends:
streamlit run eval_harness/dashboard.pyBuild the production Docker image containing only runtime dependencies:
docker build -t llm-eval-harness:latest .The pipeline defined in .github/workflows/regression.yml automates the following actions on pull requests:
- Builds the Docker image.
- Initializes the evaluation database.
- Performs a baseline run and a comparison PR run.
- Executes the
compare-regressioncommand, blocking PR merges if quality drops.
To run automated unit/integration tests, view the full test inventory, or learn how to run end-to-end local simulation runs, refer to the dedicated TESTING.md guide.