AI Hates Ambiguity: A Guide to Probability
AI Hates Ambiguity: A Guide to Probability êŽë š
We often treat Large Language Models (LLMs) like magic chat boxes. Brilliant colleagues ever awaiting our next question. This isnât terribly far off these days. Weâre certainly past the stochastic parrot (damonberes.com) phase. As with a human colleague, the more specific we are in our questions and requests, the more useful the conversation will be.
Every time you send a prompt, you are defining a probability distribution. You provide the context (the input tokens), and the model calculates the most likely/useful next set of output tokens based on the weights in its neural network.
When you constrain that distribution effectively, the result feels magical: precise, production-ready code. But when we force the AI to guess our intent â because we were vague, assumed it âknew the context,â or skipped the edge cases â we widen the continuation space. We force the model to choose from a massive array of potential answers, most of which are mediocre.
In engineering, we often call bogus results âhallucinations,â but in practice, theyâre probability drift caused by unclear guidance. It happens because we failed to anchor the modelâs completion path to a specific, high-quality distribution.
To fix this, we need to stop âchattingâ and start architecting. Letâs look at exactly what happens when we ignore the mechanism.
The âHostileâ Prompt
I call the prompt below âhostileâ because it ignores the modelâs statistical reality. It treats the AI like a mind reader rather than a pattern matcher.
The Prompt:
Write a function to fetch user data from an API and save it to state.
In this simple request, there are three distinct specification gaps that will break your production app:
- The Tutorial Bias: The modelâs training data is dominated by simple tutorials where APIs never fail. Without constraints, it defaults to this âHappy Pathâ because it is statistically the most common pattern.
- Type Blindness: It generates generic JavaScript instead of strict TypeScript because the constraints werenât negotiated.
- The State Gap: It writes the fetch logic immediately (prediction) without handling intermediate states (loading/error), causing UI flashes.
đ The âBeforeâ Output (The Drift)
// The AI's "Default" Response
useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then(data => setUsers(data)); // Risky: No loading state, no
error handling, race conditions.
}, []);
This code isnât âbrokenâ, itâs just optimized for brevity, not production. It lacks cancellation, error boundaries, and loading indicators.
The Theory (Why This Happens)
Why did the AI give us such mediocre code? It wasnât because itâs âdumb.â It was a failure of Contextual Anchoring.
To fix this, we need to respect the architecture. The model operates on a complex Transformer architecture, but the behavior can be summarized as:
- Ingest: It maps your input tokens into a high-dimensional vector space.
- Attention: It calculates âattention weightsâ â deciding which previous tokens are most relevant to predicting the next one.
- Sampling: It selects the next token based on the calculated probabilities.
The Limitation: Attention Decay
Critically, the modelâs attention mechanism is finite. It suffers from Token Locality. As a conversation grows longer, the influence of earlier tokens (like your initial instructions) can dilute.
If you paste a 500-line file and ask for a refactor at the bottom, the model is statistically less likely to âattendâ to the specific style guide you pasted at the very top. To combat this, effective engineers re-inject critical constraints (like âRemember to use strict TypeScriptâ) closer to the generation point.
The âLikelihoodâ Mistake
In our hostile prompt, we ignored this mechanism. We provided a short, vague input, which left the âsearch spaceâ for the answer too wide. When you say âWrite a functionâ, the model maximizes likelihood by choosing the path of least resistance: the tutorial snippet. Every time we leave a constraint undefined, the model fills the gap with the most common pattern in its dataset.
We need to move from Implied Intent (hoping it gets it) to Explicit Constraint (forcing the distribution toward quality).
Solutions
We are going to make three specific negotiations with the AI to ensure stability.
- The Persona Negotiation (System Context): The AI isnât âwrongâ when it gives you a simple script; it is fulfilling the pattern of a âhelpful assistantâ. We need to narrow the distribution to âSenior Engineering.â The fix here is to use a system prompt of sorts, or global context. Something like a
claude.mdfile oragents.mdfile. It could have context like this: You are a Senior Frontend Engineer who prioritizes defensive coding. You reject âhappy pathâ code. You always implement error handling, type safety, and cleanup functions. - The Format Negotiation (Output Constraints): Just as the browser struggles when elements load out of order, the AI struggles when it mixes conversational filler with code. We need to force a strict structure. The fix here is to include extra information in our prompts, to the tune of: Return only the code block. Do not add introductory text. Ensure the code is strictly typed TypeScript.
- The Logic Anchor (Chain of Thought): This is the most critical technique. Normally, the AI predicts code token-by-token immediately. This is like coding without a plan. By asking for a âplanâ first, we force the model to generate tokens that bias the attention weights for the subsequent code. If the model writes âI must handle the race condition before it writes the code, the probability of it actually writing AbortController skyrockets. The fix here might be prompting to ask for a plan first, like: Before generating the code, list the 3 most likely failure modes for this feature (e.g., race conditions, network errors) and explain how you will prevent them.
Phase 4: The âStableâ Interaction
Here is a prompt asking for the same thing we did originally, but negotiated correctly.
The Orchestrated Prompt:
Write a useUsers hook.
1. Use AbortController to handle unmounting (Race Condition).
2. Strictly type the response.
3. Return a tuple: [data, loading, error]
đ The âAfterâ Output
// The AI's "Production" Response
const useUsers = (): [User[], boolean, Error | null] => {
const [data, setData] = useState<User[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const controller = new AbortController();
setLoading(true);
setError(null); // Reset error state on new fetch
const fetchData = async () => {
try {
const res = await fetch("/api/users", {
signal: controller.signal,
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const result = await res.json();
setData(result);
} catch (err) {
if (err.name !== "AbortError") {
setError(err as Error);
}
} finally {
if (!controller.signal.aborted) {
setLoading(false); // Guard against unmounted state updates
}
}
};
fetchData();
return () => controller.abort(); // Cleanup negotiated.
}, []);
};
Notice the difference. It handles the loading state. It resets errors on retry. It cleans up after itself. It feels like it was written by a human engineer because we gave the model the constraints it needed before it started predicting.
A Note on Limitations
It is important to acknowledge that prompt engineering is not magic. Even the most perfectly constrained prompt cannot force a model to solve a problem that exceeds its training data or reasoning capabilities. If the model simply doesnât know a library, no amount of âpersona settingâ will teach it.
However, for the vast majority of daily engineering tasks, the failure point is not the modelâs capability â it is the promptâs ambiguity.
Conclusion
Prompt Engineering is not about âtrickingâ the machine; it is about constraining the machine. Every bug, every generic tutorial script, and every âhallucinationâ is a signal that the continuation space was too wide. We failed to give the AI the context it needed to converge on the right answer.
Stop hoping for good code. Start architecting for it.