Guide
Decisions API vs Structured Outputs: which to use for classification
How the Decisions API differs from Structured Outputs for LLM classification and routing, where each one's confidence comes from, and how to combine them.
Updated - 7 min read
Before the Decisions API existed, the standard way to get a classification out of a language model was Structured Outputs: define a JSON schema with an enum, and the model fills it in. That still works. So when should you use which? The short answer is that they return different kinds of information, and the choice follows from what you need to do with the result.
The core difference
Structured Outputs constrains the shape of what a model writes. The Decisions API returns a typed answer with probability information. A useful rule of thumb: use Decisions when your application needs one of its three answer types, and Structured Outputs when you need to generate an object that follows your own schema, such as extracted fields or a written explanation.
// Structured Outputs: you define the shape, the model writes values into it.
const response = await client.responses.create({
model: "<a general-purpose model>",
input: [
{ role: "system", content: "Classify the support ticket." },
{ role: "user", content: ticketText },
],
text: {
format: {
type: "json_schema",
name: "triage",
strict: true,
schema: {
type: "object",
properties: {
team: { type: "string", enum: ["sales", "support", "billing", "other"] },
reason: { type: "string" },
},
required: ["team", "reason"],
additionalProperties: false,
},
},
},
});
// → { "team": "billing", "reason": "The customer disputes an invoice amount." }// Decisions API: you define the question, the model returns a typed answer.
const decision = await client.decisions.create({
model: "gpt-6-luna",
input: ticketText,
questions: [
{
type: "choice",
name: "team",
instructions: "Which team should own this ticket?",
choices: [
{ value: "sales" }, { value: "support" }, { value: "billing" }, { value: "other" },
],
},
],
});
// → { type: "choice", choice: "billing", confidence: 0.91,
// probabilities: [{ value: "billing", probability: 0.92 }, ...] }Side by side
| Decisions API | Structured Outputs | |
|---|---|---|
| Returns | A probability, a choice, or a score. | Any JSON object matching your schema. |
| Probability for each option | Yes, in the response. | Not part of the output. |
| Free text and explanations | No. | Yes. |
| Field extraction | No. | Yes. |
| Answer guaranteed to be one of your options | Yes. | Yes, with a strict schema and an enum. |
| Several questions about one input | Built in: one request, one copy of the input. | Possible, by adding fields to the schema. |
| Models | Decision models (gpt-6-luna at the time of writing). | General-purpose models that support it. |
| Maturity | Beta, announced September 2026. | Established. |
The part that matters: where confidence comes from
If you only need a label, either approach will give you one. The difference shows up when you need to know how much to trust it, which you do as soon as you want to automate some decisions and review others.
With Structured Outputs, there are two common ways to get a confidence value:
- Ask for one in the schema. Adding
"confidence": { "type": "number" }gets you a number. That number is text the model generated, like any other field. Nothing ties it to how often answers with that number are right. It may be useful, but you have to measure that yourself. - Read token log probabilities. Where the API exposes them, the probability of the token for each enum value is a real distribution. It takes more code, depends on how labels tokenize, and gets awkward for multi-token labels.
The Decisions API returns the distribution directly, as part of the documented response. That is its main practical advantage: thresholds, review routing, and calibration all start from a probability, and here you get one without building the plumbing.
When Structured Outputs is the better tool
- You need a reason in words. Customer-facing explanations, audit notes, and reviewer summaries are generated text.
- You need to extract values. Order numbers, dates, amounts, and names are not decisions.
- The answer isn’t from a fixed set. If the model has to propose something, it isn’t choosing among options.
- You need a model the Decisions API doesn’t offer, or you can’t build on a beta API yet.
When the Decisions API is the better tool
- You will act on a threshold. Automate above, review below.
- You are making the same judgment thousands of times and latency or cost per decision matters. At launch OpenAI described the API as about ten times faster than the Responses API; we have not independently measured that yet.
- You want several facts about one input and would rather not design a schema and prompt for each.
- You want the output to be boring. A typed answer has fewer ways to go wrong than generated JSON.
Using them together
These are not competing choices. A common design uses the Decisions API for the decision and Structured Outputs for the words around it, and only pays for the second when a person will read the result.
// 1. Decide. Fast, cheap, and thresholdable.
const { answers } = await client.decisions.create({ /* ... */ });
const main = answers[0];
// 2. Only for cases going to a person, generate a summary to help them.
if (main.type !== "refusal" && main.confidence < AUTOMATE_AT) {
const note = await summarizeForReviewer(ticketText); // Structured Outputs
sendToReview({ ticket, suggestion: main.choice, confidence: main.confidence, note });
}One caution: an explanation generated afterwards is a plausible summary of the input, not a record of how the decision model reached its answer. Label it accordingly for reviewers. If you need to show which facts the model found, use evidence checks, which are evaluated by the same model in the same request.
What we have and haven’t measured
This guide compares the two approaches by design, not by benchmark. We have not yet published measured accuracy, calibration, or latency for either. Our benchmarks page describes the dataset and method we will use, and states plainly which results exist so far. Treat any comparison that offers numbers without a method, including one from us, with suspicion.
Related
- Decisions API tutorial: request and response shapes in detail.
- Predicate vs choice vs score: the three answer types.
- Feature request classification template: a classification you could build either way.
Related guides
- Guide
Decisions API tutorial
Start here. The request and response shapes, how to read each answer type safely, asking several questions about one input, and what the API does not do.
- Guide
Evaluating AI decisions
Accuracy alone hides the mistakes that matter. How to build a test set, which numbers to report, how to read failures, and when an evaluation is good enough to act on.
- Guide
Calibration metrics
Three ways to measure calibration, what each one hides, and which to use for which question, with code that computes them from labeled decisions.
Templates that use these ideas
- Choice
Feature request classification
Whether a message is a bug report, a feature request, a how-to question, or something else.
- Choice
Customer message routing
Which team should own a customer message: sales, customer success, support, or billing.
- Predicate
Spam detection
Whether an inbound message is spam rather than a real customer contact.
Put it into practice
Try a decision, check it against labeled examples, and talk to us if you want help building one for your workflow.