Most bugs in multi-step LLM pipelines are not model failures — they are underspecified contracts between your prompt and the model. The model does exactly what you asked. The problem is that you never defined what your input actually meant. We learned this the hard way while building an AI music video generation platform, when a two-word creative directive produced a completely wrong visual interpretation — not because the model was confused, but because our prompt architecture left a critical semantic gap.
This post breaks down the prompt engineering pattern we developed to fix it: treating prompts as semantic contracts rather than loose instructions. If you are building any LLM pipeline where one step's output feeds into another, this pattern will save you from an entire class of silent failures.
How a Two-Word Directive Broke Our Entire Pipeline
Our platform lets artists provide a short creative directive — a phrase that shapes the mood, characters, and narrative of their AI-generated music video. One user typed "lovers quarrel". The LLM (Gemini) accepted it without complaint, generated a narrative seed, and passed it downstream to shot generation. The result: two men fighting in a dark alley. Not a romantic couple arguing — two generic male figures in physical conflict.
The directive was technically "accepted" at every step. No errors, no refusals, no hallucinations in the traditional sense. But the semantic meaning was completely lost. "Lovers quarrel" carries a specific cultural register — it implies a romantic couple in emotional conflict, not a street fight. The model resolved the ambiguity by defaulting to the most generic interpretation: two people, both male (its statistical default), in conflict.
We initially reached for the obvious fixes: input validation, keyword lookup tables, maybe a pre-processing step that maps common phrases to explicit descriptions. All of those are brittle. They solve one phrase and miss the next. The real fix was architectural.
Why Lookup Tables and Input Validation Do Not Work Here
The instinct to build a mapping — "lovers quarrel" maps to "romantic couple arguing" — is understandable but fundamentally flawed for creative input. You cannot enumerate every idiom, cultural reference, or poetic phrase an artist might use. "Brother's keeper" implies a male sibling bond. "Femme fatale" demands a dangerous female character. "Star-crossed" implies doomed romance. The list is infinite.
What you can do is teach the model a generalizable principle rather than a lookup table. That is the core of the pattern: encode the reasoning rule, not the individual answers. This aligns with what Google's prompt engineering guidance calls "providing context over examples" — giving the model the framework to reason correctly across novel inputs rather than memorizing specific cases.
The Pattern: Prompts as Semantic Contracts
We restructured our prompt architecture around three layers, each treating the prompt as a precise contract rather than a suggestion. Here is how each layer works and why it matters.
Layer 1 — Creative Hint as Semantic Composition Constraint
We added a rule to our Step 1 system prompt (the narrative generation step) that teaches the model a generalizable principle about relationship idioms. The rule looks roughly like this:
When the creative directive contains a relationship idiom or social archetype,
resolve it to its most widely understood cultural meaning before generating characters.
Examples of correct resolution:
- "lovers quarrel" → romantic couple (man and woman) in emotional conflict
- "brother's keeper" → male sibling bond, one protecting the other
- "femme fatale" → dangerous, alluring female character
The principle: relationship idioms carry a default cultural register.
Honor that register unless the artist profile or lyrics explicitly override it.
The key detail: the rule provides examples but frames them as illustrations of a principle, not as a lookup table. When the model encounters "star-crossed" or "ride or die" or any phrase we never explicitly listed, it has the reasoning framework to resolve it correctly. We chose this approach over few-shot examples alone because few-shot patterns tend to make models match surface-level features rather than internalize the underlying rule.
Layer 2 — Narrative Seed as Single Source of Truth
The second fix addressed where ambiguity was being resolved. In our original architecture, each step in the pipeline could independently decide character composition. Step 1 might generate a vague narrative seed ("two figures in conflict"), and Step 3 would re-interpret that seed however it wanted. This meant character gender, relationship, and composition could shift between steps with no mechanism to catch the drift.
We added a hard constraint to the narrative seed generation: no gender-neutral placeholders. The rule bans phrases like "a figure," "a person," "someone," or "two people" from the narrative seed. Every human character must have explicit gender and relational context.
The narrative_seed field is a character composition contract.
Every human character must be explicitly gendered: "a man", "a woman", "a young girl".
NEVER use: "a figure", "a person", "someone", "two people", "an individual".
If the creative directive implies a relationship, state the relationship explicitly:
"a man and a woman, romantic partners, mid-argument"
This transforms the narrative seed from a loose creative brief into a single source of truth that all downstream steps inherit from. The seed is no longer a suggestion — it is a contract. Every subsequent step reads the seed and knows exactly who the characters are, what their relationship is, and what their genders are. No re-guessing, no drift.
Layer 3 — Downstream Enforcement (Defense in Depth)
Even with a precise seed, we added a third layer: an explicit rule in Step 3 (shot generation) that treats the narrative seed as a composition constraint rather than a creative suggestion. The rule instructs the model to confirm character composition against the seed before generating any shot description.
The narrative_seed is a character composition constraint.
Your Main Character block must reflect who these characters are
to each other as stated in the seed.
Do not re-decide gender, relationship, or number of characters.
The seed is authoritative — confirm, do not re-interpret.
This is classic defense in depth applied to prompt architecture. The seed is correct at the source (Layer 2), and the downstream step confirms it rather than re-deciding (Layer 3). If either layer alone fails — say the seed somehow comes through ambiguous, or the downstream model drifts — the other layer catches it. We considered skipping Layer 3 since Layer 2 should theoretically be sufficient, but our experience with multi-stage AI pipelines taught us that any step that can re-interpret shared state will eventually do so in production.
Why This Bug Was Silent — and What That Means for LLM Testing
The most dangerous aspect of this failure mode is that it produces no errors. The pipeline ran to completion. Every step returned valid JSON. The narrative was coherent. The shots were well-composed. The only problem was that the meaning was wrong — and meaning errors do not throw exceptions.
This is a fundamentally different testing challenge than traditional software. In a REST API, a wrong response code or malformed payload is easy to catch. In an LLM pipeline, the output is structurally correct but semantically wrong. We now treat prompt-level semantic contracts the same way we treat API schemas — they are explicit, versioned, and tested against known inputs that have historically produced drift.
When to Apply This Pattern
This prompt-as-contract pattern applies whenever your LLM pipeline has these characteristics:
Multi-step output dependency — one step's output feeds into another step's input. If Step 3 depends on Step 1's output, and Step 1's output is ambiguous, the ambiguity compounds silently downstream. This is also where negative constraints in LLM pipelines become valuable — explicitly prohibiting each step from delivering transitions that belong to other steps.
Implicit semantics in user input — the user provides input that carries meaning beyond its literal words. Idioms, cultural references, domain jargon, relationship archetypes. Anything where the surface text and the intended meaning diverge.
Character or entity composition — any pipeline that generates descriptions of people, characters, or entities where identity attributes (gender, age, role, relationship) matter to the final output. If your pipeline generates product descriptions or code, this specific pattern may not apply — but the principle of explicit contracts still does.
The Deeper Lesson: Prompts Are Interfaces, Not Instructions
The mental model shift that made this fix click for our team was stopping to think of prompts as instructions and starting to think of them as interfaces. An instruction says "generate a narrative." An interface says "generate a narrative where every character has explicit gender, where relationship idioms are resolved to their cultural default, and where the output is a composition contract that downstream steps must honor."
When you build a REST API, you do not leave the response schema ambiguous and hope the frontend figures it out. You define it explicitly. When you build a multi-step LLM pipeline, the prompt between steps is your interface contract — it deserves the same rigor. The model that processes it is capable enough to follow precise constraints. The question is whether you actually specified them, as we discuss in why the AI model matters less than the engineering around it.
Treating prompts as semantic contracts — encoding generalizable principles, eliminating ambiguous placeholders, and enforcing constraints at every step — turned a class of silent failures into a solved problem for our pipeline. The model was never broken. Our contract with it was.