Evals
Evals are automated quality checks on agent output. They run as a post-node step, after node completion and before any human-in-the-loop (HITL) gate check. Each eval definition specifies a type, configuration, pass threshold, and failure behavior.
Eval definition
Each eval definition has:
| Field | Description |
|---|---|
id |
Unique identifier |
name |
Human-readable name |
eval_type |
model_judge, regex, json_schema, custom_function, guardrail, or human_set |
config_json |
Type-specific configuration |
pass_threshold |
Optional numeric threshold between 0 and 1 |
suite_id |
Optional suite that groups related evals |
A node-level policy gate references an eval definition and sets what a failure does: warn logs the result and the run continues, while block stops the node before its output is used downstream.
Eval types
Eval types are described in this section and under Guardrails, which is a separate section because it runs on input rather than output.
Large language model (LLM) judge
Sends agent output to an LLM with a rubric prompt. Returns a score from 0 to 1 and reasoning. Uses a separate, independently configured model backend, not the agent’s own backend.
Regex
Applies a regex pattern to the output. Pass means a match was found. No threshold.
JSON Schema
Validates output against a JSON Schema definition. Stricter than the agent’s output schema, for catching well-typed but semantically invalid outputs.
Custom function
Calls a Python function registered via the modulo.evals entry-point group. Returns a score from 0 to 1.
Human-authored set
Runs a registered, versioned eval set written by a person: a fixed list of deterministic assertions that check correctness rules rather than output shape. Select the set with config_json.set_name; an optional version is advisory, because one version of a name is active at a time. The eval passes only if every assertion passes, and its detail names the assertions that failed. A missing set_name or an unregistered set name fails the eval.
Because the result is not model-mediated, output content cannot talk the eval into a pass, which is the gap that model_judge leaves open. The shipped demo_classification set (v1) checks a support-ticket classifier, including a business rule such as “a technical outage is always high priority” that regex and JSON Schema checks cannot express. An operator registers a new set in code and references it by name.
Eval result record
Each eval run stores a result per run per node:
| Field | Description |
|---|---|
eval_id |
The eval definition that ran |
run_id |
The run |
node_id |
The node whose output was evaluated |
score |
Numeric score, nullable for non-scored types |
passed |
Whether the eval passed |
detail |
Human-readable detail |
evaluated_at |
Timestamp |
Results are displayed in the run inspection UI. A block failure is written to the AuditEvent log.
Conditional HITL gating
A HITL gate’s hitl_config can carry an eval_condition that references an eval definition by name. The condition fires the gate when the eval result matches the comparison:
Pipeline config
{
"id": "55555555-5555-4555-8555-555555555555",
"node_type": "hitl",
"position": { "x": 680, "y": 200 },
"output_schema_id": "66666666-6666-4666-8666-666666666666",
"hitl_config": {
"label": "Quality review",
"description": "The quality eval scored below 0.8, so a human must review the output.",
"claim_expiry_minutes": 15,
"human_only": true,
"eval_condition": {
"eval_name": "quality-check",
"threshold": 0.8,
"operator": "lt"
}
}
}
If the condition is true (score < 0.8), the pipeline pauses for human review. If false, execution continues without pausing. The supported operators are lt, gt, lte, gte, eq, and neq.
Guardrails
Guardrails are the input-side analogue of evals: deterministic data-safety checks at the ingestion boundary.
- A guardrail is an
EvalDefinitionwitheval_type="guardrail" - Detection is deterministic and pure (regex or
json_schemaonly) - Interception runs at run-creation, before the input payload is persisted
Actions:
| Action | Behavior |
|---|---|
observe |
Log only |
warn |
Warn and continue |
block |
Terminal eval_failed (error code eval_blocked) |
redact |
Redact the offending content |
A block is terminal: the run is never dispatched, never retried, and has no HITL gate.
Policy-as-code
Guardrail configuration is versioned, hashed YAML. You propose a change, review the diff, and apply it through a pull request. Each run’s snapshot pins the guardrail configuration it ran under, with drift detection.
Related
- Human-in-the-Loop: review gates and governance
- Schemas: versioned input/output definitions
- Agents: the atomic units that make up a pipeline
- Pipelines: run lifecycle and where evals run
- Feedback System: rejections tagged as eval gaps