Prompt fundamentals
Clear instructions, context and constraints: the 80% of prompting.
Create a free account Try part of it here
Why it matters
The prompt is the main control you have over a model. The same model can send back a vague paragraph or exactly the output your code needs. The difference is almost always how clearly you described the task. Good prompting has little to do with secret phrases. It's much closer to leaving a clear note for a house-sitter or writing a brief for a freelancer. If you've done either, you already have the core skill.
What you'll be able to do
- Rewrite a vague request as a prompt with a task, context, constraints and an output format
- Separate instructions from the material the model works on, using XML-style tags
- Build prompts from a Python template so every request is worded the same way
- Test a prompt on several inputs, and handle replies that don't follow the format
What it covers
- Write the brief you'd give a new hire
- Specific beats clever
- Keep instructions and material apart
- Templates: the same wording every time
- Worked example: one template, several reviews
Write the brief you'd give a new hire
Picture a friend who will look after your dog for the weekend. A note that says "Feed the dog" isn't enough. They need to know how much food, when, where it's kept, and what to do if she won't eat. You know all of that already, so it's easy to forget to write it down.
A model is in the same spot as your friend. It knows a great deal about the world in general. It knows nothing about your situation: your business, your audience, why you're asking, or what happens to the answer next. You saw in "What an LLM actually does" that a model writes by picking likely next tokens. Generic text is usually the most likely text. So when a prompt leaves out the details, the model fills the gaps with the most generic guess.
A prompt is the text you send to the model. Here are two prompts for the same job, a sale email for an outdoor clothing store:
Write an email about our sale.
Write a promotional email for Trailhead Outfitters, an outdoor clothing brand. The audience is past customers who bought rain gear in the last two years. The offer: 30% off all rain jackets, ending Sunday at midnight. Keep it under 120 words, in a friendly, plain tone, with one call to action. Return the subject line on the first line, then a blank line, then the body.
The first gets you an email written for nobody in particular. The second gets you something close to ready to send.
Here's a useful test. Imagine a capable colleague who knows nothing about the task. Would they need to ask you questions before they could start? If so, the model needs those answers too. For a product description: who it's for, its key features, a word limit, where it will appear. Unlike the colleague, the model won't ask. It will guess.
Four parts of a clear prompt
The second prompt works because it covers four things:
| Part | What it answers | Example |
|---|---|---|
| Task | What should it do? Start with a verb. | "Write a promotional email" |
| Context | Who is it for, why, and what facts does it need? | "past customers who bought rain gear; 30% off, ends Sunday" |
| Constraints | What limits apply? | "under 120 words, friendly and plain, one call to action" |
| Output format | Exactly what should come back? | "subject line first, a blank line, then the body" |
The task is the job itself. The context is the background the model can't know on its own. Constraints are the limits, such as length and tone. The output format is the exact shape of the reply.
Short prompts don't need every part spelled out. When a reply disappoints, though, one of the four is usually missing.
Show the answer
Context: it says nothing about Dana or how well you know her
The task (write a birthday message), the constraints (under 40 words, warm but not cheesy) and the output format (the message only) are all there. Apart from "coworker", the model knows nothing about Dana, so it will write a message that could be for anyone.
Send the vague prompt first. Then replace it with the detailed version above and send again. It's the same model, but you'll get a very different email. If a reply comes back cut off, raise max_tokens.
Specific beats clever
Some prompting advice is about tricks: magic phrases, flattering job titles, even threats. Specific prompting means saying exactly what you want, and it works far better. A few habits make the biggest difference:
- Use numbers instead of adjectives. "Three options, each under 50 characters" beats "a few short options".
- Say what to do, not only what to avoid. "Write in plain sentences" works better than "Don't use bullet points" on its own.
- Give the reason for a rule. Say "Keep subject lines under 50 characters, because longer ones get cut off on phones." The reason lets the model apply the idea to cases your rule didn't mention.
- Give it a way out. Add "If the review doesn't mention shipping, reply
none." This stops the model from inventing an answer to fit the question. - Ask for the exact output. "Reply with the subject line only" saves your code from digging the answer out of "Sure! Here's a subject line you could use: ...".
You don't need magic phrases, threats or ALL CAPS. Current models follow plain, specific instructions closely. Shouting a rule can even backfire, because the model may then apply it too broadly.
Show the answer
Add "If the review doesn't mention shipping, reply none."
Without a way out, the model tends to invent an answer that fits the question. A stated fallback like none gives it an honest reply to choose, and gives your code something easy to check.
Keep instructions and material apart
Most real prompts mix two things. There are your instructions, and there's material to work on: a review, an article, a list of products. Think of forwarding an email to a coworker with a note on top. A clear line between your note and the forwarded text stops them from mixing the two up.
In a prompt, you draw that line with XML-style tags. These are labels you make up, written in angle brackets. An opening tag like <review> marks where the material starts. A closing tag with a slash, </review>, marks where it ends. (XML is a data format that uses labels like these. You don't need to know anything else about it.)
Classify the sentiment of the customer review below. <review> The jacket kept me dry on a six-hour hike, but the hood is too small to fit over a cap. </review> Reply with one word: positive, negative or mixed.
"Sentiment" means the feeling behind the words: happy, unhappy, or a bit of both. The tag names are yours to choose. There's nothing special about review. Tags help in three ways:
- The model can see exactly where the material starts and ends.
- You can refer to the material by name: "the review in the
<review>tags". - The model is less likely to treat text inside the material as instructions. That risk is called prompt injection, and it gets its own lesson later.
Some material is long, such as a report or a batch of reviews. Put it first, and put your instructions and question at the end. Models tend to answer questions about long documents better that way.
Show the answer
Classify the review in the <review> tags as positive, negative or mixed. Reply with the label only. <review>…</review>
It names the task, the allowed answers and the exact output. The others invite a chatty paragraph that your code would have to pick apart.
Templates: the same wording every time
An app sends the same kind of request many times, each with different material. Think of a form letter with blanks for the name and date. You write the prompt once, as a function. Then you fill in the blanks with an f-string:
def review_prompt(review, product): return f"""Classify the sentiment of this customer review of our {product}. <review> {review} </review> Reply with one word: positive, negative or mixed.""" print(review_prompt("Warm, light, and the pockets are huge.", "Ridgeline Fleece"))
Run it, and you'll see the full prompt with the product name and the review filled in.
With a template, every request is worded the same way. That makes results comparable from one review to the next. And when you improve the wording, every future request gets the improvement.
Test with more than one input
One good reply proves very little. It might be luck, and real inputs vary a lot. Before you rely on a prompt, run it on a handful of inputs. Include some awkward ones:
- a very short review
- a sarcastic one
- one about a different product
- one that's mostly a question
Check the replies with code wherever you can. When you change the prompt, run the same inputs again and compare. That list of test inputs is the start of an eval (short for evaluation). Phase 1 covers evals properly later.
Plan, too, for replies that ignore the format. Even "Reply with one word" can come back as "Mixed." or "Mixed: the reviewer liked the warmth but...". Clean up what you safely can, such as extra spaces, capital letters or a period at the end. Treat anything else as unknown. Don't guess.
Worked example: one template, several reviews
This puts the lesson together. The code fills in the template for three reviews, sends each one, and cleans up each reply. When the academy has no API key, you get a simulated reply that quotes your prompt back. That isn't a label, so every result comes out unknown. That's the correct handling for a reply you can't use.
import requests LABELS = ["positive", "negative", "mixed"] def review_prompt(review, product): return f"""Classify the sentiment of this customer review of our {product}. <review> {review} </review> Reply with one word: positive, negative or mixed.""" def ask(prompt): response = requests.post( "https://api.anthropic.com/v1/messages", headers={"x-api-key": "added-by-the-academy-server", "anthropic-version": "2026-10-21"}, json={"model": "claude-opus-5-5", "max_tokens": 1000, "messages": [{"role": "user", "content": prompt}]}, timeout=60, ) response.raise_for_status() text = "" for block in response.json()["content"]: if block["type"] == "text": text += block["text"] return text def clean_label(reply): word = reply.strip().lower().rstrip(".") if word in LABELS: return word return "unknown" reviews = [ "Warm, light, and the pockets are huge.", "Oh great, another jacket that soaks through in a drizzle.", "Love the color. The sleeves are way too long, though.", ] for review in reviews: label = clean_label(ask(review_prompt(review, "Ridgeline Fleece"))) print(label, "|", review)
clean_label tidies each reply in three steps. strip() removes spaces and newlines from both ends. lower() turns capital letters into lowercase. rstrip(".") removes periods from the end. It works like strip, but only on the right-hand side.
Only an exact label counts. Everything else becomes unknown.
With a real model, watch the second review. It's sarcastic. "Oh great" sounds positive word by word, but the reviewer is unhappy. A prompt that labels it negative is doing real work.
def clean_label(reply): word = reply.strip().lower().rstrip(".") if word in ["positive", "negative", "mixed"]: return word return "unknown" print(clean_label("NEGATIVE."), clean_label("Mixed, mostly"))
Show the answer
negative unknown
"NEGATIVE." is lowercased and loses its period, leaving "negative". "Mixed, mostly" becomes "mixed, mostly", which isn't an allowed label, so it turns into "unknown". The cleanup never guesses.
Practice what you just read
- 2 code examples you can edit and run
- a practice exercise that checks your code
- a 5-question quiz
- 5 review cards for spaced repetition
Try a quiz question
A prompt says only: "Write a product description for our fleece." Which addition would improve the result most?