Duiding6 minGevorderd

AI-agents evalueren met een LLM-judge: testbank in 4 stappen

Breekt je AI-agent na een promptwijziging? Bouw met LangChain, Ollama en Qwen 3.5 een lokale testbank die harde checks en een LLM-judge combineert.

Een messing balans met op de ene schaal een glazen knikker en op de andere een gladgepolijste steenAI-beeld

Je agent werkt vandaag. Maar werkt hij nog na je volgende promptaanpassing, modelwissel of nieuwe tool? Wie dat op gevoel beoordeelt, ziet regressies pas als gebruikers klagen. Een evaluatie-harness lost dat op: een script dat je agent langs vaste testcases draait en een overzicht print van wat slaagt en wat faalt. Dit stuk volgt de opzet van een tutorial van Darsh Shah op freeCodeCamp (17 juli 2026): lokaal, met LangChain, Ollama en Qwen 3.5, dus zonder API-kosten (Bron: freeCodeCamp).

Update 2 november 2026 De codevoorbeelden zijn gelijkgetrokken met de bron en de huidige LangChain-documentatie. Het model is nu qwen3.5:4b (was qwen3), de judge geeft een simpel YES of NO in plaats van JSON en de testcases hebben een eigen rubric voor de judge.

Stap 1: zet de lokale basis klaar

Installeer Ollama en haal het model binnen. Maak daarna een virtuele Python-omgeving en installeer LangChain met de Ollama-koppeling. De tutorial vraagt langchain>=1.0.0; de huidige versie is 1.4.7 (Bron: PyPI).

ollama pull qwen3.5:4b
python3 -m venv venv
source venv/bin/activate
pip install langchain langchain-core langchain-ollama

Het 4B-model is zo’n 3,3 tot 4 GB groot en ondersteunt tool-aanroepen (Bron: Ollama). Heb je weinig werkgeheugen, dan kan qwen3.5:0.8b, maar dan worden de oordelen van de judge rommeliger. Nieuw met Ollama? Lees eerst wat Ollama is en hoe lokale modellen werken.

Dan de agent zelf. Twee kleine tools en create_agent uit LangChain 1.x (Bron: LangChain):

from datetime import datetime
from langchain.agents import create_agent
from langchain_core.tools import tool
from langchain_ollama import ChatOllama

@tool
def current_time() -> str:
    """Return the current date and time."""
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

@tool
def word_count(text: str) -> int:
    """Count the number of words in a text."""
    return len(text.split())

model = ChatOllama(model="qwen3.5:4b", temperature=0)
agent = create_agent(
    model=model,
    tools=[current_time, word_count],
    system_prompt="You are a helpful assistant with access to tools.",
)

Gevorderden De harness behandelt de agent als black box. Hij stopt er een vraag in en kijkt naar wat eruit komt: het laatste antwoord en de tools die onderweg zijn aangeroepen. Je hoeft je agent dus niet aan te passen om hem testbaar te maken. Wat een agent precies is, lees je in AI-agents: wat zijn ze.

Stap 2: leg testcases vast als data

De kern van de harness is een lijst testcases, los van je code. Per case leg je vast wat je vraagt, welk woord in het antwoord moet staan, welke tool de agent hoort te gebruiken (of None als hij juist géén tool mag gebruiken) en een rubric voor de judge:

TEST_CASES = [
    {
        "input": "How many words are in the sentence 'AI changes everything'?",
        "expected_keyword": "3",
        "expected_tool": "word_count",
        "judge_rubric": "The answer says the sentence has 3 words.",
    },
    {
        "input": "What is the capital of France? Answer without using any tools.",
        "expected_keyword": "Paris",
        "expected_tool": None,
        "judge_rubric": "The answer names Paris and adds no invented facts.",
    },
]

Begin klein: vijf tot tien cases die je belangrijkste gedrag afdekken, met minstens één vraag waarbij de agent geen tool hoort te gebruiken. Juist die case viel in de bron bij de eerste run om, omdat het model de instructie negeerde (Bron: freeCodeCamp).

Stap 3: combineer harde checks met een judge

Per testcase draait de harness eerst de agent en verzamelt het antwoord en de gebruikte tools. Daarna volgen twee soorten controle. De harde checks zijn goedkoop en onbetwistbaar: staat het verplichte woord in het antwoord en klopt de toolkeuze? De judge, een tweede instantie van hetzelfde model met een eigen prompt, beoordeelt of het antwoord aan de rubric voldoet.

judge = ChatOllama(model="qwen3.5:4b", temperature=0)

def run_agent(case):
    result = agent.invoke({"messages": [{"role": "user", "content": case["input"]}]})
    answer = result["messages"][-1].content
    tools_used = [
        call["name"]
        for msg in result["messages"]
        for call in (getattr(msg, "tool_calls", None) or [])
    ]
    return answer, tools_used

def check_keyword(case, answer):
    return case["expected_keyword"].lower() in answer.lower()

def check_tool(case, tools_used):
    if case["expected_tool"] is None:
        return tools_used == []
    return case["expected_tool"] in tools_used

def llm_judge(case, answer):
    prompt = (
        f"User input: {case['input']}\n"
        f"Agent answer: {answer}\n"
        f"Rubric: {case['judge_rubric']}\n"
        "Does the answer meet the rubric? Reply with just YES or NO."
    )
    reply = judge.invoke(prompt).content
    return reply.strip().upper().startswith("YES")

Een kale YES of NO is voor een klein model makkelijker te volgen dan een JSON-structuur. Je script hoeft er dan ook niets ingewikkelds mee te doen. Dat is ook de keuze in de bron.

Gevorderden Judge-modellen hebben eigen voorkeuren, zoals een zwak voor lange antwoorden. Stel daarom per criterium een aparte ja-of-nee-vraag in plaats van één totaaloordeel. Houd de temperatuur op 0, zodat herhaalde runs zo veel mogelijk hetzelfde oordeel geven. Een klein model als de 4B-variant kan zich vergissen, dus lees een paar oordelen per run zelf na. Meer over dit vakgebied vind je bij evals en harness engineering.

Stap 4: draai de harness bij elke wijziging

Laat het script per case het antwoord, de tools en PASS of FAIL met de reden printen. Aan het eind volgt een totaal zoals 3/4 passed:

def run_evals():
    passed = 0
    for case in TEST_CASES:
        answer, tools_used = run_agent(case)
        reasons = []
        if not check_keyword(case, answer):
            reasons.append("keyword missing")
        if not check_tool(case, tools_used):
            reasons.append(f"wrong tools: {tools_used}")
        if not llm_judge(case, answer):
            reasons.append("judge said NO")
        print(f"[Answer] {answer}\n[Tools] {tools_used}")
        print("[PASS]" if not reasons else f"[FAIL] {', '.join(reasons)}")
        passed += not reasons
    print(f"{passed}/{len(TEST_CASES)} passed")

run_evals()

Draai dit na elke promptwijziging, modelwissel of nieuwe tool. In de bron haalde de eerste run 3 van de 4 cases: de agent gebruikte een tool terwijl dat niet mocht. Na een strengere systeemprompt slaagden alle vier. Precies dat soort stille regressie wil je in seconden zien, voordat een gebruiker hem vindt.

Meer over waar agents nu staan en waar ze vastlopen, lees je in het dossier AI-agents.

Lees verder

Veelgestelde vragen

Wat is LLM-as-a-judge?

LLM-as-a-judge betekent dat je een taalmodel inzet om het antwoord van een ander model of een agent te beoordelen. Je geeft de judge de vraag, het antwoord en een beoordelingsregel (rubric) en vraagt om een oordeel, bijvoorbeeld ja of nee. Zo vang je kwaliteitsaspecten die met vaste regels lastig te toetsen zijn, zoals volledigheid of of de agent een instructie volgde.

Hoe test je een AI-agent automatisch?

Leg een lijst testcases vast als data: per case de invoer, een woord dat in het antwoord moet staan, de tool die de agent hoort te gebruiken en een rubric voor de judge. Een script draait de agent per case, voert de harde checks en de judge uit en print per case geslaagd of gefaald met de reden. Dat script draai je na elke prompt-, model- of toolwijziging.

Waarom zou je een agent lokaal evalueren met Ollama?

Een evaluatie draai je vaak. Bij een betaalde API telt dat snel op. Met Ollama draai je een open model zoals Qwen 3.5 op je eigen computer, dus zonder kosten per aanroep. De tutorial waarop dit stuk is gebaseerd gebruikt qwen3.5:4b voor zowel de agent als de judge; met weinig werkgeheugen kan qwen3.5:0.8b, maar dan worden de oordelen rommeliger.

Is een LLM-judge betrouwbaar?

Gedeeltelijk. Een judge-model heeft eigen voorkeuren en een klein model maakt fouten. Gebruik daarom harde checks voor alles wat je met een regel kunt toetsen en laat de judge alleen doen wat regels niet kunnen. Houd de vraag aan de judge eenvoudig (ja of nee) en lees regelmatig een paar oordelen zelf na.

Heb je LangChain nodig voor een evaluatie-harness?

Nee. Het patroon (testcases, agent draaien, checks, rapport) werkt met elk framework. LangChain 1.x is handig omdat create_agent het aanroepen van tools regelt en je de agent als black box kunt testen. Bouw je je agent op een andere manier, dan blijft de opzet van de harness hetzelfde.

Bronnen

Waar deze informatie vandaan komt.