What structured output guarantees, and what it does not
The OpenAI documentation says structured outputs make the model always produce a response matching your JSON Schema: required fields are present and enum values are valid.Source: OpenAI structured outputs · 2026-10-12
That solves format. What it does not guarantee:
- That the value is right: a valid field is not a correct category.
- How certain the answer is: you get an enum value but not the model's confidence.
- Edge cases: the OpenAI documentation also states that a refusal or hitting the max-token limit can produce output that does not match the schema, and you handle that separately.Source: OpenAI structured outputs · 2026-10-12
What a decision model returns
A decision model takes state plus questions in and returns answers and probabilities, without generating text. State is whatever you want judged — text or JSON. There are three question types:
- Choice: pick one option; returns a probability and confidence per option.
- Score: rate on an ordered scale; returns a probability for each level.
- Noul: yes/no; returns P(true).
Source: System One decision primitives · 2026-10-12
New to this kind of model? Start with what is a decision model?.
Field mapping: which parts of your schema can move
| Original schema field | Becomes | Notes |
|---|---|---|
| `enum` (one of several categories)Source: System One decision primitives · Verified 2026-10-18 | Choice | Up to 255 options |
| `boolean` (yes or no)Source: System One decision primitives · Verified 2026-10-18 | Noul | Returns P(true) |
| A rating field (e.g. 1–5)Source: System One decision primitives · Verified 2026-10-18 | Score | Up to 10 levels |
| Free text, summaries, extracted names and numbersSource: OpenAI structured outputs · Verified 2026-10-18 | Stays with structured output | The answer cannot be listed in advance |
The test is simple: can the answer be listed in advance? If it can, a decision model answers it. If it cannot, the large model generates it.
The problem with a "confidence" field
Many schemas add a confidence field and ask the model to report a number from 0 to 1. That number, like every other field, is generated by the model.
A decision model returns probabilities per option: one probability for each option, derived from the model's judgement over those options, not written out as text.
This page compares mechanics only; it does not claim one is more accurate. Either way, thresholds have to be validated on your own labelled data.
Rewrite example: a ticket-classification schema
The original schema has three fields: category (enum), urgent (boolean) and replyDraft (string). The first two become a Choice and a Noul in one decision-model request; the draft stays with the large model.
The code below is illustrative and has not been run.
Before: one JSON Schema
ts// Illustrative code, not tested
const ticketSchema = {
type: 'object',
properties: {
category: { type: 'string', enum: ['billing', 'bug', 'account', 'other'] },
urgent: { type: 'boolean' },
replyDraft: { type: 'string' },
},
required: ['category', 'urgent', 'replyDraft'],
additionalProperties: false,
};
After: the decision goes to a decision model, the reply stays with the large model
ts// Illustrative code, not tested
import { choice, booleanQuestion } from '@system-one-ai/core';
import type { EvaluationClient } from '@system-one-ai/core';
const ticketQuestions = {
category: choice('Choose the category of this support ticket.', {
billing: 'Payments, invoices, and refunds',
bug: 'The product is broken or behaves unexpectedly',
account: 'Login, profile, or permission issues',
other: 'None of the above',
}),
urgent: booleanQuestion('Does this ticket need a response within one hour?'),
};
export async function classifyTicket(client: EvaluationClient, ticket: string) {
const result = await client.evaluate({ state: { ticket }, questions: ticketQuestions });
return {
category: result.answers.category.choice,
categoryConfidence: result.answers.category.confidence,
urgentProbability: result.answers.urgent.probability,
};
}
// The reply draft: generate it with the large model's structured output after the
// category is chosen; the schema then keeps only replyDraft.
For how the client is created, see what is a decision model?. Model IDs come from GET /v1/models; don't copy them by hand.
Combining them: decide first, generate second
- Let the decision model decide first: which branch, and whether a person is needed.
- High confidence follows the branch; low confidence goes to a person or to the large model.
- Inside the branch, generate the content it needs — a reply draft, for example — with structured output.
Set thresholds on your own labelled samples. For more combination patterns, see Jev vs ChatGPT, agent tool routing and using a decision model as the first pass in agent evaluation.
How the cost works
Every 4KB is one block, and anything smaller still counts as one block. Cost = blocks × questions × the model rate.
| Model | Credits per question per block |
|---|---|
| Jev | 1 |
| Clef Flash | 3 |
| Clef Omni | 4 |
| Clef | 6 |
| Decider | 1 |
Source: system-one.dev pricing · 2026-10-12
- Blocks are counted over the whole request's bytes.
- More questions in one request multiply the cost by question count. The rewrite above asks 2 questions, so the cost is 2 × blocks × rate.
- Large models bill per token, a different meter; per-unit prices are not directly comparable. Cost both on your own typical request.
New accounts start with 100 credits, and credits never expire. For how to choose a model, see Jev vs Clef.
Want to try? Run a sample (sign-in required).
Related reading
- What is a decision model?
- Jev vs ChatGPT
- Jev vs Clef: choosing a hosted model
- system-one.dev pricing
Verified 2026-10-12