Claude Certification Guides
CCDV-F/Domain 49 min read

Lesson 4.1

Evals, Testing and Debugging Claude Features

How to measure whether a Claude feature works, test it like other software, and debug failures using the fields the API already gives you.

A prompt that "seems to work" is not a tested feature. Evaluation turns subjective judgement into numbers you can track across prompt edits and model upgrades, and disciplined debugging uses the response fields and headers the API returns rather than guesswork. The exam asks you to pick the right grading method for a scenario and to diagnose common failures from their symptoms.

Build the eval set first

An eval is a set of inputs with expected outcomes plus a way to score each result. Start small and representative:

  • Pull real inputs from logs or transcripts (anonymised), not invented ones.
  • Include edge cases: empty input, very long input, adversarial phrasing, non-English text.
  • Record an expected result or a rubric for each case.
  • Version the set alongside the prompt it tests.

Even 30 well-chosen cases catch most regressions. Grow the set whenever production surfaces a new failure.

Three kinds of grader

GraderUse whenExample
Code-basedOutput is deterministic or checkableExact match, regex, JSON schema validation, unit tests passing
Model-basedQuality is subjective but describableClaude scores a summary against a rubric and returns a 1-5 rating
HumanStakes are high or the rubric is still formingReviewers label a sample each week

Prefer code-based grading wherever possible: it is cheap, fast and reproducible. Model-based grading works well when you give the grader a precise rubric, ask for a structured verdict, and spot-check it against human labels. Never let the model grade its own free-text answer without a rubric; "does this look good?" produces inflated scores.

A minimal eval harness

import json, anthropic
client = anthropic.Anthropic()

def run_case(case):
    resp = client.messages.create(
        model=MODEL, max_tokens=300, system=SYSTEM_PROMPT,
        messages=[{"role": "user", "content": case["input"]}],
    )
    text = next(b.text for b in resp.content if b.type == "text")
    return {"id": case["id"], "output": text,
            "pass": grade(case, text), "usage": resp.usage.model_dump()}

results = [run_case(c) for c in json.load(open("evals/tickets.json"))]
score = sum(r["pass"] for r in results) / len(results)
print(f"pass rate {score:.0%}")

Run it in CI on every prompt change and fail the build when the pass rate drops below a threshold. Because model outputs vary, run each case more than once if your budget allows and compare distributions rather than single runs. For bulk evals, the Message Batches API cuts cost substantially.

Testing without hitting the API

Unit tests for your orchestration code should not spend tokens or depend on network. Mock the client and return canned Message objects, including ones with stop_reason: "tool_use" and stop_reason: "max_tokens", so the loop logic around the API is exercised. Keep a separate, smaller suite of integration tests that call the real API against a pinned model.

Debugging with what the API gives you

Every response carries id, and every HTTP response carries a request-id header. Log both with your own correlation ID; Anthropic support needs the request ID to investigate. Log usage and stop_reason on every call so you can see cost spikes and truncation rates in a dashboard.

SymptomLikely causeCheck
Output ends mid-sentencemax_tokens too lowstop_reason == "max_tokens"
Tool never calledWeak tool description or tool_choice: noneInspect content for tool_use; improve description
400 about roles alternatingAppended two user turns, or history started with assistantPrint messages roles before the call
400 about tool_use_idDropped or reordered tool resultsEach tool_result must follow the assistant turn it answers
Cache never hitsSomething volatile in the prefixusage.cache_read_input_tokens stays 0
Sudden 404Model ID typo or deprecated modelCompare with client.models.list()
Intermittent 429 / 529Rate limit or overloadRead retry-after; rely on SDK retries

Most "the model is being weird" reports turn out to be one of these.

Prompt changes are code changes

Keep prompts in version control, give them identifiers, and record which prompt version and model produced each logged response. When you upgrade a model, re-run the full eval before switching production traffic; behaviour and token counts both shift between generations. Treat a drop in pass rate exactly like a failing test.

Observability in production

Sample a percentage of real traffic into a review queue, track pass rate from your model-based grader over time, and alert on drift in output length, refusal rate and max_tokens frequency. These signals usually move before users complain.

Exam focus

  • An eval is a versioned set of representative inputs plus a grader; build it from real data and grow it from production failures.
  • Code-based graders are preferred when outputs are checkable; model-based graders need an explicit rubric and spot-checking; human review is for high stakes.
  • Mock the client in unit tests to exercise loop logic, including tool_use and max_tokens stop reasons, without spending tokens.
  • Log the response id or request-id header plus usage and stop_reason on every call.
  • Truncated output means stop_reason: "max_tokens"; a zero cache_read_input_tokens means the prefix is changing.
  • Re-run the eval before any prompt or model change reaches production.

Check yourself

5 questions

  1. 1.A developer tweaks a summarisation prompt, tries it on three examples in a notebook, likes the output and deploys. What is the risk, and what practice addresses it?

  2. 2.An eval for a summarisation feature uses an exact string match against a reference summary and scores 0% even though the outputs read well. What is the issue and the better approach?

  3. 3.Users report that an assistant occasionally gives wrong answers, but the team's logs only contain the user's text. Which data should be logged to make such failures debuggable?

  4. 4.About 5% of responses from an extraction feature fail JSON.parse. Which diagnostic step should come first?

  5. 5.A test suite sets temperature: 0 and asserts that the response text is byte-identical to a stored snapshot. Is this assumption valid?