Skip to main content
Questions such as “is this explanation suitable for elementary school students” or “did the answer make up facts” cannot be written as a regex; they go to the Judge model to score. The Judge itself can go wrong too: a wrong API key, a misspelled endpoint, a misspelled model name. If you only find these problems after 200 evals have run, none of the Judge scores along the way can be obtained. So configure it first, then run one real scoring pass with a minimal eval, and use it at scale only after confirming you get a score.

Configure which service the Judge uses

In niceeval.config.ts, spell out the service, model, and endpoint with a named Provider. The example below uses an OpenAI-compatible gateway:
niceeval.config.ts
apiKeyEnv holds only the variable name. Put the key itself in an environment variable, or in the project’s .env:

Write a minimal eval

Write an eval with only one Judge assertion to confirm the configuration can get a score:
evals/judge-smoke.eval.ts
turn.closeQA(question) hands this Turn’s full conversation to the Judge, which answers your question and gives a score from 0 to 1. .gate(0.8) means this eval fails when the score is below 0.8. When the material is empty, this assertion scores 0 directly without calling the Judge. When the material is incomplete and cannot be judged, the result is unavailable, which is not counted as 0. To have the Judge look only at specific messages or tool calls, pass the matching Match to closeQA; for the application’s own business material, use a custom MaterialMatch. See NiceEval Taste for how to write them.

Attach image material

Attach images only when the criterion really needs to see them. Keep the same defineJudge and t.judge; you do not need a second Judge or score gate. First set supportsImages: true in the existing chat Provider’s configuration, and switch model to a model that supports both images and tool calls. TypesafeProvider does not support images. The eval below reads the screenshot.png the application has already saved, and does not take a new screenshot for the eval:
Images must be PNG or JPEG, at most 4 MiB each. When an image is too large or has an invalid file header, NiceEval rejects it before sending. Do not pass a path, URL, or plain base64 string in place of an image. After the run, use query’s attempt.assertion.detail to view this assertion; the result includes the image’s imageId and digest. To get the original image back, use attempt.assertion.image with the same Attempt’s entryId and imageId, reading in segments: offset is the byte offset, and limit is at most 256 KiB. It reads the saved image and never rereads the file or calls the model.

Run once and confirm you get a score

Make sure an existing Experiment’s evals includes judge-smoke, then run:
NiceEval does not contact the Judge endpoint when loading configuration; it only sends a request when a Judge assertion really executes. So a configuration mistake only shows up after a run. After the run, copy the Run ID from the terminal’s NEXT panel and open this run:
Copy the locator of the judge-smoke Attempt and view the assertion result:
When the configuration is correct, this assertion shows a score and whether it reached the threshold. You can also view it in the browser with pnpm exec niceeval view --run <run-id>. When you need the reasons the Judge gave and the material actually sent to it, use query’s attempt.assertion.detail; see the example in View Run Results. When you get no score, decide what to check from the result: To compare different Judges, have several Experiments use different model strings or named Providers, and mark the dimension being compared with labels.