Skip to content
Chapter 2 of 7 · Anatomy of a promptDiagnosing a missing part

16 min read

Diagnosing a missing part

On this page

The inverse of writing a prompt from a blank page is the thing you actually do: inherit one, watch it underperform, and hold a folder of bad outputs with no idea which part of a working prompt is at fault. Prose invites prose in reply — the role line could be stronger, the examples could be better — and neither claim can be checked, so the argument is settled by whoever is most recently annoyed.

The six slots make it checkable, because each absence produces a characteristic failure and the failures are distinguishable by looking at them. The diagnosis below is run on a folder of failing outputs from a prompt that is already in production and already has a score, which is the only situation in which it means anything: it converts a mood into a named slot and a count, and the count is what decides whether the slot is worth a sentence today or a note in a backlog.

Failures have signatures

An output tells you which question the model had to answer for itself. When a value appears that is not in your vocabulary, the model was never told the vocabulary was closed. When two calls on near-identical inputs produce structurally different replies, the model chose a structure on each call. When a reply is fluent, well-formed, and about something adjacent to what you asked, the operation was underspecified. These map cleanly enough to be worth memorising.

The mapping is worth more than a mnemonic, and it holds for a reason rather than by convenience. A model does one thing on each call. It takes the text in front of it and returns a score for every fragment of text that could come next, and ordinary code outside the model draws one of those candidates, appends it, and calls the model again on the slightly longer text. Anything your prompt does not settle is settled there, in the draw, on every call independently.

A question your prompt answers narrows that draw. If the prompt says the reply is one lowercase word from a list of six, then at the position where the label is due almost all of the score sits on those six strings, and the draw returns one of them every time because nothing else has enough score to be reached. A question your prompt leaves open does the opposite. Nothing in the text prefers a summary in prose over a summary in bullets, so the score spreads across both shapes and across several more, and the draw resolves the spread afresh on each call.

The two situations therefore leave different marks, and the mark is what you are reading when you sort a folder of failures. An absent slot shows up as variation across calls on inputs that resemble each other, because the same broad distribution is being sampled again and again and it lands in different places. A slot that is filled but says the wrong thing shows up as the same wrong answer every time, because the prompt has pinned it and there is no spread left to sample. Consistency is evidence of a decision that was made; variation on inputs that ought to behave alike is evidence of a decision that was delegated. The rows below pair each mark with the slot whose absence produces it, and with the move that treats the mark rather than the cause.

What you observeSlot that is absentThe move that will not fix it
Shape differs across calls on similar inputsOutput formatLowering temperature; it narrows the drift without removing the choice
Preamble: "Certainly!", "Here's the summary:"Output format, as an explicit prohibitionPost-processing regexes, which fail on the next phrasing
A value outside your enum or category listConstraint stating the list is exhaustiveAdding examples; none of them says the list is closed
Reasoning paragraph before the answerFormat specifying where reasoning may go, if anywhereA stronger role line
Answer is generic, ignores your situationContext that was never suppliedLonger task description
Answer drifts onto a topic in your preambleContext that is present and irrelevantAdding more context to compete with it
Correct content, wrong register or depthRoleConstraints on length, which change size and not pitch
Model performed a nearby operationTaskExamples, which will teach the nearby operation's shape

The third column is the part worth reading twice. Every one of those moves is defensible, several of them help a little, and each is a way of spending a week addressing by suggestion something a sentence would address directly.

Lowering the temperature is the clearest case, and walking it shows the shape all eight rows share. Temperature is the decoding setting that reshapes the scores before the draw is made, stretching or flattening the gaps between candidates: a high value lets the draw reach candidates well down the ranking, and at zero the draw stops being a draw at all and takes the top-scoring candidate every time. Turning it down therefore narrows the spread the shape was being sampled from, and the replies do become more consistent, which is why the move looks like it worked. What it cannot do is put a shape in the prompt. The choice was never removed, it was resolved once and in the model's favour, so the output settles on whichever shape the model's scores happened to prefer for text of this kind — a shape you did not pick and cannot predict by reading your own prompt.

The other seven rows fail the same way once you look at what each move acts on. A post-processing regex strips the preamble the model produced on this call and knows nothing about the phrasing it will produce on the next. A stronger role line changes the register of the reply and leaves untouched the question of where reasoning is allowed to sit. More context added to compete with irrelevant context puts two topically related passages in front of the model where there was one. Each of these operates on the output, or on a different slot, while the delegated question stays delegated — and each improves the numbers enough to be encouraging, which is the property that makes a week disappear into it.

Run the diagnosis in a fixed order, because the cheap questions eliminate whole categories of expensive investigation:

Flowchart: 30 failing outputs → Same shape on every call?; Same shape on every call? → no; no → Output format absent; Same shape on every call? → yes; yes → Any value outside your vocabulary?; Any value outside your vocabulary? → yes; yes → Constraint absent; Any value outside your vocabulary? → no; no → Right operation performed?; Right operation performed? → no; no → Task underspecified; Right operation performed? → yes; yes → Facts wrong or generic?; Facts wrong or generic? → yes; yes → Context missing or irrelevant; Facts wrong or generic? → no; no → Register wrong: role, or nothing is absent.

The order of those questions is not arbitrary, and the first is first for the reason the mechanism gives. Asking whether the shape is the same on every call is asking whether a decision was delegated or made, and the answer partitions everything downstream. If the shape varies, no later question can be answered from the folder, because the folder holds several different behaviours pooled together and any pattern you find in it is a pattern across a mixture. Once the shape is fixed you are reading one behaviour, and each remaining question tests one slot against it. Every one of those questions is cheap in the same specific sense: the property it asks about is already visible in outputs you are holding, so answering it costs a minute of reading and no model calls at all.

Thirty failures is enough to run this on, and the reason to fix a number is that reading two of them produces a theory and reading thirty produces a distribution. Sorting failures into buckets before touching the prompt is the whole of the technique, and it takes about twenty minutes.

Fixing the number is also what makes the buckets comparable with each other. A cause read out of two failures and a cause read out of eighteen are the same sentence in a pull request, and they stop being the same sentence the moment each carries a share of one denominator. That share is a ranking, and the ranking is the decision about the week: the largest bucket gets a sentence today, the second gets a separate change with a separate measurement, and anything down at a handful goes into a backlog with its count written beside it, so the next person can tell whether it has grown.

Three causes that are not a missing slot

Every branch of that tree except the final one ends at something you can write down. The final one ends at "or nothing is absent", and it is there because three other things produce bad outputs and none of them is a missing slot.

The first is conflict. A prompt can state every one of the six things and state two of them in a way that cannot both be satisfied, in which case the model satisfies one per call and the failure pattern looks like variance. Chapter 4, on two rules that cannot both hold, is about recognising this, and the reason it is a separate chapter is that the fix is the opposite of the fix here: you are removing or reconciling an instruction rather than adding one.

The second is irrelevant context, which the table lists but which deserves a note on how it looks in practice. Two paragraphs of company background pasted above a classification task do not cause out-of-vocabulary labels, and deleting them will not raise a score much. What they do is more subtle — they give the model material that is topically related to the input but useless for the decision, and on the ambiguous cases you sometimes see the model reason about the company's product lines instead of the input's actual content. That effect is real and it is small. If you are hunting dozens of failures, it is not where you start.

The third is variance, and it is the one that quietly wastes the most engineering time. Run one unchanged classification prompt three times over the same 400 cases at temperature 0.7 and you might see 70.6, 71.4 and 71.9. That spread of 1.3 points is what the prompt does when nothing changes at all, which means any prompt edit that moves the score by a point has told you nothing. People discover this the hard way, usually after shipping a change that measured +0.8 and then watching it measure −0.5 on the next run. Chapter 5, on the apparatus a comparison needs, makes this tractable; for now the operational rule is that a diagnosis is only worth acting on when the symptom is countable, and a count is something "the answers feel worse" can never be.

Reflexes that cost a week

Four moves reach for a prompt before its diagnosis exists, and each one is plausible enough to be worth naming.

Adding examples is the most common, and it is the trap rather than an obvious mistake, because it will probably help. Two more examples add two more demonstrations of a correctly formatted, correctly labelled case, so a preamble problem will improve a little and an out-of-vocabulary problem will improve a little, since the model sees more labels drawn from your real set and infers it more confidently. You spend the week writing and reviewing examples, land a few points up, and conclude that examples were the answer — having addressed the symptom by suggestion and left the absence in place.

The mechanism behind that partial improvement is worth having, because it also says where the improvement stops. A demonstration is ordinary text in the same document, a few hundred tokens above the position where the next label is due, and nothing in it is marked as illustrative rather than operative. The model is scoring candidates for what comes next, and the strings that already appear in this document in this position have their scores raised by appearing there. Paste four examples whose labels are billing, auth, bug and other, and those four strings are now the ones the region most resembles, so the draw reaches billing-dispute less often than it did. The out-of-vocabulary rate falls, by a route that never touches the question of whether the list is closed.

The alternative, where the diagnosis is a missing constraint and a missing format line, is two sentences:

text
Assign exactly one of these six categories: billing, auth, bug,
feature-request, integration, other. These six are the complete set;
never invent a category or return a variant spelling. If a ticket does
not clearly fit one of the first five, use "other".

Reply with the category name alone — one word, lowercase, no
punctuation, no explanation before or after it.

The reason to prefer those is not that examples are bad. It is that an absence is repaired by a statement, and a statement about a closed set is something only a constraint can express: no quantity of demonstrations says "and nothing outside these", because a demonstration only ever shows what is the case, never what is not permitted. This is a real limitation of few-shot prompting — the practice of pasting a handful of worked input-and-output pairs into the prompt so the model has something to imitate — rather than a stylistic preference, and chapter 3, on demonstrations that contradict rules, shows the sharper edge of the same property.

The asymmetry is worth stating in its own terms, because it is what lets a sentence beat a slot the examples are visibly helping with. An example is an existence proof. It establishes that billing is a legal answer, and it is silent about billing-dispute, silent about account-access, and silent about every other string the model might reach for on an input resembling none of the four you pasted. A sentence saying the six are the complete set is a claim about all of them at once, including the ones nobody has thought of yet, and one of those is the failure you have not seen. So the examples take the out-of-vocabulary rate down and never take it to zero, and the shape of that curve — better, better again, stubbornly not zero — is what persuades a team that what they need is more examples.

Swapping the model is the most expensive way to test a hypothesis you have not stated, because a stronger model will paper over a missing constraint often enough to hide the bug and not often enough to fix it, and you will have changed your cost profile in exchange for an unattributable improvement. Dropping the temperature to 0 is more defensible and still wrong as a first move, because it reduces the variance of an inference the model should never have been making; the shape stops drifting and settles on whichever shape the model prefers, which may not be yours. Both are worth trying after the missing slots are filled, when what remains is genuine judgement error.

The last reflex is rewriting the whole prompt. It is tempting when a prompt is visibly untidy, and it destroys attribution: if you change eight things and the score moves from 71 to 79, you have learned that the new prompt is better and nothing about why, so the next time it regresses you are back at a blank page. A two-sentence fix is two sentences precisely so that the measurement afterwards means something.

When the slot is already filled

There is a version of this technique that fails, and it fails when the missing slot has already been added by someone else. You will meet prompts that contain a constraint stating the categories are closed and still return billing-dispute on 14% of tickets, and at that point the taxonomy above sends you in a circle: the slot is filled, so nothing is absent, so the tree's last branch shrugs.

Two things produce that situation. One is a conflicting instruction elsewhere in the prompt, which is the next chapter but one. The other is that somewhere below the constraint there are three worked examples, and one of them was lifted from an older version of the label set, and it shows the model a category that the constraint above forbids.

The second of those is what the mechanism predicts, and predicting it is a fair test of whether the mechanism was understood. A constraint saying the list is closed and a demonstration exhibiting a category outside it are both text in the document the model is continuing. The demonstration sits nearer the position where the label is due and in the same form as what is due there, so its strings have their scores raised by exactly the route the four correct examples used, while the sentence three paragraphs above competes by describing the set instead of being a member of it. What follows is not variation. On inputs resembling the stale example the model returns the forbidden category confidently, and returns it on every call, which is the signature of a decision that was made — made by the example, in a slot you believed you had filled.

A second limit is that the tree tells you what the failures are not evidence about, and that is easy to skip past. In the earnings-summary case from chapter 1, where 387 calls in one Monday failed to parse, the shapes differed across calls — prose, bullets, preamble — so the first question answered itself and the diagnosis was the format slot. The role line was the only slot that prompt filled, and it is the one people reach for, because "you are a senior financial analyst" reads like the kind of thing you could improve by making it more senior. Nothing about that line caused a single one of those parse failures. The same goes for the transcripts themselves: an engineer looking at 387 failures will notice that the longest ones fail more often and start theorising about truncation, which is a real phenomenon and, in that case, an explanation for perhaps a dozen of them.

What the diagnosis produces, then, is not a fix but a ranked list with counts attached, and the counts are what make the list arguable. A colleague can dispute whether 58 out of 116 is really one cause, can ask to see ten of them, can point out that your buckets overlap. None of that is available against "the outputs feel worse", which is why the twenty minutes buys more than it costs even when the first sentence you write turns out to be the wrong one.

When a written rule and a demonstration disagree, the outcome is not a coin flip.

Anatomy of a prompt — read the current version at https://daviddominguez.dev/learn/en/anatomy-of-a-prompt/diagnosing-a-missing-part

Back to top