@outputai/evals package lets you test workflow quality across datasets — without modifying your workflow code. You define evaluators with verify(), write datasets in YAML, and run them with the CLI. Each dataset case feeds a saved workflow input/output pair through your evaluators, and the framework reports pass/partial/fail verdicts per case.
This is the complement to evaluator steps that run inside workflows. Those evaluators power generate-evaluate-retry loops in production. Evaluation workflows answer a different question: “across a set of known inputs, does my workflow still produce acceptable output?” For the full guide, see Evaluation Workflow.
What’s in the Package
Creating Evaluators with verify()
verify() creates a typed evaluator that receives the workflow’s input, output, and optional ground truth from the dataset. It wraps evaluator() from @outputai/core so it integrates with both the eval workflow and the Temporal worker.
input and output schemas are optional — they default to z.any() if omitted. The check function receives a CheckContext:
Basic Example
A deterministic evaluator that checks a sum calculation:tests/evals/evaluators.ts
Ground Truth Example
Evaluators can read per-evaluator ground truth from the dataset. The framework merges global ground truth with evaluator-specific overrides:tests/evals/evaluators.ts
tests/datasets/stripe_blog.yml
notes) are available to all evaluators. Fields under evals.<evaluator_name> are merged in for that specific evaluator, overriding globals with the same key.
Verdict Helpers
TheVerdict object provides deterministic assertion helpers and LLM result wrappers. All deterministic helpers return results with confidence 1.0.
Deterministic Assertions
Manual Verdicts
LLM Result Wrappers
These wrap LLM judge output into evaluation results with confidence0.9:
LLM Judge Functions
For subjective evaluation — “is this blog post on-topic?”, “rate the quality 0-100” — use the judge functions. They load a.prompt file, call the LLM, and return a typed evaluation result.
tests/evals/evaluators.ts
All judge functions accept a
JudgeArgs object:
Judge
.prompt files live in the same tests/evals/ directory as your evaluators:
tests/evals/judge_topic@v1.prompt
Creating an Eval Workflow
evalWorkflow() ties your evaluators together into a workflow that the CLI can run against datasets:
tests/evals/workflow.ts
evals array defines:
A more complete example mixing deterministic and LLM evaluators:
tests/evals/workflow.ts
Criticality
required(default): If this evaluator fails, the entire case fails.informational: Failure is reported but doesn’t affect the case verdict. Use for metrics you want to track without gating on.
Interpret Types
Theinterpret config tells the framework how to convert the raw evaluator result into a pass/partial/fail verdict:
The
partial threshold is optional for both number and string types — omit it to have only pass and fail.
Case Verdict Aggregation
Each dataset case runs all evaluators. The case-level verdict is determined by:- If any required evaluator fails → case fails
- Else if any required evaluator is partial → case is partial
- Otherwise → case passes
Datasets
Datasets are YAML files that live intests/datasets/ within your workflow directory. Each file contains one or more test cases — the top-level key is the case name.
tests/datasets/core_cases.yml
name: field inside. Every case must have an input field; the framework throws if one is missing.
Organise files however makes sense for your project — by topic, test suite version, or importance level:
--dataset flag filters by case name regardless of which file it lives in:
Ground Truth Structure
Ground truth supports global values and per-evaluator overrides:Directory Structure
Eval files live alongside your workflow in atests/ directory:
tests/evals/workflow.ts) is discovered automatically by the worker alongside your regular workflow.