0% read
    ← All stories
    ––
    ★ One Night Only — Every Night ★

    Same Show
    Every Night

    You have hired the most gifted improv actor in the world… for a role that must be performed exactly the same way, eight shows a week. This is the story of the crew that makes it possible.

    A comedy in five acts · Getting the same result every time from AI that never answers the same way twice

    take your seat

    Congratulations. You have just cast the most talented performer in the business. This actor can do Shakespeare, explain income tax, write Python and put on a surprisingly good pirate accent, sometimes in the same sentence. And that is exactly the problem. The role you gave them is "Enterprise Backend Service, a drama in JSON", and the audience (your users, your auditors, your on-call engineer) expects the same performance every single night.

    Ask a normal function "what is 2+2" a thousand times and you get "4" a thousand times. Ask your new star the same question and you might get "4", "Four!", "Great question — the answer is 4 🎉", and once, unforgettably, a haiku about arithmetic. The talent is real. The consistency is still being worked on.

    This is the basic comedy of building software on top of LLMs: we are casting improvisers in roles written for machines. The real answer, and the whole discipline of AI engineering along with it, is that you do not fix this by asking the actor to behave. You fix it by building a theatre around them.

    ACT I — MEET THE TALENTWhy the actor never gives the same performance twice

    An LLM does not "look up" an answer. It rolls weighted dice to choose the next word, again and again, very fast. Turn the temperature setting up and the dice become more random. Turn it down to 0 and the model picks the most likely word each time, which is mostly repeatable but still not a promise. Tiny rounding differences, how the provider groups requests together, and model updates on their side mean even your most predictable answer can change slightly from one run to the next.

    So let us drop one idea right at the start: you will not make the actor give the same answer every time. Improvising is not a defect in this performer. It is where the talent comes from. The consistency has to come from the system around the actor, not from the actor. That is the main idea of this article:

    Don't make the model predictable.
    Make the show predictable.

    ACT II — HAND THEM A SCRIPTStructured output: freedom inside a fixed format

    The first crew member you hire is the scriptwriter. Instead of asking the actor an open question like "tell me about this invoice in your own words", you give them a script with fixed blanks to fill. In practice this means: your answer is a JSON object, these are the fields, these are their types. You can improvise what goes inside, but never the shape.

    Every serious model API supports this now, through JSON schemas, structured outputs and function (tool) calling. It is the difference between a long paragraph about the customer's mood and a clear, structured answer like this:

    The script — a schema the actor cannot wander out of
    {
      "sentiment":  "negative",          // enum: positive | neutral | negative
      "confidence": 0.87,                // number, 0–1
      "refund_eligible": true,           // boolean, no interpretive dance
      "reason_code": "DAMAGED_ITEM"      // enum, not freestyle poetry
    }

    See what happened here. The actor is still acting, using judgement to read between the lines of an angry customer email. But the answer now comes in a fixed format that your code can check in one line. Many complaints that "AI is unreliable" come from asking for a vague, open answer and then getting exactly that.

    ACT III — THE SCRIPT SUPERVISORCheck, retry, and never fully trust a live performance

    The next hire is the script supervisor, the person at the side of the stage with a clipboard, checking every line against the script. When the actor goes off-script, the supervisor stops the take and says, "Again, from the top, and this time the date field must be a real date."

    In code, this is a validation check plus a retry loop with a limit. First, check the answer against the schema. Then check the business rules the schema cannot express: the refund is not more than the order total, and the date is not something like the year 1847. If a check fails, try again and send the error back to the model, because models are good at fixing a mistake once you show it to them. After a fixed number of tries, fall back to a safe path you control: a default value, a queue, or a human reviewer.

    ScriptSupervisor.cs — bounded takes, then fallback (.NET)
    public async Task<RefundDecision> GetDecisionAsync(string email, Order order)
    {
        for (var take = 1; take <= 3; take++)          // max three takes
        {
            var raw = await _model.CompleteAsync(_prompt.Render(email));
    
            if (!RefundDecision.TryParse(raw, out var d, out var errors))
            {
                _prompt.AddNote(errors);              // "again — with the fixes"
                continue;
            }
            if (d.Amount > order.Total)               // business rules: no method acting
            {
                _prompt.AddNote("refund exceeds order total");
                continue;
            }
            return d;                                 // a take we can print
        }
        return RefundDecision.EscalateToHuman();     // the understudy is a person
    }

    That simple loop hides a big change: the system as a whole now behaves the same way every time, even though the model does not. Every possible outcome (a valid answer, a corrected answer, or a hand-over to a person) was written by you, in advance, in normal code. The actor can surprise you. The show cannot.

    🎭 Live Demo — Interrogate the Actor
    You ask: "Is this customer eligible for a refund?"
    // press ACTION a few times. then flip the switch and press it again.
    Same question every time. Without the crew: a different performance per take. With the crew: the improvisation happens inside the box — the shape that reaches your code never changes.

    ACT IV — THE STAGE MANAGERThe predictable sandwich

    Now the most important hire of all: the stage manager, the person who runs the show. The curtain goes up at 8. Scene 2 always comes after Scene 1. Props are placed in advance. However talented someone is, nobody decides in the middle of the show to jump to Act III.

    In architecture terms: the LLM should be one small, clearly defined box inside a much bigger system that you control. Normal code decides when the model is called, what it can see, which tools it can use, and what happens for every possible type of answer. The overall flow is a set of steps you wrote, and the model fills one creative slot at each step. Call it a sandwich: plain code on top, plain code at the bottom, and improvisation only in the middle.

    Deterministic code — gather context, render versioned prompt your rules · your order of operations · your state machine 🎭 LLM (improvises here) small box · schema-constrained · tool allowlist Validator + business rules parse · check · retry (max N) Typed outcomes only accept · correct · escalate to human
    The deterministic sandwich: improvisation lives inside one small box. Everything the outside world sees was decided by code that you wrote.

    ACT V — DRESS REHEARSALS, FOREVEREvals: how you know the show still works

    The last hire, and the one most teams skip until a bad review forces them, is the rehearsal director. Normal software tests ask a narrow question like "does this function return 4?", which does not help much with an actor who might rightly say "Four!" instead. Evaluations, or evals, ask a more practical question: across 500 typical scenarios, how often is the performance acceptable, and did this week's change make it better or worse?

    Evals answer the question every stakeholder asks sooner or later, often with some doubt: "But how do you KNOW it works?" The answer should never be "we tried it a few times and it looked fine". It should be a specific number, on a chart, for every release.

    ★ CURTAIN ★

    Curtain call

    So no, you never made the actor predictable. Nobody ever has. What you built instead is a theatre around them: a script that fixes the shape of the answer (schemas), a supervisor who checks every take (validation and limited retries), a stage manager who runs the show (your own code controlling the steps, versioned prompts, fixed model versions, cached results and approved tools), and a rehearsal director who proves with real numbers that tonight's show is at least as good as last night's (evals).

    Inside that theatre, the improviser is the star. The talent stays, and the unpredictability stays behind a stage door it cannot walk out of. That is the whole craft of AI engineering in one sentence:

    Let the model improvise the lines. Never let it improvise the show. 🎭

    ← Back to all stories
    ––

    Discussion