- Explain in-context learning and design few-shot examples that are relevant, diverse and correctly formatted
- Decide when chain-of-thought prompting helps, and explain how built-in reasoning models changed that advice
- Calculate how self-consistency (majority voting over samples) raises accuracy under stated assumptions
- Implement prompt chaining, delimiters, templates and structured output in a reusable prompt
- Build a small prompt evaluation set and harness to compare prompt variants objectively
Before this: Prompting Fundamentals, Hallucinations and How to Verify
Basic prompting gets you a reasonable answer. Professional prompting gets you the same good answer a thousand times in a row, in a format your code can parse, at a cost you can afford, and with evidence that it works. This lesson covers the techniques practitioners use for that: few-shot examples, reasoning prompts, sampling and voting, decomposition, structure, templates, and above all systematic testing. Provider-specific advice below is drawn from official documentation as of November 2026 and is labelled as such, because it changes as models change.
Intuition: briefing a brilliant contractor who has no memory
Imagine hiring an exceptionally capable contractor who has read most of the internet but knows nothing about your company and forgets everything after each job. Everything they need must be in the brief: the role, the goal, the materials (clearly separated from the instructions), examples of what good work looks like, how to format the deliverable, and what to do when something is unclear. Advanced prompting is the craft of writing that brief, and then checking the contractor's work on many jobs, not just one.
In-context learning and few-shot prompting
In-context learning is a model's ability to pick up a task from instructions and examples placed in the prompt, without any change to its weights. Brown et al. (2020) showed with GPT-3 that adding a handful of input-output examples ("few-shot"; none is "zero-shot") could substantially improve performance on many tasks.
What good examples do: they pin down format, tone, label set, edge-case handling and the level of detail far more precisely than prose instructions. Guidelines:
- Relevant: drawn from your real input distribution.
- Diverse: cover different classes and tricky edge cases, so the model does not copy surface features of one example. If every example's answer is "positive", the model learns a bias, not the task.
- Consistent: every example must follow your instructions exactly; models imitate examples more faithfully than they obey instructions.
- Clearly marked: wrap them, for example in
<example>tags, so the model knows they are illustrations, not part of the current input.
Anthropic's prompting documentation recommends 3 to 5 examples for best results. OpenAI's reasoning-model guidance suggests trying zero-shot first and adding examples only if needed, keeping them closely aligned with the instructions. These are not contradictory: examples cost tokens and can over-constrain a strong reasoning model, so add them when evaluation shows they help.
Cost check. Five examples of 150 tokens each add 750 input tokens per call. At 1 million calls per month, that is 750 million extra input tokens; at a hypothetical price of 1 US dollar per million input tokens, that is 750 dollars per month. Prompt caching (covered in the next lesson) can cut this sharply because the examples form a static prefix.
Chain-of-thought, and how reasoning models changed it
Chain-of-thought (CoT) prompting asks the model to write intermediate reasoning steps before the answer. Wei et al. (2022) showed that few-shot examples containing worked reasoning greatly improved large models on arithmetic, commonsense and symbolic reasoning; Kojima et al. (2022) found that simply adding "Let's think step by step" helped in the zero-shot setting. Why it works, intuitively: a model produces each token with a fixed amount of computation, so writing out steps gives it more computation and lets later steps condition on earlier results.
It does not help everywhere. A large meta-analysis by Sprague et al. ("To CoT or not to CoT?", ICLR 2025) found the benefits concentrated mainly on math and symbolic or logical reasoning tasks, with much smaller gains elsewhere. Reasoning text also costs output tokens and latency.
Reasoning models changed the advice. Models trained to produce an internal reasoning process before answering (see the reasoning-models lesson) already do this work. As of November 2026:
- OpenAI's reasoning best-practices guide says prompting these models to "think step by step" or "explain your reasoning" is unnecessary, and recommends simple, direct prompts with clear constraints and success criteria.
- Anthropic's documentation says newer Claude models use adaptive thinking controlled by an effort setting, that general instructions such as "think thoroughly" often beat a hand-written step-by-step plan, and that manual chain-of-thought is a fallback for when thinking is off.
Rule of thumb: with a non-reasoning model on a multi-step problem, ask for reasoning (and put it in a separate tagged section so you can strip it before showing the answer). With a reasoning model, describe the goal, constraints and what a good answer looks like, set the reasoning effort, and let it plan.
Self-consistency: sample several, then vote
Self-consistency (Wang et al., 2022) samples several independent reasoning paths at a non-zero temperature and returns the most common final answer. It works because a correct answer can be reached by many routes, while errors tend to scatter.
Worked calculation. Suppose a single sample is correct with probability , samples are independent, and (pessimistically) all wrong samples agree on the same wrong answer, so we need a strict majority. With samples, the vote is correct when at least 3 are correct. With :
So accuracy rises from 60% to about 68%, at five times the cost. If wrong answers scatter across different values, plurality voting does even better. If under the same pessimistic assumption, voting makes things worse, and if errors are correlated (the model has a systematic misconception) voting cannot fix them. Use self-consistency for high-value questions with short, comparable final answers (a number, a label), and measure the gain on your eval set.
Decomposition and prompt chaining
Complex tasks often fail because one prompt asks for too much. Decomposition splits a task into sub-tasks; prompt chaining runs them as a pipeline in which each step's output feeds the next. Least-to-most prompting (Zhou et al., 2022) applies the idea within reasoning: first list simpler sub-problems, then solve them in order. Example chain for analysing a contract:
- Extract all clauses about termination, liability and payment, quoting them verbatim, as JSON.
- For each clause, classify the risk level against a provided policy.
- Write a one-page summary for a non-lawyer using only the outputs of step 2.
Benefits: each prompt is simpler and testable on its own; you can use a cheaper model for easy steps; you can validate between steps (does step 1's JSON parse? are the quotes really in the document?). Cost: more calls and more latency, plus errors that propagate down the chain if unchecked.
Role and system prompts
The system prompt (called a developer message in some APIs) holds standing instructions that apply to the whole conversation: role, audience, tone, rules, output format, available tools. A role ("You are a senior tax accountant reviewing small-business returns") focuses vocabulary, depth and tone; Anthropic's docs note that even one sentence of role makes a difference. Roles do not add knowledge the model lacks, and "You are the world's greatest expert" adds nothing measurable compared with a concrete description of the job and the audience.
Structure: delimiters, tags and output formats
Delimiters separate instructions from data. XML-style tags are widely used because they are unambiguous and nest naturally:
<instructions>
Classify the support ticket into exactly one category from <categories>.
If none fits, use "other". Respond with JSON only.
</instructions>
<categories>billing, bug, feature_request, account_access, other</categories>
<ticket>
{{ticket_text}}
</ticket>
Delimiters also reduce prompt injection risk slightly, by making clear which text is data, though they are not a security boundary (see ai-security-risks).
For structured output, specify the exact schema, give an example, and, where the API supports it, use native structured-output or JSON-schema modes, which constrain generation so the output parses. Always validate in code anyway. Put long documents near the top of the prompt and the question or instructions at the end: Anthropic's documentation reports this ordering can improve response quality by up to 30% in its tests on complex multi-document inputs.
Templates and variables
Production prompts are templates: fixed text with variables filled at run time. Keep templates in version control, give them IDs, and log which template version produced each output.
from string import Template
CLASSIFY_V3 = Template('''<instructions>
Classify the ticket into exactly one of: $categories.
Return JSON: {"category": "...", "confidence": "high|low"}.
</instructions>
<ticket>
$ticket
</ticket>''')
def render(ticket: str) -> str:
cats = "billing, bug, feature_request, account_access, other"
# Template.substitute does not re-scan inserted text, so a ticket
# containing "$categories" stays literal.
return CLASSIFY_V3.substitute(categories=cats, ticket=ticket.strip())
print(render("I was charged twice this month."))
Using string.Template instead of f-strings or str.format avoids clashes with the literal braces in the JSON example.
Negative instructions
"Don't do X" instructions are weaker than positive ones, because they name the unwanted behaviour without saying what to do instead. Prefer "Write in flowing prose paragraphs" over "Don't use bullet points", and explain why a rule exists ("this will be read aloud by a speech engine, so avoid symbols"), which helps the model generalise. Keep hard constraints, but pair each with the desired alternative.
Testing prompts systematically
A prompt that worked on the three inputs you tried is an anecdote. Professionals build a prompt eval set: typically 50 to 500 realistic inputs with expected outputs or grading criteria, including edge cases and past failures. Every prompt change is run against the whole set before it ships.
import json
from collections import Counter
def evaluate(prompt_fn, model_fn, cases):
# prompt_fn: input -> prompt; model_fn: prompt -> raw text; cases: list of dicts
results = Counter()
failures = []
for case in cases:
raw = model_fn(prompt_fn(case["input"]))
try:
pred = json.loads(raw)["category"]
except (json.JSONDecodeError, KeyError, TypeError):
results["parse_error"] += 1
failures.append((case["input"], raw))
continue
ok = pred == case["expected"]
results["correct" if ok else "wrong"] += 1
if not ok:
failures.append((case["input"], pred))
n = len(cases)
return {k: v / n for k, v in results.items()}, failures
# Demo with a stand-in model (uses render() from the template example above);
# replace fake_model with a real API call.
def fake_model(prompt):
return '{"category": "billing"}' if "charged" in prompt else '{"category": "bug"}'
cases = [{"input": "I was charged twice", "expected": "billing"},
{"input": "App crashes on login", "expected": "bug"},
{"input": "Please add dark mode", "expected": "feature_request"}]
print(evaluate(render, fake_model, cases))
Track accuracy, parse-error rate, cost and latency per prompt version. Because sampling is stochastic, run each case more than once (or at temperature 0 where supported) and compare variants on the same cases. Differences of a couple of percent on 50 cases are within noise; the evaluation lessons (evaluating-ai-systems) cover confidence intervals and model-graded rubrics.
Using models to help write prompts
Models are useful prompt-writing assistants, provided the eval set stays the judge. Common uses: asking a model to critique a draft prompt for ambiguity or contradictions; asking it to generate additional diverse few-shot examples from two or three hand-written seeds (Anthropic's documentation suggests this), which you then check by hand; asking it to produce adversarial and edge-case inputs for your eval set; and analysing a batch of failures to propose a hypothesis about what the prompt is missing. Automated prompt-optimisation tools take this further by proposing many variants and scoring them on a labelled set. All of these speed up iteration, but they can also overfit: a prompt tuned until it aces 50 cases may have memorised their quirks. Keep a held-out set of cases that you never look at while editing, and confirm the final prompt on it, exactly as you would hold out test data when training a model.
Common pitfalls
- Unrepresentative examples: few-shot examples that are all easy, all one class, or inconsistent with the instructions.
- Forcing chain-of-thought on reasoning models: adds tokens and can degrade results; set the effort level instead.
- Showing reasoning to users by accident: if you ask for reasoning, tag it and strip it before display.
- Unvalidated structured output: even schema-constrained output can be semantically wrong; validate values, not just syntax.
- Prompt edits without regression tests: fixing one failure often breaks two other cases.
- Copying provider tricks across models: assistant prefill, magic phrases and formatting switches differ between providers and model generations; for example, Anthropic's documentation states that prefilling the assistant's response is no longer supported on its newer models. Check the current docs.
- Instruction sprawl: a 3,000-word system prompt of accumulated patches often contradicts itself. Refactor periodically.
In practice
Teams treat prompts as code: templated, versioned, reviewed and tested against an eval set in CI. A typical workflow is: write a clear brief with role, goal, constraints and output schema; add tags to separate data; establish a baseline score on the eval set; then change one thing at a time (add examples, restructure, decompose into a chain, switch model or reasoning effort) and keep only changes that improve the score at acceptable cost. Use self-consistency or larger reasoning effort selectively for high-stakes items, and cheaper models for easy chain steps. Re-run the eval whenever the provider updates the model.
Key takeaways
- Few-shot examples teach format and edge cases more precisely than instructions, but must be relevant, diverse, consistent and clearly tagged.
- Chain-of-thought helps mostly on math and symbolic reasoning; with reasoning models, describe goals and constraints and set effort rather than scripting steps.
- Self-consistency improves accuracy only when single-sample accuracy is reasonably high and errors are not systematic, and it multiplies cost.
- Delimiters, explicit schemas, templates and prompt chaining make prompts reliable, testable and maintainable.
- A prompt change is not an improvement until it beats the baseline on a representative eval set.
Terms in this lesson
- In-context learning
- A model's ability to perform a task from instructions and examples in the prompt without updating its weights.
- Few-shot prompting
- Including a small number of example inputs and desired outputs in the prompt to demonstrate the task.
- Chain-of-thought (CoT)
- Prompting a model to produce intermediate reasoning steps before its final answer.
- Reasoning model
- A model trained to generate an internal reasoning process before answering, making explicit step-by-step prompting largely unnecessary.
- Self-consistency
- Sampling several independent reasoning paths and returning the most frequent final answer.
- Prompt chaining
- Splitting a task into a sequence of prompts in which each step's output becomes input to the next.
- Prompt template
- Reusable prompt text with named variables that are filled in at run time.
- Prompt eval set
- A fixed collection of representative inputs with expected outputs or grading criteria used to compare prompt versions.
Check your understanding
- 1.
A single sample is correct with probability 0.7. Assuming independent samples and that all wrong answers agree (strict majority needed), what is the accuracy of a 3-sample majority vote?
- 2.
You are using a model with built-in reasoning (thinking) for a hard planning task. Which prompt change is most consistent with current official guidance?
- 3.
Your few-shot classifier labels most inputs 'positive' even when they are negative. All four examples in the prompt are positive. What is the most likely fix?
- 4.
Which statement about chain-of-thought prompting is best supported by the research covered in this lesson?
- 5.
Prompt A scores 82% and prompt B 84% on a 50-case eval set, each run once. What should you conclude?
Exercises
Work each problem before opening the solution.
- Exercise 1Core
Rewrite this weak prompt into a structured, production-ready prompt with a role, tagged inputs, positive instructions and an exact output schema:
"Look at this review and tell me if it's good or bad. Don't be wordy. Don't make stuff up. {review}"
Show solution
You analyse customer reviews for an online furniture store. Your output feeds a dashboard, so it must be valid JSON that our code can parse. <instructions> Read the review in <review>. Decide its overall sentiment toward the product: "positive", "negative" or "mixed". Base your judgment only on the review text; if the review does not express an opinion, use "mixed" and set evidence to "". Quote the single phrase from the review that best supports your label. </instructions> <output_format> {"sentiment": "positive|negative|mixed", "evidence": "<verbatim quote>"} </output_format> <review> {{review}} </review>Improvements: a concrete role and purpose; data separated with tags; "don't be wordy" replaced by a strict schema; "don't make stuff up" replaced by the positive rule "base your judgment only on the review text" plus a verbatim quote requirement that can be checked in code; an explicit fallback for unclear inputs.
- Exercise 2Core
Compute the accuracy of self-consistency with n = 5 samples when single-sample accuracy is p = 0.4, under the pessimistic assumption that all wrong answers agree. Compare with p = 0.4 for a single sample and explain the result.
Show solution
We need at least 3 correct out of 5, X ~ Binomial(5, 0.4):
- P(X=3) = 10 × 0.4^3 × 0.6^2 = 10 × 0.064 × 0.36 = 0.2304
- P(X=4) = 5 × 0.4^4 × 0.6 = 5 × 0.0256 × 0.6 = 0.0768
- P(X=5) = 0.4^5 = 0.01024
Total = 0.31744 ≈ 31.7%, which is worse than a single sample's 40%. When the model is more often wrong than right and its errors agree, majority voting amplifies the wrong answer. Self-consistency helps when p > 0.5 under this assumption, or when wrong answers scatter so the correct answer wins a plurality.
- Exercise 3Challenge
Extend the lesson's
evaluateharness to (a) run each casektimes, (b) report mean accuracy and the fraction of cases whose answers were not identical across runs (an instability rate), and (c) compare two prompt functions on the same cases. Use a stand-in model that is random so the code runs without an API.Show solution
import json, random def run_case(prompt_fn, model_fn, case, k): preds = [] for _ in range(k): try: preds.append(json.loads(model_fn(prompt_fn(case["input"])))["category"]) except (json.JSONDecodeError, KeyError, TypeError): preds.append(None) # parse failure counts as wrong return preds def evaluate_k(prompt_fn, model_fn, cases, k=5): correct, unstable = 0, 0 for case in cases: preds = run_case(prompt_fn, model_fn, case, k) correct += sum(p == case["expected"] for p in preds) unstable += len(set(preds)) > 1 n = len(cases) return {"accuracy": correct / (n * k), "instability": unstable / n} def noisy_model(prompt): label = "billing" if "charged" in prompt else "bug" if random.random() < 0.2: # 20% random flips label = random.choice(["billing", "bug", "other"]) return json.dumps({"category": label}) cases = [{"input": "I was charged twice", "expected": "billing"}, {"input": "App crashes on login", "expected": "bug"}, {"input": "Please add dark mode", "expected": "feature_request"}] prompt_a = lambda x: f"Classify: {x}" prompt_b = lambda x: f"<ticket>{x}</ticket> Return JSON with a category." random.seed(1) for name, p in [("A", prompt_a), ("B", prompt_b)]: print(name, evaluate_k(p, noisy_model, cases, k=5))Each case is run k times; accuracy is averaged over all n × k runs; a case counts as unstable if its k predictions are not all identical. Both prompts are scored on the same cases. With seed 1 this prints accuracy 0.60 for A and about 0.53 for B, each with instability 0.33. Because the fake model ignores prompt wording entirely, that gap is pure sampling noise, which is itself the lesson: differences between prompts must exceed run-to-run noise before you trust them.
- Exercise 4Challenge
Design a three-step prompt chain that turns a 40-page vendor contract into a risk summary for a non-lawyer. For each step give: its input, its output format, the model tier you would use (small/large/reasoning) and an automatic check you would run before the next step.
Show solution
Step 1: Extraction. Input: the contract text (placed at the top of the prompt, instructions after it). Output: JSON array of
{clause_id, topic, quote}for clauses on termination, liability, indemnity, payment, data protection and auto-renewal. Model: large model with a long context (the cost is mostly input tokens). Check: the JSON parses; everyquoteappears verbatim in the source (string search); each required topic is present or explicitly markednot_found.Step 2: Risk assessment. Input: the step 1 JSON plus the company's contract policy. Output: JSON
{clause_id, risk: low|medium|high, reason, policy_rule}. Model: reasoning model, since this compares clauses to rules. Check: every clause_id from step 1 is assessed exactly once; eachpolicy_ruleexists in the policy; anyhighitems are routed to a human lawyer.Step 3: Summary. Input: step 2 JSON only. Output: a one-page plain-English summary with a table of high and medium risks. Model: small or mid-sized model (it is a writing task over clean, short input). Check: every high-risk clause_id is mentioned; a length limit; a readability check (for example, average sentence length).
The checks stop errors from propagating, and each step can be evaluated and improved independently.
Further reading
- paperTom B. Brown et al., Language Models are Few-Shot Learners (2020)
- paperJason Wei et al., Chain-of-Thought Prompting Elicits Reasoning in Large Language Models (2022)
- paperXuezhi Wang et al., Self-Consistency Improves Chain of Thought Reasoning in Language Models (2022)
- paperZayne Sprague et al., To CoT or not to CoT? Chain-of-thought helps mainly on math and symbolic reasoning (2024)
- docsAnthropic, Prompting best practices (Claude documentation)
- docsOpenAI, Reasoning best practices (API documentation)
Go further
Sources
Fact-checked and last reviewed 2026-11-05