Prompt patterns are small shapes you reuse
A prompt pattern is a shape of prompt that you use on purpose because it fixes a known problem. Persona, template, critique and rewrite, and constraints first are four of them.
Naming a pattern lets a team talk about prompts and test them. "This one uses constraints first" is a sentence you can act on.
By the end of this lesson
Note
I can use a small set of prompt patterns on purpose.
Key words
| Word | What it means | Example |
|---|---|---|
| Pattern | a prompt shape with a known use | |
| Persona | a role the model is asked to play | |
| Template | a prompt with gaps to fill in | |
| Placeholder | a gap in a template | {{name}} |
| Critique | a list of what is wrong | |
| Constraint | a rule the answer must obey |
The cells students fill in are left blank in this preview.
What do the four patterns do?
A persona sets a role and a voice. A template has gaps that code fills, so every prompt has the same shape. Critique and rewrite asks the model to find faults first and then fix them. Constraints first puts the rules before the task so they are not forgotten.
Patterns combine. A template may open with constraints.
Four patterns and what each fixes
| Pattern | Cue in the prompt | It fixes |
|---|---|---|
| Persona | Starts "You are" or "Act as" | A voice that drifts |
| Template | Gaps such as {{name}} | Prompts that all differ |
| Critique and rewrite | Asks for both steps | A first draft left as it is |
| Constraints first | Starts "Rules:" or "Limits:" | Rules lost at the end |
The cells students fill in are left blank in this preview.
Write the model helper, part 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// The token counts of a reply, or null when the reply carries none.' 'function count(data, name) {' ' return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the model helper, part 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' ' try {' ' const res = await fetch(base + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"status \" + res.status);' ' const data = await res.json();' ' const text = data.choices[0].message.content;' ' return { text, inTokens: count(data, \"prompt_tokens\"), outTokens: count(data, \"completion_tokens\"), recorded: false };' ' } catch (error) {' ' console.log(\"Recorded sample: no model answered (\" + error.message + \").\");' ' return { text: sample, inTokens: null, outTokens: null, recorded: true };' ' }' '}' 'module.exports = { ask };' >> model.js"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the pattern finder, part 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const prompts = [' ' \"You are a patient maths tutor. Explain fractions.\",' ' \"Rules: under 20 words. No jargon.\nTask: explain tides.\",' ' \"Write a note to {{name}} about {{topic}}.\",' ' \"Critique this paragraph, then rewrite it.\",' ' \"Explain tides.\",' '];' > pat4.js"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the pattern finder, part 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function patternOf(p) {' ' const low = p.toLowerCase();' ' if (low.includes(\"critique\") && low.includes(\"rewrite\")) return \"critique and rewrite\";' ' if (p.startsWith(\"Rules:\") || p.startsWith(\"Limits:\") || p.startsWith(\"Constraints:\")) return \"constraints first\";' ' if (p.includes(\"{{\") && p.includes(\"}}\")) return \"template\";' ' if (p.startsWith(\"You are \") || p.startsWith(\"Act as \")) return \"persona\";' ' return \"plain\";' '}' 'function fill(t, values) {' ' let out = t;' ' for (const key of Object.keys(values)) out = out.split(\"{{\" + key + \"}}\").join(values[key]);' ' return out;' '}' >> pat4.js"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the pattern finder, part 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' prompts.forEach(function (p, i) { console.log((i + 1) + \": \" + patternOf(p)); });' ' const filled = fill(prompts[2], { name: \"Mina\", topic: \"the school trip\" });' ' console.log(\"filled: \" + filled);' ' const reply = await ask([{ role: \"user\", content: filled }], \"Dear Mina, the school trip leaves at nine.\", 50);' ' console.log(\"model: \" + reply.text);' '}' 'main();' >> pat4.js"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Run and name the patterns
docker exec -w /home/node/project agent node pat4.jsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
What the Run prints
Five lines name the pattern of each prompt: persona, constraints first, template, critique and rewrite, plain. The checks run in a fixed order, so a prompt with two cues gets the first that fits.
Then it fills the template and sends it. The last line is one short reply. With no model it prints a Recorded sample first.
A common mistake
Warning
Many people think a persona makes a model more accurate. A role sets the voice and the level of detail. It does not add facts the model does not have. Use a persona for tone, and use limits and examples for correctness.