Adrian Love← Back to portfolio

Guide · Prompt engineering

Prompt engineering techniques that actually move the needle.

A practical field guide to the prompting patterns I use every day when building AI-assisted apps — few-shot prompting, chain-of-thought prompting, role prompting, and structured-output prompting — with examples pulled from real projects like the communication logic inside Uspeak.

1. What prompt engineering really is

Prompt engineering is the craft of shaping the input to a language model so it produces a useful, predictable output. It is part writing, part interface design, and part product thinking. The model is the runtime; the prompt is the program.

The techniques below aren't tricks — they're patterns. Each one changes how the model reasons about your request, and each has a clear moment when it's the right tool.

2. Zero-shot prompting

Zero-shot is the baseline: you describe the task in plain language with no examples. It works surprisingly well for common tasks the model has seen many times in training (summarise, translate, rewrite).

Rewrite the following message so it sounds calmer
and less accusatory, without changing the underlying request.

Message: "You never listen when I talk about money."

Use zero-shot first. If the output drifts, that's the signal to reach for few-shot or chain-of-thought.

3. Few-shot prompting

Few-shot prompting gives the model two to five worked examples before the real input. The examples teach format and tone far more reliably than instructions alone.

In Uspeak — a communication app that helps people rephrase harsh messages — the rewriter is a few-shot prompt. A handful of before/after pairs is enough to lock in a consistent voice:

You rewrite messages so they stay honest but land softer.

Harsh: "You never listen when I talk about money."
Calm:  "When money comes up, I feel unheard. Can we sit down with it tonight?"

Harsh: "You always leave the dishes for me."
Calm:  "The dishes have piled up again — can we split them this week?"

Harsh: "{{user_message}}"
Calm:

Two notes that took me a while to learn: keep example formatting identical to the target output, and put the hardest edge case last — the model anchors on recent examples.

4. Chain-of-thought prompting

Chain-of-thought (CoT) asks the model to reason step-by-step before answering. It dramatically improves accuracy on tasks with multiple sub-decisions — classification with overlapping categories, multi-step transformations, anything where a single jump to the answer tends to be wrong.

The simplest version is one line:

Think through this step by step before giving your final answer.

A stronger version is structured CoT, where you name the steps:

Classify this message on three axes:
  1. Emotion (anger / sadness / fear / neutral)
  2. Intent (request / complaint / accusation / question)
  3. Severity (low / medium / high)

For each axis, briefly explain your reasoning, then output a JSON
object with the three fields.

Message: "{{user_message}}"

For production, hide the reasoning from end users — return only the final structured field — but keep it in the prompt. The reasoning step is doing the work.

5. Role and system prompting

Role prompting sets the model's persona and constraints up front, usually in the system message. It's the cheapest way to make a model behave consistently across many calls.

You are a calm, non-judgemental communication coach.
You never moralise. You never tell the user they were wrong.
You only suggest one rewrite at a time, in the user's own voice.

Treat the system prompt as configuration, not copy. Version it alongside your code.

6. Structured-output prompting

When the output feeds another piece of software, ask for JSON and show the exact schema. Pair it with the API's JSON-mode or tool-calling support where available.

Return ONLY valid JSON matching this TypeScript type:

type Result = {
  rewrite: string;
  tone: "calm" | "warm" | "firm";
  changed_phrases: string[];
};

Two safety nets: validate the response with Zod on the way back, and fall back to a second call with the validator error appended when parsing fails.

7. Putting it together: a real workflow

In practice these techniques stack. A typical Uspeak call is a role prompt for the coach persona, a short chain-of-thought to classify the message, a few-shot block of rewrite examples, and a structured-output instruction at the end. Each layer is small; together they make a fragile feature feel reliable.

The discipline I'd pass on: start with the simplest prompt that could work, add one technique at a time, and write evals as soon as you've shipped anything you care about.

Want help with this on your product?

I build AI-assisted apps and design prompt pipelines for small teams. Get in touch →