Once a distilled student is live in Ollama, the question is no longer "did it train?" but "is it actually better, and better at the thing we wanted?" At theLAB we answer that with a fixed eval set and four escalating levels of scrutiny — from a 30-second smoke test to an auto-graded benchmark.
The single most important move comes before training: build a fixed held-out eval set of 30–50 representative prompts and set it aside. It must not overlap with the training data. Without it you can't compare the base against the fine-tune fairly, and you'll be tempted to eval on the training set — which only ever tells you the model memorized.
01Smoke tests — does it even work?
The cheapest level catches broken conversions. The model should appear in ollama list at the expected size, load, and run without crashing. Then read a few outputs: they should be coherent and non-repeating — no gibberish, no token loops, no degenerate "the the the." A bad GGUF conversion or a botched merge usually shows up here as garbage on the very first prompt.
ollama run adi-qwen3.5-4b-glm5.2-general \
"Explain the CAP theorem in two sentences."
# looking for: coherent, on-topic, ends cleanly — not looping
02Side-by-side on the held-out set
Now run the base and the fine-tuned model on the same held-out prompts and read the diffs. This is where you confirm the intended behavior actually transferred — better structure, the house style, tighter instruction-following. If base and tuned answers look identical, the fine-tune didn't take; if the tuned one is just longer but no more correct, that's a warning sign (see below).
03LLM-as-judge
Reading every diff by hand doesn't scale. Hand the pair to a strong judge model — we use glm-5.2 — and score each answer against a rubric: correctness, structure, style adherence, instruction-following. It's cheaper and far faster than human grading and good enough to rank models. Average the scores, then go read the losers: the low-scoring answers are where the real signal is.
import requests, json
def chat(model, prompt):
r = requests.post("http://localhost:11434/api/chat", json={
"model": model,
"messages": [{"role": "user", "content": prompt}],
"stream": False,
}, timeout=300)
return r.json()["message"]["content"]
RUBRIC = """Score the answer 1-5 on correctness, structure,
style, and instruction-following. Reply ONLY as JSON:
{"correctness":n,"structure":n,"style":n,"following":n}"""
for p in held_out: # the frozen 30–50 prompts
base = chat("qwen3.5:4b", p) # the unmodified base
tuned = chat("adi-qwen3.5-4b-glm5.2-general", p)
judge = chat("glm-5.2",
f"{RUBRIC}\n\nPROMPT:\n{p}\n\nANSWER:\n{tuned}")
score = json.loads(judge) # average these across the set
04Task benchmarks
For models with a checkable output, stop trusting opinions and run the work. For coders, actually execute the generated code against tests or a runner and measure pass@1 — the code either passes or it doesn't. For general models, keep a small QA set with known answers you can auto-grade by string or numeric match. This is the only level that's immune to a confident-but-wrong judge.
05What to watch for
Three failure modes hide behind nice-looking averages:
- Overfitting / parroting — the model echoes training phrasing and sounds smarter without being more correct.
- Catastrophic forgetting — a regression on general ability the base model used to have. Your held-out set should include a few off-topic prompts to catch this.
- Format drift — the style mutates in ways you didn't intend (stray markdown, dropped sections).
06The practical loop
Putting it together: fixed eval set → generate base + tuned answers → judge with glm-5.2 → human spot-check the disagreements (where judge and your gut differ) → decide ship or iterate. The spot-check is small because the judge already narrowed it down.
One tie-in worth weighting your rubric around: distillation mainly moves style and reasoning, not net-new facts. So weight correctness toward reasoning on familiar tasks and structure, not obscure factual recall — grading a 4B student on trivia punishes it for something fine-tuning was never going to fix. See Does distillation add knowledge or just style? for why.