1. Prepare the rows
Each row is one input and the exact JSON you expect back. A CSV with aninput and an output column is enough:
2. Create the task
json_f1 is a deterministic metric: it parses both sides as JSON and scores field-level overlap. No judge model is involved, so the score is exact and cheap.
3. Upload with a baseline prompt
prompt is the instruction you want to beat. The optimizer measures its gain against this baseline.
4. Optimize
optimize returns a Job. wait polls until the run finishes, then report returns the scores and the rewritten prompt. The run is gated by a minimum number of verified rows, so upload enough before you call it.
5. Ship the optimized prompt
prompts.get returns the latest versioned prompt; pass version= to pin an older one.
Call best.messages(...) rather than pasting best.text. The optimized text is
instruction text, not a template: it has no input placeholder and usually contains
literal JSON braces, so formatting it raises KeyError and substituting into it drops
your input without any error. messages() rebuilds the exact call the score was
measured with, so the number in the report describes the request you are sending.
If the optimized score does not improve, the prompt was already close to the ceiling for this data, or the metric does not match the task. Add cleaner rows or change the metric. The tool will not invent a gain.