DeepEval Guide: Unit Testing & G-Eval for AI Applications

The Problem: The Absence of Deterministic Unit Tests in LLM Engineering
In enterprise software engineering, autonomous research copilots, and intelligent data extraction systems like AiFetchly, deploying reliable software has always rested on a single bedrock practice: automated unit testing.
In traditional deterministic programming, writing tests is straightforward:
# Deterministic assertion in traditional software:
assert calculate_sales_tax(100.0, 0.08) == 8.00 If an engineer refactors a helper function or upgrades a dependency, running pytest immediately catches any regression before the code reaches staging or production.
However, as software development adopted Large Language Models (LLMs) and autonomous agents, this safety net dissolved into what the AI community calls the prompt regression dilemma.
The LLM Prompt Regression Dilemma:
┌─────────────────────────────────────────────────────────────────┐
│ Step 1: User reports edge-case failure │
│ • "The model generated an invalid date format in financial sum" │
├─────────────────────────────────────────────────────────────────┤
│ Step 2: Developer tweaks system prompt │
│ • Adds 2 sentences: "Always format dates as YYYY-MM-DD..." │
├─────────────────────────────────────────────────────────────────┤
│ Step 3: Developer performs a manual "Vibe Check" │
│ • Tests 3 queries in the web playground: looks great! │
│ • Merges pull request to production │
├─────────────────────────────────────────────────────────────────┤
│ Step 4: Silent Production Catastrophe │
│ ❌ Prompt change caused model to drop JSON quotes on 8% of tasks│
│ ❌ Hallucination rate on multi-page PDF extraction spiked by 12%│
│ ❌ Autonomous agent enters infinite tool-calling loop │
└─────────────────────────────────────────────────────────────────┘
Result: Without automated unit testing, every prompt edit is a gamble! 1. The Fallacy of Manual “Vibe Checks” and Playgrounds
Before automated evaluation frameworks, the standard engineering workflow for prompt updates consisted of manual testing in vendor playgrounds:
- An engineer tests two or three cherry-picked prompts in a browser tab. If the output looks plausible, the change is deemed safe.
- In production, however, user queries span long-tail distributions, subtle variations in syntax, and adversarial inputs.
- Manual reviews cannot test 500 edge cases across every Git commit, creating an environment where team velocity slows to a crawl out of fear of breaking working flows.
2. Why Lexical Metrics (BLEU, ROUGE) Fail on LLM Tasks
Early machine learning teams attempted to write automated tests using classical string-matching algorithms:
- Surface-Level Rigidity: A response that accurately explains a concept using synonyms or inverted sentence structures receives a near-zero BLEU score simply because the exact n-grams differ from the reference string.
- Rewarding Hallucinations: A response with high lexical overlap that introduces a fatal hallucination (e.g., changing “increased by 5%” to “decreased by 5%”) receives a deceptive 90%+ ROUGE score.
- Software teams need semantic evaluation metrics that measure factual faithfulness, logical reasoning, and tool accuracy rather than character similarity.
3. The Multi-Step Agentic Testing Crisis
When evaluating autonomous agents (such as workflows built with Agno or LangGraph), testing becomes exponentially more complex:
- Did the agent select the correct tool given the user’s objective?
- Were the generated JSON tool arguments valid and compliant with schemas?
- Did the agent synthesize the tool observation accurately or hallucinate new facts?
- Testing agent loops requires dedicated, multi-modal evaluation metrics integrated into automated build pipelines.
The Solution: DeepEval’s Pytest-Native Testing Architecture
To bridge the gap between traditional unit testing and generative AI, Confident AI created DeepEval.
DeepEval is an open-source, Pytest-native evaluation framework designed to bring continuous integration (CI/CD) and automated testing to Large Language Models and autonomous agent pipelines. By treating LLM evaluations as standard Python unit tests, DeepEval enables developers to write test assertions (assert_test), benchmark models against customizable rubrics, and run automated regression suites directly inside GitHub Actions.
DeepEval System Architecture:
┌─────────────────────────────────────────────────────────────────┐
│ Developer Workflow / CI/CD Pipeline (GitHub Actions / GitLab) │
│ Command: deepeval test run test_rag_pipeline.py │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ DeepEval Test Runner & Assertion Engine │
│ • Dispatches LLMTestCase instances to evaluation metrics │
│ • Runs tests in parallel across asynchronous worker threads │
│ • Enforces strict pass/fail thresholds (e.g., threshold=0.7) │
└─────────────────────────────────────────────────────────────────┘
│
├──► Metric 1: G-Eval (Chain-of-Thought Custom Evaluation Rubrics)
├──► Metric 2: Hallucination & Faithfulness (RAG Factual Grounding)
├──► Metric 3: Tool Correctness (Agent Tool Selection & Arguments)
└──► Metric 4: Conversational Coherence (Multi-Turn Dialogue Eval)
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Synthesizer & Cloud Observability Layer │
│ ├──► Synthesizer: Generates golden test sets from raw docs │
│ └──► Confident AI Cloud: Web dashboard, trends, & alerts │
└─────────────────────────────────────────────────────────────────┘ The Core Pillars of DeepEval
- Pytest-Native Integration: DeepEval integrates directly with the standard Python testing ecosystem. Tests are written in standard Python files (
test_*.py), run viadeepeval test runorpytest, and report familiar pass/fail statuses with detailed diagnostic traces. - G-Eval Framework: DeepEval’s flagship metric, G-Eval, implements state-of-the-art research from Microsoft and Stanford. Using Chain-of-Thought (CoT) reasoning, G-Eval allows developers to define custom evaluation criteria in plain natural language (e.g., “Verify that the agent politely declined medical advice and cited official documentation”), achieving a 0.84+ correlation with human expert judges.
- Comprehensive Agent & RAG Metrics: Includes over 50 pre-built metrics covering tool correctness, hallucination detection, answer relevancy, contextual recall, toxicity, and bias.
- Synthetic Dataset Generation (Synthesizer): Generates hundreds of realistic gold-standard question-context-answer test cases directly from raw unstructured documents (PDFs, Markdown, text) using evolution algorithms.
- Automated CI/CD Quality Gates: Developers can define strict quality thresholds (e.g.,
threshold=0.8). If a pull request modifies a prompt that causes hallucination scores to dip below the threshold, the CI build fails immediately, blocking the bad prompt from production.
Comparing LLM Evaluation Frameworks
The table below contrasts DeepEval against other popular evaluation tools:
LLM Evaluation Framework Comparison:
┌───────────────────────────┬───────────────────────────────┬───────────────────────────────┬───────────────────────────────┐
│ Dimension │ Ragas │ Promptfoo │ DeepEval (Confident AI) │
├───────────────────────────┼───────────────────────────────┼───────────────────────────────┼───────────────────────────────┤
│ Primary Architecture │ Python RAG evaluation library │ CLI & YAML-first prompt runner│ Pytest-native Python framework│
│ Core Specialty │ RAG Triad metrics only │ Red-teaming & prompt comparisons│ End-to-end CI/CD unit testing │
│ Test Execution Workflow │ Ad-hoc Python script execution│ YAML configuration files │ Standard Python `assert_test` │
│ Custom Metric Creation │ Complex prompt engineering │ Custom JS/Python assertions │ G-Eval (Natural language CoT) │
│ Autonomous Agent Testing │ Limited │ Basic tool calling assertions │ Native Tool Correctness metric│
│ Synthetic Data Generation │ Basic RAG query evolution │ ❌ No native generator │ Advanced Synthesizer engine │
│ CI/CD Integration │ Manual glue code │ GitHub Action CLI runner │ Native `deepeval test run` │
│ Production Cloud Web UI │ Third-party dashboards │ Local web dashboard │ Native Confident AI platform │
└───────────────────────────┴───────────────────────────────┴───────────────────────────────┴───────────────────────────────┘ Deep Dive into DeepEval Primitives & Metrics
DeepEval models LLM evaluation through decoupled, composable abstractions: Test Cases, Metrics, Assertions, and Synthesizers.
DeepEval Core Primitives:
DeepEval Architecture
├──► 1. LLMTestCase: Standard data container (input, output, context, tools)
├──► 2. G-Eval Metric: Natural language criteria with Chain-of-Thought steps
├──► 3. Specialized Metrics: Hallucination, Faithfulness, Tool Correctness
├──► 4. Assertion Engine (assert_test): Enforces numeric thresholds (0.0 to 1.0)
└──► 5. Synthesizer: Converts raw documents into golden test datasets 1. The LLMTestCase Primitive
The LLMTestCase is the universal data structure in DeepEval. It encapsulates all data associated with a single model invocation or agent step:
input: The prompt or query provided to the model.actual_output: The text or structured JSON completion generated by the application.expected_output: (Optional) The ground-truth reference answer.context: (Optional) The reference documentation or factual ground truth.retrieval_context: (Optional) The specific chunks retrieved by an upstream vector database like Qdrant.tools_called: (Optional) The list of tools selected and executed by an autonomous agent.
2. The G-Eval Metric: Natural-Language Chain-of-Thought Scoring
Traditional evaluation metrics rely either on rigid regex patterns or uncalibrated “yes/no” LLM queries. G-Eval transforms custom evaluation into a disciplined, four-stage cognitive process:
- Evaluation Criteria: The developer defines the target behavior in plain English (e.g., “Clarity, conciseness, and complete absence of sales jargon”).
- Auto-Generated Evaluation Steps: G-Eval prompts an evaluation LLM (such as GPT-4o) to break down the criteria into a series of sequential evaluation steps (Chain-of-Thought).
- Reasoning & Score Generation: The evaluation model analyzes the
LLMTestCase, writes out a step-by-step reasoning log, and outputs a continuous score from 0.0 to 1.0. - Weighted Probability Calculation: G-Eval computes output probabilities across token logits to generate a high-precision, non-binned continuous score.
from deepeval.metrics import GEval
from deepeval.test_case import LLMTestCaseParams
politeness_metric = GEval(
name="Customer Service Tone",
criteria="Determine whether the response maintains an empathetic, professional, and patient tone without passive aggression.",
evaluation_params=[LLMTestCaseParams.INPUT, LLMTestCaseParams.ACTUAL_OUTPUT],
threshold=0.8
) 3. Agent Tool Correctness Metric
For autonomous agents, evaluating tool execution is as critical as evaluating final prose:
- DeepEval’s
ToolCorrectnessMetriccompares the tools an agent called against expected tools. - It validates:
- Did the agent pick the correct tool (e.g.,
web_searchinstead ofdatabase_delete)? - Were the argument values syntactically and semantically valid?
- Was the order of tool invocation logically sound?
- Did the agent pick the correct tool (e.g.,
4. The Synthesizer Engine
A major bottleneck in writing LLM unit tests is curating golden datasets:
- Manually writing 200 question-answer pairs takes days of developer time.
- DeepEval’s
Synthesizeringests raw documents (PDFs, Markdown, web scrapes) and uses LLM agents to automatically synthesize high-quality test cases. - It applies evolutionary algorithms: rewriting basic queries into complex multi-hop questions, adding hypothetical scenarios, and introducing subtle edge-case distractors to rigorously test the application.
Hands-On Implementation: Building a Production Test Suite with DeepEval
Let’s build an automated regression test suite for a financial research assistant in Python. We will test for factual faithfulness, hallucination prevention, and custom tone adherence using G-Eval.
1. Environment Setup
Install DeepEval, Pytest, and the OpenAI SDK:
pip install deepeval openai pytest Set your OpenAI API key:
export OPENAI_API_KEY="sk-..." 2. Writing the Test Suite (test_financial_assistant.py)
Create a test file following standard Pytest naming conventions:
import pytest
from deepeval import assert_test
from deepeval.test_case import LLMTestCase, LLMTestCaseParams
from deepeval.metrics import (
FaithfulnessMetric,
HallucinationMetric,
GEval
)
# 1. Define Custom G-Eval Metric for Financial Compliance
compliance_metric = GEval(
name="Financial Advisory Compliance",
criteria="""
Check if the response explicitly contains a standard financial disclaimer
(e.g., 'not financial advice') and avoids making guaranteed future return promises.
""",
evaluation_params=[LLMTestCaseParams.ACTUAL_OUTPUT],
threshold=0.8
)
# 2. Define Standard RAG Faithfulness Metric
faithfulness_metric = FaithfulnessMetric(
threshold=0.7,
model="gpt-4o",
include_reason=True
)
# 3. Define Hallucination Metric
hallucination_metric = HallucinationMetric(
threshold=0.3, # Lower score indicates less hallucination; must be <= 0.3
model="gpt-4o"
)
# 4. Write Pytest Unit Test Function
def test_quarterly_earnings_summary():
"""Validates that financial earnings synthesis is grounded and compliant."""
# Context retrieved from vector database (e.g., Qdrant)
retrieved_context = [
"Nvidia reported Q3 FY25 revenue of $35.1 billion, up 94% year-over-year.",
"Data Center revenue for Q3 reached $30.8 billion, representing 112% annual growth.",
"GAAP gross margin was 74.6%, down slightly from 75.1% in the prior quarter."
]
# Query submitted by user
user_query = "Summarize Nvidia's Q3 FY25 performance and data center growth."
# Actual output generated by the application LLM
actual_llm_response = (
"In Q3 FY25, Nvidia generated $35.1 billion in revenue, marking a 94% year-over-year increase. "
"The Data Center division drove the majority of growth, delivering $30.8 billion in revenue (up 112% YoY). "
"GAAP gross margin stood at 74.6%. Please note that this information is for educational purposes "
"and does not constitute investment advice."
)
# Construct the DeepEval Test Case
test_case = LLMTestCase(
input=user_query,
actual_output=actual_llm_response,
retrieval_context=retrieved_context,
context=retrieved_context
)
# 5. Execute Assertions across Metrics
assert_test(
test_case=test_case,
metrics=[faithfulness_metric, hallucination_metric, compliance_metric]
)
def test_hallucination_detection():
"""Negative test case: verifies that fabricated metrics trigger an assertion failure."""
context = ["Company ABC generated $10 million in revenue with a net profit of $1 million."]
query = "What was Company ABC's revenue and profit margin?"
# Model hallucinated 50% profit margin and $20 million revenue
hallucinated_response = "Company ABC generated $20 million in revenue with an extraordinary 50% profit margin."
test_case = LLMTestCase(
input=query,
actual_output=hallucinated_response,
context=context
)
# This test asserts that hallucination is low; in production, this should fail if the model hallucinates
with pytest.raises(AssertionError):
# We enforce a strict threshold where hallucination <= 0.1
strict_hallucination = HallucinationMetric(threshold=0.1, model="gpt-4o")
assert_test(test_case=test_case, metrics=[strict_hallucination]) 3. Running the Test Suite via CLI
Execute the test suite using DeepEval’s native CLI runner:
deepeval test run test_financial_assistant.py 4. Diagnostic Terminal Output Analysis
When running the tests, DeepEval renders rich terminal diagnostics:
PASSEDstatus: Confirms thattest_quarterly_earnings_summarysatisfied all three metrics:FaithfulnessMetric: Score1.0(all statements grounded in retrieved context).HallucinationMetric: Score0.0(zero contradictions).Financial Advisory Compliance (G-Eval): Score1.0(proper disclaimers included).
- Diagnostic Reasons: If a test fails, DeepEval outputs the exact step-by-step reasoning generated by the evaluation model, allowing developers to immediately isolate which sentence triggered the failure.
Production Architecture & Best Practices for aiFetchly
Integrating DeepEval into automated web scraping, data extraction, and desktop agent pipelines in AiFetchly establishes a resilient, continuous quality gate for production deployments.
aiFetchly Continuous Evaluation CI/CD Pipeline:
┌─────────────────────────────────────────────────────────────────┐
│ Git Repository Pull Request (Prompt Edit / Code Refactor) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ GitHub Actions Runner (deepeval test run) │
│ ├──► Executes 200 Golden Test Cases via Pytest Parallel Workers │
│ ├──► Evaluates Tool Correctness on Agno / LangGraph Agents │
│ └──► Evaluates Faithfulness on Qdrant RAG Chunks │
└─────────────────────────────────────────────────────────────────┘
│
├──► All Metrics >= Threshold: PR Approved & Merged to Production
└──► Any Metric < Threshold: Build Blocked with Diagnostic Trace
│
▼ (Production Runtime Telemetry)
┌─────────────────────────────────────────────────────────────────┐
│ Online Observability Layer (Langfuse / Confident AI) │
│ • Streams real-world production traces for continuous auditing │
│ • Flags production failures to automatically expand golden tests│
└─────────────────────────────────────────────────────────────────┘ 1. Automated Pull Request Quality Gates in GitHub Actions
Configure a GitHub Actions workflow (.github/workflows/eval.yml) that runs on every pull request:
name: LLM Evaluation Quality Gate
on: [pull_request]
jobs:
evaluate-prompts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Dependencies
run: pip install deepeval pytest openai
- name: Run DeepEval Regression Suite
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: deepeval test run tests/ If a developer changes a system prompt that degrades answer relevancy on 5% of test cases, GitHub blocks the merge automatically.
2. Testing Autonomous Tool-Calling Agents
For autonomous web agents operating in AiFetchly:
- Use
ToolCorrectnessMetricto verify that when an agent is instructed to extract table data, it invokes web scraping tools rather than attempting to guess values from pre-trained weights. - Test that tool arguments conform strictly to Pydantic schemas created via Instructor or FastMCP.
3. Closing the Loop: From Online Tracing to Offline Unit Tests
Connect production observability with continuous evaluation:
- When an open-source observability platform like Langfuse flags a production trace with low user feedback (thumbs down), export that trace directly into DeepEval as a new regression test case.
- Over time, your automated test suite organically expands to cover all real-world failure modes, making your system increasingly resilient to foundation model drift.
Summary: Bringing Software Engineering Rigor to AI Development
The transition of artificial intelligence from experimental research into mission-critical production infrastructure requires abandoning manual “vibe checks” in favor of automated, deterministic software engineering discipline.
By integrating seamlessly into Pytest, providing state-of-the-art G-Eval Chain-of-Thought rubrics, auditing autonomous agent tool calls, and automating CI/CD quality gates, Confident AI’s DeepEval provides the testing infrastructure necessary to build reliable LLM applications. For autonomous web research agents, complex document extraction engines, and desktop intelligence platforms powered by AiFetchly, DeepEval ensures that every prompt change, model upgrade, and code refactor is verified, grounded, and safe for production.