hamsa software
← All articles
AI developments8 min read

What a valid JSON response can promise

The August 2024 announcement made output shape more dependable. A worked repairs enquiry shows why structure, evidence and diary availability still need different checks.

A magnifying glass overlaps a lined sheet, suggesting closer inspection of the difference between a valid record and its source.

The neat object is only the beginning

A date can arrive in precisely the right field and still be the wrong day. That is a useful place to start when deciding what structured model output buys an application. Having dependable JSON removes the work of stripping introductions, repairing trailing commas and persuading a paragraph to become a record. It also leaves us with a much easier object to inspect when the proposed appointment disagrees with the customer’s message.

OpenAI announced Structured Outputs on 6 August 2024, describing schema-constrained outputs for supported API use [1]. For software consuming the response, the stronger contract reduced the guesses needed to parse it. The checks that remain after parsing concern whether the values reflect the enquiry and whether the business can act on them. Those questions require evidence beyond the shape of the response.

Take an invented repairs enquiry asking for a visit on 13 August at 9 Pine Road. The accompanying checker uses hand-written candidate records, rather than calling a model, to separate the decisions an application must make. One candidate changes the day; another changes the house number. Both look orderly. Putting the message beside them reveals the disagreement immediately, which is more helpful than asking a single validation result to stand for parsing, faithful extraction and permission to book.

Four fields, three different questions

The source message says: Please visit on 13 August 2024 at 9 Pine Road. A useful draft keeps the requested date and address beside the words supporting them. Here those four fields are requested_date, date_evidence, requested_address and address_evidence, each accepting text or an explicit null. The faithful candidate pairs 2024-08-13 with 13 August 2024 and preserves 9 Pine Road. The office can inspect both the proposed value and the part of the message it claims to represent.

A second candidate uses 2024-08-14 but keeps the same evidence phrase. It is still JSON, still an object, and still has four permitted string values. A third changes the proposed address to 99 Pine Road. A shape validator accepting either object has done its own job correctly. It was asked about keys and value types, not whether those values corresponded to the message.

JSON Schema’s object documentation distinguishes property definitions, required properties and restrictions on additional properties [2]. Those choices need to be explicit in a real contract. Declaring that a property can contain text does not require it to appear; defining known properties does not by itself reject extra ones. A superficially strict-looking schema may therefore be looser than its author intended, even before semantic accuracy enters the discussion.

A production integration needs a complete JSON Schema validator and the request configuration appropriate to its API version. The downloadable checker only enforces this four-field nullable-string contract. The August announcement explains the feature as released; current documentation covers implementation and failure handling [3]. Keeping those responsibilities clear matters when replacing this small checker: a stricter validator can reject extra fields or a missing property, but it still needs a separate way to discover that the customer asked for the thirteenth and the record proposes the fourteenth.

Which part of the response can be checked?

The repairs example separates API response handling from four-field interpretation.

Follow the labelled arrows. On a narrow screen, scroll sideways if needed.

Which part of the response can be checked?Identify the response kind. The adapter distinguishes output, refusal and incomplete before field interpretation. Refusal or incomplete. These are non-output outcomes; they bypass the field checker. Check the object contract. Required nullable strings: property definitions, presence and additional-property restrictions are separate decisions. Check source support and diary state. An accepted object still needs agreement with the enquiry and a check of current appointment availability. From Identify the response kind to Refusal or incomplete: Non-output. From Identify the response kind to Check the object contract: Output. From Check the object contract to Check source support and diary state: Shape accepted.Non-outputOutputShape acceptedIdentify the responsekindThe adapter distinguishesoutput, refusal andincomplete before fieldinterpretation.Refusal or incompleteThese are non-outputoutcomes; they bypass thefield checker.Check the objectcontractRequired nullable strings:property definitions,presence andadditional-propertyrestrictions are separatedecisions.Check source supportand diary stateAn accepted object stillneeds agreement with theenquiry and a check ofcurrent appointmentavailability.
The local checker implements only the stated tiny shape contract, not a complete provider integration.

Put evidence next to the value

The date and address comparisons use an answer key labelled by hand. The wrong-day and wrong-house candidates pass the shape check, then fail against those expected facts. For an explicit message, that disagreement is straightforward to explain: the retained phrase names 13 August, while the proposed value names 14 August. A reviewer can correct the value without wondering whether the diary caused the rejection. Less explicit messages require a different response, because there may be no single date in the source to compare with the draft.

In production, the evidence stage might combine deterministic checks with review. A clearly stated date can be compared with a parsed source phrase. A reference to the usual address may require an authorised customer lookup and still remain ambiguous if several addresses exist. Do not give every extracted value the same apparent status merely because each occupies a column. Stated, resolved from another record and inferred are different reasons to believe a value.

Consider a second constructed message: Tuesday afternoon would be ideal; use the same address as before. A record with unresolved date and address can be a faithful intermediate result. The message contains preferences, but this contract has not established which date or which address. Converting absence into a fabricated completed record would improve the spreadsheet’s appearance while worsening its account of what the customer actually supplied.

An unresolved record therefore passes the small structure contract and goes to clarification. An unsupported value goes to review for a different reason: it proposes something the evidence does not justify. An office colleague needs that distinction. Asking which Tuesday the customer means is ordinary missing-information work; discovering that the record says Wednesday when the message says Tuesday is a different problem. Keeping the stopping reason with the record saves them from reopening the whole workflow just to work out which conversation to have.

A correct request can still be unavailable

Return to the explicit 13 August message and suppose both the date and address are represented correctly, with the address inside the service area. The diary may still have no available slot. Extraction quality cannot answer that question because availability depends on current business state. The application needs to check the diary after interpreting the request, while keeping a proposed visit separate from a reserved appointment.

Check that same faithful candidate against two invented diary states. When slot_available is false, it stays draft-only and needs an alternative; when true, it becomes an eligible draft awaiting separate approval. The source message is unchanged. A person can therefore see why a perfectly extracted request still cannot be booked, and avoid sending it back for another extraction. If the diary changes between that check and reservation, the reservation operation must still establish whether the slot is available when it commits.

Calendar validity belongs earlier in the process. A string such as 2024-02-31 fits an unrestricted text field but cannot name an appointment day. Python’s date parser rejects that candidate in the checker. A constrained schema or format validator could catch it sooner. That would save the office an impossible-date review, while leaving the Wednesday-versus-Tuesday problem untouched: both days can be real dates. The choice of validator should make an error easier to locate rather than turn every rejected draft into another unexplained extraction failure.

This suggests a practical processing order: confirm the response is usable, validate its structure, establish evidence support, then apply the rules and current state that govern the proposed action. Preserve the reasons for stopping. The operator needs to distinguish missing customer information from an unavailable diary slot; otherwise both become an unexplained failed item and the automation merely moves the investigation into a queue.

The same shape can lead to different work

Nine local assertions passed for constructed records separating structure, source support and diary conditions. No model calls or bookings were made.

Scroll sideways to see all columns.

Constructed caseShapeSource supportBusiness checkNext action
Date 14; source says 13PassFailNot runReview unsupported value
Address 99; source says 9PassFailNot runReview unsupported value
Correct source; full diaryPassPassNo slotOffer alternative
Correct source; free slotPassPassSlot availableEligible draft
Date and address unresolvedPassPassMissing detailsClarify
2024-02-31PassNot checkedInvalid dateReview date
Refusal / incompleteNot parsedNot checkedNot runKeep original enquiry
The checker compares hand-labelled expected facts with constructed candidates. A shape pass can leave an unsupported date, an unavailable slot or a response that still needs approval.

Some responses should never reach the field checker

The original announcement also described refusal and unfinished generation as cases requiring handling [1]. A response that stops before completing the object is not an extraction with several empty fields. It is an incomplete response. A refusal is not a successful object whose contents happen to say no. Check those outcomes through the documented API response information rather than manufacture an empty success record because downstream code expects one.

The example translates API outcomes into three internal kinds: output, refusal and incomplete. Only output reaches the field checks. A refusal keeps its reason; an incomplete response leaves the enquiry waiting for a usable result. This translation belongs in an adapter tied to the chosen API version, rather than in assumptions scattered through the booking code. The office should not see four empty fields when the actual problem is that no complete record arrived. Otherwise it may ask the customer for information the customer already supplied.

What the trial should measure next

A live trial would add representative messages and independently agreed expected outcomes. Corrected dates, forwarded threads, multiple addresses and enquiries that are not booking requests belong there if they occur in the real workload. Keep source agreement separate from schema compliance, and record how much time reviewers spend resolving each stopping reason. A parser improvement may be valuable even when autonomous booking remains inappropriate.

There is a cost to retaining evidence: more fields, more review context and potentially more personal information. Keep only what the task needs, control access and establish retention. If every draft still requires a full reread, simplify the task before adding more elaborate metadata. For a very small inbox, a clearer enquiry form or a few deterministic checks may do more useful work than an extraction model.

I would want the person using this workflow to see whether the record describes the customer’s request, an available proposal or a reserved appointment. The distinction should survive export as well as the original screen. If availability is the obstacle, show that beside the supported date instead of discarding a good extraction. If the date is unsupported, keep the message visible for correction. A dependable structure makes these records easier to handle; the stopping reason tells the office which part of the job still needs doing.

Working on a workflow like this? Hamsa helps finance and operations teams connect their tools and handle the exceptions, starting with one workflow.

See the Payment Operations Pilot

References & further reading

Primary sources behind this article. Living documentation may change.

  1. OpenAI: Introducing Structured Outputs in the API Published 6 August 2024
  2. JSON Schema: Object reference
  3. OpenAI: Structured model outputs
Hamsa Jama

Practical engineering. A human perspective.

More about Hamsa Software and the person behind it. Editorial notes.

A few more things
worth a read.

Back to the reading room
AI developments7 min read

Why replacing a compromised key may not end an incident

A saved replacement, a running service and an attacker’s existing access can change at different times. Railway’s guidance explains why that matters; PingCAP and PHP show where the next job differs.

AI developments7 min read

What did the browser actually confirm?

Computer use needs an observation contract for account, object and outcome, especially when a visible click produces only partial completion.

AI developments7 min read

What comes with an AI model on your laptop?

Local inference offers a different operating boundary. Evaluate the completed task, data routes and maintenance responsibility before buying into it.