Prompt Tip: Avoid Conditionals
I was going to write a post about gameplay prompt writing tips, and realized that likely more of these will crop up as I go, so maybe I’ll stick to one per post and make a series of it. So here’s the first tip: Avoid Conditionals.
The Problem
A conditional in a prompt is simply a statement of “If X then do Y”. These seem to appear in my prompts organically over time as I add features, and it’s easy to accidentally let them slide. It takes a moment to step back and see them, but once I do it seems so obvious it’s almost not worth writing about. And yet here we are.
Here’s an example of how it might manifest. I have a prompt for generating the opening text of an encounter with an NPC. After the general guidance, I had this text:
## Hostile and Wrathful NPCs
If the NPC's reputation is hostile or wrathful, the `combat` anchor will be in the input. The `text` field should open with confrontation: blocking the path, issuing a warning, reaching for a weapon. Even non-combat options must feel like attempts to defuse a tense situation, not friendly overtures.
The NPC’s reputation is one of the variables injected into the prompt, and I do still want that in there to flavor the tone of the text. However, the above has an obvious problem: I’m asking the LLM to evaluate a conditional and change its response based on that conditional which would would be better served by code.
Why would we trust a nondeterministic system to evaluate and respect a deterministic problem like this? We’d be much better served performing that conditional ourselves in the code, and then replacing the content of the prompt with different text based on the outcome.
The Solution
My code already supported putting variable substitution tags into prompts. IE, in the above, the prompt has something like:
NPC Reputation: {npc_reputation}
At runtime the {npc_reputation} value is substituted by the actual reputation value, which is an enum of values like “friendly”, “neutral”, “hostile”, etc.
I extended this system to support fragments, which are additional blocks of text loaded from a file adjacent to the prompt file itself. So now, the hostile/wrathful block from the problem section above just looks like this:
{disposition_guidance}
In code, I check the value of the NPC’s reputation and substitute the contents of a different fragment file for disposition_guidance. In the case of a hostile NPC, that fragment contains:
## Disposition
This NPC is hostile to the player, and the `combat` anchor is in the input. Open the `text` field with confrontation: blocking the path, issuing a warning, reaching for a weapon. Even non-combat options must read as attempts to defuse a tense situation, not friendly overtures.
This is so much better - nice declarative statements for the LLM to follow that based on hard data. For contrast, if the NPC’s reputation is wary, I plug in this:
## Disposition
This NPC is guarded toward the player — wary and watchful, but not yet an enemy. Open with caution rather than warmth: a measured greeting, a held distance, questions before trust. Acknowledge any past history plainly, without fondness. Keep the tone transactional — the player must earn openness, and nothing is offered freely.
There are others, but I don’t have a fragment for every single reputation value. For those cases, dispostion_guidance is an empty string. No special guidance is needed beyond the base prompt in these cases, and I save some tokens!
Final Thoughts
It’s very easy to accidentally let these in and not notice, but it’s now a pattern I look for regularly in my prompts. Any time the prompt says “If X then do Y”, I try to break the prompt down into multiple variants or use the fragment system. The prompts are thus leaner, faster, and more reliable.