← All courses ← Course home

Lesson 03 of 05

Turn signals into synthetic data

Write new examples from the signal. Review them. Then you may use Apple's SampleGenerator to grow the set.

Agent brief (llms.md)

A thumbs-down on "wrong fact" plus a feature name is enough to write three new prompt and target pairs. You write them. A second person reviews them. That is the seed set.

SignalWrong fact on feature X
SignalWrong fact on feature X
SeedHand-written pairs
SignalWrong fact on feature X
SeedHand-written pairs
GrowSampleGenerator

The Evaluations framework can generate more ModelSample rows, including trajectory expectations, as shown in WWDC26 session 299. Use that to grow evals and, if you choose, to draft training paraphrases. Keep the rejects. Do not train on a row nobody read.

Synthetic data will miss slang and languages you did not write. Say that out loud. It is still safer than uploading a week of chats to a public lab.

These rows feed two places: the eval harness in Test AI behavior before you ship, and the LoRA JSONL you will train on a Mac. Same facts. Two files if the formats differ. Evaluations SampleGenerator stays in Swift tests. The training file is Python because PEFT reads JSONL on the Mac.

import json
from pathlib import Path

rows = [
    {
        "instruction": "What is the refund window for order 1842?",
        "input": "",
        "response": "Order 1842 can be refunded within 30 days of delivery.",
        "reviewed": True,
        "signal": "wrong-fact",
        "feature": "support-refunds",
    }
]

out = Path("data/clean/train.jsonl")
out.parent.mkdir(parents=True, exist_ok=True)
with out.open("w", encoding="utf-8") as handle:
    for row in rows:
        if not row.get("reviewed"):
            raise SystemExit("unread row")
        handle.write(json.dumps(row, ensure_ascii=False) + "\n")
print("wrote", out, "rows", len(rows))
Rule. No unread synthetic row enters training.

Next, train and bake.

Key concepts

  • Hand-write seed prompt and target pairs from signals. A second person reviews them.
  • Evaluations SampleGenerator can grow reviewed paraphrases.
  • The same facts feed the eval harness and LoRA JSONL in different formats.
  • No unread synthetic row enters training.

Takeaways

  • SampleGenerator stays in Swift tests. The training file is Python for PEFT.
  • Reviewed synthetic rows are safer than uploading a week of chats.
  • Synthetic data misses slang and languages you did not write.