Prompting

A prompt is the text you put in front of the model before it predicts. That is the whole idea this chapter sharpens: a prompt is not a command you give to a mind, it is the context you arrange so the answer you want becomes the most probable continuation.
What a prompt really is
Same model, two prompts. "Write about climate change" gives you a wandering essay you did not ask for. "Write three sentences on the main causes of climate change for a 12-year-old, no statistics" gives you something you can use. The model did not change between those two calls. The context did, and the output followed.
The previous chapter covered how a model generates text by predicting the most probable next token, guided by everything in front of it. A prompt is that "everything in front of it". This is the definition worth holding onto: a prompt is not a request you make to a person, it is the context you set up so the continuation you are hoping for is the one the model finds most likely.
That reframing changes how you write. You are not persuading or instructing someone. You are arranging text so the answer you want is the probable next thing. Every technique in this chapter is a different way of doing that, and each makes more sense once you can see the prediction machine underneath it.
The three roles
When you talk to a model through code, you do not send one block of text. You send a list of messages, and each message carries a role that marks where it came from. There are three:
- system: your standing instructions. Who the model should act as, the rules it follows, the format you want. Set once, applies to the whole conversation.
- user: a message from the person using your app. The actual request.
- assistant: a message the model produced earlier. This is how a conversation keeps its history.
messages = [
{"role": "system", "content": "You are a concise assistant for a cooking app. Answer in one sentence."},
{"role": "user", "content": "What can I use instead of butter in cookies?"},
]Under the hood, those roles are not separate channels into the model. They get flattened into one stream of text with special marker tokens around each message, and that whole stream is what the model predicts from. The roles matter because the model was trained on conversations laid out this way, so it learned to treat system content as the authoritative standing rules and user content as the request to answer.
The system message is the one beginners underuse. It is where you set the behaviour you want on every turn: the tone, the audience, the format, the things the model should never do. Put durable rules there, and put the specific request in the user message.
Because the model has no memory between requests, the assistant role is also how you replay what was said before: to continue a conversation, you send the earlier exchange back as assistant and user messages. More on that when you start calling models from code.
system, user, or assistant. Those tags get flattened into one stream of text the model predicts from, but it was trained to treat system as authoritative rules and user as the request. Put durable instructions in system, the specific ask in user, and replay past assistant and user messages to carry a conversation's history. Specific beats vague
Two prompts, one model. "Write about climate change" returns a generic essay of unpredictable length and tone. "Write a three-sentence summary of the main causes of climate change, for a 12-year-old, in plain language, with no statistics" returns close to what you pictured. Same machine, wildly different output, and the only difference is how much you pinned down.
The reason traces back to the prediction loop. At every step the model is choosing from a spread of plausible continuations. A vague prompt leaves that spread wide, so the model fills the gaps with whatever is most common in general, which is rarely the exact thing you had in mind. A specific prompt narrows the spread toward the answer you want, before the model has written a single token.
# vague: the model decides length, tone, audience, format
"Write about climate change."
# specific: you decide
(
"Write a 3-sentence summary of the main causes of climate change, "
"for a 12-year-old, in plain language, with no statistics."
)The vague version could continue a thousand sensible ways, and you get a random one of them. The specific version rules almost all of those out in advance. When you write a prompt, say what you actually want:
- Format: a sentence, a list, JSON, a table.
- Length: one paragraph, three bullets, under 50 words.
- Audience: a beginner, an expert, a 12-year-old.
- What to do when unsure: "If the text does not say, reply 'not specified' rather than guessing."
That last one carries more weight than it looks. Left to its own devices the model fills a gap with a confident guess, because a fluent guess is the probable continuation. Explicitly giving it the option to say "I do not know" makes that the likely path instead, which is one of the few prompt-level moves that reduces the hallucination problem from the last chapter. Specificity narrows the model's options before it writes a token.
Show it examples
Sometimes the clearest way to set up the right continuation is to show it. Putting a few worked examples in the prompt is called few-shot prompting (no examples is zero-shot). It works because the model is, at heart, a pattern-continuer: give it two or three examples of input-then-correct-output and the most probable thing to come next is the same pattern applied to your new input.
messages = [
{"role": "system", "content": "Label each review as POSITIVE, NEGATIVE, or NEUTRAL. Reply with only the label."},
{"role": "user", "content": "The food was cold and slow to arrive."},
{"role": "assistant", "content": "NEGATIVE"},
{"role": "user", "content": "Decent meal, nothing special."},
{"role": "assistant", "content": "NEUTRAL"},
{"role": "user", "content": "Best burger I have had in years!"},
]
# the model now answers: POSITIVEThe two completed examples establish the exact pattern: one word, all caps, from a fixed set. Continuing that pattern for the third review is now far more probable than writing a paragraph of analysis, so that is what you get. This is why a couple of clear examples often beat a paragraph of description, especially for classification and formatting: you are demonstrating the shape of the output rather than describing it and hoping. Choose examples that cover the tricky cases, since the model patterns itself on what you show, including any mistakes in your examples.
Ask it to reason
Here is one of the most useful prompting ideas, and one of the least intuitive, and it falls straight out of how the model works. The model generates one token at a time, and the only working space it has is the text it has already written. It has no hidden scratchpad to quietly work out a hard problem before answering. Its thinking, such as it is, happens out loud, in the tokens it produces.
So if you ask a multi-step question and demand only the final answer, you are forcing the model to leap to the end in a single token with nowhere to work, and on anything involving reasoning, math, or logic it often leaps wrong. The fix is to let it work in the open. Ask it to lay out its steps before the answer:
messages = [
{"role": "system", "content": "Work through the problem step by step, then give the final answer on its own line."},
{"role": "user", "content": "A shop sells pens at 3 for $2. How much do 12 pens cost?"},
]
# without "step by step", models often blurt a wrong number
# with it, the model writes out the working, and each step makes the next more reliableThis is called chain-of-thought prompting, and the reason it works is mechanical, not magical. Every step the model writes becomes part of the context it reads for the next token, so writing "12 pens is 4 groups of 3" makes "4 groups times $2 is $8" the natural, probable continuation. You are giving the model room to compute on the page instead of demanding the answer in one impossible jump. "Think step by step" or "show your working" is the everyday version.
Two caveats. The written reasoning is still generated text, so it can look sound and reach a wrong answer, and you should not treat it as a guaranteed proof. And some newer models do this kind of working internally without being asked. But the underlying principle is durable across whatever models come next: a model reasons better when it has space to write out the steps, because its own output is the only place it has to think.
Structure the prompt
As prompts grow, structure keeps the context clear so the model weighs each part correctly. A few habits help:
- Put instructions first, data last. State what to do, then provide the text to do it on.
- Separate instructions from data with delimiters. Wrap any provided text in clear markers so the boundary between your rules and the input is unmistakable.
- Ask for the output shape explicitly. If you want JSON, say so, and describe the fields.
prompt = f'''Summarise the customer message below in one sentence.
Then list any product names it mentions.
Customer message:
"""
{user_message}
"""'''The triple quotes are a delimiter. They mark off "everything inside here is data to process, not instructions to follow". This is not only tidiness, and here the prediction view shows why it is a real safeguard.
To the model it is all one stream of text, so if user input flows straight into your instructions with no boundary, a user can write "ignore the above and do this instead" and the model has no reliable way to tell that line apart from your real instructions. It may well continue by obeying it.
That attack is called prompt injection, and keeping instructions and untrusted data clearly fenced off is the first line of defense, covered in Safety and limits. To the model it is all one stream of text, so fence untrusted input.
In practice
Here is a prompt that stacks several of these ideas: a system message for durable rules, a specific request, an example to fix the format, and clearly delimited data.
messages = [
{
"role": "system",
"content": (
"You extract action items from meeting notes. "
"Reply with a numbered list, one action per line, each starting with a verb. "
"If there are no action items, reply 'None'."
),
},
{"role": "user", "content": 'Notes: """We agreed Sam will send the budget by Friday and Lee will book the venue."""'},
{"role": "assistant", "content": "1. Send the budget by Friday (Sam)\n2. Book the venue (Lee)"},
{"role": "user", "content": f'Notes: """{meeting_notes}"""'},
]The system message sets the rules once, the example fixes the exact format, and each request delivers fenced data. Every piece is arranging the context so the output you want is the probable continuation. That is the whole craft: this is a reliable prompt, not a lucky one. Next you will send messages like these to a model from real code in Calling models from code.
system message for durable rules, a specific request, an example to fix the format, and clearly delimited data. Each piece arranges the context so your wanted output is the probable next text. That is the craft, a prompt that works by design rather than by luck. 
