Attributed compile + one small offline smoke test
Primary sources (OpenAI, 2026-10-22): Build more responsive apps with the Decisions API (OpenAI blog), Decisions (developer guide), Decisions API is now generally available with new updates (Community), GPT-6 Luna + Pricing for list rates
Also trending on: 掘金 AI 日报 2026-10-23 (OpenAI Decisions API GA callout)
Latency multiples, customer speedups, and cost-savings quotes are OpenAI's / customers'. This box has noOPENAI_API_KEY, so I did not callPOST /v1/decisions. What I ran is an offline request/response linter against hand-built mocks from the docs, described below as exactly that.
OpenAI made the Decisions API generally available on 2026-10-22, powered by gpt-6-luna only. Same product category as Liquid's open d1 and Microsoft-Decision-1 (covered earlier as post #16): stop begging a chat model for JSON and ask a decision endpoint for a typed probability, choice, or score. Different vendor, different path, different pricing — and this one sits next to the Responses API you already use.
Chinese digests on 2026-10-23 led with the GA. The practical question for an applied-AI stack is narrower: when does /v1/decisions beat routing the same Luna call through Responses?
What GA added (vs beta)
From OpenAI's blog and guide, since public beta:
- Up to 400 questions per request (was 200)
-
Prompt caching on shared
input - Native
input_jsoncontent parts - Images in question instructions (compare candidates against a shared reference)
- Native GPT-Live integration
- US / EU regional processing; ZDR for eligible customers
OpenAI's claim (label as vendor): Decisions is up to 10× faster than GPT-6 Luna via the Responses API for bounded answers. I did not measure that.
Three answer types
| type | you ask | you get |
|---|---|---|
predicate |
is this condition true? |
probability in [0, 1]
|
choice |
pick one of my options |
choice + per-option probabilities + confidence
|
score |
rate against ordered levels (2–10) | probability-weighted level index |
No free-form prose. That is the point. Your code thresholds the number and routes, gates, or escalates.
First request shape
Endpoint: POST /v1/decisions. Model field: gpt-6-luna only. Shared evidence goes in input (string or message array). Questions are an array (not Microsoft's name→object map from post #16).
from openai import OpenAI # only if you have a key; I did not call this
client = OpenAI()
decision = client.decisions.create(
model="gpt-6-luna",
input="I was charged twice for my order.",
questions=[
{
"type": "predicate",
"name": "duplicate_charge",
"instructions": "Does the message describe a duplicate charge?",
},
{
"type": "choice",
"name": "department",
"instructions": "Which department should handle this complaint?",
"choices": [
{"value": "billing", "description": "Payments, invoices, and refunds."},
{"value": "technical", "description": "Problems using the product."},
{"value": "shipping", "description": "Delivery and tracking."},
{"value": "other", "description": "Requests outside these categories."},
],
},
{
"type": "score",
"name": "severity",
"instructions": "How severe is this issue?",
"levels": [
{"label": "Cosmetic", "description": "Appearance only."},
{"label": "Workaround available", "description": "Task fails; another way works."},
{"label": "Fully blocked", "description": "Task fails with no workaround."},
],
},
],
)
# answers = decision.answers # typed; threshold in your code
Three habits before production:
-
Always include an abstention option on
choice(other/cannot_tell). Without it, junk still gets a department. -
Put reusable context in
input, not in every question — that is what prompt caching discounts. Question content is outside the reusable prefix; OpenAI says the prefix needs ≥1,024 tokens to cache. - Dependent decisions are separate requests. Independent checks (damage + category) can share one call; "if damaged, then repair type" needs a second call after you see the first answer.
For structured app state, pass input_json inside a user message instead of stringifying first — keys inside data are ordinary data, not messages.
Cost math (published list prices only)
OpenAI lists Decisions at $0.10 / 1M uncached input, $0.01 / 1M cached input, and no output-token charges. Cache writes follow Luna rates on the pricing guide: $0.125 / 1M (30m) and $0.25 / 1M (12h). GPT-6 Luna via Responses still lists $0.50 / 1M output on the model page — relevant only as a hypothetical if you had generated prose or JSON there instead.
Illustrative arithmetic (not a bill): 10,000 requests/day × 2,000 input tokens
| path | day cost (list) |
|---|---|
| Decisions, all uncached | $2.00 |
| Decisions, all cached reads | $0.20 |
| Hypothetical Responses Luna, same 2k in + ~150 out tokens | $2.75 |
The free-output line is why decision endpoints look cheap for hot-path routing: you are not paying for a rationale you would throw away. Caching is where the bigger gap appears once a shared policy doc or reference image sits in input.
What customers told OpenAI (quotes, not my numbers)
Attributed to the GA blog:
- Box (Biswaroop Palit): ~5× faster route selection on 30 certificate-of-insurance cases, same accuracy as Responses.
- Datadog (AJ Stuyvenberg): 40× faster p95 scoring agent-generated rshell risk before remediating.
- Ramp (René Sultan): 4× faster and 30% cheaper AI-cost attribution vs GPT-6 Luna.
- Sierra (Ajeet Grewal): under 280 ms p95, ~3× faster and 90% lower cost per call.
- Speak (Andrew Hsu): GPT-Live + Decisions cut time-to-next-action from 1.4s → 0.13s.
Treat those as launch anecdotes. Measure on your labeled tickets.
Light contrast with Microsoft-Decision-1
Same category, different shelf. Microsoft-Decision-1 (post #16) is a Foundry / OpenRouter systemone surface with noul / choice / score, list input around $0.042 / 1M, and a planned Qwen→MAI/OpenAI rebase. OpenAI Decisions is predicate / choice / score, $0.10 / 1M uncached, Luna-only, images + JSON + Live, and lives next to your existing OpenAI key. If you already ship on OpenAI, Decisions is the lower-friction hot path; if you live in Azure and need Foundry residency, Decision-1 stays the natural fit. Do not assume the probability calibrations match across vendors — re-threshold.
What I actually ran (offline)
No OpenAI key on this box, so I wrote a preflight that only checks shapes and list-price arithmetic:
- A legacy
messagesbody is flagged as the wrong API. -
model: gpt-6-solis rejected (Luna only). - A multi-question body with
predicate+choice+scorelints clean. - An
input_jsonuser-message body lints clean. - A two-option
choicewithout abstention gets a warning. - 401 questions trips the GA 400 cap.
- A hand-built mock
answersarray (shaped like the docs' illustrative excerpts) parses; a chat-completions mock raisesValueError: missing answers array. - The $2.00 / $0.20 / $2.75 figures above are the same published-rate arithmetic the script prints.
That is a smoke test of your client, not of Luna. Scripts: runs/25-decisions-api/ (preflight.py, run_output.txt).
When I'd prefer Decisions over Responses
- Hot-path classify / route / gate where the answer is one of a fixed set or a probability you threshold.
- Many independent questions over the same evidence (batch up to 400).
- Voice / Live loops that need a reaction without waiting for a full chat turn.
- Shared long prefix (policy, catalog, reference image) where cache reads dominate.
Keep Responses (or a stronger model) when you need generated text, tool-call arguments, or a custom JSON schema that is not a predicate/choice/score. Decisions does not replace writing. It stops you from using a writer for a multiple-choice question.
Wire it like any other decision model: log input, question definitions, answers, and the action you took; tune thresholds on labeled examples; escalate on low confidence or other. Then decide whether OpenAI, Microsoft, or an open d1 wins on your tickets — not on anyone's launch blog.
YongBo Yu · Toronto AI engineer · https://yongbo-yu.vercel.app · GitHub YongBoYu1
Top comments (0)