Few-shot and structured prompting
A model does whatever the prompt steers it toward. Two cheap, powerful levers control that: showing it worked examples, and demanding a fixed output shape.
Few-shot prompting means putting a handful of example input→output pairs in the prompt before the real question. The model copies the pattern it sees. Zero examples ("zero-shot") is just asking; a few examples ("few-shot") shows it exactly what "good" looks like — the format, the tone, the level of detail.
The second lever is the output schema: an explicit instruction like Respond as JSON with keys: sentiment, score. Without it the model writes prose you can't parse; with it you get back something your code can actually read with json.loads.
None of this needs a model to *learn*. A prompt is just a string you assemble — a task line, the examples, the schema instruction, and the open question — joined together. In production that string becomes the body of an API request; here you build the string and stop there, because the string IS the engineering.
Syntax
# A prompt is just assembled text:
parts = [task]
for inp, out in examples:
parts.append(f"Input: {inp}\nOutput: {out}")
parts.append("Respond as JSON with keys: " + ", ".join(fields))
parts.append(f"Input: {query}\nOutput:")
prompt = "\n\n".join(parts)Worked examples
One example block (input → output pair)
def format_example(inp, out):
return f"Input: {inp}\nOutput: {out}"
print(format_example("great", "positive"))
# Output:
# Input: great
# Output: positivePinning the output shape with a schema line
def schema_instruction(fields):
return "Respond as JSON with keys: " + ", ".join(fields)
print(schema_instruction(["sentiment", "score"]))
# Output:
# Respond as JSON with keys: sentiment, scoreAssembling the whole few-shot prompt
def build_few_shot_prompt(task, examples, fields, query):
parts = [task]
for inp, out in examples:
parts.append(f"Input: {inp}\nOutput: {out}")
parts.append("Respond as JSON with keys: " + ", ".join(fields))
parts.append(f"Input: {query}\nOutput:")
return "\n\n".join(parts)
examples = [("great", "positive"), ("terrible", "negative")]
print(build_few_shot_prompt("Classify the sentiment.", examples, ["sentiment"], "it was fine"))
# Output:
# Classify the sentiment.
#
# Input: great
# Output: positive
#
# Input: terrible
# Output: negative
#
# Respond as JSON with keys: sentiment
#
# Input: it was fine
# Output:Common mistakes & gotchas
Example order is a real lever
Models weight later examples more heavily, so the order you append them in genuinely changes behaviour. If you shuffle the examples you may get a different answer. Keep the order deliberate, and if results are inconsistent, suspect the examples before you blame the model.
A schema instruction is a request, not a guarantee
Telling the model Respond as JSON makes the right shape far more likely — but a model can still return malformed or extra text. Always parse defensively (try/except around json.loads) rather than trusting the shape blind. The schema line reduces failures; it doesn't eliminate them.
The prompt is plain text — whitespace counts
The model only sees the characters you assemble, so a missing \n or a join with "" instead of "\n\n" runs your examples together and confuses it. Build the string carefully and print() it once to eyeball the layout before you ever send it.
Why it matters
Prompting is the cheapest way to change what an AI feature does — no training, no fine-tuning, just better text. Few-shot examples plus a pinned output schema turn a chatty, unreliable model into something whose output your code can actually parse and depend on, and assembling that prompt cleanly is the first thing every AI engineer does.