Skills DirectorySearch all skills ↗

AI agent skill · by @sunny-glow

Tool Use Data Synthesis

Synthesize training data for ANY tool-use / agentic benchmark, in ANY repo. Given a handful of runnable reference tasks, produce thousands of "same-distribution, different-entity" tasks, roll out real trajectories, and emit SFT, RL data. Use this when: you have a tool-calling / MCP / agentic benchmark and want to expand a few dozen tasks into thousands of in-distribution training samples without changing the environment or tools; when synthetic data mysteriously LOWERS the benchmark score and you need to diagnose why; or when you must produce checkable ground-truth for agentic tasks and cannot trust an LLM to fabricate facts. The first decision is set by the benchmark's SCORING MECHANISM (rule-based vs LLM-judged), which picks one of two synthesis paradigms. The overriding principle throughout is DISTRIBUTION ALIGNMENT.

Archived 2026-10-23 · Source updated 2026-07-24. Check the original repository for the latest version.

SKILL.md instructions

# Tool-Use Data Synthesis

## Overview

This skill is a **generic recipe** for synthesizing training data inside any **tool-calling
environment**, validated end-to-end on two very different benchmarks (one LLM-judged, one
rule-based). The
concrete goal: you have N runnable benchmark tasks and want to expand them into K×N "same-pattern,
different-entity" tasks, then roll out real trajectories for SFT.

What makes tool-use synthesis different from **plain-text QA synthesis**: the entities in a tool-use
task must **really exist in the environment and be reachable by the tools**, and the task must be
**scorable** by whatever mechanism the benchmark uses. You cannot swap in a book/repo/order that
doesn't exist — the task becomes unsolvable and the trajectory is garbage. And you cannot invent a
"gold answer" for free — how the benchmark scores decides *how* you must produce ground-truth.

Two things carry the entire skill. Internalize both before touching code:

1. **The scoring mechanism dictates the paradigm.** Read the evaluator FIRST. It splits the world in
   two (see the decision below). Choosing the wrong paradigm wastes days.
2. **Distribution alignment is the whole game.** Synthetic data that is *structurally simpler* than
   the target benchmark does not "clean up" the distribution — it **shifts** it, and training on it
   **lowers** the score. This is not a corner case; it is the single most common way tool-use
   synthesis silently fails. See "The overriding principle" below.

## The first decision: read the evaluator, pick the paradigm

Before generating anything, find and read the benchmark's scoring code. Ask one question: **is the
final reward computed by a deterministic rule, or by an LLM judge?** The answer picks the paradigm.

```
                      ┌─────────────────────────────────────────────┐
                      │  Read the benchmark's evaluator/scoring code  │
                      └─────────────────────────────────────────────┘
                                          │
            ┌─────────────────────────────┴─────────────────────────────┐
            ▼                                                             ▼
  Reward is RULE-BASED / deterministic                     Reward is LLM-JUDGED / free-text
  (DB-state hash, exact/substring match,                   (a judge model rates the answer,
   env-state assertions, unit tests)                        per-claim coverage, rubric score)
            │                                                             │
            ▼                                                             ▼
  PARADIGM B: construct-then-verify                        PARADIGM A: execute-then-extract
  Ground-truth must EXIST BEFORE the rollout               Ground-truth is EXTRACTED AFTER the rollout
  (you build gold actions/answer, then replay              (generate prompt only, roll it, then pull
   through the evaluator to self-check it scores)           atomic-fact claims from the real answer)
            │                                                             │
            ▼                                                             ▼
  → references/paradigm-b-construct-then-verify.md         → references/paradigm-a-execute-then-extract.md
```

Why this is the root fork, in one sentence each:

- **Rule-based evaluators score against a pre-existing target** (a target DB hash, an assertion over
  final device state, an expected string). You therefore must **produce the ground-truth up front**
  and prove it is valid by replaying it through the *same* evaluator interface at construction time.
  You cannot "roll first and see" — there is nothing to roll against until the gold exists.
- **LLM-judged evaluators score free-text answers**, so there is no pre-existing target to hit. You
  **roll first**, then extract checkable claims from the answer the strong model actually produced.
  Realness of entities is enforced by execution + filtering (unreal entity → empty answer → dropped).

A benchmark can even mix both across task types (e.g. one task type scored by DB-hash + substring,
another by env-assertions within the same benchmark). Classify **per task type**, not per benchmark.

Quick evaluator-reading checklist (do this for every new benchmark):
- What is the top-level reward function, and how does it combine sub-scores (product? mean? min?)?
- What is each task's `reward_basis` / enabled dimensions? Which sub-scores actually count?
- For rule-based: what exactly is compared — a state hash, a substring, an assertion function? Are
  read-only tool calls scored at all? (Often not — e.g. a benchmark may not score `calculate`/`get_*`.)
- For substring/text checks: is there normalization (lowercasing, comma-stripping)? That dictates
  number/string formatting in your gold (e.g. `1,234.5` must be emitted as `1234.5`).

## The overriding principle: align the distribution — to sub-type granularity

This principle governs **both** paradigms and is the highest-leverage thing in the skill.

Synthetic data must match the **structural distribution** of the target benchmark. A distribution
that is *simpler* than the target is not cleaner data — it is **distribution drift** that drags the
model toward an easier behavior and **lowers** the benchmark score.

Real, measured example (a rule-based retail-style benchmark, first synth version):

| metric | official base (114) | v1 synth (1000) | result |
|---|---|---|---|
| avg writes / task | 1.56 | 1.00 | |
| tasks with ≥2 writes | 39% | 0% | |
| tasks with communicate-info | 33% | 0% | |
| → benchmark effect | — | — | **score DROPPED** |

v1 taught the model a "find user → read one order → do one step → stop" distribution and drowned out
the compound operations and information-return the benchmark actually tests. The fix was to rebuild
the generator to hit the official structural stats (multi-write %, communicate %, tool mix).

But hitting the **top-level** stats is not enough. The second, subtler lesson: **align to sub-type
granularity.** After v1's fix matched avg-write and communicate-rate, the model still scored only
65.79% on base — because the official `communicate` dimension has **four sub-types** (amount-sum,
per-order amounts, item count, product attribute) and the official write-tasks include a
**pending+delivered mixed** case, and the synth had covered *none* of those sub-types. Top-level
metric parity ≠ real parity. Enumerate the sub-types the benchmark exercises and cover each.

Practical rule: **before generating, compute the target's structural histogram** (writes/task,
tool-type mix, communicate-type mix, multi-step %, mixed-mode %), and after generating, compute the
same histogram on your synth and diff them. Treat any gap as a bug.

## Diagnose from failures: let the benchmark tell you what data is missing

The most reliable way to know *which* distribution gaps matter is not to guess — it is to **train on
your synth, run the target benchmark, and read the failure analysis.** The failures ARE the data
requirements document.

The loop:
1. Train on the current synth; run the official benchmark; collect the failing tasks.
2. For each failure, read the reward sub-scores to see *which dimension* failed (a DB/state mismatch?
   a missing communicated value? a wrong tool choice?).
3. Cross-reference three things at once: **(a) the failure analysis, (b) the official base's
   structural stats, (c) what your generator currently produces.** The gap between (b) and (c) that
   also shows up in (a) is your next batch of data to synthesize.
4. Add exactly that distribution to the generator; re-verify at construction time; re-roll; re-test.

This "failure → gap → targeted synth" loop is how one rule-based benchmark went from a diagnosis of "three
missing sub-distributions" (mixed pending+delivered writes, count/attr/per-order communicate,
`calculate` usage) to a targeted generator fix — rather than blindly adding volume.

A caution when reading failures: **low pass-rate ≠ weak model.** First bucket failures by reward
sub-score and by task type. If simple task types pass at 90%+ while one type is at 0%, the culprit is
almost always a **task bug** (missing info in the prompt, an unsolvable entity), not model weakness.
(In one benchmark, address tasks scored 0% purely because the generated prompt omitted the `address2`/`Suite`
line the gold action required — the agent had no way to know it. Fixing the prompt took it to 100%.)

## What is common to both paradigms

Regardless of paradigm, these hold:

- **Vary entities/wording, never the tool skeleton.** A synthesized task must be solvable with the
  *same* toolset as its reference. No tool recombination — that changes difficulty and breaks
  same-distribution.
- **Tasks over fixed local resources cannot swap entities freely.** Tools like `filesystem`/`git`
  operate on files mounted in the environment; their "entity" is the fixed inventory under `/data`,
  not an arbitrary real-world thing. For these, **vary the question, not the path** — dump the real
  inventory first and force generation to range only over real files.
- **Self-contained prompts.** The solver is typically told never to ask the user for clarification,
  so every needed detail (full address incl. suite, every product option, exact target) must be in
  the prompt. A dropped detail = a guaranteed failure the model cannot recover from.
- **The evaluator-interface replay is the lifeline.** Whether you verify gold up front (B) or filter
  answers after (A), you must run through the *same* interface the real evaluator uses. Placeholder
  tool outputs will fail replay checks — use the environment's real tool responses.

## Paradigm references (read the one your evaluator selected)

| Reference | When | Core loop |
|---|---|---|
| [references/paradigm-a-execute-then-extract.md](references/paradigm-a-execute-then-extract.md) | LLM-judged / free-text answers | generate prompt → roll → extract claims from real answer → filter empties |
| [references/paradigm-b-construct-then-verify.md](references/paradigm-b-construct-then-verify.md) | Rule-based / deterministic scoring | build gold actions (block + compose) → replay through evaluator to self-check → phrase → roll |
| [references/operational-playbook.md](references/operational-playbook.md) | Both — read before any full run | capturing the exact API payload (messages/tools) as the only complete data, resume/checkpoint discipline |

## Quick start (both paradigms share this shape)

```
0.  Read the evaluator → classify each task type as rule-based (B) or LLM-judged (A).
1.  Compute the target benchmark's structural histogram (the alignment target).
2.  Build the generator for your paradigm:
      A: templates → generate prompts → (roll) → extract+filter claims
      B: entity samplers / blocks → compose → construct-time verify (replay)
3.  Smoke-test tiny (e.g. --num 300, no-LLM if possible): diff your synth histogram
    vs the target; run positive/negative construct-time checks; hand-inspect a few.
4.  Scale up; roll trajectories (mind the rate-limit ceiling; resume is your friend).
5.  Run the official benchmark; read failures; feed gaps back to step 2. (Failure-driven loop.)
```

**Always smoke-test before a full run.** For paradigm A, spot-check that prompts are self-contained,
entities are real (look up 2–3 by hand), and each claim matches the answer. For paradigm B, diff the
structural histogram against the target and confirm positive checks reward=1 / negative checks
reward=0 for **each** sub-type you generate.

## Resources

- `references/paradigm-a-execute-then-extract.md` — full 5-stage pipeline for LLM-judged benchmarks
  (templates → generate → roll → extract → convert), with a reference implementation.
- `references/paradigm-b-construct-then-verify.md` — full pipeline for rule-based benchmarks (block
  samplers, `compose_for_user`, construct-time replay verify, communicate/answer typing,
  distribution control), with a reference implementation.
- `references/operational-playbook.md` — cross-cutting operational hard-won lessons: capturing the
  exact `messages`/`tools` payload at the API call site as the only complete training data, and
  resume/checkpoint discipline.

This skill provides methodology; the executable scripts vary with each benchmark's interface. Adapt
the reference implementations named in each paradigm doc.

Related skills