Structured outputs¶
A request has an input (context, messages or an
image) and a schema: an object whose keys are the field names
you want back and whose values describe each field.
"schema": {
"merchant": {"type": "string", "extract": true, "instruction": "Store name"},
"total": {"type": "number", "integer": true, "instruction": "Final total"},
"paid": {"type": "bool", "instruction": "Was it paid?"},
"category": {"enum": ["food", "transport", "other"]},
"items": {"type": "list", "items": {"type": "string"}, "max_items": 10}
}
Every field is filled in parallel from the same input, and result
contains one value per field, in schema order.
Field types¶
| Type | Spec | Value in result |
|---|---|---|
| string | {"type": "string"} or just "string" |
text |
| number | {"type": "number"}; "integer": true for whole numbers |
number |
| bool | {"type": "bool"} |
true / false |
| enum | {"enum": ["a", "b", "c"]} |
one of the listed values |
| list | {"type": "list", "items": {...}, "max_items": 20} |
array (may be empty) |
| compute | {"type": "compute", "expr": "a / b * 100"} |
number calculated by code; see Computed fields |
| call | {"type": "call", "http": {...}} |
data fetched from an HTTP API; see Tool calls |
Aliases: boolean, integer / int (number with integer: true), float,
str, array (list). JSON-Schema style nullable types are accepted:
{"type": ["number", "null"]}.
number, bool and enum are constrained while they are generated: the
model can only produce a valid value. string is free text.
Options¶
| Option | Applies to | Meaning |
|---|---|---|
instruction (alias description) |
all | What the field means. This is the most important option for accuracy. |
nullable: true |
all | The field may be null when the input does not contain it. For enums, add null to the list instead: {"enum": ["a", "b", null]}. |
extract: true |
string | The value must be copied verbatim from the input: the model cannot invent or re-spell it. Use it for names, IDs, reference numbers. |
free_form: true |
string | Long text (reasoning, summaries, replies). Without it, the model is told to answer with only the value. |
max_digits |
number | Maximum characters of the number, including - and . (default 8). Money fields often need 10–12. |
integer: true |
number | No decimal point; the value is an integer. |
max_items |
list | Maximum number of items (default 20). |
items |
list | Spec of each item: string, number, bool or enum (not lists, not objects). |
depends_on: [...] |
all | Run after other fields and see their values. See Multi-step schemas. |
on: [...] |
all | Rules checked in code after the field is filled. See Flow rules. |
on_reject |
all | Value to use when a rule rejects the request before this field is filled. |
votes |
typed fields | Fill the field 1–5 times with different wordings and take the majority. See Confidence and review. |
Shared instructions: system¶
Put rules that apply to every field in system, not in each instruction:
{
"system": "You extract data from Indonesian receipts. Copy values exactly; write numbers without thousands separators. Never guess.",
"context": "...",
"schema": {...}
}
system is read once for all fields, so it costs nothing extra per field.
Writing good instructions¶
- Say what the value is, not how to find it. "Final total paid by the customer, in rupiah" beats "look for the total".
- Name the traps. If the document has a subtotal and a total, say which one you want. If tax can be called PPN, PB1 or Tax, list them.
- Define
null. "null if the document does not show a tax amount" is clearer than relying onnullablealone. - Give examples of odd formats. "(56rb = 56000)" fixed a real error.
- Keep one fact per field. Two small fields are more accurate than one field that asks for two things.
Limits¶
- An enum can have at most 24 values.
- Numbers are digits with an optional sign and decimal point; no thousands separators in the output.
- Lists hold simple values only (not objects) for now.
- Formatting requests in free text (bullets, date formats) are followed on a best-effort basis; use typed fields when the format matters.