LLM-evaluering med DeepEval: Byg en pålidelig eval-pipeline i Python (2026)
DeepEval er blevet det mest brugte open source-framework til LLM-evaluering i Python. Denne guide dækker G-Eval, RAG-metrikker, hallucinationsdetektion og CI-integration med praktiske kodeeksempler fra tre produktions-implementeringer.
LLM-evaluering er processen med systematisk at måle, hvor godt en sprogmodel eller LLM-applikation løser en defineret opgave, typisk ved at kombinere referencebaserede metrikker (BLEU, ROUGE), model-baserede vurderinger (LLM-as-judge, G-Eval) og opgavespecifikke domænemetrikker (faithfulness, answer relevancy, contextual precision). I 2026 er DeepEval blevet det mest udbredte open source-framework til denne opgave i Python-økosystemet, fordi det behandler LLM-tests som pytest-tests og integrerer direkte i CI/CD. Jeg har brugt DeepEval på tre produktions-RAG-systemer det seneste år, og denne guide destillerer det, jeg ville have ønsket at vide fra dag ét.
DeepEval kører LLM-tests som pytest-cases, hvilket gør regression testing af prompts trivielt i CI.
G-Eval er DeepEvals fleksible LLM-as-judge-metrik, der lader dig definere kriterier i naturligt sprog.
For RAG bør du altid måle mindst tre dimensioner: faithfulness, answer relevancy og contextual precision.
Deterministiske metrikker (BLEU, exact match) er billige, men fanger sjældent semantiske fejl. Kombinér dem med LLM-as-judge.
Confident AI-platformen giver et dashboard oven på DeepEval, men frameworket kan køre helt lokalt uden konto.
En god baseline for et produktions-eval-sæt er 50–200 kuraterede testcases per use case, ikke tusinder af syntetiske eksempler.
Hvorfor LLM-evaluering ikke er valgfrit længere
Der findes en påstand, jeg møder ofte: "Vi kigger bare manuelt på outputtet og ser om det ser rigtigt ud." Det holder præcis indtil den dag, hvor din prompt ændres, en model opdateres, eller en ny retriever-strategi rulles ud, og pludselig producerer systemet subtilt værre svar for 8% af trafikken uden at nogen opdager det. Uden en automatiseret eval-pipeline er du blind for regressions.
Det er også blevet en compliance-nødvendighed. EU AI Act, der trådte i fuld kraft i august 2026, kræver dokumenteret systematisk testning for højrisiko-AI-systemer, herunder LLM-baserede beslutningsstøttesystemer. En eval-suite er ikke længere "nice to have". Det er dokumentation, du skal kunne fremvise ved audit.
Endelig er der økonomien. Uden evals ender teams typisk med at re-teste manuelt hver gang de rører en prompt, hvilket er den dyreste form for QA, der findes. En eval-pipeline med 100 testcases, der kører på 3 minutter, er billigere at eje end fem manuelle QA-runder om måneden.
DeepEval vs. RAGAS: hvad er forskellen?
Både DeepEval og RAGAS er open source-frameworks til LLM-evaluering, men de har forskellige styrker. Kort sagt: RAGAS er specialiseret til RAG-pipelines og har en meget kompakt API. DeepEval er bredere. Det dækker RAG, agenter, chatbots, red teaming og lader dig definere brugerdefinerede metrikker via G-Eval.
Egenskab
DeepEval
RAGAS
Primært fokus
Bred LLM-evaluering
RAG-pipelines
Test-integration
Native pytest-integration
Kræver wrapper-kode
Brugerdefinerede metrikker
Ja, via G-Eval (naturligt sprog)
Begrænset
Agent-evaluering
Task Completion, Tool Correctness
Ikke understøttet
Red teaming
DeepTeam (integreret)
Nej
Dashboard
Confident AI (SaaS eller self-hosted)
Ingen officiel
Modeller understøttet
Alle via LiteLLM
Alle via LiteLLM
I min erfaring vælger jeg DeepEval, når jeg bygger noget nyt fra bunden, fordi pytest-integrationen sparer så meget lim-kode. Hvis jeg overtager et eksisterende RAG-projekt, der allerede bruger RAGAS, bevarer jeg det. Begge frameworks er velvedligeholdte, og skiftet er sjældent umagen værd.
Installation og første testcase
DeepEval installeres via pip. Frameworket understøtter Python 3.9+ og kræver en OpenAI- eller Anthropic-nøgle for de LLM-baserede metrikker (du kan også pege det på en lokal Ollama-model).
Her er den enkleste tænkelige test. Vi tjekker, om et modelsvar er relevant for et input:
from deepeval import assert_test
from deepeval.metrics import AnswerRelevancyMetric
from deepeval.test_case import LLMTestCase
def test_answer_relevancy():
test_case = LLMTestCase(
input="Hvad er hovedstaden i Danmark?",
actual_output="København er hovedstaden i Danmark og har cirka 660.000 indbyggere.",
)
metric = AnswerRelevancyMetric(threshold=0.7, model="gpt-4o-mini")
assert_test(test_case, [metric])
Kør testen præcis som en almindelig pytest:
deepeval test run test_relevancy.py
Bag kulisserne kalder AnswerRelevancyMetric en dommer-LLM (som standard gpt-4o-mini), som deler outputtet op i statements, vurderer hver enkelts relevans for spørgsmålet, og returnerer en score mellem 0 og 1. Threshold på 0.7 er en rimelig start. Jeg strammer den ofte til 0.8 for produktionskritiske use cases.
G-Eval: LLM-as-judge med brugerdefinerede kriterier
De indbyggede metrikker dækker de mest almindelige tilfælde, men før eller siden vil du evaluere noget domænespecifikt: "Er tonen professionel?", "Nævnes alle produkter i faktura-summeringen?", "Er kodesvaret idiomatisk Python?". Her kommer G-Eval ind. G-Eval er DeepEvals implementation af den G-Eval-paper-metode, hvor du beskriver et evalueringskriterium i naturligt sprog, og LLM-dommeren genererer chain-of-thought-trin og en score.
from deepeval.metrics import GEval
from deepeval.test_case import LLMTestCaseParams, LLMTestCase
professionel_tone = GEval(
name="Professionel tone",
criteria=(
"Vurder om svaret bruger en professionel, respektfuld tone "
"uden slang, sarkasme eller kolloquialismer. Formelt dansk "
"forretningssprog forventes."
),
evaluation_params=[
LLMTestCaseParams.INPUT,
LLMTestCaseParams.ACTUAL_OUTPUT,
],
threshold=0.8,
model="gpt-4o",
)
test_case = LLMTestCase(
input="Kan I refundere min ordre?",
actual_output=(
"Selvfølgelig, vi behandler din refundering inden for "
"5 hverdage. Send venligst ordrenummeret til support@..."
),
)
professionel_tone.measure(test_case)
print(professionel_tone.score, professionel_tone.reason)
Det, jeg synes gør G-Eval brugbar i praksis, er reason-feltet. Når en test fejler, får du en forklaring på dansk, du kan læse, ikke bare et tal. Det gør det trivielt at diskutere fejl med domæneeksperter, der ikke kender til embeddings eller cosine similarity.
RAG-metrikker: faithfulness, relevancy og precision
Hvis du bygger en RAG-pipeline (og du har fulgt vores RAG-pipeline med ChromaDB-guide), vil du bruge mindst tre af DeepEvals indbyggede RAG-metrikker:
Faithfulness: Er svaret understøttet af den hentede kontekst, eller hallucinerer modellen fakta udenfor konteksten?
Contextual Precision: Rangeres de mest relevante chunks højest af din retriever?
Contextual Recall: Henter din retriever al nødvendig information for at besvare spørgsmålet?
from deepeval.metrics import (
FaithfulnessMetric,
AnswerRelevancyMetric,
ContextualPrecisionMetric,
ContextualRecallMetric,
)
from deepeval.test_case import LLMTestCase
test_case = LLMTestCase(
input="Hvornår trådte EU AI Act i fuld kraft?",
actual_output="EU AI Act trådte i fuld kraft i august 2026.",
expected_output="EU AI Act blev fuldt anvendelig 2. august 2026.",
retrieval_context=[
"EU AI Act blev vedtaget i 2024 og blev fuldt "
"anvendelig den 2. august 2026 for højrisikosystemer.",
"Forordningen dækker biometrisk identifikation, "
"kritisk infrastruktur og LLM-baserede beslutningsstøttesystemer.",
],
)
metrics = [
FaithfulnessMetric(threshold=0.8),
AnswerRelevancyMetric(threshold=0.7),
ContextualPrecisionMetric(threshold=0.7),
ContextualRecallMetric(threshold=0.7),
]
for m in metrics:
m.measure(test_case)
print(f"{m.__class__.__name__}: {m.score:.2f} — {m.reason[:100]}...")
Læg mærke til, at Faithfulness og Answer Relevancy ikke behøver expected_output; de er reference-fri. Dette er nyttigt i produktion, hvor du ofte har logs uden ground truth. ContextualPrecision og ContextualRecall kræver derimod en forventet output for at sammenligne mod.
Hallucinationsdetektion i praksis
Hallucinationer er den enkeltstående største grund til, at LLM-applikationer mister brugertillid. DeepEvals HallucinationMetric sammenligner modellens output mod en liste af kontekstpassager og markerer alle påstande, der ikke er understøttet:
from deepeval.metrics import HallucinationMetric
from deepeval.test_case import LLMTestCase
test_case = LLMTestCase(
input="Beskriv Claude Sonnet 5's context window.",
actual_output=(
"Claude Sonnet 5 har et 500K token context window "
"og understøtter 40 sprog."
),
context=[
"Claude Sonnet 5 har et 200K token context window "
"og understøtter over 100 sprog."
],
)
metric = HallucinationMetric(threshold=0.3)
metric.measure(test_case)
print(f"Hallucination score: {metric.score}")
print(f"Reason: {metric.reason}")
I dette eksempel vil scoren være høj (dårlig), fordi outputtet påstår "500K token context window" og "40 sprog", mens konteksten siger "200K" og "over 100 sprog". Reason-feltet vil nævne præcis hvilke påstande, der er ubelagte.
Et almindeligt setup, jeg bruger, er at køre HallucinationMetric som en gate i CI: hvis nogen ændrer en prompt og hallucination-score stiger over baseline med mere end 0.05, fejler builden. Dette har fanget adskillige subtile prompt-regressioner for mig, som manuel review ville have misset.
Evaluering af AI-agenter og tool use
Evaluering af agenter er svært, fordi de involverer flerhandlings-trajektorier, ikke bare et enkelt input/output-par. DeepEval 2.x introducerede TaskCompletionMetric og ToolCorrectnessMetric specifikt til dette. Hvis du bygger agenter, anbefaler jeg også vores guide til function calling og tool use med LLM'er i Python, som dækker de underliggende primitiver.
from deepeval.metrics import ToolCorrectnessMetric
from deepeval.test_case import LLMTestCase, ToolCall
test_case = LLMTestCase(
input="Bestil en Uber til Nørreport Station kl. 18:00",
actual_output="Din Uber er bestilt til kl. 18:00.",
tools_called=[
ToolCall(name="get_current_location"),
ToolCall(
name="book_uber",
input_parameters={
"destination": "Nørreport Station",
"pickup_time": "18:00",
},
),
],
expected_tools=[
ToolCall(name="book_uber"),
],
)
metric = ToolCorrectnessMetric(threshold=0.9)
metric.measure(test_case)
print(metric.score, metric.reason)
Metrikken tjekker, at agenten kaldte de forventede værktøjer (og kun dem), med de rigtige argumenter. For mere komplekse agent-workflows (som dem, du kunne bygge med LangGraph) kan du kombinere TaskCompletionMetric (blev slutmålet nået?) med custom G-Eval-metrikker for delmål.
Integration i CI/CD med GitHub Actions
Den virkelige gevinst kommer, når evals kører automatisk på hver pull request. Her er en minimal GitHub Actions-workflow:
--cache-flaget er kritisk her: det genbruger metric-resultater for uændrede testcases, hvilket reducerer omkostninger og runtime dramatisk. En suite med 200 testcases går fra ~15 minutter til ~90 sekunder på en typisk PR, hvor kun en håndfuld tests er berørt.
Dataset-strategi: hvor mange testcases?
Et almindeligt spørgsmål er, hvor mange testcases du har brug for. Mit svar, baseret på tre produktionsimplementationer: 50–200 kuraterede cases per use case slår 5.000 syntetisk genererede cases hver eneste gang. Kvalitet trumfer volumen.
En balanceret suite indeholder typisk:
Golden cases (20–40%): Kanoniske eksempler, hvor du kender det korrekte svar præcist.
Edge cases (30–40%): Uklare, tvetydige eller ondsindede inputs. Prompt injections, kodeblokke i normale spørgsmål, meget lange inputs.
Regression cases (20–30%): Konkrete bugs, du har rettet, for at sikre, at de ikke vender tilbage.
Domænespecifikke cases (10–20%): Fra faktiske produktionslogs, anonymiseret.
DeepEval kan generere syntetiske cases via Synthesizer-klassen, hvilket er nyttigt til at bootstrappe et dataset. Men behandl syntetiske cases som et udgangspunkt, aldrig som endelig sandhed. De tenderer til at teste de mest åbenlyse ting og misser den slags subtile fejl, brugere faktisk møder.
Ofte stillede spørgsmål
Hvad er forskellen på DeepEval og LangSmith?
LangSmith er en observability-platform (traces, logs, dashboards) primært designet omkring LangChain-økosystemet. DeepEval er et evalueringsframework, der fokuserer på at score outputs mod metrikker og køre som tests. De er komplementære: mange teams bruger LangSmith til produktions-traces og DeepEval til CI-tests.
Kan DeepEval køre uden en OpenAI-nøgle?
Ja. Du kan konfigurere en lokal model via deepeval set-local-model (fx en Ollama- eller vLLM-endpoint), eller bruge Anthropic Claude med deepeval set-anthropic. Referencebaserede metrikker som BLEU og ROUGE kræver slet ingen LLM.
Hvor meget koster det at køre en eval-suite?
Med gpt-4o-mini som dommer og 100 testcases på 4 metrikker koster en fuld kørsel typisk 0,10–0,40 USD. Med caching aktiveret betaler du kun for berørte testcases på efterfølgende kørsler, hvilket gør daglig CI-kørsel praktisk økonomisk overkommelig.
Hvordan tester jeg AI-agenter, der har flere trin?
Brug TaskCompletionMetric til at vurdere om slutmålet blev nået, og ToolCorrectnessMetric til at verificere, at de rigtige værktøjer blev kaldt. For komplekse agenter (fx LangGraph-baserede) kan du desuden logge hvert delskridt som en separat LLMTestCase og evaluere trajektorien som en helhed.
Er LLM-as-judge pålideligt?
Pålideligt nok til de fleste use cases, men ikke perfekt. Studier viser 80–85% enighed mellem GPT-4-baserede dommere og menneskelige annotatorer på tekstkvalitet. For høj-stakes beslutninger bør du kalibrere dommer-modellen mod et menneskeligt-mærket referencesæt og supplere med deterministiske checks.
Sådan tilføjer du Cohere Rerank 3.5 til en Python RAG-pipeline og løfter Recall@5 med 15-35%: to-trins retrieval, hybrid-søgning, eval, latency og priser.
Sådan bruger du prompt caching i Claude API til at reducere både omkostninger med op til 90% og latens med op til 85%. Inkluderer Python-eksempler, prismodel, TTL-strategier og de mest almindelige fejl der dræber cache hit-raten.
Komplet praktisk guide til at bygge en MCP-server i Python med FastMCP. Lær JSON-RPC-protokollen, opsætning af tools, resources og prompts, samt hvordan du forbinder din server til Claude Desktop og kører den i produktion.