DeepEval: Unit Testing dan Evaluasi untuk Aplikasi LLM
Membangun aplikasi berbasis Large Language Model (LLM) seperti chatbot RAG, asisten AI, atau pipeline generatif bukan hanya soal membuat model bekerja. Tantangan sebenarnya adalah memastikan kualitas output secara konsisten. Bagaimana Anda tahu bahwa chatbot Anda tidak berhalusinasi? Bagaimana Anda mengukur relevansi jawaban terhadap pertanyaan pengguna? Bagaimana Anda mendeteksi bias atau konten toxic dalam respons?
DeepEval adalah framework open-source yang dirancang khusus untuk menjawab semua pertanyaan tersebut. DeepEval memungkinkan Anda menulis unit test untuk aplikasi LLM layaknya Anda menulis unit test untuk software tradisional, lengkap dengan metrik evaluasi yang sudah teruji dan integrasi pytest.Apa Itu DeepEval?
DeepEval adalah framework Python untuk testing dan evaluasi aplikasi LLM. Framework ini menyediakan:
- Unit Testing untuk LLM: Menulis test case yang memvalidasi output LLM dengan metrik terukur
- 14+ Metrik Bawaan: Hallucination, Answer Relevancy, Faithfulness, Bias, Toxicity, dan lainnya
- Integrasi Pytest: Jalankan evaluasi LLM seperti test suite biasa
- Custom Metrics: Buat metrik evaluasi sesuai kebutuhan bisnis Anda
- Conversational Metrics: Evaluasi kualitas percakapan multi-turn
- Benchmarks: Uji model Anda terhadap benchmark standar seperti MMLU dan HellaSwag
- Confident AI Dashboard: Platform monitoring dan analytics untuk hasil evaluasi
- CI/CD Ready: Integrasikan evaluasi ke dalam pipeline deployment Anda
Instalasi
Instalasi Dasar
pip install deepeval
Instalasi dengan Dependensi Tambahan
# Untuk menggunakan semua fitur termasuk benchmark
pip install deepeval[benchmark]
Untuk integrasi dengan Confident AI
pip install deepeval[dashboard]
Setup Awal
Setelah instalasi, login ke Confident AI (opsional tapi direkomendasikan untuk tracking):
deepeval login
Atau set API key secara manual:
export DEEPEVALAPIKEY="your-api-key-here"
Pastikan juga Anda memiliki API key untuk LLM yang akan digunakan sebagai evaluator:
export OPENAIAPIKEY="your-openai-api-key"
Konsep Dasar: LLMTestCase
LLMTestCase adalah unit dasar dalam DeepEval. Setiap test case merepresentasikan satu interaksi dengan LLM yang ingin Anda evaluasi.
from deepeval.testcase import LLMTestCase
test
case = LLMTestCase(
input="Apa ibu kota Indonesia?",
actualoutput="Ibu kota Indonesia adalah Jakarta. Namun, pemerintah Indonesia sedang membangun ibu kota baru bernama Nusantara (IKN) di Kalimantan Timur.",
expectedoutput="Jakarta (dengan catatan IKN Nusantara sebagai ibu kota baru)",
retrievalcontext=[
"Jakarta adalah ibu kota Indonesia sejak kemerdekaan tahun 1945.",
"Ibu Kota Nusantara (IKN) adalah proyek pemindahan ibu kota Indonesia ke Kalimantan Timur yang diresmikan pada 2024."
]
)
Parameter utama LLMTestCase:
| Parameter | Deskripsi | Wajib |
|-----------|-----------|-------|
| input | Pertanyaan atau prompt yang diberikan ke LLM | Ya |
| actualoutput | Respons aktual dari LLM | Ya |
| expectedoutput | Respons yang diharapkan (ground truth) | Tergantung metrik |
| retrievalcontext | Konteks yang di-retrieve dari knowledge base | Tergantung metrik |
| context | Konteks ground truth (ideal) | Tergantung metrik |
Metrik Evaluasi Bawaan
DeepEval menyediakan berbagai metrik evaluasi yang sudah siap pakai. Berikut penjelasan metrik-metrik utama:
1. Hallucination Metric
Mengukur apakah output LLM mengandung informasi yang tidak didukung oleh konteks yang diberikan.
from deepeval.metrics import HallucinationMetric
from deepeval.testcase import LLMTestCase
metric = HallucinationMetric(threshold=0.5)
testcase = LLMTestCase(
input="Ceritakan tentang perusahaan PT ABC",
actualoutput="PT ABC didirikan pada tahun 1990 di Jakarta. Perusahaan ini memiliki 5000 karyawan dan bergerak di bidang teknologi.",
context=[
"PT ABC didirikan pada tahun 1990 di Jakarta.",
"PT ABC bergerak di bidang teknologi informasi.",
"PT ABC memiliki sekitar 2000 karyawan."
]
)
metric.measure(testcase)
print(f"Score: {metric.score}") # 0.0 - 1.0 (semakin rendah semakin baik)
print(f"Reason: {metric.reason}") # Penjelasan mengapa score tersebut diberikan
Dalam contoh di atas, LLM mengatakan "5000 karyawan" padahal konteks menyebutkan "2000 karyawan", sehingga terjadi halusinasi.
2. Answer Relevancy Metric
Mengukur seberapa relevan jawaban LLM terhadap pertanyaan yang diberikan.
from deepeval.metrics import AnswerRelevancyMetric
metric = AnswerRelevancyMetric(threshold=0.7)
testcase = LLMTestCase(
input="Bagaimana cara menginstall Python di Ubuntu?",
actualoutput="Untuk menginstall Python di Ubuntu, jalankan: sudo apt update && sudo apt install python3. Anda juga bisa menggunakan pyenv untuk mengelola multiple versi Python.",
retrievalcontext=[
"Python dapat diinstall di Ubuntu menggunakan apt package manager.",
"Pyenv adalah tool untuk mengelola multiple versi Python."
]
)
metric.measure(testcase)
print(f"Score: {metric.score}")
print(f"Reason: {metric.reason}")
3. Faithfulness Metric
Mengukur apakah output LLM setia (faithful) terhadap konteks yang di-retrieve. Berbeda dengan hallucination metric, faithfulness lebih fokus pada apakah klaim dalam output didukung oleh retrieval context.
from deepeval.metrics import FaithfulnessMetric
metric = FaithfulnessMetric(threshold=0.7)
testcase = LLMTestCase(
input="Apa manfaat olahraga rutin?",
actualoutput="Olahraga rutin dapat meningkatkan kesehatan jantung, menurunkan risiko diabetes, dan meningkatkan mood.",
retrievalcontext=[
"Penelitian menunjukkan olahraga rutin meningkatkan kesehatan kardiovaskular.",
"Aktivitas fisik membantu mengatur kadar gula darah dan menurunkan risiko diabetes tipe 2.",
"Olahraga melepaskan endorfin yang dapat memperbaiki suasana hati."
]
)
metric.measure(testcase)
print(f"Score: {metric.score}")
4. Bias Metric
Mendeteksi apakah output LLM mengandung bias terkait gender, ras, agama, atau kelompok lainnya.
from deepeval.metrics import BiasMetric
metric = BiasMetric(threshold=0.5)
testcase = LLMTestCase(
input="Siapa yang cocok menjadi software engineer?",
actualoutput="Siapa saja bisa menjadi software engineer, terlepas dari gender, usia, atau latar belakang. Yang terpenting adalah kemauan belajar, kemampuan problem-solving, dan dedikasi untuk terus berkembang."
)
metric.measure(testcase)
print(f"Score: {metric.score}") # Score rendah = tidak bias (bagus)
5. Toxicity Metric
Mendeteksi konten toxic, ofensif, atau berbahaya dalam output LLM.
from deepeval.metrics import ToxicityMetric
metric = ToxicityMetric(threshold=0.5)
testcase = LLMTestCase(
input="Berikan feedback untuk kode ini",
actualoutput="Kode Anda sudah cukup baik, namun ada beberapa area yang bisa ditingkatkan: 1) Gunakan naming convention yang konsisten, 2) Tambahkan error handling, 3) Pisahkan logic bisnis dari controller."
)
metric.measure(testcase)
print(f"Score: {metric.score}") # Score rendah = tidak toxic (bagus)
Menjalankan Test dengan Pytest
Salah satu keunggulan DeepEval adalah integrasinya dengan pytest. Anda bisa menjalankan evaluasi LLM sebagai test suite.
Struktur File Test
project/
├── tests/
│ ├── testchatbot.py
│ ├── testragpipeline.py
│ └── conftest.py
├── src/
│ └── chatbot.py
└── pyproject.toml
Menulis Test File
# tests/testchatbot.py
import pytest
from deepeval import asserttest
from deepeval.testcase import LLMTestCase
from deepeval.metrics import (
AnswerRelevancyMetric,
FaithfulnessMetric,
HallucinationMetric,
)
Import fungsi chatbot Anda
from src.chatbot import getchatbotresponse
def generatetestcase(question: str) -> LLMTestCase:
"""Helper untuk membuat test case dari chatbot."""
response = getchatbotresponse(question)
return LLMTestCase(
input=question,
actualoutput=response["answer"],
retrievalcontext=response["sources"],
context=response.get("groundtruthcontext", [])
)
def testanswerrelevancy():
testcase = generatetestcase("Apa kebijakan refund perusahaan?")
metric = AnswerRelevancyMetric(threshold=0.7)
asserttest(testcase, [metric])
def testfaithfulness():
testcase = generatetestcase("Bagaimana cara mengajukan cuti?")
metric = FaithfulnessMetric(threshold=0.7)
asserttest(testcase, [metric])
def testnohallucination():
testcase = generatetestcase("Berapa gaji minimum karyawan?")
metric = HallucinationMetric(threshold=0.5)
asserttest(testcase, [metric])
def testmultiplemetrics():
"""Test dengan beberapa metrik sekaligus."""
testcase = generatetestcase("Apa benefit kesehatan karyawan?")
metrics = [
AnswerRelevancyMetric(threshold=0.7),
FaithfulnessMetric(threshold=0.7),
HallucinationMetric(threshold=0.5),
]
asserttest(testcase, metrics)
Menjalankan Test
# Jalankan semua test
deepeval test run tests/
Jalankan file test tertentu
deepeval test run tests/testchatbot.py
Jalankan dengan verbose output
deepeval test run tests/testchatbot.py -v
Jalankan dan kirim hasil ke Confident AI
deepeval test run tests/testchatbot.py --confident
Anda juga bisa menggunakan pytest langsung:
pytest tests/testchatbot.py -v
Custom Metrics
Ketika metrik bawaan tidak cukup, Anda bisa membuat custom metric sesuai kebutuhan bisnis.
Custom Metric dengan LLM sebagai Judge
from deepeval.metrics import GEval
from deepeval.testcase import LLMTestCase, LLMTestCaseParams
Buat metrik custom untuk mengukur kelengkapan jawaban
completenessmetric = GEval(
name="Completeness",
criteria="Evaluate whether the response comprehensively addresses all aspects of the user's question. A complete response should cover all key points without leaving important information out.",
evaluationparams=[
LLMTestCaseParams.INPUT,
LLMTestCaseParams.ACTUALOUTPUT,
],
threshold=0.7,
)
testcase = LLMTestCase(
input="Jelaskan langkah-langkah membuat REST API dengan FastAPI",
actualoutput="Untuk membuat REST API dengan FastAPI: 1) Install FastAPI dan uvicorn, 2) Buat file main.py, 3) Definisikan route dengan decorator, 4) Jalankan dengan uvicorn."
)
completenessmetric.measure(testcase)
print(f"Completeness Score: {completenessmetric.score}")
print(f"Reason: {completenessmetric.reason}")
Custom Metric dengan Logika Sendiri
from deepeval.metrics import BaseMetric
from deepeval.testcase import LLMTestCase
class ResponseLengthMetric(BaseMetric):
"""Metrik untuk memastikan respons memiliki panjang yang sesuai."""
def init(self, minwords: int = 50, maxwords: int = 500, threshold: float = 0.5):
self.threshold = threshold
self.minwords = minwords
self.maxwords = maxwords
def measure(self, testcase: LLMTestCase) -> float:
wordcount = len(testcase.actualoutput.split())
if self.minwords <= wordcount <= self.maxwords:
self.score = 1.0
self.reason = f"Response length ({wordcount} words) is within acceptable range."
elif wordcount < self.minwords:
self.score = wordcount / self.minwords
self.reason = f"Response too short ({wordcount} words). Minimum: {self.minwords}."
else:
self.score = self.maxwords / wordcount
self.reason = f"Response too long ({wordcount} words). Maximum: {self.maxwords}."
self.success = self.score >= self.threshold
return self.score
def issuccessful(self) -> bool:
return self.success
@property
def name(self):
return "Response Length"
Conversational Metrics
Untuk aplikasi chatbot, DeepEval menyediakan metrik khusus yang mengevaluasi kualitas percakapan multi-turn.
from deepeval.testcase import ConversationalTestCase, LLMTestCase
from deepeval.metrics import ConversationRelevancyMetric
Simulasi percakapan multi-turn
conversation = ConversationalTestCase(
turns=[
LLMTestCase(
input="Halo, saya ingin bertanya tentang produk Anda",
actualoutput="Halo! Tentu, saya dengan senang hati membantu. Produk apa yang ingin Anda ketahui?"
),
LLMTestCase(
input="Berapa harga paket Enterprise?",
actualoutput="Paket Enterprise kami mulai dari Rp 50 juta per bulan. Paket ini mencakup akses unlimited user, dedicated support 24/7, custom integration, dan SLA 99.9%."
),
LLMTestCase(
input="Apakah ada trial gratis?",
actualoutput="Ya, kami menyediakan free trial selama 14 hari untuk paket Enterprise. Anda bisa mendaftar di website kami tanpa kartu kredit."
),
]
)
metric = ConversationRelevancyMetric(threshold=0.7)
metric.measure(conversation)
print(f"Conversation Relevancy: {metric.score}")
Benchmarks: MMLU dan HellaSwag
DeepEval memungkinkan Anda menguji model terhadap benchmark standar untuk mengukur kemampuan umum.
MMLU (Massive Multitask Language Understanding)
MMLU menguji pemahaman model terhadap 57 subjek, dari STEM hingga humanities.
from deepeval.benchmarks import MMLU
from deepeval.benchmarks.tasks import MMLUTask
Evaluasi pada subjek tertentu
benchmark = MMLU(
tasks=[
MMLUTask.COMPUTERSCIENCE,
MMLUTask.MATHEMATICS,
MMLUTask.PHYSICS,
],
nshots=5 # few-shot examples
)
Jalankan benchmark pada model Anda
benchmark.evaluate(model=yourmodel)
HellaSwag
HellaSwag menguji kemampuan model dalam commonsense reasoning dengan melengkapi skenario.
from deepeval.benchmarks import HellaSwag
benchmark = HellaSwag(
nshots=10
)
Jalankan benchmark
benchmark.evaluate(model=yourmodel)
Confident AI Dashboard
Confident AI adalah platform companion untuk DeepEval yang menyediakan dashboard visual untuk monitoring dan analytics.Setup Confident AI
# Login ke Confident AI
deepeval login
Jalankan test dan kirim hasil ke dashboard
deepeval test run tests/ --confident
Fitur Utama Dashboard
- Test Run History: Lihat semua hasil test run dengan tren waktu
- Metric Breakdown: Analisis detail per metrik dengan distribusi score
- Failure Analysis: Identifikasi test case yang gagal dan alasannya
- Comparison: Bandingkan performa antar model atau antar versi prompt
- Dataset Management: Kelola golden dataset untuk evaluasi konsisten
- Collaboration: Bagikan hasil dengan tim melalui workspace bersama
Mengirim Hasil Secara Programatik
import deepeval
from deepeval.testcase import LLMTestCase
from deepeval.metrics import AnswerRelevancyMetric
from deepeval.dataset import EvaluationDataset
Buat dataset evaluasi
dataset = EvaluationDataset(
testcases=[
LLMTestCase(
input="Apa itu machine learning?",
actualoutput="Machine learning adalah cabang AI yang memungkinkan komputer belajar dari data tanpa diprogram secara eksplisit.",
retrievalcontext=["Machine learning adalah subset dari artificial intelligence."]
),
# ... lebih banyak test case
]
)
Evaluasi dan kirim ke Confident AI
results = deepeval.evaluate(
testcases=dataset.testcases,
metrics=[AnswerRelevancyMetric(threshold=0.7)],
)
Integrasi CI/CD
Integrasikan DeepEval ke dalam pipeline CI/CD Anda untuk memastikan kualitas LLM tetap terjaga setiap kali ada perubahan.
GitHub Actions
# .github/workflows/llm-tests.yml
name: LLM Evaluation
on:
push:
branches: [main]
pullrequest:
branches: [main]
jobs:
evaluate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install deepeval
- name: Run LLM evaluations
env:
OPENAIAPIKEY: ${{ secrets.OPENAIAPIKEY }}
DEEPEVALAPIKEY: ${{ secrets.DEEPEVALAPIKEY }}
run: |
deepeval test run tests/ --confident
- name: Check evaluation results
if: failure()
run: echo "LLM evaluation failed. Check Confident AI dashboard for details."
GitLab CI
# .gitlab-ci.yml
llm-evaluation:
stage: test
image: python:3.11
script:
- pip install -r requirements.txt
- pip install deepeval
- deepeval test run tests/ --confident
variables:
OPENAIAPIKEY: $OPENAIAPIKEY
DEEPEVALAPIKEY: $DEEPEVALAPIKEY
only:
- main
- mergerequests
Contoh Praktis: Test Suite untuk RAG Chatbot
Mari kita bangun test suite lengkap untuk chatbot RAG yang menjawab pertanyaan tentang kebijakan perusahaan.
Struktur Proyek
rag-chatbot/
├── src/
│ ├── chatbot.py
│ ├── retriever.py
│ └── config.py
├── tests/
│ ├── conftest.py
│ ├── testhallucination.py
│ ├── testrelevancy.py
│ └── testcomprehensive.py
├── data/
│ └── testgoldendataset.json
└── requirements.txt
Golden Dataset
[
{
"input": "Berapa lama masa probation karyawan baru?",
"expectedoutput": "Masa probation karyawan baru adalah 3 bulan.",
"context": [
"Setiap karyawan baru menjalani masa probation selama 3 bulan.",
"Selama masa probation, karyawan mendapat evaluasi mingguan dari supervisor."
]
},
{
"input": "Bagaimana prosedur pengajuan cuti tahunan?",
"expectedoutput": "Cuti tahunan diajukan melalui sistem HR minimal 3 hari sebelumnya dan harus disetujui atasan langsung.",
"context": [
"Pengajuan cuti tahunan dilakukan melalui sistem HR online.",
"Karyawan harus mengajukan cuti minimal 3 hari kerja sebelumnya.",
"Persetujuan cuti diberikan oleh atasan langsung karyawan."
]
},
{
"input": "Apakah perusahaan menyediakan asuransi kesehatan?",
"expectedoutput": "Ya, perusahaan menyediakan asuransi kesehatan untuk karyawan tetap dan keluarga inti.",
"context": [
"Perusahaan menyediakan asuransi kesehatan untuk seluruh karyawan tetap.",
"Asuransi mencakup karyawan, pasangan, dan maksimal 3 anak.",
"Karyawan probation belum mendapatkan fasilitas asuransi."
]
}
]
Conftest untuk Shared Fixtures
# tests/conftest.py
import json
import pytest
from deepeval.testcase import LLMTestCase
def loadgoldendataset():
with open("data/testgoldendataset.json", "r") as f:
return json.load(f)
def simulatechatbotresponse(question: str, context: list[str]) -> str:
"""
Simulasi respons chatbot RAG.
Pada implementasi nyata, ini akan memanggil chatbot Anda.
"""
# Ganti dengan panggilan ke chatbot Anda
from src.chatbot import getresponse
return getresponse(question)
@pytest.fixture
def goldendataset():
return loadgoldendataset()
@pytest.fixture
def testcases(goldendataset):
cases = []
for item in goldendataset:
response = simulatechatbotresponse(item["input"], item["context"])
cases.append(
LLMTestCase(
input=item["input"],
actualoutput=response,
expectedoutput=item["expectedoutput"],
context=item["context"],
retrievalcontext=item["context"],
)
)
return cases
Test Hallucination
# tests/testhallucination.py
import pytest
from deepeval import asserttest
from deepeval.metrics import HallucinationMetric
class TestHallucination:
"""Test suite untuk mendeteksi halusinasi chatbot."""
@pytest.fixture
def metric(self):
return HallucinationMetric(
threshold=0.5,
model="gpt-4o",
)
def testprobationnohallucination(self, testcases, metric):
"""Pastikan jawaban tentang probation tidak berhalusinasi."""
testcase = testcases[0]
asserttest(testcase, [metric])
def testcutinohallucination(self, testcases, metric):
"""Pastikan jawaban tentang cuti tidak berhalusinasi."""
testcase = testcases[1]
asserttest(testcase, [metric])
def testasuransinohallucination(self, testcases, metric):
"""Pastikan jawaban tentang asuransi tidak berhalusinasi."""
testcase = testcases[2]
asserttest(testcase, [metric])
Test Relevancy
# tests/testrelevancy.py
import pytest
from deepeval import asserttest
from deepeval.metrics import AnswerRelevancyMetric, FaithfulnessMetric
class TestRelevancy:
"""Test suite untuk mengukur relevansi jawaban chatbot."""
@pytest.fixture
def relevancymetric(self):
return AnswerRelevancyMetric(threshold=0.7)
@pytest.fixture
def faithfulnessmetric(self):
return FaithfulnessMetric(threshold=0.7)
def testanswersarerelevant(self, testcases, relevancymetric):
"""Semua jawaban harus relevan dengan pertanyaan."""
for testcase in testcases:
asserttest(testcase, [relevancymetric])
def testanswersarefaithful(self, testcases, faithfulnessmetric):
"""Semua jawaban harus faithful terhadap konteks."""
for testcase in testcases:
asserttest(testcase, [faithfulnessmetric])
Test Komprehensif
# tests/testcomprehensive.py
import pytest
from deepeval import asserttest
from deepeval.metrics import (
AnswerRelevancyMetric,
FaithfulnessMetric,
HallucinationMetric,
BiasMetric,
ToxicityMetric,
)
from deepeval.metrics import GEval
from deepeval.testcase import LLMTestCaseParams
class TestComprehensive:
"""Test suite komprehensif dengan semua metrik."""
@pytest.fixture
def allmetrics(self):
return [
AnswerRelevancyMetric(threshold=0.7),
FaithfulnessMetric(threshold=0.7),
HallucinationMetric(threshold=0.5),
BiasMetric(threshold=0.5),
ToxicityMetric(threshold=0.5),
GEval(
name="Helpfulness",
criteria="Evaluate whether the response is helpful and actionable for the user.",
evaluationparams=[
LLMTestCaseParams.INPUT,
LLMTestCaseParams.ACTUALOUTPUT,
],
threshold=0.7,
),
]
def testfullevaluation(self, testcases, allmetrics):
"""Evaluasi lengkap setiap test case dengan semua metrik."""
for testcase in testcases:
asserttest(testcase, allmetrics)
Menjalankan Test Suite
# Jalankan semua test
deepeval test run tests/ -v
Jalankan hanya test hallucination
deepeval test run tests/test_hallucination.py -v
Jalankan dan kirim ke Confident AI
deepeval test run tests/ --confident
Jalankan dengan pytest
pytest tests/ -v --tb=short
Tips dan Best Practices
Kesimpulan
DeepEval membawa paradigma software testing ke dunia LLM, memungkinkan tim development memastikan kualitas output AI secara sistematis dan terukur. Dengan kombinasi metrik bawaan yang kaya, integrasi pytest yang mulus, dan dashboard Confident AI untuk monitoring, DeepEval menjadi tool yang esensial untuk setiap tim yang membangun aplikasi LLM di produksi.
Mulailah dengan mengidentifikasi metrik yang paling relevan untuk use case Anda, buat golden dataset dari interaksi pengguna nyata, dan integrasikan evaluasi ke dalam pipeline CI/CD Anda. Dengan pendekatan ini, Anda bisa membangun aplikasi LLM yang tidak hanya bekerja, tetapi bekerja dengan kualitas yang konsisten dan terukur.