> ## Documentation Index
> Fetch the complete documentation index at: https://docs.freesolo.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Structured outputs

> Constrain training rollouts and served responses to valid JSON, a regex, or a fixed choice set with guided decoding.

**Guided decoding** forces the model to emit only text that matches a constraint —
a JSON schema, a regular expression, or one of a fixed set of choices. Once the
grammar is active, the sampler cannot produce off-format answer tokens.

You use it in two places:

* **In training:** use a JSON schema, regex, fixed choice set, or any-JSON
  constraint so your reward measures the answer's *content* instead of malformed
  wrappers.
* **At serving:** the training constraint becomes the adapter default. The
  OpenAI-standard per-request override supports `text`, `json_object`, and
  `json_schema`. Give the request enough output tokens and check `finish_reason`
  for truncation.

## In training

`structured_outputs` in the `[train]` table constrains every GRPO and OPD rollout.
It applies only to the rollout algorithms — SFT never samples, so it rejects the
key at submit. When rollouts can't drift off-format, your `score_response` parses
the field it cares about directly and rewards the content, which makes the reward
easier to write and the signal cleaner.

### Write a constraint

Set exactly **one** constraint under `[train]`. A JSON schema is the common case;
write it as a JSON string or an inline TOML table.

<CodeGroup>
  ```toml JSON schema (string) theme={null}
  [train]
  structured_outputs = '{"type": "object", "properties": {"answer": {"type": "string"}}, "required": ["answer"]}'
  ```

  ```toml JSON schema (inline table) theme={null}
  [train]
  structured_outputs = { type = "object", properties = { answer = { type = "string" } }, required = ["answer"] }
  ```

  ```toml Choice theme={null}
  [train]
  structured_outputs = { choice = ["yes", "no", "maybe"] }
  ```

  ```toml Regex theme={null}
  [train]
  structured_outputs = { regex = "\\d{4}-\\d{2}-\\d{2}" }
  ```

  ```toml Any JSON theme={null}
  [train]
  structured_outputs = { json_object = true }
  ```
</CodeGroup>

| Constraint  | Write it as                                                                 | Forces the output to be              |
| ----------- | --------------------------------------------------------------------------- | ------------------------------------ |
| JSON schema | a JSON string or inline table; key `json` (aliases `json_schema`, `schema`) | JSON matching your schema            |
| Choice      | `{ choice = ["a", "b", ...] }` (alias `choices`), non-empty strings         | exactly one of the listed strings    |
| Regex       | `{ regex = "..." }`                                                         | text matching the pattern            |
| Any JSON    | `{ json_object = true }`, or the string `"json_object"`                     | any valid JSON, with no fixed schema |

A bare schema table with **no** constraint key is read as a JSON schema — its
`type`/`properties` keys are schema vocabulary, not Flash's. Setting more than one
constraint, or the unsupported `grammar` / `structural_tag` forms, is rejected at
submit. To turn guided decoding off, omit the key or set `false`, `""`, or
`"none"`.

### Options

These optional keys tune the constraint. Set them **alongside** a constraint (an
option on its own is rejected):

| Option                          | Type   | Effect                                                                                           |
| ------------------------------- | ------ | ------------------------------------------------------------------------------------------------ |
| `disable_any_whitespace`        | bool   | Forbid insignificant whitespace, so JSON comes out compact (and decodes slightly faster).        |
| `disable_additional_properties` | bool   | Reject object properties your schema doesn't declare, even when it omits `additionalProperties`. |
| `whitespace_pattern`            | string | Custom pattern for the whitespace the sampler may emit between JSON tokens.                      |

```toml theme={null}
[train]
structured_outputs = { json = { type = "object", properties = { answer = { type = "string" } }, required = ["answer"] }, disable_any_whitespace = true }
```

### Thinking mode

Structured outputs work with `thinking = true`. For a single-turn rollout and
the first assistant turn of a multi-turn rollout, reasoning remains free-form and
the grammar begins after the model closes `</think>`. The final answer must
satisfy the configured constraint.

A later multi-turn prompt may already contain an earlier `</think>` boundary, so
its grammar can apply from the first new token. Test later-turn behavior when a
multi-turn environment combines thinking and structured outputs.

Keep the reasoning and final answer within `max_completion_tokens`. An unclosed
or truncated thinking block never reaches the constrained answer and is invalid.

### Score a completed constrained answer

For a non-truncated rollout that reaches the constrained final answer, the
wrapper is guaranteed. Still return zero if reasoning or generation ends before
that answer is complete:

```python theme={null}
import json

def score_response(self, example, completion: str) -> float:
    try:
        answer = json.loads(completion)["answer"]
    except (json.JSONDecodeError, KeyError, TypeError):
        return 0.0
    return 1.0 if answer.strip() == example.output.strip() else 0.0
```

## At serving

A deployed adapter or a base model accepts the OpenAI-standard `response_format`.
A training `structured_outputs` constraint becomes the deployed adapter's
default. A request-level `response_format` overrides that default without a
redeploy:

```python theme={null}
resp = client.chat.completions.create(
    model="<run-id>",
    messages=[{"role": "user", "content": "Give me a person as JSON."}],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "schema": {
                "type": "object",
                "properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
                "required": ["name", "age"],
            }
        },
    },
)
```

`{"type": "json_object"}` forces any valid JSON with no fixed schema, and
`{"type": "text"}` leaves output unconstrained. With thinking enabled, reasoning
remains free-form and the requested grammar begins after `</think>`. Give each
request enough output tokens and check `finish_reason` before parsing the answer.

Every real adapter deployment runs a bounded smoke when a default constraint is
present. Deployment fails before alias activation if output is invalid or leaves
thinking unclosed or truncated. See
[Deploy & chat](/guides/deploy-and-chat#structured-outputs).

## Next steps

<CardGroup cols={2}>
  <Card title="Configuration reference" icon="gear" href="/reference/configuration#structured-outputs">
    The `structured_outputs` field in the training config.
  </Card>

  <Card title="Deploy & chat" icon="comments" href="/guides/deploy-and-chat#structured-outputs">
    Constrain a served model's responses per request.
  </Card>
</CardGroup>
