Getting Reliable LLM Outputs
The most common frustration with LLMs in production is not that they are wrong - it is that they are unpredictably wrong. One request returns perfect JSON, the next returns markdown-wrapped JSON, the third returns an apology. Reliability engineering for LLMs is about narrowing that variance to something you can build on.
Structured Outputs
The single biggest reliability lever is forcing the model to emit a defined structure rather than free text. Modern APIs provide two mechanisms for this.
JSON Mode
JSON mode guarantees that the model's entire response is valid JSON. You enable it via an API parameter (response_format: { type: 'json_object' } on OpenAI, for example) and the model will never emit invalid JSON. What it does not guarantee is that the JSON has the fields you expect - only that it parses.
When to use JSON mode
- โข You need machine-readable output but do not need a specific schema enforced
- โข You are extracting structured data from unstructured text
- โข You want to prevent markdown-fenced code blocks wrapping your JSON
Structured Output / Function Calling
Function calling (also called tool use or structured output with a schema) constrains the model to emit JSON that exactly matches a schema you provide. The API rejects responses that do not conform - so you get schema-valid output every time. This is the strongest reliability guarantee available.
// OpenAI Structured Output example
const response = await client.chat.completions.parse({
model: "gpt-4o-2024-08-06",
messages: [{ role: "user", content: "Extract: John Smith, 32, engineer" }],
response_format: zodResponseFormat(PersonSchema, "person"),
});
// response.choices[0].message.parsed is always a valid PersonTemperature and Sampling
Temperature controls how much randomness is injected into token selection. Lower is more deterministic; higher introduces more variability.
| Temperature | Behaviour | Use when |
|---|---|---|
| 0 | Fully deterministic (greedy decoding) | Data extraction, classification, code generation |
| 0.2โ0.5 | Mostly consistent, slight variation | Q&A, summarisation, structured tasks |
| 0.7โ1.0 | Creative, diverse outputs | Brainstorming, creative writing, ideation |
For reliability, set temperature to 0 or near-0 for any task where correctness matters more than variety. Note that temperature 0 is not fully deterministic in practice due to floating-point non-determinism across hardware - expect ~99% identical outputs, not 100%.
Grounding
Grounding means providing the model with the specific information it should use to answer, rather than relying on its training data. This is the most effective technique for reducing hallucinations on factual tasks.
Ungrounded (risky)
"What is the current price of our product?" - the model answers from training data, which may be outdated or fabricated.
Grounded (reliable)
"Using ONLY the following product catalogue: [data]. What is the price of X?" - the model answers from the provided text and should refuse if the answer is not there.
Grounding also pairs with an explicit instruction: "If the answer is not in the provided context, say 'I don't have that information' rather than guessing."This refusal-as-default pattern is highly effective.
Output Validation
Even with structured outputs and low temperature, validate the model's response in code before using it downstream. Add a validation layer that checks:
- Required fields are present and non-empty
- Values are within expected ranges or enum sets
- Business rules are satisfied (e.g. dates are in the future)
Retry Patterns
When validation fails, retry with additional context rather than giving up or silently returning bad output.
Retry prompt pattern
On failure: "Your previous response was: [bad output]. It was invalid because [reason]. Please try again, ensuring [specific constraint]." - pass the failure reason back to the model so it can self-correct.
Limit retries to 2โ3 attempts. If validation still fails, escalate to a human or return a graceful error rather than looping indefinitely.
Reliability Checklist
- Use structured output / function calling for any machine-readable output
- Set temperature to 0 for classification, extraction, and data tasks
- Ground factual prompts in provided context; instruct the model to refuse when unsure
- Validate all model outputs in code before using downstream
- Retry with failure context on validation failure; cap at 3 retries
- Log the raw model output alongside the validated result for debugging