Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

How to write a clear prompt

After this lesson: I can turn a vague request into a prompt with a role, a task, limits and an output form.

60 min lesson6 commandsAI coding agent lab: use opencode to explain and fix code, and check its work

Four parts make a clear prompt

A prompt is the text you send to a language model. The model reads only that text, so it cannot guess what you meant to add.

"Tell me about the match" gets a different answer every time. A prompt with a role, a task, limits and an output form gets one you can use.

By the end of this lesson

Note

I can turn a vague request into a prompt with a role, a task, limits and an output form.

Key words

WordWhat it means
Promptthe text you send to a model
Rolewho the model should act as
Taskthe one job to do now
Limitswhat the answer must not go beyond
Output formthe shape the answer must take
Checklista list of things to tick off

The cells students fill in are left blank in this preview.

What are the four parts of a prompt?

The role says who the model acts as. The task says the one job. The limits say what it must not go beyond, such as length or sources. The output form says the shape of the answer, such as one sentence or a list.

Put each on its own line with a label. A label makes the prompt easy to read and easy to check.

The same request, badly and well

PartVagueClear
Role(nothing)You are a sports club reporter.
TaskTell me about the match.Write a news line about the result below.
Limits(nothing)One sentence. Use only the facts given.
Output form(nothing)Plain text, no title.

The cells students fill in are left blank in this preview.

Write the model helper, part 1

Command
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

Command
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 prompt checker, part 1

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const vague = \"Tell me about the match.\";' 'const good = [' '  \"Role: You are a sports club reporter.\",' '  \"Task: Write a news line about the match result below.\",' '  \"Limits: One sentence. Use only the facts given.\",' '  \"Form: Plain text, no title.\",' '  \"Facts: Riverside 3, Hillside 1. Two goals by Sam.\",' '].join(\"\n\");' > say1.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the prompt checker, part 2

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const PARTS = [\"Role\", \"Task\", \"Limits\", \"Form\"];' 'function missing(prompt) {' '  const lines = prompt.split(\"\n\");' '  const gone = [];' '  for (const part of PARTS) {' '    const has = lines.some(function (l) {' '      return l.startsWith(part + \": \") && l.length > part.length + 2;' '    });' '    if (has === false) gone.push(part);' '  }' '  return gone;' '}' >> say1.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the prompt checker, part 3

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  for (const p of [vague, good]) {' '    const gone = missing(p);' '    console.log(\"score \" + (4 - gone.length) + \" of 4, missing: \" + (gone.join(\", \") || \"nothing\"));' '  }' '  const sample = \"Riverside beat Hillside 3 to 1, with two goals from Sam.\";' '  const reply = await ask([{ role: \"user\", content: good }], sample, 60);' '  console.log(\"model: \" + reply.text);' '}' 'main();' >> say1.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run and score two prompts

Command
docker exec -w /home/node/project agent node say1.js

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

What the Run prints

The first two lines score the vague prompt and the written one. The vague one scores 0 of 4 and lists all four parts as missing. The written one scores 4 of 4.

The last line is one short reply from the lab's model. With no model it prints a Recorded sample first. The words in a reply can differ each run, and that is normal.

A common mistake

Warning

Many people think a longer prompt is a better prompt. It is not. A prompt is better when each part is there and says one thing. Add a line only when it limits the answer or shapes it.

About this lab and its source: AI coding agent lab: use opencode to explain and fix code, and check its work

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.