Skip to main content
Laravel, thinking fast.
Chapter 3 · Prompts Are Code

The Prompts You Did Not Write

Julian Beaujardin

If you only version the system prompt, you have versioned some of your prompting.

Every one of these is prompt surface, read by the model, shaping behaviour:

  • Tool descriptions. The sentence explaining what a tool does is the entire basis on which the model decides to call it. A vague description is a tool that fires at the wrong time.
  • Parameter descriptions. These carry your validation rules in prose — resolve relative dates before sending, extract the city from the description, use this field for events and that one for businesses.
  • Server-level instructions. The recommended order of operations across a whole toolset.
  • What your tools return. A tool result is text the model reads next; a field called next_action telling it what to do with the result is a prompt, delivered mid-turn.

They all deserve the same treatment as the system prompt — reviewed, versioned, deployed — and they are the subject of Chapter 7. Mention them here only so that when someone says "the prompt", you ask which one.

Put the Stable Part First

Prompts are usually the largest, most repeated part of what you send. Providers cache them, and the caching is prefix-based: an identical leading span of a request can be reused across calls, and you mark where that span ends.

'system' => [
    [
        'type' => 'text',
        'text' => $this->systemPrompt,
        'cache_control' => ['type' => 'ephemeral'],
    ],
],

Two consequences for how you write prompts.

Order by stability. Everything invariant goes first — role, rules, output contract, tool guidance. Anything varying per request goes after the marker. A prompt that opens with the user's name has no cacheable prefix at all, however long it is.

Verify it is working. Providers have a minimum cacheable size, and a prompt near that threshold may be marked and never actually cached. The usage block tells you: if the cache-read counter stays at zero across turns, the marker is decorative and should be moved or dropped. Logging that number is how you find out — which is Chapter 14, and is the difference between believing you have caching and having it.

Changing a Prompt Is a Deploy

Treat it as one, with the same ceremony.

Know which version produced what. Generated content outlives the prompt that made it. When output looks wrong six weeks later, the first question is what it was generated under — so stamp a schema or prompt version onto stored content, as Chapter 2 does.

Change one thing. Prompt edits cannot be bisected after the fact; if three rules changed and behaviour got worse, you have no way to attribute it. Ship one change, watch it, then ship the next.

Watch the right signal. A prompt change rarely breaks loudly. It shifts a distribution — slightly longer outputs, one more tool call per turn, a refusal rate that creeps. Those are the numbers to have on a dashboard before you start editing prose.

The FAQ fix in the last chapter is the model case: a genuine production bug — fabricated prices on live sites — whose fix was entirely a prompt edit. It went through review and a deploy, exactly as a code fix would, because that is what it was.

Testing Prose

You cannot assert that a prompt is good. You can assert plenty about what it contains, and those assertions are cheap.

Assert structure, never wording. A test that pins an exact sentence fails on every legitimate edit and teaches the team to delete tests. A test that asserts the prompt declares every section the schema requires — the sync test from the last chapter — fails only when something is genuinely wrong.

Assert composition. That the event variant contains the event-only actions, that the business variant does not, and that both contain the shared base. Three assertions, no tokens, and they catch a fork that has started to drift.

Assert interpolation. That a supplied service name appears inside its own description instruction. That is the hair-salon bug, permanently.

None of these call a model. All of them run in milliseconds. They will not tell you the prompt is well written, and they will tell you the moment it stopped saying what the rest of the system assumes it says.

What This Chapter Argued

  • A prompt is a function returning behaviour. Version it, review it, deploy it, and be able to revert it.
  • Keep it in a class as a nowdoc constant. Quoted heredoc, so the model's braces and placeholders are not interpolated by PHP.
  • Compose variants from a shared base. Forked prompts drift silently; a base plus a delta cannot.
  • The AI-facing copy belongs with the schema, not scattered through assembly code.
  • Name the thing in the instruction. "Describe this" drifts to the sector average; "describe X and nothing else" does not.
  • Resolve ambiguity to a defined output, not to the model's judgement — and give refusals the same shape as successes.
  • A prompt is never a security boundary. It is a speed bump in front of one.
  • System prompts are not your only prompts. Tool and parameter descriptions are read just as carefully.
  • Order the prompt by stability so a prefix can be cached — then check the cache counter to prove it is.
  • Test structure and composition, never wording.