GPT-6 Luna Structured Outputs: Extract JSON You Can Check
Build a GPT-6 Luna extraction request, validate evidence and handle incomplete responses. Download synthetic tickets, a schema and an offline Python lab.
GPT-6 Luna supports Structured Outputs, but your application still needs to decide whether the extracted values are supported by the source. This tutorial gives developers a small customer-ticket task with three output fields, a request example and local checks you can run before spending on an API evaluation.
We checked the Luna model documentation and Structured Outputs guide on September 24, 2026. The downloadable data is synthetic and the expected answers are authored. We tested the validator and response parser locally, not Luna’s accuracy or latency.
Define the extraction decision before the schema
Our teaching dataset contains four tickets: a duplicate charge, a sign-in problem, a cosmetic request and a message containing an instruction to ignore the schema. The last item is deliberately untrusted ticket content, not an instruction for the application to execute.
Return category, order_id and evidence. The category is billing, access or other; an absent order identifier is null; evidence is a short exact span copied from the ticket. Write down the classification policy before collecting answers. For example, a delivery notification with no request for help belongs to other in this exercise. A different real support team might use a shipping category instead.
Do not reuse the toy label policy without consulting the people who will act on the records. An extraction can satisfy the schema and still assign work to the wrong team. Keep the raw source alongside the result so a reviewer can reconstruct the decision.
Build a strict Responses request
Download the workflow lab and open request.json. Its model is gpt-6-luna, with an explicit reasoning.effort of none for this starting configuration. That is a reproducible setting, not a claim that it is the best effort for every extraction task.
The relevant output configuration is:
"text": {
"format": {
"type": "json_schema",
"name": "ticket",
"strict": true,
"schema": {"...": "use the complete schema.json in the lab"}
}
}
This fragment explains placement; it is not a complete executable schema. Use the full request JSON or schema. All three properties are required; order_id permits a string or null; additional properties are disallowed. The developer instruction fixes the extraction policy, while the user message holds the ticket as data.
Send the complete request through your own authorized Responses API integration. This article does not run that paid step for you. For endpoint and parameter differences, use the Sol/Luna migration guide.
Keep transport, schema and business checks separate
A successful HTTP response is only the first checkpoint. Inspect completion status and refusal content before treating output as data. The lab’s extract_text function iterates over message content instead of assuming the first output item contains the answer. It returns no accepted text for the incomplete and refusal fixtures.
| Check | What it establishes | What it does not establish |
|---|---|---|
| Response completed without refusal | Candidate text is available | Correct classification |
| Object has the expected keys and types | Application shape is usable | Truth of the values |
| Evidence occurs in the source | Quote was not invented | Quote supports the category |
| Order ID appears in the ticket | Identifier is grounded | Correct order ownership |
| Human-labeled comparison | Agreement on this sample | Accuracy on future traffic |
The local validator checks only part of this contract. It permits order_id: null even when the ticket contains an ID, so completeness needs a separate business check. It is not a general JSON Schema engine, and the response parser assumes the documented Responses object structure rather than validating arbitrary JSON. After parsing actual response text with a JSON parser, apply a maintained schema validator in production, then your own business rules. Authentication, timeouts, rate limits, persistence and retries remain responsibilities of the API client.
Run the offline checks and inspect the counterexample
Extract the archive into a directory, open a terminal there and run:
python3 lab.py test
The package needs Python 3 and no additional dependencies. Its 11 assertions include rejecting an invented ID, rejecting an invented evidence span, rejecting an extra key, and handling authored refusal and incomplete responses. No network request is made.
One deliberate counterexample changes the duplicate-charge ticket’s category to access while retaining a real quote. It passes the local structural and evidence checks but disagrees with the authored label. That is the point of the example: a schema-valid answer can still be semantically wrong. Eleven passing assertions are a test of these checks, not an 11-out-of-11 model score.
Measure a live evaluation without hiding failures
For a real pilot, use an independently labeled sample with duplicates, missing IDs, conflicting instructions, mixed languages and ambiguous cases. Split development examples from a held-out evaluation set. Have a second person review ambiguous labels before using them as ground truth.
Log the exact model ID, provider, effort, request ID, output status, raw result, usage and adjudication. Report at least schema-valid records, correct categories, supported IDs, unsupported claims, refusals and unresolved records. Keep failed attempts in both the denominator and the cost ledger; a retry is not a free replacement for the first request.
Set acceptance criteria before seeing the results. If a wrongly routed billing complaint has a high business cost, do not hide it inside one overall average. Review errors by class and language, and decide which cases require manual review. The Luna pricing guide explains the separate cost accounting, while the Luna-to-Sol routing tutorial uses the same fixtures to test escalation logic.
Frequently Asked Questions
- Does valid JSON prove the extracted data is correct?
- No. A valid category or quoted sentence can still support the wrong interpretation. Compare records with independently labeled examples.
- Were these examples generated by GPT-6 Luna?
- No. They are authored synthetic fixtures. The local tests check application logic; no live model accuracy is reported.
- What should happen when a response is incomplete?
- Keep it out of the accepted dataset. Record the status and decide whether a bounded retry or manual review is appropriate.


