EVAL-DRIVEN AI: AUTOMATED CI/CD FOR LLM APPLICATIONS
InnvoLabs
Technical Architecture & Engineering Systems
Traditional unit testing assumes deterministic software: 'add(2, 2)' must always equal '4'. But when your custom software incorporates large language models, outputs are non-deterministic. A subtle prompt tweak or upstream model update can cause reasoning to drift without triggering a single syntax error.
To ship AI systems with enterprise confidence, we follow Eval-Driven AI Development. We build automated CI/CD regression suites using production traces, calibrated LLM-as-a-judge scoring, and statistical pass/fail thresholds that block regressions before they reach production.
Here is the evaluation harness architecture, scoring math, and Python runner implementation.
The Three-Tier Framework: Deterministic, Structural, and Evaluative
We divide evaluations into three distinct layers to balance speed, cost, and qualitative accuracy.
+-------------------------------------------------------------------------+
| Layer 1: Deterministic Heuristics (Regex, Schema, Length, Speed) |
| Executed in < 5ms per test | Zero API Cost |
+-------------------------------------------------------------------------+
|
v
+-------------------------------------------------------------------------+
| Layer 2: Model-Based Evals (LLM-as-a-Judge with Calibrated Rubrics) |
| Executed in parallel | Evaluates Semantic Accuracy, Tone & Relevance |
+-------------------------------------------------------------------------+
|
v
+-------------------------------------------------------------------------+
| Layer 3: Trajectory & Tool Evals (Agent Action Sequence Validation) |
| Evaluates Tool Selection Order, State Mutations, Recovery Efficiency |
+-------------------------------------------------------------------------+
Layer 1: Deterministic Heuristic Assertions
Before invoking expensive judge models, outputs run through fast code-level assertions:
- Schema Validation: Validates that JSON outputs conform exactly to Pydantic/Zod definitions.
- Refusal Detection: Checks if the model inappropriately refused a valid request using pattern matching.
- Context Grounding Check: Ensures hallucinated terms absent from retrieved chunks do not appear in the response.
Layer 2: Model-Based Evals (LLM-as-a-Judge)
For open-ended generation, we use a judge model trained on calibrated scoring rubrics.
To eliminate positional bias and verbosity bias, we implement pairwise evaluation with position swapping:
- Run Model Variant A and Model Variant B.
- Send outputs to the Judge model in order (A, B) and evaluate against the rubric.
- Send outputs in reversed order (B, A) to a second evaluation instance.
- Accept the score only if both ordering evaluations agree.
Layer 3: Trajectory Evals for Multi-Step Agents
For autonomous agents, evaluating the final text is insufficient; the execution path matters. Trajectory evals check:
- Did the agent execute redundant tool calls?
- Did it recover gracefully when an internal tool returned a 500 error?
- Did it respect authorization boundaries?
Golden Datasets: Curating High-Leverage Evaluation Suites
A robust evaluation suite requires representative test cases. Relying solely on manually written test inputs yields poor coverage.
We build dynamic eval datasets by sampling production telemetry traces:
- Log Sanitization: PII (personally identifiable information) is stripped automatically using regex and named-entity recognition (NER).
- Edge-Case Clustering: Production queries are embedded into a vector space. Outliers—queries far from existing cluster centers—are flagged as candidate eval cases.
- Synthetic Mutation: A pipeline mutates high-value production queries into 5 stylistic variations (e.g., adding typos, changing domain terminology, introducing adversarial instructions).
This maintains a living evaluation dataset of 800+ curated benchmark scenarios per custom application.
Production Implementation: Automated Python Evaluation Runner
Below is a core snippet from our async evaluation engine. It runs test scenarios in parallel, calculates semantic compliance scores, and computes pass/fail thresholds:
import asyncio
from typing import List, Dict, Any
from pydantic import BaseModel
class EvalResult(BaseModel):
test_id: str
passed: bool
score: float
reason: str
class AsyncEvalEngine:
def __init__(self, judge_client, threshold: float = 0.85):
self.judge = judge_client
self.threshold = threshold
async def evaluate_single(self, scenario: Dict[str, Any], candidate_output: str) -> EvalResult:
rubric = scenario["rubric"]
prompt = f"""
System Rubric: {rubric}
Input Prompt: {scenario['input']}
Candidate Response: {candidate_output}
Grade the candidate response from 0.0 to 1.0 based strictly on the rubric.
Return JSON format: {{"score": float, "reason": "explanation"}}
"""
response = await self.judge.generate_json(prompt)
score = response.get("score", 0.0)
return EvalResult(
test_id=scenario["id"],
passed=score >= self.threshold,
score=score,
reason=response.get("reason", "")
)
async def run_suite(self, scenarios: List[Dict[str, Any]], outputs: List[str]) -> List[EvalResult]:
tasks = [
self.evaluate_single(scen, out)
for scen, out in zip(scenarios, outputs)
]
return await asyncio.gather(*tasks)
CI/CD Integration: Setting Statistical Merging Gates
Our evaluation engine runs inside GitHub Actions on every pull request targeting main.
name: AI Regression Eval Suite
on:
pull_request:
branches: [ main ]
jobs:
evaluate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Run Eval Suite
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
python -m evals.run_suite --dataset data/eval_benchmark_v2.json --min-pass-rate 0.92
If an updated prompt drops overall accuracy below 92% or causes a regression on any critical compliance test, the GitHub PR check fails and blocks merging automatically.
Production Results: Regressions Caught and Confidence Gained
Implementing Eval-Driven Development across our custom software client builds achieved:
- Zero production prompt regressions over 6 months of continuous deployment.
- 4-minute CI pipeline execution for 500 parallelized eval scenarios.
- Confident Model Upgrades: Upgraded core LLM providers 3 times with 100% verified behavior compliance before pushing live.