Nondeterminism is not a bug you can file
A team logged the model's varying output as a defect and waited for a fix that was never coming. The variation is a property of the system, not a broken part of it.
Nondeterminism is not a bug you can file
A QA lead at a fintech company showed me a ticket she had reopened four times. Same input, different model output, marked as a defect each time. Engineering kept closing it as “cannot reproduce,” which was true in the narrow sense and useless in every other sense. The output was different because the system produces different output. She was waiting for a fix that no one could ship.
The ticket was describing the system, not a flaw in it
Her bug report read like any other. Expected result, actual result, steps to reproduce. The trouble is that “expected: the same answer every time” was never a promise the model made. A language model samples from a distribution. Run it twice on identical input and you can get two valid answers that differ in wording, structure, or the exact claim they land on. That is how the thing works.
So the ticket was not documenting a defect. It was documenting the nature of the component they had chosen. You cannot file that away and wait. There is no build where it gets patched out. The team had spent weeks treating a permanent property as a temporary regression, and the calendar kept moving while the ticket sat open.
This matters because the instinct to eliminate variation sends you down a dead end. You start chasing reproducibility that the model will not give you, and every hour there is an hour not spent making the feature correct across the outputs you will actually get.
Design for the range, not for one answer
The useful move is to stop asking “how do I make it return the same thing” and start asking “is every plausible thing it returns acceptable.” That reframes the work from suppression to specification. You define what a good output looks like, and you build the machinery to check it.
Once the QA lead did that, her ticket queue changed shape. Instead of “output varies,” she wrote acceptance criteria. Does the response contain the required fields. Is it in the format the downstream system parses. Does it stay inside policy. Those are testable across a range of wordings, which the original ticket never was.
Here is where the effort actually pays off.
- Write acceptance criteria, not a golden string. Assert on the properties a good answer must have, so any valid phrasing passes and a bad one fails.
- Validate the output before it moves. Put a check between the model and the next step that confirms format, required content, and policy, and rejects what fails.
- Retry on a failed check. If an output does not pass, generate again rather than shipping it, and cap the attempts so a bad run degrades cleanly.
- Test with many runs, not one. Send the same input through repeatedly and measure how often it passes, so you know your real failure rate instead of guessing from a single lucky pass.
- Set a pass bar you will hold to. Decide the rate the feature needs to clear before it ships, and treat anything below it as unfinished work, not a flaky test.
None of that removes the variation. It makes the variation safe. The model can phrase the answer twenty ways and the feature still behaves, because the system checks the properties that matter and reruns the ones that do not hold.
How we approach it at Density Labs
When we scope an AI feature in the AI Opportunity Assessment, our fixed two-week, $2,500 engagement, we treat output variation as a design input from the first day, the same as data quality or an integration point. We map what a correct output has to satisfy, put a validation gate in the path, and decide the retry behavior before anyone writes the happy path. That conversation is short. It saves you from shipping a feature whose only test was “it worked the one time we looked.”
A model that gives you a different answer twice is not malfunctioning. Build the feature so both answers are fine.