Prompt Patterns and System Prompts: Programming in Plain English

Prompting is programming with natural language specs. Learn the patterns that make LLM output reliable.

Intro

Same Model, Different Prompt

Two people ask the same model to do the same job. One gets a clean, usable answer every time. The other gets rambling paragraphs that break their code half the time. The model is identical. The only difference is the prompt.

  • Same model
  • Different prompts
  • Very different results

Where We Are

Last time we looked at why language models hallucinate, and saw that clear context and grounding reduce the problem. Today we start the prompting block of the course with the foundation: prompt patterns and system prompts. By the end you will write prompts like specifications and wrap them in reusable Python code.

  • Previous: hallucination
  • Today: prompt patterns
  • Then: in-context learning

Prompting Is Programming

Here is the core idea. Prompting is programming with natural language specifications. The model is a very capable but literal executor of whatever you describe. If your spec is vague, it fills the gaps with guesses, and those guesses are what you experience as bad output.

  • Natural language is the spec
  • Gaps become guesses
  • Clarity is the skill

Roles and Message Format

Three Roles

Modern chat models do not take a single string. They take a list of messages, and each message has a role. There are three you must know: system, user, and assistant. Each role carries a different kind of authority and purpose.

  • System: the rules
  • User: the request
  • Assistant: the reply

Who Writes What

The system message is written by the developer. It defines who the model is, what rules it follows, and how it should answer. The user message carries the end user's request. The assistant message is what the model produced, and you also include earlier assistant turns to give the model its conversation history.

  • Developer writes system
  • End user writes user
  • Model writes assistant

Provider-Neutral Format

Providers differ in small details, but the shape is the same everywhere. A provider-neutral format is just a list of dictionaries, each with a role and a content field. A conversation might start with a system message, then a user message, then an assistant reply, then another user message. The model reads the entire list on every call, because it has no memory between calls.

  • List of role and content
  • Full history every call
  • No hidden memory

Instruction Hierarchy

Roles also form an instruction hierarchy. When a system rule and a user request conflict, well-built models and applications favor the system message. So you place durable rules, such as safety limits and output format, in the system prompt, and keep the task specific content in the user message.

  • System outranks user
  • User outranks documents
  • Durable rules go on top

The Anatomy of a Good Prompt

Role, Context, Task, Format

Now the patterns. The first and most useful is a four part structure: role, context, task, and format. Role says who the model should act as. Context gives the facts it needs. Task states exactly what to do. Format describes the shape of the answer.

  • Role: who
  • Context: what it needs
  • Task and format: what and how

Each Part Removes Guesses

Why does this help? Because each part removes a family of guesses. Without a role, the model picks a tone. Without context, it invents or generalizes. Without a task, it chooses its own goal. Without a format, it chooses prose, and prose is hard for programs to parse.

  • Role fixes tone
  • Context fixes facts
  • Format fixes shape

Use Delimiters

The second pattern is delimiters. When your prompt mixes instructions with data, such as an email or a document, mark the boundary clearly. Use triple quotes, XML style tags, or markdown fences. The model then knows which part is the thing to process and which part is the instruction.

  • Separate data from instructions
  • Tags, quotes, or fences
  • Clear boundaries reduce errors

Say What To Do

Third, state explicit constraints, and prefer positive instructions. Saying write in plain sentences works better than saying do not use jargon, because a description of what to do gives the model a target, while a prohibition only marks one place to avoid. Use a negative rule only when there is no clean positive form.

  • Prefer positive instructions
  • Targets beat prohibitions
  • Negatives only when needed

Audience and Length

Fourth, specify the audience and the length. Explain TCP to a ten year old and explain it to a network engineer are very different tasks. In the same way, answer in at most three sentences, or return exactly five bullet points, turns a fuzzy request into something you can check.

  • Name the reader
  • Set a length limit
  • Make output checkable

Decompose Tasks

Fifth, decompose big tasks. A single prompt that says read this contract, find risks, rewrite the clauses, and draft an email asks for four jobs at once. Split it into a chain of smaller prompts, where each output feeds the next. Each step is simpler to write, test, and debug.

  • One job per prompt
  • Outputs feed the next step
  • Easier to test and debug

Worked Example: Support Email Classifier

The Task: Route Emails

Let us apply this to a real task. A company wants to route incoming support emails into categories: billing, bug report, feature request, or other. The first attempt at a prompt looks like this: classify this email. Then the email text pasted below it.

  • Billing
  • Bug report
  • Feature request
  • Other

Before: Inconsistent Output

Imagine an email saying: I was charged twice this month and the export button crashes the app. What does the weak prompt return? Maybe a paragraph that says this email seems to be about a few issues, including billing. Another run says it is a complaint. A third says urgent. None of these plug into a routing system.

  • Free-form answers
  • Different every run
  • Cannot route automatically

After: Structured Prompt

Now rewrite it with the patterns. Role: you are a support triage assistant for a software company. Task: assign the email to exactly one category. Context: the categories are billing, bug, feature request, and other, with a short definition of each. Delimiters: the email goes inside email tags. Format: respond with only the category name in lowercase.

  • Role and task
  • Category definitions
  • Delimited email
  • Strict output format

Fixing Ambiguity

But our email has two problems at once, billing and a crash. The rewritten prompt exposed a gap in the spec, so we add a rule: if several categories apply, choose the one the customer mentions first. Now both answers are predictable, and the output is one word we can match with a simple string comparison. Notice that writing a better prompt forced us to make a product decision.

  • Two issues in one email
  • Add a tie-break rule
  • Output is now deterministic

Testable Prompts

To measure the improvement, imagine running both prompts on twenty emails. The vague prompt gives you twenty differently shaped answers, and you must read each by hand. The structured prompt gives twenty single words, and you can count matches against your labels in one line of code. Even before accuracy, the prompt became testable, and that is the real win. We will build systematic evaluation in a later lesson.

  • Machine-readable output
  • Easy to compare to labels
  • Evaluation comes later

System Prompt Design

Anatomy of a System Prompt

Now let us design a full system prompt. Think of it as the job description and handbook you give a new employee before their first day. A solid system prompt has four parts: a persona, a set of rules, descriptions of any tools, and instructions for refusals.

  • Persona
  • Rules
  • Tool descriptions
  • Refusal behavior

Persona: Identity and Scope

The persona sets identity, scope, and tone. For example: you are Aria, the assistant for Northwind Bank's help center. You answer questions about accounts and cards in a calm, concise voice. Keep the persona tied to the job. A long theatrical backstory costs tokens and rarely improves answers.

  • Name the job
  • Set tone
  • Skip long backstories

Rules: Short and Testable

Rules are the durable behaviors. Keep them short, numbered, and testable. For instance: answer only from the provided help articles; if the answer is not there, say you do not know and offer to connect a human; never ask for a full card number. Each rule should be something you could check by reading a transcript.

  • Numbered and concise
  • One behavior per rule
  • Verifiable from transcripts

Describe Your Tools

If the application uses tools, such as a function that looks up an order, describe each one in the system prompt or tool schema. Give its name, what it does, what arguments it takes, and when to use it or not use it. A tool with a vague description gets called at the wrong times. We will study tool calling properly in a later lesson.

  • Name and purpose
  • Arguments
  • When to use it

Refusal Behavior

Refusal behavior needs design too. Decide what the assistant should do when a request is out of scope or unsafe. A good instruction says to decline briefly, without lecturing, state what it can help with, and offer a next step. Without this, models either comply with things they should not, or refuse in long, unhelpful ways.

  • Decline briefly
  • Offer what you can do
  • Give a next step

Injection Hazard

A warning before we move on. Everything the model reads is just text in one context window, including text from users, web pages, and documents. A malicious email can contain a sentence like ignore your previous instructions. This is called prompt injection, and the system prompt alone cannot fully stop it. For now, remember to delimit untrusted data and treat it as data, never as commands. We will do a deep dive in the production lessons.

  • Untrusted text is in context
  • Delimit it as data
  • Deep dive later

Templates and Python

Prompt Templates

Prompts in real applications are not typed by hand each time. They are templates with variables: the customer's name, the email, the list of categories. A template keeps the fixed instructions in one place and fills in the changing parts at run time. That makes prompts versionable, reviewable, and testable like any other code.

  • Fixed text plus variables
  • Filled at run time
  • Versioned like code

The call_llm Wrapper

First, a provider-neutral wrapper. We define call_llm that takes a list of messages and returns the reply text. Inside, you plug in whichever provider client you use. The rest of your application never touches provider specifics, so switching models means editing one function.

  • One function boundary
  • Messages in, text out
  • Swap providers easily

Low Temperature for Tasks

Notice the temperature default of zero. For classification and extraction you want the most repeatable behavior, so keep sampling low, as we saw in the sampling lesson. Also keep the wrapper small. Retries, logging, and timeouts can be added later in this one place.

  • Temperature near zero
  • Repeatable outputs
  • Central place for retries

A PromptTemplate Class

Now the template class. A simple version uses Python's string format with named fields. A PromptTemplate stores the system text and the user text, and its render method fills in variables and returns the message list. If a variable is missing, it raises an error instead of silently sending a broken prompt.

  • Stores system and user text
  • render fills variables
  • Missing variable fails loudly

Putting It Together

Using it looks like this. We create the classifier template once, then for each email call render with the email text and the category list, and pass the result to call_llm. If you need loops or conditionals, such as listing a variable number of categories, Jinja templates handle that cleanly. For simple prompts, plain f-strings or format are enough.

  • Create template once
  • Render per email
  • Jinja for loops and logic

Treat Prompts Like Code

One safety habit with templates: when you insert untrusted text, place it inside delimiters and keep it out of the system message. Also store templates in version control, and change them with the same care as code, because a one word edit can change behavior across thousands of requests.

  • Version control
  • Untrusted text in delimiters
  • Small edits, big effects

Real-World Use

Internal Assistants

Where does this show up in practice? Internal assistants are one big use. A company builds a helper for HR questions or engineering docs, and the system prompt sets scope, tone, and what to do when the answer is unknown. The same assistant behaves consistently for every employee because the rules live in one place.

  • Scope and tone in system prompt
  • Consistent for everyone
  • Rules in one place

Extraction Pipelines

Another is extraction. Given an invoice, a contract, or a ticket, you ask the model to pull out specific fields such as vendor, date, and total. Delimiters mark the document, constraints say what to do when a field is missing, and format rules make the output easy to parse. Later we will make that output strictly structured with schemas.

  • Pull fields from documents
  • State what to do if missing
  • Schemas come later

Common Mistakes

Mistake: Vague Instructions

Now the common mistakes. Mistake one is vague instructions. Make it better, be concise, be professional: these words mean different things to different readers. Replace them with measurable specs, like at most two sentences, no greeting, and address the customer by first name.

  • Words without measures
  • Replace with checkable specs
  • Numbers beat adjectives

Mistake: Contradictions

Mistake two is contradictory rules. One line says always answer in one sentence, and another says always explain your reasoning in detail. The model must break one of them, and you cannot predict which. When a prompt grows over months of patches, review it end to end, and state priorities explicitly, such as safety rules override style rules.

  • Rules that collide
  • Audit the whole prompt
  • State priorities explicitly

Mistake: Stuffing Everything

Mistake three is stuffing everything in. Teams paste the whole handbook, every edge case, and every past incident into the system prompt. The result is slower, more expensive calls, and important rules get buried in the middle. Keep the prompt focused, and move large reference knowledge to retrieval, which we will cover in the RAG lessons.

  • Costs more and runs slower
  • Key rules get buried
  • Use retrieval for big knowledge

Test Before You Trust

One more habit to avoid is changing a prompt based on a single bad output. Prompts are tested by many examples, not one. Keep a small set of realistic test inputs, rerun them after every edit, and you will see whether a change helps or quietly breaks something else.

  • Keep a small test set
  • Rerun after each edit
  • Catch regressions

Recap and Next Lesson

Recap: Patterns

Let us recap. Prompting is programming with natural language specs. Messages have roles: system for durable rules, user for requests, assistant for replies. The key patterns are role, context, task, and format, plus delimiters, explicit constraints stated positively, audience and length, and decomposed tasks.

  • Roles and hierarchy
  • Role, context, task, format
  • Delimiters, constraints, decomposition

Recap: Systems and Code

A good system prompt has a persona, short testable rules, tool descriptions, and refusal behavior, and it treats untrusted text as data. In code, wrap your provider in a call_llm function and keep prompts in templates. Avoid vague instructions, contradictions, and stuffing.

  • Four-part system prompt
  • call_llm and templates
  • Three mistakes to avoid

Next: In-Context Learning

Next time, we add one of the most powerful tools in the prompt toolbox: examples. In the next lesson, few-shot prompting and in-context learning, we will see how showing the model a few input and output pairs can teach it a task without changing a single weight, and why it works.

  • Examples inside the prompt
  • No weight updates
  • Subscribe for the next lesson