Prompt Engineering

Prompt engineering is the practice of structuring model inputs so an LLM reliably produces the output you need. In production it is less about clever phrasing and more about engineering discipline: clear instructions, well-delimited context, examples, a fixed output contract, and an evaluation set that tells you whether a change helped.

This page covers prompt structure, core techniques (few-shot, chain-of-thought, self-consistency), structured output, prompt injection defence, and an evaluation-driven workflow. Parent topic: LLM Engineering.


1. Anatomy of a Prompt

Anatomy of a Production Prompt System / Role persona, rules, constraints, refusal policy Context retrieved docs, user data, tool results — delimited with tags Examples (few-shot) 2–5 input → output pairs covering edge cases Task / Instruction the specific request, stated explicitly Output Format JSON schema, XML tags, length, style Order matters: long context first, the question last — models attend best to the end of the prompt.

Most chat APIs separate a system prompt (stable instructions, role, constraints) from user turns (per-request content). Keep the system prompt stable to benefit from prompt caching, and put variable data in the user turn.

2. Core Techniques

Reasoning Techniques Compared Zero-shot Instruction Answer Few-shot Examples + Q Answer Chain-of-Thought Q + think step Reasoning Answer Self-Consistency Sample k paths k answers Majority vote Cost grows left → right: more tokens and calls buy accuracy on multi-step problems.

Zero-shot: instruction only. Works for well-known tasks on capable models. Few-shot: include examples; the model imitates their format and decision boundary. Choose diverse examples including edge cases, and vary them so the model does not copy surface details.

Chain-of-thought (CoT): ask the model to reason before answering (or use a model with built-in extended thinking). This improves multi-step arithmetic, logic, and planning, at the cost of latency and tokens. Ask for the reasoning inside <thinking> tags and the answer in <answer> tags so you can parse only the answer.

Self-consistency: sample several CoT paths at non-zero temperature and take the majority answer. Prompt chaining: split a complex task into sequential calls (extract → analyse → write), each with a focused prompt — easier to debug and evaluate than one giant prompt.

3. Structured Output

When code consumes the output, define a contract. Prefer native mechanisms — JSON mode, tool/function schemas, or constrained decoding — over "please return JSON". See Function Calling / Structured Output.

import json
from anthropic import Anthropic

client = Anthropic()
SYSTEM = """You classify customer support tickets.
Categories: billing, bug, feature_request, account, other.
Return only JSON: {"category": str, "urgency": 1-5, "summary": str (max 20 words)}.
Urgency 5 means data loss or full outage; 1 means a cosmetic question."""

FEW_SHOT = [
    {"role": "user", "content": "<ticket>I was charged twice this month.</ticket>"},
    {"role": "assistant", "content": '{"category": "billing", "urgency": 3, "summary": "Customer reports a duplicate charge this month."}'},
]

def classify(ticket: str) -> dict:
    msg = client.messages.create(
        model="claude-sonnet-4-5",          # use your current model id
        max_tokens=200,
        temperature=0,
        system=SYSTEM,
        messages=FEW_SHOT + [{"role": "user", "content": f"<ticket>{ticket}</ticket>"}],
    )
    out = json.loads(msg.content[0].text)
    assert out["category"] in {"billing", "bug", "feature_request", "account", "other"}
    return out

print(classify("The export button crashes the app and I lost my report."))

Always validate the parsed result (Pydantic or JSON Schema) and have a retry path that feeds the validation error back to the model.

4. Prompt Injection and Safety

Any text the model reads — web pages, emails, retrieved documents, tool outputs — can contain instructions. The model cannot reliably distinguish your instructions from injected ones, so treat prompting as a mitigation, not a security boundary.

See also OWASP Top 10 for LLMs.

5. Evaluation-Driven Iteration

Prompt Development Loop Define task success criteria Build eval set 50–200 cases Draft prompt v1 Run + score auto + human Analyze fails categorize errors revise prompt (one change at a time), re-run full eval Version prompts like code: store in git, diff outputs, gate deploys on eval regressions.

Prompt changes without measurement are guesswork. Build a fixed evaluation set of real inputs with expected outputs or grading rubrics, score each prompt version (exact match, schema validity, an LLM-as-judge rubric, or human review), and only ship changes that improve the aggregate without regressing important slices.

Change one thing at a time, keep a changelog, and re-run the full set when you switch model versions — a prompt tuned for one model is not guaranteed to transfer. For RAG pipelines see Evaluation (RAGAS); for operations see LLMOps.

6. Common Pitfalls

7. Ordering and Long Context

Prompt Layout That Caches Well System prompt role, rules, output contract (stable) Examples few-shot pairs (stable) Context retrieved docs in <document> tags (per request) Question user input last, restate the task Stable content first lets the provider cache the prefix; variable content goes last.

Order matters for cost and for quality. Providers that support prompt caching reuse computation for an identical prefix, so place stable material (system instructions, tool definitions, few-shot examples) first and per-request material last. With long documents, a common pattern that works well is to put the documents near the top of the user turn, each wrapped in tags with metadata such as source and date, and to put the question and output instructions after them. For very long inputs, asking the model to first quote the passages relevant to the question, then answer from those quotes, reduces answers built on material that is not in the documents and makes the result easy to verify.

8. A Worked Example: Iterating a Classifier Prompt

Consider routing support emails into four queues. Version 1 is a single sentence: "Classify this email as billing, technical, account or other." On a 200-email labeled set it scores, say, a modest accuracy, and the confusion matrix shows the errors concentrate on password-reset emails, which humans label account but the model labels technical. Version 2 adds a one-line definition of each queue, including "password resets and login problems are account". Version 3 adds three short examples, one per frequently confused pair, and requires output as a JSON object with a queue field from a fixed enum. Each version is scored on the same set and the change is kept only if it improves the metric without regressing other classes. The specific numbers will vary by model; the method is the point: one change at a time, measured against a fixed set, with the confusion matrix telling you what to change next.

9. Sampling Parameters and Model Choice

SettingGuidance
TemperatureLow (0 to 0.3) for extraction, classification and code; higher for brainstorming and varied phrasing. Note that temperature 0 reduces but does not always eliminate variation between runs.
Max output tokensSet a ceiling that fits the expected answer plus headroom; truncated JSON is a common production failure.
Stop sequencesStop at a closing tag to avoid paying for trailing text.
Reasoning / thinking budgetEnable for multi-step problems; disable for simple lookups where it adds latency without benefit.
Model tierPrototype on a capable model to learn what is possible, then test whether a smaller, cheaper model passes the same evaluation set.

10. Prompts in Production

Automated prompt optimization is also possible: frameworks such as DSPy treat instructions and few-shot examples as parameters and search over them against a metric, which works well once a reliable evaluation set exists.

Further reading. Brown et al. (2020), "Language Models are Few-Shot Learners"; Wei et al. (2022), "Chain-of-Thought Prompting Elicits Reasoning in Large Language Models", arXiv:2201.11903; Wang et al. (2022), "Self-Consistency Improves Chain of Thought Reasoning"; Kojima et al. (2022), "Large Language Models are Zero-Shot Reasoners"; Yao et al. (2022), "ReAct: Synergizing Reasoning and Acting in Language Models"; Liu et al. (2023), "Lost in the Middle: How Language Models Use Long Contexts"; Greshake et al. (2023), "Not What You've Signed Up For" (indirect prompt injection); the Anthropic and OpenAI prompt engineering guides; OWASP Top 10 for LLMs.