AI agents

A Synthetic Task Is a Contract: Fields a Generator Must Fill

Antonio Evans6 min read

A whiteboard-style diagram on a light gray background.
Key points

Key points

  1. 1A synthetic task is a contract between the task author and the grader, and the JSON spec is the only shared artifact they have.
  2. 2Six field groups should be mandatory: intent, source slice, expected behavior, allowed tools, failure rubric, and provenance.
  3. 3Missing fields force the grader to guess, and guessing is where silent label errors enter an eval set.
  4. 4A lint rule should reject any generated task with a missing field, an empty failure rubric, or a source slice that does not resolve to a real input.

Why the task spec is a contract, not a prompt

When you generate synthetic evaluation data, two parties touch every task: whoever writes the generator, and whoever writes the grader (a code check or an LLM judge). In a small team they may be the same person, but they are never the same role. The generator decides what input to use and what should happen. The grader decides whether what happened was right. If the two roles share nothing but a free-text prompt, every omitted detail becomes a private assumption on one side and a guess on the other.

That gap is the source of most silent label errors. Research on agent evaluation is blunt about this failure mode: an agent can produce a correct final answer through a wrong process, and scoring only the output hides the broken reasoning underneath LangChain's trajectory evaluation framework. Google's evaluation guidance calls the same thing a silent failure, where an inventory report gives the right number but cites last year's document Google Cloud's methodical approach to agent evaluation. In both cases the grader lacked a field that told it what to inspect, so it inspected only the artifact it could see.

The fix is a spec that is strict on paper. Treat the generated task as a data contract, in the same sense that JSON Schema treats a document as an instance that either validates or does not JSON Schema validation vocabulary. The spec is the agreement; the task instance either satisfies it or gets rejected before it ever reaches the grader.

The six required field groups

A working spec needs exactly six groups, no more as mandatory fields and no fewer. Each maps to a question a grader would otherwise have to answer alone.

Field groupQuestion it answersTypical failure if omitted
intentWhich single capability does this task exercise?Task becomes a compound test; a pass says nothing about which skill worked
source sliceWhich exact input is this built from?Grader cannot reproduce the input or spot a stale fixture
expected behaviorWhat should a correct response do?Grader falls back to surface style judgments
allowed toolsWhich calls are permitted?Agent succeeds through an out-of-scope tool and scores clean
failure rubricWhat counts as wrong, and why?Empty rubric means every answer passes
provenanceWho or what generated it, from where, with what checksum?No way to audit, dedupe, or retire a bad batch

The intent field deserves special emphasis. Google's framework insists on a measurable success statement per agent, contrasting "the agent should be helpful" with "success is a factually correct, concise summary fully grounded in known documents" Google Cloud. A synthetic task with a vague intent inherits the same defect, and your rubric inherits it too.

Intent: one capability per task

Intent should be a short string plus a pointer to a capability registry, not a paragraph. The registry is a list of capabilities your product actually claims, such as "extract line items from an invoice" or "refuse an out-of-policy refund request." One task, one entry.

A worked example makes the cost concrete. Suppose a generator emits a task whose intent reads "handle a refund request correctly." The grader then has to decide whether correctness means policy compliance, tone, identity verification, or the refund actually being processed. A support agent handling a refund across eight conversational turns makes each of those a separate opportunity for failure LangChain. If the task records one intent, the rubric can check one thing and a pass is interpretable.

The decision rule: if you cannot name the capability in a noun phrase that also appears in your product documentation, the task is not ready. Split it, or drop it.

Source slice: pin the input with an ID and checksum

The source slice is where most generated-task pipelines quietly break. A source slice should contain three things: a stable identifier for the source record (a primary key, not a row number), a content checksum over the exact bytes the task used, and the path or query that produced it.

Why both ID and checksum? The ID lets you find the record again when you investigate a failure. The checksum lets you detect that the record changed under you. Schema-inference research shows that document stores permit structural drift and partial documentation, so a task built from a record that later mutated will grade against an input nobody can reconstruct the SVEF framework paper on schema validation. A checksum turns that silent mismatch into a loud lint failure.

The same principle appears in golden-dataset practice: a curated, trusted set is used for benchmarking rather than learning, and its value comes from being stable enough that a score movement means something DAC.digital on golden datasets. If your synthetic task cannot name its source slice precisely, it is not a fixture, it is a rumor.

Expected behavior and allowed tools

Expected behavior is a description of a correct response, stated as observable properties. "Returns JSON with the fields invoice_id, total, and currency, where total equals the sum of line items" is a spec. "Answers well" is not. Rubric-writing guidance makes the same point: the key attribute of a criterion is that it is observable, with clear definitions of success and edge cases Twine's guide to writing an LLM evaluation rubric.

Allowed tools is the field teams skip most often, and it is the one that catches deceptive passes. List every permitted call explicitly. Anything not on the list is a hard failure even if the final answer is correct. Google's framework places tool selection accuracy inside its process-quality pillar precisely because output-only scoring cannot see it Google Cloud. LangChain reports the same: an agent that hallucinates a tool call and still gets lucky looks fine to an output-only grader LangChain.

A practical rule: if a task needs more than three tools, split it, or record the permitted sequence. Trajectory evaluation exists because the path matters, and a tool allowlist is the cheapest way to make the path checkable the agent evaluation crash course.

Failure rubric: enumerate what wrong looks like

An empty failure rubric is worse than no rubric, because it silently converts the grader into a vibes check. The rubric should list named failure modes, each with a short definition and, where possible, a deterministic check.

For each task, write at least one failure mode with an exact condition. For example:

failure_modes:
  - id: missing_currency
    when: output.total present and output.currency absent
    check: code
  - id: wrong_policy_citation
    when: agent cites a refund window other than the one in source slice
    check: llm_judge
  - id: out_of_scope_tool
    when: any tool outside allowed_tools appears in trace
    check: code

Judges that score against structured criteria are more consistent than free-form judges, and combining code checks with an LLM judge covers both deterministic and subjective failures Confident AI's guide to LLM-as-a-judge. Google's comparison of evaluation methods notes that code-based checks are the cheapest and most deterministic, while judges are best for subjective qualities at scale Google Cloud. Writing both kinds into the rubric, labeled by check type, is what lets a pipeline run cheap checks first and reserve judge calls for the cases that need them.

Provenance: make every task auditable

Provenance is the field that costs nothing to write and saves an afternoon when a batch goes bad. Record the generator identity, the generation parameters that matter, the source slice checksum, and the spec version. When a batch starts failing a regression test, provenance is what lets you retire exactly the affected tasks instead of quarantining everything.

Provenance also supports reuse. A randomized, deterministic pipeline that samples tasks from a golden set should record enough to regenerate any given task, which is what makes a benchmark worth trusting over time DAC.digital. The ChatLog work shows the value of this discipline at the research scale: large-scale records of model responses kept over a long period let researchers detect step-wise changes that a one-shot benchmark would miss the ChatLog paper. Synthetic task sets without provenance cannot support that kind of longitudinal analysis.

The lint rule: reject, do not repair

The check is a single function with three reject conditions: any required field missing or empty, an empty failure rubric, or a source slice that does not resolve to a real input with a matching checksum. Reject means the task never enters the eval set. Do not auto-fill, do not flag for later.

REQUIRED = ["intent", "source_slice", "expected_behavior",
            "allowed_tools", "failure_rubric", "provenance"]

def lint_task(task, resolver):
    errors = []
    for field in REQUIRED:
        if not task.get(field):
            errors.append(f"missing:{field}")
    rubric = task.get("failure_rubric") or []
    if not rubric:
        errors.append("empty:rubric")
    elif any(not m.get("when") for m in rubric):
        errors.append("incomplete:rubric")
    slice_ = task.get("source_slice") or {}
    record = resolver.fetch(slice_.get("id"))
    if record is None:
        errors.append("unresolved:source")
    elif checksum(record) != slice_.get("checksum"):
        errors.append("stale:source")
    if not task.get("allowed_tools"):
        errors.append("missing:tools")
    return errors

Run it on every generated task, before human review and before any model call. Two operational details matter. First, run the lint in the generator's own CI, so a bad template fails fast rather than producing a thousand broken tasks. Second, sample the rejected tasks periodically; a rising rejection rate usually signals a source system drifting, not a generator bug.

Teams building synthetic eval sets across many models and modalities have a second problem after lint passes: running the grader cheaply and consistently. Routing judge calls through Quanta Inference keeps the pipeline behind one OpenAI-compatible key, which matters when the grader compares responses from several providers and you want costs in one prepaid balance.

FAQ

FAQ

Why is a synthetic task called a contract rather than a test case?

A test case usually lives inside one test suite written by one author. A synthetic task is generated in bulk and then graded by code or a judge that may be written by someone else and later run on different models. Because generator and grader share only the task spec, the spec has to state everything the grader needs, which is what makes it a contract rather than an assertion.

What happens if the failure rubric is empty?

The grader falls back to whatever default it has, usually surface-style judgment. That is exactly the condition that produces silent label errors: tasks look graded, scores look stable, and a real failure mode like an out-of-scope tool call goes unrecorded. An empty rubric should be a hard rejection at lint time, not a warning.

Does the source slice need a checksum if it already has a stable ID?

Yes. The ID lets you find the record, but only a checksum tells you whether the record still holds the bytes the task was generated from. Document stores allow structures to evolve without coordinated versioning, so a record can change underneath a stored task and quietly invalidate its labels.

How many failure modes should a task list?

Enough to cover its intent, typically one to five. More than that usually means the intent field is too broad and the task should be split. Named failure modes also tell a judge what to look for, and structured criteria are what make judge output consistent enough to compare across model versions.

Where should the lint rule run?

Inside the generator's continuous integration, before tasks are written to the eval set, and again as a gate before any grading run. Two checkpoints catch different problems: the first catches bad templates, the second catches sources that drifted after generation.

Sources

Sources

  1. LLM Evaluation Framework: Trajectories vs. Outputs - LangChain
  2. A methodical approach to agent evaluation | Google Cloud Blog
  3. A Vocabulary for Structural Validation of JSON
  4. Schema validation and evaluation framework for extracted ...
  5. What Is a Golden Dataset in AI and Why Does It Matter?
  6. How to Write an LLM Evaluation Rubric - Twine Blog
  7. Evaluate & Improve AI Agents for Production - YouTube
  8. LLM-as-a-Judge Simply Explained: The Complete Guide ... - Confident AI
  9. Carefully Evaluating the Evolution of ChatGPT Across Time
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles