Session 2 comes with Assignment 01 in the course. Everything you practise on this page โ writing clear prompts, using few-shot examples, chain-of-thought, and getting clean JSON out โ is exactly what the assignment will ask you to do hands-on. Read first, then go build prompts.
1 GIGO โ "Garbage In, Garbage Out"
Imagine asking a super-helpful friend for directions. If you mumble "uh, get me there," they have no idea what you mean. But if you say "I'm at the library, take me to the ice-cream shop on Main Street, the fastest way, and tell me each turn," you get perfect directions. The AI is exactly the same: the clearer and more complete your request, the better its answer. Sloppy question in โ sloppy answer out.
GIGO (Garbage In, Garbage Out) is an old computing saying: a system can only be as good as what you feed it. For LLMs it's the single most important rule of prompt engineering. Remember from Session 1 that the model just predicts the next token based on the text you give it โ it has no idea what's in your head. If your prompt is vague, the model has to guess what you meant, and it often guesses wrong.
You cannot easily change the model (that would be training, from Session 1). The prompt is your only steering wheel. So the quality of your output is almost entirely decided by the quality of your input. Better prompt โ better answer, every time.
What makes a prompt "garbage" vs "great"?
A weak prompt is vague, ambiguous, and missing context. A strong prompt tells the model exactly who to be, what to do, what it's working with, and how to format the answer. Compare:
| Garbage prompt | Why it fails | Great prompt |
|---|---|---|
| "Write about dogs." | No length, audience, angle, or format. The model picks at random. | "Write a friendly 100-word paragraph for 8-year-olds explaining why dogs are good first pets. Use simple words." |
| "Fix my code." | No code shown, no language, no description of the bug. | "Here is my Python function (below). It throws a KeyError. Find the bug, explain it in one sentence, then show the corrected function." |
| "Is this email okay?" | "Okay" for what? Tone? Grammar? Length? | "Review this email for a formal client. Check tone is polite, fix any grammar, and keep it under 80 words." |
The six components of a strong prompt
A reliable way to avoid garbage input is to deliberately include these building blocks. Not every prompt needs all six, but the more you include, the less the model has to guess.
| Component | What it does | Mini-example |
|---|---|---|
| Role | Who the model should act as (sets tone & expertise). | "You are an experienced travel agent." |
| Task | The single, specific thing you want done. | "Plan a 3-day trip to Tokyo." |
| Context | Background facts the model needs. | "The traveller is vegetarian and on a tight budget." |
| Format | How the answer should be structured. | "Give a day-by-day bullet list." |
| Constraints | Limits and rules to follow. | "Keep it under 200 words. No flights โ trains only." |
| Examples | A sample of what good output looks like (covered in Topic 5). | "Format each day like: Day 1 โ Morning: โฆ" |
Here's a single prompt that uses every building block:
You are an experienced travel agent. [ROLE] Plan a 3-day trip to Tokyo. [TASK] The traveller is vegetarian and on a tight budget of $500. [CONTEXT] Give the answer as a day-by-day bullet list. [FORMAT] Keep it under 200 words and use trains only, no flights. [CONSTRAINTS] Format each day like: "Day 1 โ Morning: ... / Afternoon: ... / Evening: ...". [EXAMPLE]
Expected output: a tidy, budget-aware, vegetarian-friendly, train-based 3-day itinerary, under 200 words, formatted exactly as requested โ because the model had nothing left to guess. Try deleting one component (say, the budget) and watch the answer drift.
2 Anatomy of a prompt: the three message roles
Think of a school play. There's the director who whispers from backstage telling the actor how to behave ("be polite, speak slowly"). There's you in the audience asking questions. And there's the actor on stage who answers. The AI conversation has these exact three voices: the director (system), you (user), and the actor (assistant).
When you chat with a modern LLM, your conversation isn't one blob of text. It's a list of messages, and every message has a role that tells the model who is "speaking." There are three roles:
| Role | Who it is | What it's for |
|---|---|---|
| system | The app developer (hidden from end users). | Sets the AI's persona, rules, and behaviour for the whole chat. This is the system prompt we met in Session 1. It comes first and has strong influence. |
| user | You, the person typing. | Your actual questions and requests. |
| assistant | The model itself. | The model's replies. Past assistant messages are included so the model can "see" what it already said and stay consistent. |
Why separate them? Two reasons. First, it lets the developer set behaviour (system) that the end
user can't easily override. Second, recall from Session 1 that the model is stateless
โ the app resends the whole message list every turn, so including past user
and assistant messages is exactly how the model "remembers" the conversation.
Here's what the app actually sends (shown as the structure most APIs use):
[
{ "role": "system", "content": "You are a patient maths tutor for kids. Always explain in simple steps." },
{ "role": "user", "content": "What is 7 times 8?" },
{ "role": "assistant", "content": "Let's count by 8s: 8, 16, 24... it's 56!" },
{ "role": "user", "content": "And 7 times 9?" }
]
Expected output: because the system message set a "patient kids' tutor" persona and the earlier turns are visible, the model answers the new question ("7 times 9") in the same gentle, step-by-step style: "Almost the same! Add one more 7 to 56 โ 63."
The system message is your most powerful lever for controlling behaviour across an entire conversation โ set the persona and rules once, and they apply to every following turn. We use this heavily in Topic 8 (persona prompting).
3 Prompt formats & chat templates
Imagine three friends from different countries. To say "hello" politely, one expects a handshake, one expects a bow, and one expects a wave. Same friendly intent, but each was trained to recognise a different greeting. AI models are the same: each was trained to recognise a particular way of marking "this is the instruction, this is the user, this is the answer." Use the wrong style and the model gets confused.
The three roles from Topic 2 are the idea. But a model doesn't actually see neat JSON โ it sees a single long string of tokens (Session 1). So those roles must be stamped into the text using special marker tokens. The exact set of markers is called a prompt template or chat template. Crucially, each model family was trained on a specific template, so it only "speaks" that one fluently.
If you feed a model a template it wasn't trained on, results degrade: it may keep talking when it should stop, ignore your instruction, leak the marker tokens into its answer, or just get noticeably dumber. The good news: chat APIs and libraries usually apply the right template for you automatically. You mostly need to know this exists when running models yourself (e.g. local Llama).
The common templates you'll meet
Alpaca format
A simple, human-readable, instruction-style template made popular by the Alpaca project. It uses plain English headers, not special tokens โ great for instruction-tuned models.
Below is an instruction that describes a task. Write a response that appropriately completes the request. ### Instruction: Translate "good morning" into French. ### Response: Bonjour
INST format ([INST] โฆ [/INST]) โ Llama & Mistral
Used by Meta's Llama and Mistral chat models. The
user's turn is wrapped in [INST] โฆ [/INST], and the system prompt sits inside
special <<SYS>> markers.
<s>[INST] <<SYS>> You are a helpful assistant. <</SYS>> Translate "good morning" into French. [/INST] Bonjour</s>
The <s> and </s> are the model's
begin/end-of-sequence tokens.
FLAN-T5 style
Google's FLAN-T5 family is instruction-tuned but very plain: you simply give the instruction as natural text, with no role markers at all. It was trained on thousands of tasks phrased as direct instructions.
Translate the following English sentence to French: good morning
No system/user/assistant scaffolding โ just the task, stated plainly.
ChatML (<|im_start|> โฆ <|im_end|>) โ OpenAI
ChatML (Chat Markup Language) is the role format used by OpenAI's models.
Each message is wrapped between <|im_start|>role and
<|im_end|> markers ("im" = instant message).
<|im_start|>system You are a helpful assistant.<|im_end|> <|im_start|>user Translate "good morning" into French.<|im_end|> <|im_start|>assistant Bonjour<|im_end|>
Notice how cleanly the three roles from Topic 2 map onto the markers โ ChatML is basically those roles written out as special tokens.
Every snippet above asks for the same thing ("translate good morning to French" โ "Bonjour"),
but the wrapping differs. A Llama model wants [INST]; an OpenAI model wants
<|im_start|>. Send Llama's template to an OpenAI-style model and you may
see the raw [INST] tokens echoed back, or sloppier answers โ a classic
beginner bug when self-hosting models.
When you use a hosted chat API, you just send the role-tagged messages from Topic 2 and the
provider applies the correct template. When you run an open model yourself, libraries like Hugging
Face provide tokenizer.apply_chat_template(...) to format it correctly โ use
it rather than hand-writing markers.
### Instruction/### Response; Llama/Mistral use
[INST]โฆ[/INST]; FLAN-T5 uses plain instructions; OpenAI uses ChatML
(<|im_start|>). Using the wrong template degrades quality โ let the API or
tokenizer apply the right one.
4 Zero-shot prompting
Imagine asking a really smart friend to do something they already know how to do, without showing them an example first. "Hey, spell 'banana' backwards." You don't need to demonstrate โ they just do it. That's zero-shot: you ask cold, with no examples, and trust the AI already knows.
Zero-shot prompting means asking the model to do a task without giving it any examples of the task first. The word "shot" means "example," so "zero-shot" = "zero examples." You rely entirely on the knowledge the model picked up during training (Session 1).
Prompt (no examples, just the request):
Classify the sentiment of this review as Positive, Negative, or Neutral. Review: "The food was cold and the waiter was rude."
Expected output: Negative
The model has seen millions of reviews during training, so it already understands sentiment โ no example needed.
When zero-shot works well
- Common, well-known tasks the model has seen endlessly: translation, summarising, basic sentiment, answering general-knowledge questions, simple rewriting.
- When you want speed and short prompts โ fewer input tokens means lower cost (token economics, Session 1).
- With strong, modern instruction-tuned models, which are specifically trained to follow direct instructions.
When zero-shot struggles
- Unusual or custom tasks the model hasn't really seen (e.g. your company's own labelling rules).
- When you need a very specific format and the model keeps guessing it differently.
- Nuanced judgement calls where "your" definition of a category differs from the obvious one.
When zero-shot isn't enough, the natural next step is to show the model examples โ that's few-shot prompting, our next topic.
5 Few-shot prompting & in-context learning
Imagine teaching a friend a new game by showing them two or three quick rounds first. "Watch: like thisโฆ and like thisโฆ now you try." After seeing a couple of examples, they copy the pattern perfectly. That's few-shot: you give the AI a few worked examples right inside your prompt, and it copies the pattern.
Few-shot prompting means giving the model a handful of examples of the task inside the prompt, before asking it to do a new one. "Few-shot" = "a few examples." The model studies your examples and continues the pattern โ this ability to learn from examples in the prompt (without any training) is called in-context learning.
Recall from Session 1 that the model just predicts the next token from the text so far. If the text so far is a clear pattern of input โ output, input โ output, the single most likely continuation isโฆ the next output in the same pattern. The model "learns" your task purely from context, with no parameters changing โ that's why it's called in-context learning.
Suppose you have your own categories and want consistent output. Show three examples, then ask:
Classify each message as: BUG, FEATURE, or QUESTION. Message: "The app crashes when I click save." Label: BUG Message: "Could you add a dark mode?" Label: FEATURE Message: "How do I reset my password?" Label: QUESTION Message: "The export button does nothing when pressed." Label:
Expected output: BUG
The examples did two jobs at once: they taught the model your exact label set and the precise output format (just the label, nothing else). That's why the answer is clean and predictable.
Tips for good few-shot examples
- Be consistent. Use the exact same format in every example โ the model copies the format precisely, including stray spaces or punctuation.
- Cover the variety. Include examples of each category or edge case you care about.
- 2โ5 examples is usually plenty; more examples cost more input tokens (Session 1) and can crowd the context window for little extra gain.
- Put the real question last, in the identical format, with the answer slot left blank for the model to fill.
Examples eat tokens, so a few-shot prompt costs more than a zero-shot one and is resent every turn. Use the fewest examples that get reliable results. If two examples already work, don't add ten.
6 Chain-of-Thought (CoT) reasoning
If a teacher asks "what's 17 plus 28?" and demands the answer instantly, you might blurt out a wrong guess. But if she says "take your time, show your working," you write 17 + 28 โ 30 + 15 โ 45, and get it right. The AI is the same: forcing it to "show its working" makes it far more accurate on hard problems.
Chain-of-Thought (CoT) prompting means asking the model to work through a problem step by step before giving the final answer, instead of jumping straight to it. The famous magic phrase is simply: "Let's think step by step."
The model predicts one token at a time with a fixed amount of computation per token. When you force a single-token answer to a multi-step problem, it has no room to "work things out." By letting it generate the reasoning first, each intermediate step becomes part of the context that the next step can build on โ the model literally uses its own written words as a scratchpad. More reasoning tokens = more chances to get it right.
Without CoT (asking for the answer directly):
Q: A shop has 23 apples. It sells 9 in the morning and buys 12 more. Then it sells 7 in the afternoon. How many apples are left? A:
The model may blurt a wrong number like 19, having tried to do it all in
one leap.
With CoT (adding the magic phrase):
Q: A shop has 23 apples. It sells 9 in the morning and buys 12 more. Then it sells 7 in the afternoon. How many apples are left? A: Let's think step by step.
Expected output:
Start with 23 apples. Sell 9 in the morning: 23 - 9 = 14. Buy 12 more: 14 + 12 = 26. Sell 7 in the afternoon: 26 - 7 = 19. So there are 19 apples left.
By showing each step, the model is far more likely to land on the correct
19 โ and you can check its working.
Zero-shot CoT: just add "Let's think step by step" (no examples). Few-shot CoT: combine Topic 5 with this โ show a couple of examples that include the reasoning steps, so the model copies the habit of explaining. Few-shot CoT tends to be the most reliable for tricky tasks.
CoT generates more tokens, so it's slower and costs more (output tokens, Session 1). It shines on reasoning, maths, logic, and multi-step tasks โ but is overkill for simple lookups like "capital of France." If you only want the final answer in production, you can ask it to reason internally and then output just the result.
7 Self-consistency
If one friend solves a tricky maths puzzle, they might slip up. But if you ask five friends to each solve it their own way, and four of them say "42," you can be pretty confident the answer is 42. Asking several times and taking the most common answer is safer than trusting one try.
Self-consistency builds directly on Chain-of-Thought (Topic 6). Instead of generating one step-by-step solution, you generate several different ones, then take the majority-vote answer โ the final answer that appears most often across all the attempts.
How it works, step by step
The key trick: you use a non-zero temperature (Session 1) so each run takes a different reasoning path. Some paths may make a mistake, but correct reasoning tends to converge on the same right answer more often than any single wrong path. The majority vote filters out the flukes.
You ask the same hard maths question 5 times with temperature 0.7. The final answers come back as:
Run 1 โ 19 Run 2 โ 19 Run 3 โ 17 (made an arithmetic slip) Run 4 โ 19 Run 5 โ 19
Majority vote โ 19. A single run might have unluckily been Run 3 and given you the wrong answer; voting across five runs rescues you.
One CoT pass can confidently follow a flawed line of reasoning to a wrong answer. Self-consistency accepts that any single path might be wrong, and trusts the consensus of many independent paths instead. On hard reasoning benchmarks this reliably boosts accuracy over plain CoT.
You're now paying for 5โ10 full answers instead of one, so it's several times more expensive and slower (token economics, Session 1). Reserve it for high-value questions where being right really matters, not everyday chat.
8 Persona / role-based prompting
If you ask a friend "explain rain," you get one answer. But if you say "pretend you're a fun science teacher and explain rain to a 6-year-old," you get a totally different, friendlier answer. Telling the AI who to be changes how it talks โ same brain, different costume.
Persona prompting (also called role-based prompting) means telling the model to act as a specific kind of person or expert: "You are an expert Python tutor," "You are a friendly pediatric nurse," "You are a strict copy editor." This is usually placed in the system message (Topic 2) so it shapes the whole conversation.
Remember the model predicts the next token from patterns in its training data. By naming a role, you nudge it toward the slice of its training that matches that role โ the vocabulary, tone, depth, and habits of, say, an expert tutor. You're not giving it new knowledge; you're aiming it at the right style and rigour it already has.
No persona:
Explain what a variable is in programming.
โ A generic, possibly dry, one-size-fits-all definition.
With persona (in the system message):
System: You are an enthusiastic coding tutor for absolute beginners. You use simple everyday analogies, avoid jargon, and keep answers short and encouraging. User: Explain what a variable is in programming.
Expected output: "Think of a variable like a labelled box where you keep
something. You write a name on the box (like age) and put a value inside it
(like 10). Later you can open the box to use the value, or swap it for a new
one. That's all a variable is โ a named box for storing data!"
Same facts, but the persona made it beginner-friendly, warm, and concrete.
Tips for personas
- Be specific: "expert tax accountant specialising in freelancers" beats just "accountant."
- Add the persona's behaviour, not just title: "explains simply," "is concise," "asks a clarifying question if unsure."
- Combine with other techniques: a persona + format constraints + few-shot examples is very powerful.
A persona changes style and emphasis, not the model's actual knowledge. Telling it "you are a Nobel-winning physicist" doesn't grant it new facts or make it immune to hallucinations (Session 1). It mainly improves tone, framing, and the kind of detail it offers.
9 Structured outputs (getting clean JSON)
Imagine you ask a helper to fill in a form instead of writing a messy paragraph. A form has fixed boxes โ Name: ___, Age: ___ โ so it's easy for a machine to read afterwards. We often want the AI to fill in a "form" too, so our app can use the answer automatically instead of trying to read free text.
So far our outputs have been free-flowing text, which is great for humans but a nightmare for
programs. Structured output means making the model return data in a
fixed, machine-readable shape โ most commonly JSON (JavaScript Object
Notation), a simple "key": value format that almost every programming language
can parse.
Why apps need this
If your app asks the model to extract a customer's order, it can't reliably pull fields out of a
chatty paragraph like "Sure! It looks like they want 2 pizzas and a coke ๐". But if the model
returns {"pizzas": 2, "drink": "coke"}, the app can read
order.pizzas directly. Structured output is what turns an LLM from a chatbot
into a reliable component inside real software (and it's essential for the agents and
tool-calling we'll meet in Session 3).
Techniques for reliable JSON
| Technique | What you do | Why it helps |
|---|---|---|
| Explicit schema | Spell out the exact fields, types, and rules in the prompt. | Removes guesswork about field names and shape. |
| Examples | Show a sample input and the exact JSON you want back (few-shot, Topic 5). | The model copies the format precisely. |
| "Only JSON" instruction | Say "Respond with only valid JSON, no extra text." | Stops chatty wrappers like "Sure, here you go:". |
JSON mode / response_format | A provider setting that forces the output to be valid JSON. | Guarantees parseable output at the API level. |
| Low temperature | Turn temperature down (Session 1). | More consistent, less "creative" formatting. |
Most major providers now offer a built-in JSON mode or
response_format option (some even let you supply a strict schema). When
available, this is the most reliable approach because the system guarantees the output is valid JSON
shaped like your schema โ you don't have to hope the prompt worked.
Prompt with an explicit schema and a "JSON only" instruction:
Extract the booking details from the text below.
Respond with ONLY valid JSON in exactly this schema:
{
"name": string,
"guests": number,
"date": string (YYYY-MM-DD),
"vegetarian": boolean
}
Text: "Hi, this is Priya. Table for 4 on the 12th of July please, all veg."
Expected output:
{
"name": "Priya",
"guests": 4,
"date": "2025-07-12",
"vegetarian": true
}
Now your app can read each field directly โ no fragile text-parsing required.
Even with all these techniques, never blindly trust the output. Validation means your code checks the returned JSON actually parses and matches the expected schema (right fields, right types) before using it. Tools like JSON Schema or Python's Pydantic make this easy. If validation fails, you can retry or ask the model to fix it. Treat the model's output as untrusted until checked.
โ Putting it all together
You just learned how to actually steer an LLM. Here's the one-paragraph story that connects all 9 topics:
Because of GIGO, your output is only as good as your prompt, so build prompts from
role, task, context, format, constraints, and examples. Every prompt is really a list of
messages with three roles โ system (the persona & rules),
user (you), and assistant (the model) โ which each model expects wrapped in its own
chat template (Alpaca, [INST] for Llama/Mistral, plain
FLAN-T5, or ChatML for OpenAI); use the wrong one and quality drops. For common tasks you can ask cold
(zero-shot); for trickier or custom tasks you show examples
(few-shot / in-context learning). For reasoning and maths, make the model show its
working (Chain-of-Thought), and for the hardest questions sample several CoT runs and
take the majority vote (self-consistency). A persona in the system
message steers tone and depth, and when an app needs the answer, you demand
structured output (JSON via schema, examples, JSON mode, and low temperature) โ then
validate it before trusting it. Master these and you control the model far more than
most people ever do.
Quick self-check
What does GIGO mean, and why is it the most important rule of prompting?
"Garbage In, Garbage Out" โ the model can only be as good as your prompt. Since the prompt is your only steering wheel (you can't retrain the model), vague input gives vague output, so including role, task, context, format, constraints, and examples is what drives quality.
Name the three message roles and what each is for.
system = the developer's hidden instructions / persona & rules for the whole chat; user = your input; assistant = the model's replies. The whole list is resent each turn, which is how a stateless model holds a conversation.
What's the difference between zero-shot and few-shot prompting?
Zero-shot gives the model no examples and relies on its training; few-shot puts a few inputโoutput examples in the prompt so it copies the pattern (in-context learning). Few-shot helps for unusual tasks or strict formats, but costs more tokens.
Why does Chain-of-Thought improve accuracy, and how is self-consistency different?
CoT makes the model write out its reasoning step by step, using its own words as a scratchpad (it thinks one token at a time, so more reasoning tokens = better answers). Self-consistency runs CoT several times at non-zero temperature and takes the majority-vote answer, so consensus across many paths beats any single (possibly flawed) path.
Your app needs to read the model's answer automatically. What do you ask for, and what must you never skip?
Ask for structured output (usually JSON) using an explicit schema,
examples, a "JSON only" instruction, JSON mode / response_format, and low
temperature. Never skip validation โ check the JSON parses and matches the schema
before trusting it.
๐ References & Further Reading
Class material
- ๐ Original course notes / handout (source sheet) โ open the shared GenAI class material for this session.
- Class handout: "Prompt Engineering โ roles, few-shot, chain-of-thought & structured outputs".
- ๐ Assignment 01 โ Persona-Based AI Chatbot โ the assignment shared for this session.
Papers, docs & deep dives
- OpenAI โ Prompt engineering guide โ practical strategies and tactics for writing effective prompts.
- Prompt Engineering Guide (promptingguide.ai) โ comprehensive reference covering zero-shot, few-shot, and advanced techniques.
- "Chain-of-Thought Prompting Elicits Reasoning in LLMs" (Wei et al., 2022) โ the paper behind CoT reasoning.
- "Self-Consistency Improves Chain of Thought Reasoning" (Wang et al., 2022) โ sampling multiple reasoning paths and voting for the answer.